diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..670bcb2e25 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +.git/ +.idea/ +.settings/ +*/target/ +dspace/modules/*/target/ diff --git a/.gitignore b/.gitignore index 223473806d..08023a5ad2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ tags /bin/ .project .classpath +.checkstyle ## Ignore project files created by IntelliJ IDEA *.iml @@ -25,7 +26,6 @@ dist/ nbdist/ nbactions.xml nb-configuration.xml -META-INF/ ## 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) @@ -39,3 +39,6 @@ META-INF/ ##Mac noise .DS_Store + +##Ignore JRebel project configuration +rebel.xml diff --git a/Dockerfile.jdk8 b/Dockerfile.jdk8 new file mode 100644 index 0000000000..c404ad451f --- /dev/null +++ b/Dockerfile.jdk8 @@ -0,0 +1,60 @@ +# This image will be published as dspace/dspace +# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details +# +# This version is JDK8 compatible +# - tomcat:8-jre8 +# - ANT 1.10.5 +# - maven:latest +# - note: +# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8 + +# Step 1 - Run Maven Build +FROM maven as build +WORKDIR /app + +# Copy the DSpace source code into the workdir (excluding .dockerignore contents) +ADD . /app/ +COPY dspace/src/main/docker/local.cfg /app/local.cfg + +RUN mvn package + +# Step 2 - Run Ant Deploy +FROM tomcat:8-jre8 as ant_build +ARG TARGET_DIR=dspace-installer +COPY --from=build /app /dspace-src +WORKDIR /dspace-src/dspace/target/${TARGET_DIR} + +# Create the initial install deployment using ANT +ENV ANT_VERSION 1.10.5 +ENV ANT_HOME /tmp/ant-$ANT_VERSION +ENV PATH $ANT_HOME/bin:$PATH + +RUN mkdir $ANT_HOME && \ + wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME + +RUN ant update_configs update_code update_webapps update_solr_indexes + +# Step 3 - Run tomcat +# Create a new tomcat image that does not retain the the build directory contents +FROM tomcat:8-jre8 +COPY --from=ant_build /dspace /dspace +EXPOSE 8080 8009 + +# Ant will be embedded in the final container to allow additional deployments +ENV ANT_VERSION 1.10.5 +ENV ANT_HOME /tmp/ant-$ANT_VERSION +ENV PATH $ANT_HOME/bin:$PATH + +RUN mkdir $ANT_HOME && \ + wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME + +ENV DSPACE_INSTALL=/dspace +ENV JAVA_OPTS=-Xmx2000m + +RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \ + ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ + ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \ + ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \ + ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \ + ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \ + ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2 diff --git a/Dockerfile.jdk8-test b/Dockerfile.jdk8-test new file mode 100644 index 0000000000..3cae9e4b66 --- /dev/null +++ b/Dockerfile.jdk8-test @@ -0,0 +1,64 @@ +# This image will be published as dspace/dspace +# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details +# +# This version is JDK8 compatible +# - tomcat:8-jre8 +# - ANT 1.10.5 +# - maven:latest +# - note: expose /solr to any host; provide /rest over http +# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8-test + +# Step 1 - Run Maven Build +FROM maven as build +WORKDIR /app + +# Copy the DSpace source code into the workdir (excluding .dockerignore contents) +ADD . /app/ +COPY dspace/src/main/docker/local.cfg /app/local.cfg + +# Provide web.xml overrides to make webapps easier to test +COPY dspace/src/main/docker/test/solr_web.xml /app/dspace-solr/src/main/webapp/WEB-INF/web.xml +COPY dspace/src/main/docker/test/rest_web.xml /app/dspace-rest/src/main/webapp/WEB-INF/web.xml + +RUN mvn package + +# Step 2 - Run Ant Deploy +FROM tomcat:8-jre8 as ant_build +ARG TARGET_DIR=dspace-installer +COPY --from=build /app /dspace-src +WORKDIR /dspace-src/dspace/target/${TARGET_DIR} + +# Create the initial install deployment using ANT +ENV ANT_VERSION 1.10.5 +ENV ANT_HOME /tmp/ant-$ANT_VERSION +ENV PATH $ANT_HOME/bin:$PATH + +RUN mkdir $ANT_HOME && \ + wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME + +RUN ant update_configs update_code update_webapps update_solr_indexes + +# Step 3 - Run tomcat +# Create a new tomcat image that does not retain the the build directory contents +FROM tomcat:8-jre8 +COPY --from=ant_build /dspace /dspace +EXPOSE 8080 8009 + +# Ant will be embedded in the final container to allow additional deployments +ENV ANT_VERSION 1.10.5 +ENV ANT_HOME /tmp/ant-$ANT_VERSION +ENV PATH $ANT_HOME/bin:$PATH + +RUN mkdir $ANT_HOME && \ + wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME + +ENV DSPACE_INSTALL=/dspace +ENV JAVA_OPTS=-Xmx2000m + +RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \ + ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ + ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \ + ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \ + ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \ + ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \ + ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2 diff --git a/LICENSES_THIRD_PARTY b/LICENSES_THIRD_PARTY index 38a739ca9f..b23938748d 100644 --- a/LICENSES_THIRD_PARTY +++ b/LICENSES_THIRD_PARTY @@ -1,19 +1,19 @@ -DSpace uses third-party libraries which may be distributed under different +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 +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 +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 --------------------------------------------------- @@ -199,8 +199,6 @@ https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines * 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) - * databene ContiPerf (org.databene:contiperf:2.3.4 - http://databene.org/contiperf) - * elasticsearch (org.elasticsearch:elasticsearch:1.4.0 - http://nexus.sonatype.org/oss-repository-hosting.html/elasticsearch) * 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) @@ -300,7 +298,7 @@ https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines * 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-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core) + * Hamcrest Core (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all) * 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/) diff --git a/README.md b/README.md index aa38a079d4..a62fc1943d 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,9 @@ Please be aware that, as a Java web application, DSpace requires a database (Pos and a servlet container (usually Tomcat) in order to function. More information about these and all other prerequisites can be found in the Installation instructions above. +## Dockerfile Usage +See the [DSpace Docker Tutorial](https://dspace-labs.github.io/DSpace-Docker-Images/). + ## Contributing DSpace is a community built and supported project. We do not have a centralized development or support team, diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml new file mode 100644 index 0000000000..77e27b8768 --- /dev/null +++ b/checkstyle-suppressions.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 0000000000..554e187641 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index c4ab59035d..3597126c94 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.dspace dspace-api @@ -50,6 +51,10 @@ true true + + org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor + + @@ -80,6 +85,7 @@ **/src/test/resources/** **/src/test/data/** **/.gitignore + **/src/main/resources/rebel.xml src/test/data/dspaceFolder/config/spiders/** src/main/java/org/apache/solr/handler/extraction/ExtractingParams.java @@ -205,14 +211,15 @@ setproperty - generate-test-resources + generate-test-resources + execute - project.properties['agnostic.build.dir']=project.build.directory.replace(File.separator,'/'); - println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']); + project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/'); + println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']); @@ -239,40 +246,39 @@ xml-maven-plugin 1.0.1 - - validate-ALL-xml-and-xsl - process-test-resources - - validate - - + + validate-ALL-xml-and-xsl + process-test-resources + + validate + + - - - - ${agnostic.build.dir}/testing - - **/*.xml - **/*.xsl - **/*.xconf - - - - - ${root.basedir} - - **/*.xml - **/*.xsl - **/*.xmap - - - + + + + ${agnostic.build.dir}/testing + + **/*.xml + **/*.xsl + **/*.xconf + + + + + ${root.basedir} + + **/*.xml + **/*.xsl + **/*.xmap + + + - maven-failsafe-plugin @@ -291,7 +297,6 @@ - org.hibernate @@ -304,13 +309,28 @@ - org.hibernate - hibernate-ehcache + org.hibernate + hibernate-ehcache + + + org.hibernate + hibernate-jpamodelgen + + + org.hibernate + hibernate-validator-cdi + ${hibernate-validator.version} org.springframework spring-orm + + org.glassfish + javax.el + 3.0.1-b10 + + org.dspace handle @@ -331,16 +351,6 @@ org.apache.jena apache-jena-libs pom - - - com.fasterxml.jackson.core - jackson-core - - - com.fasterxml.jackson.core - jackson-databind - - commons-cli @@ -351,8 +361,8 @@ commons-codec - commons-collections - commons-collections + org.apache.commons + commons-collections4 org.apache.commons @@ -385,7 +395,7 @@ javax.servlet - servlet-api + javax.servlet-api provided @@ -415,8 +425,8 @@ pdfbox - org.apache.pdfbox - fontbox + org.apache.pdfbox + fontbox org.bouncycastle @@ -496,16 +506,12 @@ h2 test - - org.databene - contiperf - test - org.mockito mockito-core test + org.rometools rome-modules @@ -569,9 +575,9 @@ commons-configuration - com.maxmind.geoip - geoip-api - 1.3.0 + com.maxmind.geoip2 + geoip2 + 2.11.0 org.apache.ant @@ -584,9 +590,9 @@ - org.elasticsearch - elasticsearch - 1.4.0 + org.apache.lucene + lucene-core + 4.10.4 @@ -672,7 +678,6 @@ joda-time joda-time - 2.9.2 javax.inject @@ -697,7 +702,7 @@ org.glassfish.jersey.core jersey-client - 2.22.1 + ${jersey.version} @@ -709,27 +714,19 @@ joda-time joda-time - - com.fasterxml.jackson.core - jackson-databind - - + + - com.fasterxml.jackson.core - jackson-core - 2.7.0 + org.dspace + orcid-jaxb-api + 2.1.0 - com.fasterxml.jackson.core - jackson-databind - 2.7.0 - - - com.fasterxml.jackson.core - jackson-annotations - 2.7.0 + org.json + json + 20180130 diff --git a/dspace-api/src/main/java/org/apache/solr/handler/extraction/ExtractingParams.java b/dspace-api/src/main/java/org/apache/solr/handler/extraction/ExtractingParams.java index 014d4e0d6b..c2015cdb19 100644 --- a/dspace-api/src/main/java/org/apache/solr/handler/extraction/ExtractingParams.java +++ b/dspace-api/src/main/java/org/apache/solr/handler/extraction/ExtractingParams.java @@ -19,147 +19,145 @@ 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"; + /** + * 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"; + /** + * 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. - *

- * To map a field, add a name like: - *

fmap.title=solr.title
- * - * 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 param prefix for mapping Tika metadata to Solr fields. + *

+ * To map a field, add a name like: + *

fmap.title=solr.title
+ * + * 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. - *

- * For example - *

-   * map.title=solr.title
-   * boost.solr.title=2.5
-   * 
- * will boost the solr.title field for this document by 2.5 - * - */ - public static final String BOOST_PREFIX = "boost."; + /** + * The boost value for the name of the field. The boost can be specified by a name mapping. + *

+ * For example + *

+     * map.title=solr.title
+     * boost.solr.title=2.5
+     * 
+ * 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 - *
-   *  literal.myField=Foo 
-   * 
- * - */ - public static final String LITERALS_PREFIX = "literal."; + /** + * Pass in literal values to be added to the document, as in + *
+     *  literal.myField=Foo
+     * 
+ */ + 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}. - *

- * See Tika's docs for what the extracted document looks like. - * - * @see #CAPTURE_ELEMENTS - */ - public static final String XPATH_EXPRESSION = "xpath"; + /** + * 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}. + *

+ * 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"; + /** + * 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"; + /** + * 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"; + /** + * 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"; + /** + * 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. - *

- * 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. - *

- * For instance, a Tika document may look like: - *

-   *  <html>
-   *    ...
-   *    <body>
-   *      <p>some text here.  <div>more text</div></p>
-   *      Some more text
-   *    </body>
-   * 
- * 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"; + /** + * 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. + *

+ * 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. + *

+ * For instance, a Tika document may look like: + *

+     *  <html>
+     *    ...
+     *    <body>
+     *      <p>some text here.  <div>more text</div></p>
+     *      Some more text
+     *    </body>
+     * 
+ * 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"; + /** + * 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 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. 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, 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 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. - *

- * 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"; + /** + * Optional. If specified, loads the file as a source for password lookups for Tika encrypted documents. + *

+ * 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"; } diff --git a/dspace-api/src/main/java/org/dspace/administer/CommunityFiliator.java b/dspace-api/src/main/java/org/dspace/administer/CommunityFiliator.java index 70b525347b..261e623130 100644 --- a/dspace-api/src/main/java/org/dspace/administer/CommunityFiliator.java +++ b/dspace-api/src/main/java/org/dspace/administer/CommunityFiliator.java @@ -17,7 +17,7 @@ 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.apache.commons.collections4.CollectionUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Community; import org.dspace.content.factory.ContentServiceFactory; @@ -30,13 +30,12 @@ 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 -{ +public class CommunityFiliator { protected CommunityService communityService; protected HandleService handleService; @@ -47,12 +46,10 @@ public class CommunityFiliator } /** - * * @param argv the command line arguments given * @throws Exception if error */ - public static void main(String[] argv) throws Exception - { + public static void main(String[] argv) throws Exception { // create an options object and populate it CommandLineParser parser = new PosixParser(); @@ -60,11 +57,11 @@ public class CommunityFiliator options.addOption("s", "set", false, "set a parent/child relationship"); options.addOption("r", "remove", false, - "remove a parent/child relationship"); + "remove a parent/child relationship"); options.addOption("p", "parent", true, - "parent community (handle or database ID)"); + "parent community (handle or database ID)"); options.addOption("c", "child", true, - "child community (handle or databaseID)"); + "child community (handle or databaseID)"); options.addOption("h", "help", false, "help"); CommandLine line = parser.parse(options, argv); @@ -73,57 +70,48 @@ public class CommunityFiliator String parentID = null; String childID = null; - if (line.hasOption('h')) - { + 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"); + .println("\nestablish a relationship: CommunityFiliator -s -p parentID -c childID"); System.out - .println("remove a relationship: CommunityFiliator -r -p parentID -c childID"); + .println("remove a relationship: CommunityFiliator -r -p parentID -c childID"); System.exit(0); } - if (line.hasOption('s')) - { + if (line.hasOption('s')) { command = "set"; } - if (line.hasOption('r')) - { + if (line.hasOption('r')) { command = "remove"; } - if (line.hasOption('p')) // parent - { + if (line.hasOption('p')) { // parent parentID = line.getOptionValue('p'); } - if (line.hasOption('c')) // child - { + if (line.hasOption('c')) { // child childID = line.getOptionValue('c'); } // now validate // must have a command set - if (command == null) - { + if (command == null) { System.out - .println("Error - must run with either set or remove (run with -h flag for details)"); + .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) - { + 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) - { + if (childID == null) { System.out.println("Error - a childID must be specified (run with -h flag for details)"); System.exit(1); } @@ -135,71 +123,57 @@ public class CommunityFiliator // we are superuser! c.turnOffAuthorisationSystem(); - try - { + 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) - { + if (parent == null) { System.out.println("Error, parent community cannot be found: " - + parentID); + + parentID); System.exit(1); } - if (child == null) - { + if (child == null) { System.out.println("Error, child community cannot be found: " - + childID); + + childID); System.exit(1); } - if ("set".equals(command)) - { + if ("set".equals(command)) { filiator.filiate(c, parent, child); - } - else - { + } else { filiator.defiliate(c, parent, child); } - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { System.out.println("Error - SQL exception: " + sqlE.toString()); - } - catch (AuthorizeException authE) - { + } catch (AuthorizeException authE) { System.out.println("Error - Authorize exception: " - + authE.toString()); - } - catch (IOException ioE) - { + + authE.toString()); + } catch (IOException ioE) { System.out.println("Error - IO exception: " + ioE.toString()); } } /** - * - * @param c context + * @param c context * @param parent parent Community - * @param child child community - * @throws SQLException if database error + * @param child child community + * @throws SQLException if database error * @throws AuthorizeException if authorize error - * @throws IOException if IO error + * @throws IOException if IO error */ public void filiate(Context c, Community parent, Community child) - throws SQLException, AuthorizeException, IOException - { + 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; + Community childDad = CollectionUtils.isNotEmpty(child.getParentCommunities()) ? child.getParentCommunities() + .iterator().next() : null; - if (childDad != null) - { + if (childDad != null) { System.out.println("Error, child community: " + child.getID() - + " already a child of: " + childDad.getID()); + + " already a child of: " + childDad.getID()); System.exit(1); } @@ -207,12 +181,10 @@ public class CommunityFiliator // child List parentDads = parent.getParentCommunities(); - for (int i = 0; i < parentDads.size(); i++) - { - if (parentDads.get(i).getID().equals(child.getID())) - { + 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"); + .println("Error, circular parentage - child is parent of parent"); System.exit(1); } } @@ -223,39 +195,34 @@ public class CommunityFiliator // complete the pending transaction c.complete(); System.out.println("Filiation complete. Community: '" + parent.getID() - + "' is parent of community: '" + child.getID() + "'"); + + "' is parent of community: '" + child.getID() + "'"); } /** - * - * @param c context + * @param c context * @param parent parent Community - * @param child child community - * @throws SQLException if database error + * @param child child community + * @throws SQLException if database error * @throws AuthorizeException if authorize error - * @throws IOException if IO error + * @throws IOException if IO error */ public void defiliate(Context c, Community parent, Community child) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { // verify that child is indeed a child of parent List parentKids = parent.getSubcommunities(); boolean isChild = false; - for (int i = 0; i < parentKids.size(); i++) - { - if (parentKids.get(i).getID().equals(child.getID())) - { + for (int i = 0; i < parentKids.size(); i++) { + if (parentKids.get(i).getID().equals(child.getID())) { isChild = true; break; } } - if (!isChild) - { + if (!isChild) { System.out - .println("Error, child community not a child of parent community"); + .println("Error, child community not a child of parent community"); System.exit(1); } @@ -269,37 +236,33 @@ public class CommunityFiliator // complete the pending transaction c.complete(); System.out.println("Defiliation complete. Community: '" + child.getID() - + "' is no longer a child of community: '" + parent.getID() - + "'"); + + "' is no longer a child of community: '" + parent.getID() + + "'"); } /** * Find a community by ID - * @param c context + * + * @param c context * @param communityID community ID * @return Community object * @throws SQLException if database error */ protected Community resolveCommunity(Context c, String communityID) - throws SQLException - { + throws SQLException { Community community = null; - if (communityID.indexOf('/') != -1) - { + if (communityID.indexOf('/') != -1) { // has a / must be a handle community = (Community) handleService.resolveToObject(c, - communityID); + communityID); // ensure it's a community if ((community == null) - || (community.getType() != Constants.COMMUNITY)) - { + || (community.getType() != Constants.COMMUNITY)) { community = null; } - } - else - { + } else { community = communityService.find(c, UUID.fromString(communityID)); } diff --git a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java index c1c80e5f52..7d603158ba 100644 --- a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java +++ b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java @@ -15,7 +15,6 @@ 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; @@ -34,20 +33,20 @@ import org.dspace.eperson.service.GroupService; *

* 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 + * + * 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 */ +public final class CreateAdministrator { + /** + * DSpace Context object + */ private final Context context; protected EPersonService ePersonService; @@ -56,160 +55,142 @@ public final class CreateAdministrator /** * 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 - { + 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")) - { + line.hasOption("c") && line.hasOption("p")) { ca.createAdministrator(line.getOptionValue("e"), - line.getOptionValue("f"), line.getOptionValue("l"), - line.getOptionValue("c"), line.getOptionValue("p")); - } - else - { + 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 - { + 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 + * 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 - { + 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) - { + + while (!dataOK) { System.out.print("E-mail address: "); System.out.flush(); - + email = console.readLine(); - if (!StringUtils.isBlank(email)) - { + if (!StringUtils.isBlank(email)) { email = email.trim(); - } - else - { + } else { System.out.println("Please provide an email address."); continue; } - + System.out.print("First name: "); System.out.flush(); - + firstName = console.readLine(); - if (firstName != null) - { + if (firstName != null) { firstName = firstName.trim(); } - + System.out.print("Last name: "); System.out.flush(); - + lastName = console.readLine(); - if (lastName != null) - { + 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")); + + 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) - { + 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)) - { + 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) - { + if (s != null) { s = s.trim(); - if (s.toLowerCase().startsWith("y")) - { + if (s.toLowerCase().startsWith("y")) { dataOK = true; } } - } - else - { + } 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)); @@ -217,60 +198,56 @@ public final class CreateAdministrator 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 last user's last name * @param language preferred language - * @param pw desired password - * + * @param pw desired password * @throws Exception if error */ protected void createAdministrator(String email, String first, String last, - String language, String pw) - throws Exception - { + 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) - { + + if (admins == null) { throw new IllegalStateException("Error, no admin group (group 1) found"); } - + // Create the administrator e-person - EPerson eperson = ePersonService.findByEmail(context,email); - + 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) - { + 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"); } } diff --git a/dspace-api/src/main/java/org/dspace/administer/MetadataExporter.java b/dspace-api/src/main/java/org/dspace/administer/MetadataExporter.java index 57f1bccef1..27579a5b8e 100644 --- a/dspace-api/src/main/java/org/dspace/administer/MetadataExporter.java +++ b/dspace-api/src/main/java/org/dspace/administer/MetadataExporter.java @@ -7,7 +7,19 @@ */ package org.dspace.administer; -import org.apache.commons.cli.*; +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; @@ -19,69 +31,63 @@ import org.dspace.content.service.MetadataSchemaService; import org.dspace.core.Context; import org.xml.sax.SAXException; -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; - /** * @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 * - * - * dc - * http://dublincore.org/documents/dcmi-terms/ - * + * + * dc + * http://dublincore.org/documents/dcmi-terms/ + * * * } */ -public class MetadataExporter -{ +public class MetadataExporter { - protected static MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); - protected static MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); + 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 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 - { + 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("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 file = null; String schema = null; - if (line.hasOption('f')) - { - file = line.getOptionValue('f'); - } - else - { + if (line.hasOption('f')) { + file = line.getOptionValue('f'); + } else { usage(); System.exit(0); } - - if (line.hasOption('s')) - { + + if (line.hasOption('s')) { schema = line.getOptionValue('s'); } @@ -90,15 +96,16 @@ public class MetadataExporter /** * Save a registry to a filepath - * @param file 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 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 - { + public static void saveRegistry(String file, String schema) + throws SQLException, IOException, SAXException, RegistryExportException { // create a context Context context = new Context(); context.turnOffAuthorisationSystem(); @@ -106,113 +113,102 @@ public class MetadataExporter 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 mdFields = null; // If a single schema has been specified - if (schema != null && !"".equals(schema)) - { + if (schema != null && !"".equals(schema)) { // Get the id of that schema MetadataSchema mdSchema = metadataSchemaService.find(context, schema); - if (mdSchema == null) - { + 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 - { + } else { // Get the metadata fields for all the schemas mdFields = metadataFieldService.findAll(context); } - + // Output the metadata fields - for (MetadataField mdField : mdFields) - { + 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 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 + * @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)) - { + 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 - { + } else { // Find all schemas List mdSchemas = metadataSchemaService.findAll(context); - - for (MetadataSchema mdSchema : mdSchemas) - { + + 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 + * @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 - { + 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) - { + if (mdSchema == null) { throw new RegistryExportException("no schema to export"); } - - String name = mdSchema.getName(); + + String name = mdSchema.getName(); String namespace = mdSchema.getNamespace(); - - if (name == null || "".equals(name)) - { + + if (name == null || "".equals(name)) { System.out.println("name is null, skipping"); return; } - if (namespace == null || "".equals(namespace)) - { + 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()); @@ -225,26 +221,25 @@ public class MetadataExporter xmlSerializer.endElement("dc-schema"); } - + /** * Serialize a single metadata field registry entry to xml - * - * @param context DSpace context + * + * @param context DSpace context * @param xmlSerializer xml serializer - * @param mdField DSpace metadata field - * @throws SAXException if XML error + * @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 + * @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 - { + 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) - { + 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(); @@ -252,8 +247,7 @@ public class MetadataExporter String scopeNote = mdField.getScopeNote(); // We must have a schema and element - if (schemaName == null || element == null) - { + if (schemaName == null || element == null) { throw new RegistryExportException("incomplete field information"); } @@ -271,73 +265,64 @@ public class MetadataExporter xmlSerializer.endElement("element"); // Output the qualifier, if present - if (qualifier != null) - { + if (qualifier != null) { xmlSerializer.startElement("qualifier", null); xmlSerializer.characters(qualifier.toCharArray(), 0, qualifier.length()); xmlSerializer.endElement("qualifier"); - } - else - { + } else { xmlSerializer.comment("unqualified"); } - + // Output the scope note, if present - if (scopeNote != null) - { + if (scopeNote != null) { xmlSerializer.startElement("scope_note", null); xmlSerializer.characters(scopeNote.toCharArray(), 0, scopeNote.length()); xmlSerializer.endElement("scope_note"); - } - else - { + } else { xmlSerializer.comment("no scope note"); } - + xmlSerializer.endElement("dc-type"); } - + static Map schemaMap = new HashMap(); + /** * 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 SQLException if database error * @throws RegistryExportException if export error */ - private static String getSchemaName(Context context, MetadataField mdField) throws SQLException, RegistryExportException - { + 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) - { + if (name == null) { // Name not retrieved before, so get the schema now MetadataSchema mdSchema = metadataSchemaService.find(context, mdField.getMetadataSchema().getID()); - if (mdSchema != null) - { + if (mdSchema != null) { name = mdSchema.getName(); schemaMap.put(mdSchema.getID(), name); - } - else - { + } 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() - { + public static void usage() { String usage = "Use this class with the following options:\n" + - " -f : specify the output file for the schemas\n" + - " -s : name of the schema to export\n"; + " -f : specify the output file for the schemas\n" + + " -s : name of the schema to export\n"; System.out.println(usage); } } diff --git a/dspace-api/src/main/java/org/dspace/administer/MetadataImporter.java b/dspace-api/src/main/java/org/dspace/administer/MetadataImporter.java index 49e6661a55..ac547f1839 100644 --- a/dspace-api/src/main/java/org/dspace/administer/MetadataImporter.java +++ b/dspace-api/src/main/java/org/dspace/administer/MetadataImporter.java @@ -9,7 +9,6 @@ package org.dspace.administer; import java.io.IOException; import java.sql.SQLException; - import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; @@ -18,9 +17,7 @@ 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; @@ -31,79 +28,81 @@ 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 + * 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 * - * - * icadmin - * status - * dateset - * the workflow status of an item - * - * - * [....] - * + * + * icadmin + * status + * dateset + * the workflow status of an item + * + * + * [....] + * * * } */ -public class MetadataImporter -{ - protected static MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); - protected static MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); +public class MetadataImporter { + protected static MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); + protected static MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance() + .getMetadataFieldService(); - /** logging category */ + /** + * 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 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 + * @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 - { + 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')) - { + if (line.hasOption('f')) { file = line.getOptionValue('f'); - } - else - { + } else { usage(); System.exit(0); } @@ -111,29 +110,27 @@ public class MetadataImporter 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 + * + * @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 + * @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 - { + throws SQLException, IOException, TransformerException, ParserConfigurationException, + AuthorizeException, SAXException, NonUniqueMetadataException, RegistryImportException { Context context = null; - try - { + try { // create a context context = new Context(); context.turnOffAuthorisationSystem(); @@ -145,8 +142,7 @@ public class MetadataImporter 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++) - { + for (int i = 0; i < schemaNodes.getLength(); i++) { Node n = schemaNodes.item(i); loadSchema(context, n, forceUpdate); } @@ -155,110 +151,95 @@ public class MetadataImporter 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++) - { + 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()) + } 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 + * + * @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 + * @throws RegistryImportException if import fails */ private static void loadSchema(Context context, Node node, boolean updateExisting) throws SQLException, IOException, TransformerException, - AuthorizeException, NonUniqueMetadataException, RegistryImportException - { + AuthorizeException, NonUniqueMetadataException, RegistryImportException { // Get the values String name = RegistryImporter.getElementData(node, "name"); String namespace = RegistryImporter.getElementData(node, "namespace"); - - if (name == null || "".equals(name)) - { + + if (name == null || "".equals(name)) { throw new RegistryImportException("Name of schema must be supplied"); } - if (namespace == null || "".equals(namespace)) - { + 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) - { + + if (s == null) { // Schema does not exist - create log.info("Registering Schema " + name + " (" + namespace + ")"); metadataSchemaService.create(context, name, namespace); - } - else - { + } else { // Schema exists - if it's the same namespace, allow the type imports to continue - if (s.getNamespace().equals(namespace)) - { + 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) - { + 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."); + } 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 + * + * @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 + * @throws RegistryImportException if import fails */ private static void loadType(Context context, Node node) - throws SQLException, IOException, TransformerException, - AuthorizeException, NonUniqueMetadataException, RegistryImportException - { + throws SQLException, IOException, TransformerException, + AuthorizeException, NonUniqueMetadataException, RegistryImportException { // Get the values String schema = RegistryImporter.getElementData(node, "schema"); String element = RegistryImporter.getElementData(node, "element"); @@ -266,44 +247,41 @@ public class MetadataImporter String scopeNote = RegistryImporter.getElementData(node, "scope_note"); // If the schema is not provided default to DC - if (schema == null) - { + if (schema == null) { schema = MetadataSchema.DC_SCHEMA; } - + // Find the matching schema object MetadataSchema schemaObj = metadataSchemaService.find(context, schema); - - if (schemaObj == null) - { + + 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) - { + 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) + 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() - { + public static void usage() { String usage = "Use this class with the following option:\n" + - " -f : specify which xml source file " + - "contains the DC fields to import.\n"; + " -f : specify which xml source file " + + "contains the DC fields to import.\n"; System.out.println(usage); } } diff --git a/dspace-api/src/main/java/org/dspace/administer/RegistryExportException.java b/dspace-api/src/main/java/org/dspace/administer/RegistryExportException.java index d40a11ec19..9df2d6caf7 100644 --- a/dspace-api/src/main/java/org/dspace/administer/RegistryExportException.java +++ b/dspace-api/src/main/java/org/dspace/administer/RegistryExportException.java @@ -12,45 +12,40 @@ package org.dspace.administer; * * An exception to report any problems with registry exports */ -public class RegistryExportException extends Exception -{ +public class RegistryExportException extends Exception { /** * Create an empty authorize exception */ - public RegistryExportException() - { + public RegistryExportException() { super(); } /** * create an exception with only a message - * + * * @param message exception message */ - public RegistryExportException(String 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 + * @param e reference to Throwable */ - public RegistryExportException(String message, Throwable e) - { + 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) - { + public RegistryExportException(Throwable e) { super(e); } - + } diff --git a/dspace-api/src/main/java/org/dspace/administer/RegistryImportException.java b/dspace-api/src/main/java/org/dspace/administer/RegistryImportException.java index 5a15631dfb..83f9c9fa88 100644 --- a/dspace-api/src/main/java/org/dspace/administer/RegistryImportException.java +++ b/dspace-api/src/main/java/org/dspace/administer/RegistryImportException.java @@ -12,45 +12,40 @@ package org.dspace.administer; * * An exception to report any problems with registry imports */ -public class RegistryImportException extends Exception -{ +public class RegistryImportException extends Exception { /** * Create an empty authorize exception */ - public RegistryImportException() - { + public RegistryImportException() { super(); } /** * create an exception with only a message - * + * * @param message error message */ - public RegistryImportException(String message) - { + public RegistryImportException(String message) { super(message); } - + /** * create an exception with an inner exception and a message - * - * @param message error message - * @param e throwable + * + * @param message error message + * @param e throwable */ - public RegistryImportException(String message, Throwable e) - { - super(message, e); + public RegistryImportException(String message, Throwable e) { + super(message, e); } - + /** * create an exception with an inner exception - * - * @param e throwable + * + * @param e throwable */ - public RegistryImportException(Throwable e) - { - super(e); + public RegistryImportException(Throwable e) { + super(e); } - + } diff --git a/dspace-api/src/main/java/org/dspace/administer/RegistryImporter.java b/dspace-api/src/main/java/org/dspace/administer/RegistryImporter.java index b8a7c2456a..5b5f70412a 100644 --- a/dspace-api/src/main/java/org/dspace/administer/RegistryImporter.java +++ b/dspace-api/src/main/java/org/dspace/administer/RegistryImporter.java @@ -9,18 +9,15 @@ 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; /** @@ -31,30 +28,32 @@ import org.xml.sax.SAXException; * I am the author, really I ripped these methods off from other * classes */ -public class RegistryImporter -{ +public class RegistryImporter { + + /** + * Default constructor + */ + private RegistryImporter() { } + /** * Load in the XML from file. - * - * @param filename - * the filename to load from - * + * + * @param filename the filename to load from * @return the DOM representation of the XML file - * @throws IOException if IO error + * @throws IOException if IO error * @throws ParserConfigurationException if configuration parse error - * @throws SAXException if XML parse error + * @throws SAXException if XML parse error */ - public static Document loadXML(String filename) - throws IOException, ParserConfigurationException, SAXException - { + public static Document loadXML(String filename) + throws IOException, ParserConfigurationException, SAXException { DocumentBuilder builder = DocumentBuilderFactory.newInstance() - .newDocumentBuilder(); + .newDocumentBuilder(); Document document = builder.parse(new File(filename)); - + return document; } - + /** * Get the CDATA of a particular element. For example, if the XML document * contains: @@ -66,22 +65,18 @@ public class RegistryImporter * return application/pdf. *

* 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 - * @throws TransformerException if error + * + * @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 String + * @throws TransformerException if error */ public static String getElementData(Node parentElement, String childName) - throws TransformerException - { + throws TransformerException { // Grab the child node Node childNode = XPathAPI.selectSingleNode(parentElement, childName); - if (childNode == null) - { + if (childNode == null) { // No child node, so no values return null; } @@ -89,8 +84,7 @@ public class RegistryImporter // Get the #text Node dataNode = childNode.getFirstChild(); - if (dataNode == null) - { + if (dataNode == null) { return null; } @@ -106,32 +100,28 @@ public class RegistryImporter *

* * <foo> - * <bar>val1</bar> - * <bar>val2</bar> + * <bar>val1</bar> + * <bar>val2</bar> * </foo> * * passing this the foo node and bar will * return val1 and val2. *

* 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 - * @throws TransformerException if error + * + * @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 String + * @throws TransformerException if error */ public static String[] getRepeatedElementData(Node parentElement, - String childName) throws TransformerException - { + 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++) - { + for (int i = 0; i < childNodes.getLength(); i++) { // Get the #text node Node dataNode = childNodes.item(i).getFirstChild(); diff --git a/dspace-api/src/main/java/org/dspace/administer/RegistryLoader.java b/dspace-api/src/main/java/org/dspace/administer/RegistryLoader.java index 4ec485fb43..f1b8a0684c 100644 --- a/dspace-api/src/main/java/org/dspace/administer/RegistryLoader.java +++ b/dspace-api/src/main/java/org/dspace/administer/RegistryLoader.java @@ -12,7 +12,6 @@ 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; @@ -40,32 +39,37 @@ import org.xml.sax.SAXException; * RegistryLoader -bitstream bitstream-formats.xml *

* RegistryLoader -dc dc-types.xml - * + * * @author Robert Tansley * @version $Revision$ */ -public class RegistryLoader -{ - /** log4j category */ +public class RegistryLoader { + /** + * log4j category + */ private static Logger log = Logger.getLogger(RegistryLoader.class); - protected static BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + 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 - { + public static void main(String[] argv) throws Exception { String usage = "Usage: " + RegistryLoader.class.getName() - + " (-bitstream | -metadata) registry-file.xml"; + + " (-bitstream | -metadata) registry-file.xml"; Context context = null; - try - { + try { context = new Context(); // Can't update registries anonymously, so we need to turn off @@ -73,17 +77,12 @@ public class RegistryLoader context.turnOffAuthorisationSystem(); // Work out what we're loading - if (argv[0].equalsIgnoreCase("-bitstream")) - { + if (argv[0].equalsIgnoreCase("-bitstream")) { RegistryLoader.loadBitstreamFormats(context, argv[1]); - } - else if (argv[0].equalsIgnoreCase("-metadata")) - { + } else if (argv[0].equalsIgnoreCase("-metadata")) { // Call MetadataImporter, as it handles Metadata schema updates MetadataImporter.loadRegistry(argv[1], true); - } - else - { + } else { System.err.println(usage); } @@ -91,81 +90,69 @@ public class RegistryLoader context.complete(); System.exit(0); - } - catch (ArrayIndexOutOfBoundsException ae) - { + } catch (ArrayIndexOutOfBoundsException ae) { System.err.println(usage); System.exit(1); - } - catch (Exception e) - { + } catch (Exception e) { log.fatal(LogManager.getHeader(context, "error_loading_registries", - ""), e); + ""), e); System.err.println("Error: \n - " + e.getMessage()); System.exit(1); - } - finally - { + } finally { // Clean up our context, if it still exists & it was never completed - if(context!=null && context.isValid()) + 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 + * + * @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 + * @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 - { + 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"); + "dspace-bitstream-types/bitstream-type"); // Add each one as a new format to the registry - for (int i = 0; i < typeNodes.getLength(); i++) - { + 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())); + "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 + * + * @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 AuthorizeException if authorization error */ private static void loadFormat(Context context, Node node) - throws SQLException, IOException, TransformerException, - AuthorizeException - { + throws SQLException, IOException, TransformerException, + AuthorizeException { // Get the values String mimeType = getElementData(node, "mimetype"); String shortDesc = getElementData(node, "short_description"); @@ -181,16 +168,14 @@ public class RegistryLoader // 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) - { + if (exists == null) { exists = bitstreamFormatService.findByShortDescription(context, shortDesc); } - + // If it doesn't exist, create it..otherwise skip it. - if(exists==null) - { + if (exists == null) { // Create the format object BitstreamFormat format = bitstreamFormatService.create(context); @@ -213,19 +198,17 @@ public class RegistryLoader /** * Load in the XML from file. - * - * @param filename - * the filename to load from - * @throws IOException if IO error - * @throws ParserConfigurationException if config error - * @throws SAXException if parser error + * + * @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 - { + ParserConfigurationException, SAXException { DocumentBuilder builder = DocumentBuilderFactory.newInstance() - .newDocumentBuilder(); + .newDocumentBuilder(); return builder.parse(new File(filename)); } @@ -241,22 +224,18 @@ public class RegistryLoader * return application/pdf. *

* 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 - * @throws TransformerException if transformer error + * + * @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 String + * @throws TransformerException if transformer error */ private static String getElementData(Node parentElement, String childName) - throws TransformerException - { + throws TransformerException { // Grab the child node Node childNode = XPathAPI.selectSingleNode(parentElement, childName); - if (childNode == null) - { + if (childNode == null) { // No child node, so no values return null; } @@ -264,8 +243,7 @@ public class RegistryLoader // Get the #text Node dataNode = childNode.getFirstChild(); - if (dataNode == null) - { + if (dataNode == null) { return null; } @@ -281,32 +259,28 @@ public class RegistryLoader *

* * <foo> - * <bar>val1</bar> - * <bar>val2</bar> + * <bar>val1</bar> + * <bar>val2</bar> * </foo> * * passing this the foo node and bar will * return val1 and val2. *

* 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 - * @throws TransformerException if transformer error + * + * @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 String + * @throws TransformerException if transformer error */ private static String[] getRepeatedElementData(Node parentElement, - String childName) throws TransformerException - { + 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++) - { + for (int i = 0; i < childNodes.getLength(); i++) { // Get the #text node Node dataNode = childNodes.item(i).getFirstChild(); diff --git a/dspace-api/src/main/java/org/dspace/administer/StructBuilder.java b/dspace-api/src/main/java/org/dspace/administer/StructBuilder.java index c1f8f928fd..8c408b0e8a 100644 --- a/dspace-api/src/main/java/org/dspace/administer/StructBuilder.java +++ b/dspace-api/src/main/java/org/dspace/administer/StructBuilder.java @@ -14,7 +14,6 @@ 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; @@ -44,116 +43,119 @@ 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 * - * - * .... - * ... - * - * .... - * - * + * + * .... + * ... + * + * .... + * + * * * } * 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 * + * @author Richard Jones */ -public class StructBuilder -{ - /** the output xml document which will contain updated information about the +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 */ + + /** + * a hashtable to hold metadata for the collection being worked on + */ private static Map collectionMap = new HashMap(); - - /** a hashtable to hold metadata for the community being worked on */ + + /** + * a hashtable to hold metadata for the community being worked on + */ private static Map communityMap = new HashMap(); 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 - { + 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("f", "file", true, "file"); + options.addOption("e", "eperson", true, "eperson"); options.addOption("o", "output", true, "output"); - - CommandLine line = parser.parse( options, argv ); - + + CommandLine line = parser.parse(options, argv); + String file = null; String eperson = null; String output = null; - - if (line.hasOption('f')) - { + + if (line.hasOption('f')) { file = line.getOptionValue('f'); } - - if (line.hasOption('e')) - { + + if (line.hasOption('e')) { eperson = line.getOptionValue('e'); } - - if (line.hasOption('o')) - { + + if (line.hasOption('o')) { output = line.getOptionValue('o'); } - - if (output == null || eperson == null || file == null) - { + + 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"); @@ -161,267 +163,232 @@ public class StructBuilder 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++) - { + for (int i = 0; i < elements.length; i++) { root.addContent(elements[i]); } - + // finally write the string into the output file - try - { + try { BufferedWriter out = new BufferedWriter(new FileWriter(output)); out.write(new XMLOutputter().outputString(xmlOutput)); out.close(); - } - catch (IOException e) - { + } 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() - { + private static void usage() { System.out.println("Usage: java StructBuilder -f -o -e "); - 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"); + 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 + * + * @param document the XML document object * @throws TransformerException if transformer error - * */ private static void validate(org.w3c.dom.Document document) - throws TransformerException - { + 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) - { + 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) - { + if (errs != null) { err.append(errs); trip = true; } - - if (trip) - { + + 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 - * + * @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. + * no errors. */ private static String validateCommunities(NodeList communities, int level) - throws TransformerException - { + throws TransformerException { StringBuffer err = new StringBuffer(); boolean trip = false; String errs = null; - - for (int i = 0; i < communities.getLength(); i++) - { + + for (int i = 0; i < communities.getLength(); i++) { Node n = communities.item(i); NodeList name = XPathAPI.selectNodeList(n, "name"); - if (name.getLength() != 1) - { + 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) - { + 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) - { + if (colErrs != null) { err.append(colErrs); trip = true; } } - - if (trip) - { + + 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 - * + * @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 - { + throws TransformerException { StringBuffer err = new StringBuffer(); boolean trip = false; String errs = null; - - for (int i = 0; i < collections.getLength(); i++) - { + + for (int i = 0; i < collections.getLength(); i++) { Node n = collections.item(i); NodeList name = XPathAPI.selectNodeList(n, "name"); - if (name.getLength() != 1) - { + 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) - { + + if (trip) { errs = err.toString(); } - + return errs; } - + /** * Load in the XML from file. - * - * @param filename - * the filename to load from - * + * + * @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 - { + private static org.w3c.dom.Document loadXML(String filename) + throws IOException, ParserConfigurationException, SAXException { DocumentBuilder builder = DocumentBuilderFactory.newInstance() - .newDocumentBuilder(); + .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) - { + public static String getStringValue(Node node) { String value = node.getNodeValue(); - if (node.hasChildNodes()) - { + if (node.hasChildNodes()) { Node first = node.getFirstChild(); - if (first.getNodeType() == Node.TEXT_NODE) - { + 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 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) + * @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 - { + throws TransformerException, SQLException, Exception { Element[] elements = new Element[communities.getLength()]; - - for (int i = 0; i < communities.getLength(); i++) - { + + for (int i = 0; i < communities.getLength(); i++) { Community community; Element element = new Element("community"); - + // create the community or sub community - if (parent != null) - { + if (parent != null) { community = communityService.create(parent, context); - } - else - { + } 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 entry : communityMap.entrySet()) - { + for (Map.Entry entry : communityMap.entrySet()) { NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey()); - if (nl.getLength() == 1) - { + 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 @@ -432,7 +399,7 @@ public class StructBuilder // 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 @@ -442,151 +409,134 @@ public class StructBuilder // 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) - { + + 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) - { + + 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) - { + + 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) - { + + 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++) - { + for (j = 0; j < subCommunityElements.length; j++) { element.addContent(subCommunityElements[j]); } - for (j = 0; j < collectionElements.length; 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 + * 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 - * + * @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) + * created collections (e.g. the handle) */ private static Element[] handleCollections(Context context, NodeList collections, Community parent) - throws TransformerException, SQLException, AuthorizeException, IOException, Exception - { + throws TransformerException, SQLException, AuthorizeException, IOException, Exception { Element[] elements = new Element[collections.getLength()]; - - for (int i = 0; i < collections.getLength(); i++) - { + + 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 entry : collectionMap.entrySet()) - { + for (Map.Entry entry : collectionMap.entrySet()) { NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey()); - if (nl.getLength() == 1) - { + 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) - { + + 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) - { + + 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) - { + + 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) - { + + 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) - { + + 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) - { + + 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; } - + } diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/BulkEditChange.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/BulkEditChange.java index 28fb39b0f5..0dbb8bd7bb 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/BulkEditChange.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/BulkEditChange.java @@ -7,67 +7,93 @@ */ package org.dspace.app.bulkedit; -import org.dspace.content.Item; -import org.dspace.content.Collection; - 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 */ +public class BulkEditChange { + /** + * The item these changes relate to + */ private Item item; - /** The List of hashtables with the new elements */ + /** + * The List of hashtables with the new elements + */ private List adds; - /** The List of hashtables with the removed elements */ + /** + * The List of hashtables with the removed elements + */ private List removes; - /** The List of hashtables with the unchanged elements */ + /** + * The List of hashtables with the unchanged elements + */ private List constant; - /** The List of the complete set of new values (constant + adds) */ + /** + * The List of the complete set of new values (constant + adds) + */ private List complete; - /** The list of old collections the item used to be mapped to */ + /** + * The list of old collections the item used to be mapped to + */ private List oldMappedCollections; - /** The list of new collections the item has been mapped into */ + /** + * The list of new collections the item has been mapped into + */ private List newMappedCollections; - /** The old owning collection */ + /** + * The old owning collection + */ private Collection oldOwningCollection; - /** The new owning collection */ + /** + * The new owning collection + */ private Collection newOwningCollection; - /** Is this a new item */ + /** + * Is this a new item + */ private boolean newItem; - /** Has this item been deleted? */ + /** + * Has this item been deleted? + */ private boolean deleted; - /** Has this item been withdrawn? */ + /** + * Has this item been withdrawn? + */ private boolean withdrawn; - /** Has this item been reinstated? */ + /** + * Has this item been reinstated? + */ private boolean reinstated; - /** Have any changes actually been made? */ + /** + * Have any changes actually been made? + */ private boolean empty; /** - * Initialise a change holder for a new item + * Initialise a change holder for a new item */ - public BulkEditChange() - { + public BulkEditChange() { // Set the item to be null item = null; newItem = true; @@ -89,8 +115,7 @@ public class BulkEditChange * * @param i The Item to store */ - public BulkEditChange(Item i) - { + public BulkEditChange(Item i) { // Store the item item = i; newItem = false; @@ -110,8 +135,7 @@ public class BulkEditChange * * @param i The item */ - public void setItem(Item i) - { + public void setItem(Item i) { // Store the item item = i; } @@ -121,8 +145,7 @@ public class BulkEditChange * * @param dcv The value to add */ - public void registerAdd(BulkEditMetadataValue dcv) - { + public void registerAdd(BulkEditMetadataValue dcv) { // Add the added value adds.add(dcv); complete.add(dcv); @@ -134,8 +157,7 @@ public class BulkEditChange * * @param dcv The value to remove */ - public void registerRemove(BulkEditMetadataValue dcv) - { + public void registerRemove(BulkEditMetadataValue dcv) { // Add the removed value removes.add(dcv); empty = false; @@ -146,8 +168,7 @@ public class BulkEditChange * * @param dcv The value to keep unchanged */ - public void registerConstant(BulkEditMetadataValue dcv) - { + public void registerConstant(BulkEditMetadataValue dcv) { // Add the removed value constant.add(dcv); complete.add(dcv); @@ -158,8 +179,7 @@ public class BulkEditChange * * @param c The new mapped Collection */ - public void registerNewMappedCollection(Collection c) - { + public void registerNewMappedCollection(Collection c) { // Add the new owning Collection newMappedCollections.add(c); empty = false; @@ -170,27 +190,22 @@ public class BulkEditChange * * @param c The old mapped Collection */ - public void registerOldMappedCollection(Collection c) - { + 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()))) - { + (this.getOldOwningCollection().getHandle().equals(c.getHandle()))) { found = true; } - for (Collection collection : oldMappedCollections) - { - if (collection.getHandle().equals(c.getHandle())) - { + for (Collection collection : oldMappedCollections) { + if (collection.getHandle().equals(c.getHandle())) { found = true; } } - if (!found) - { + if (!found) { oldMappedCollections.add(c); empty = false; } @@ -202,8 +217,7 @@ public class BulkEditChange * @param oldC The old owning collection * @param newC The new owning collection */ - public void changeOwningCollection(Collection oldC, Collection newC) - { + public void changeOwningCollection(Collection oldC, Collection newC) { // Store the old owning collection oldOwningCollection = oldC; @@ -217,8 +231,7 @@ public class BulkEditChange * * @param newC The new owning collection */ - public void setOwningCollection(Collection newC) - { + public void setOwningCollection(Collection newC) { // Store the new owning collection newOwningCollection = newC; //empty = false; @@ -229,8 +242,7 @@ public class BulkEditChange * * @return The item */ - public Item getItem() - { + public Item getItem() { // Return the item return item; } @@ -240,8 +252,7 @@ public class BulkEditChange * * @return the list of elements and their values that have been added. */ - public List getAdds() - { + public List getAdds() { // Return the array return adds; } @@ -251,8 +262,7 @@ public class BulkEditChange * * @return the list of elements and their values that have been removed. */ - public List getRemoves() - { + public List getRemoves() { // Return the array return removes; } @@ -262,8 +272,7 @@ public class BulkEditChange * * @return the list of unchanged values */ - public List getConstant() - { + public List getConstant() { // Return the array return constant; } @@ -273,8 +282,7 @@ public class BulkEditChange * * @return the list of all values */ - public List getComplete() - { + public List getComplete() { // Return the array return complete; } @@ -284,8 +292,7 @@ public class BulkEditChange * * @return the list of new mapped collections */ - public List getNewMappedCollections() - { + public List getNewMappedCollections() { // Return the array return newMappedCollections; } @@ -295,8 +302,7 @@ public class BulkEditChange * * @return the list of old mapped collections */ - public List getOldMappedCollections() - { + public List getOldMappedCollections() { // Return the array return oldMappedCollections; } @@ -306,8 +312,7 @@ public class BulkEditChange * * @return the old owning collection */ - public Collection getOldOwningCollection() - { + public Collection getOldOwningCollection() { // Return the old owning collection return oldOwningCollection; } @@ -317,8 +322,7 @@ public class BulkEditChange * * @return the new owning collection */ - public Collection getNewOwningCollection() - { + public Collection getNewOwningCollection() { // Return the new owning collection return newOwningCollection; } @@ -328,8 +332,7 @@ public class BulkEditChange * * @return Whether or not this is for a new item */ - public boolean isNewItem() - { + public boolean isNewItem() { // Return the new item status return newItem; } @@ -339,8 +342,7 @@ public class BulkEditChange * * @return Whether or not this is for a deleted item */ - public boolean isDeleted() - { + public boolean isDeleted() { // Return the new item status return deleted; } @@ -359,8 +361,7 @@ public class BulkEditChange * * @return Whether or not this is for a withdrawn item */ - public boolean isWithdrawn() - { + public boolean isWithdrawn() { // Return the new item status return withdrawn; } @@ -379,8 +380,7 @@ public class BulkEditChange * * @return Whether or not this is for a reinstated item */ - public boolean isReinstated() - { + public boolean isReinstated() { // Return the new item status return reinstated; } @@ -399,8 +399,7 @@ public class BulkEditChange * * @return Whether or not changes have been made */ - public boolean hasChanges() - { + public boolean hasChanges() { return !empty; } } diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java index 51dbe5b402..e66c96782b 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java @@ -7,7 +7,26 @@ */ package org.dspace.app.bulkedit; -import org.apache.commons.lang3.StringUtils; +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; @@ -16,19 +35,14 @@ 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.content.authority.Choices; import org.dspace.core.Context; import org.dspace.services.factory.DSpaceServicesFactory; -import java.util.*; -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import java.io.*; - /** * Utility class to read and write CSV files * @@ -38,50 +52,74 @@ import java.io.*; * * 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? + * 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 */ +public class DSpaceCSV implements Serializable { + /** + * The headings of the CSV file + */ protected List headings; - /** An array list of CSV lines */ + /** + * An array list of CSV lines + */ protected List lines; - /** A counter of how many CSV lines this object holds */ + /** + * A counter of how many CSV lines this object holds + */ protected int counter; - /** The value separator (defaults to double pipe '||') */ + /** + * The value separator (defaults to double pipe '||') + */ protected String valueSeparator; - /** The value separator in an escaped form for using in regexes */ + /** + * The value separator in an escaped form for using in regexes + */ protected String escapedValueSeparator; - /** The field separator (defaults to comma) */ + /** + * The field separator (defaults to comma) + */ protected String fieldSeparator; - /** The field separator in an escaped form for using in regexes */ + /** + * The field separator in an escaped form for using in regexes + */ protected String escapedFieldSeparator; - /** The authority separator (defaults to double colon '::') */ + /** + * The authority separator (defaults to double colon '::') + */ protected String authoritySeparator; - /** The authority separator in an escaped form for using in regexes */ + /** + * 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(); + 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 */ + /** + * Whether to export all metadata such as handles and provenance information + */ protected boolean exportAll; - /** A list of metadata elements to ignore */ + /** + * A list of metadata elements to ignore + */ protected Map ignore; @@ -90,8 +128,7 @@ public class DSpaceCSV implements Serializable * * @param exportAll Whether to export all metadata such as handles and provenance information */ - public DSpaceCSV(boolean exportAll) - { + public DSpaceCSV(boolean exportAll) { // Initialise the class init(); @@ -104,48 +141,37 @@ public class DSpaceCSV implements Serializable * * @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 - { + 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")); + 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) - { + for (String element : headingElements) { columnCounter++; // Remove surrounding quotes if there are any - if ((element.startsWith("\"")) && (element.endsWith("\""))) - { + if ((element.startsWith("\"")) && (element.endsWith("\""))) { element = element.substring(1, element.length() - 1); } // Store the heading - if ("collection".equals(element)) - { + if ("collection".equals(element)) { // Store the heading headings.add(element); - } - // Store the action - else if ("action".equals(element)) - { + } else if ("action".equals(element)) { // Store the action // Store the heading headings.add(element); - } - else if (!"id".equals(element)) - { + } else if (!"id".equals(element)) { String authorityPrefix = ""; AuthorityValue authorityValueType = authorityValueService.getAuthorityValueType(element); if (authorityValueType != null) { @@ -180,7 +206,8 @@ public class DSpaceCSV implements Serializable } // Check that the metadata element exists in the schema - MetadataField foundField = metadataFieldService.findByElement(c, foundSchema, metadataElement, metadataQualifier); + MetadataField foundField = metadataFieldService + .findByElement(c, foundSchema, metadataElement, metadataQualifier); if (foundField == null) { throw new MetadataImportInvalidHeadingException(clean[0], MetadataImportInvalidHeadingException.ELEMENT, @@ -196,8 +223,7 @@ public class DSpaceCSV implements Serializable StringBuilder lineBuilder = new StringBuilder(); String lineRead; - while ((lineRead = input.readLine()) != null) - { + while ((lineRead = input.readLine()) != null) { if (lineBuilder.length() > 0) { // Already have a previously read value - add this line lineBuilder.append("\n").append(lineRead); @@ -236,11 +262,8 @@ public class DSpaceCSV implements Serializable addItem(lineRead); } } - } - finally - { - if (input != null) - { + } finally { + if (input != null) { input.close(); } } @@ -249,8 +272,7 @@ public class DSpaceCSV implements Serializable /** * Initialise this class with values from dspace.cfg */ - protected void init() - { + protected void init() { // Set the value separator setValueSeparator(); @@ -273,13 +295,16 @@ public class DSpaceCSV implements Serializable 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())) - { + 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()); } } @@ -307,16 +332,13 @@ public class DSpaceCSV implements Serializable * * If not set, defaults to double pipe '||' */ - private void setValueSeparator() - { + private void setValueSeparator() { // Get the value separator - valueSeparator = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("bulkedit.valueseparator"); - if ((valueSeparator != null) && (!"".equals(valueSeparator.trim()))) - { + valueSeparator = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("bulkedit.valueseparator"); + if ((valueSeparator != null) && (!"".equals(valueSeparator.trim()))) { valueSeparator = valueSeparator.trim(); - } - else - { + } else { valueSeparator = "||"; } @@ -336,32 +358,22 @@ public class DSpaceCSV implements Serializable * Special values are 'tab', 'hash' and 'semicolon' which will * get substituted from the text to the value. */ - private void setFieldSeparator() - { + private void setFieldSeparator() { // Get the value separator - fieldSeparator =DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("bulkedit.fieldseparator"); - if ((fieldSeparator != null) && (!"".equals(fieldSeparator.trim()))) - { + fieldSeparator = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("bulkedit.fieldseparator"); + if ((fieldSeparator != null) && (!"".equals(fieldSeparator.trim()))) { fieldSeparator = fieldSeparator.trim(); - if ("tab".equals(fieldSeparator)) - { + if ("tab".equals(fieldSeparator)) { fieldSeparator = "\t"; - } - else if ("semicolon".equals(fieldSeparator)) - { + } else if ("semicolon".equals(fieldSeparator)) { fieldSeparator = ";"; - } - else if ("hash".equals(fieldSeparator)) - { + } else if ("hash".equals(fieldSeparator)) { fieldSeparator = "#"; - } - else - { + } else { fieldSeparator = fieldSeparator.trim(); } - } - else - { + } else { fieldSeparator = ","; } @@ -371,23 +383,20 @@ public class DSpaceCSV implements Serializable 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() - { + private void setAuthoritySeparator() { // Get the value separator - authoritySeparator = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("bulkedit.authorityseparator"); - if ((authoritySeparator != null) && (!"".equals(authoritySeparator.trim()))) - { + authoritySeparator = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("bulkedit.authorityseparator"); + if ((authoritySeparator != null) && (!"".equals(authoritySeparator.trim()))) { authoritySeparator = authoritySeparator.trim(); - } - else - { + } else { authoritySeparator = "::"; } @@ -401,11 +410,9 @@ public class DSpaceCSV implements Serializable * 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 - { + 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) { @@ -421,49 +428,42 @@ public class DSpaceCSV implements Serializable // Add in any mapped collections List collections = i.getCollections(); - for (Collection c : collections) - { + for (Collection c : collections) { // Only add if it is not the owning collection - if (!c.getHandle().equals(owningCollectionHandle)) - { + if (!c.getHandle().equals(owningCollectionHandle)) { line.add("collection", c.getHandle()); } } // Populate it List md = itemService.getMetadata(i, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue value : md) - { + 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) - { + 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) - { + if (value.getLanguage() != null) { key = key + "[" + value.getLanguage() + "]"; } // Store the item - if (exportAll || okToExport(metadataField)) - { + 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); + 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)) - { + if (!headings.contains(key)) { headings.add(key); } } @@ -478,12 +478,10 @@ public class DSpaceCSV implements Serializable * @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 - { + 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)) - { + if (line.endsWith(fieldSeparator)) { // Add a space to the end, then remove it later last = true; line += " "; @@ -496,15 +494,12 @@ public class DSpaceCSV implements Serializable // Merge parts with embedded separators boolean alldone = false; - while (!alldone) - { + while (!alldone) { boolean found = false; int i = 0; - for (String part : bits) - { + for (String part : bits) { int bitcounter = part.length() - part.replaceAll("\"", "").length(); - if ((part.startsWith("\"")) && ((!part.endsWith("\"")) || ((bitcounter & 1) == 1))) - { + if ((part.startsWith("\"")) && ((!part.endsWith("\"")) || ((bitcounter & 1) == 1))) { found = true; String add = bits.get(i) + fieldSeparator + bits.get(i + 1); bits.remove(i); @@ -519,10 +514,8 @@ public class DSpaceCSV implements Serializable // Deal with quotes around the elements int i = 0; - for (String part : bits) - { - if ((part.startsWith("\"")) && (part.endsWith("\""))) - { + for (String part : bits) { + if ((part.startsWith("\"")) && (part.endsWith("\""))) { part = part.substring(1, part.length() - 1); bits.set(i, part); } @@ -531,10 +524,8 @@ public class DSpaceCSV implements Serializable // Remove embedded quotes i = 0; - for (String part : bits) - { - if (part.contains("\"\"")) - { + for (String part : bits) { + if (part.contains("\"\"")) { part = part.replaceAll("\"\"", "\""); bits.set(i, part); } @@ -546,34 +537,25 @@ public class DSpaceCSV implements Serializable DSpaceCSVLine csvLine; // Is this an existing item, or a new item (where id = '+') - if ("+".equals(id)) - { + if ("+".equals(id)) { csvLine = new DSpaceCSVLine(); - } - else - { - try - { + } else { + try { csvLine = new DSpaceCSVLine(UUID.fromString(id)); - } - catch (NumberFormatException nfe) - { + } 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); + "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) - { + for (String part : bits) { + if (i > 0) { // Is this a last empty item? - if ((last) && (i == headings.size())) - { + if ((last) && (i == headings.size())) { part = ""; } @@ -585,10 +567,8 @@ public class DSpaceCSV implements Serializable } csvLine.add(headings.get(i - 1), null); String[] elements = part.split(escapedValueSeparator); - for (String element : elements) - { - if ((element != null) && (!"".equals(element))) - { + for (String element : elements) { + if ((element != null) && (!"".equals(element))) { csvLine.add(headings.get(i - 1), element); } } @@ -604,8 +584,7 @@ public class DSpaceCSV implements Serializable * * @return The lines */ - public final List getCSVLines() - { + public final List getCSVLines() { // Return the lines return lines; } @@ -615,22 +594,19 @@ public class DSpaceCSV implements Serializable * * @return the array of CSV formatted Strings */ - public final String[] getCSVLinesAsStringArray() - { + public final String[] getCSVLinesAsStringArray() { // Create the headings line String[] csvLines = new String[counter + 1]; csvLines[0] = "id" + fieldSeparator + "collection"; List headingsCopy = new ArrayList<>(headings); Collections.sort(headingsCopy); - for (String value : headingsCopy) - { + for (String value : headingsCopy) { csvLines[0] = csvLines[0] + fieldSeparator + value; } Iterator i = lines.iterator(); int c = 1; - while (i.hasNext()) - { + while (i.hasNext()) { csvLines[c++] = i.next().toCSV(headingsCopy, fieldSeparator, valueSeparator); } @@ -641,15 +617,13 @@ public class DSpaceCSV implements Serializable * 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 - { + public final void save(String filename) throws IOException { // Save the file BufferedWriter out = new BufferedWriter( - new OutputStreamWriter( - new FileOutputStream(filename), "UTF-8")); + new OutputStreamWriter( + new FileOutputStream(filename), "UTF-8")); for (String csvLine : getCSVLinesAsStringArray()) { out.write(csvLine + "\n"); } @@ -666,12 +640,10 @@ public class DSpaceCSV implements Serializable * @param md The Metadatum to examine * @return Whether or not it is OK to export this element */ - protected boolean okToExport(MetadataField md) - { + protected boolean okToExport(MetadataField md) { // Now compare with the list to ignore String key = md.getMetadataSchema().getName() + "." + md.getElement(); - if (md.getQualifier() != null) - { + if (md.getQualifier() != null) { key += "." + md.getQualifier(); } if (ignore.get(key) != null) { @@ -687,8 +659,7 @@ public class DSpaceCSV implements Serializable * * @return The headings */ - public List getHeadings() - { + public List getHeadings() { return headings; } @@ -698,13 +669,11 @@ public class DSpaceCSV implements Serializable * @return The formatted String as a csv */ @Override - public final String toString() - { + public final String toString() { // Return the csv as one long string StringBuilder csvLines = new StringBuilder(); String[] lines = this.getCSVLinesAsStringArray(); - for (String line : lines) - { + for (String line : lines) { csvLines.append(line).append("\n"); } return csvLines.toString(); diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSVLine.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSVLine.java index bb5fdd4bb3..7fb09cfb4a 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSVLine.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSVLine.java @@ -7,30 +7,41 @@ */ 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; -import java.io.Serializable; -import java.util.*; - /** * 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 */ +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 */ + /** + * The elements in this line in a hashtable, keyed by the metadata type + */ private final Map items; protected transient final AuthorityValueService authorityValueService - = AuthorityServiceFactory.getInstance().getAuthorityValueService(); + = AuthorityServiceFactory.getInstance().getAuthorityValueService(); - /** ensuring that the order-sensible columns of the csv are processed in the correct order */ + /** + * ensuring that the order-sensible columns of the csv are processed in the correct order + */ private transient final Comparator headerComparator = new Comparator() { @Override public int compare(String md1, String md2) { @@ -41,8 +52,7 @@ public class DSpaceCSVLine implements Serializable int compare; if (source1 == null && source2 != null) { compare = -1; - } - else if (source1 != null && source2 == null) { + } else if (source1 != null && source2 == null) { compare = 1; } else { // the order of the rest does not matter @@ -57,8 +67,7 @@ public class DSpaceCSVLine implements Serializable * * @param itemId The item ID of the line */ - public DSpaceCSVLine(UUID itemId) - { + public DSpaceCSVLine(UUID itemId) { // Store the ID + separator, and initialise the hashtable this.id = itemId; items = new TreeMap<>(headerComparator); @@ -68,8 +77,7 @@ public class DSpaceCSVLine implements Serializable /** * Create a new CSV line for a new item */ - public DSpaceCSVLine() - { + public DSpaceCSVLine() { // Set the ID to be null, and initialise the hashtable this.id = null; this.items = new TreeMap<>(headerComparator); @@ -80,8 +88,7 @@ public class DSpaceCSVLine implements Serializable * * @return The item ID */ - public UUID getID() - { + public UUID getID() { // Return the ID return id; } @@ -89,20 +96,17 @@ public class DSpaceCSVLine implements Serializable /** * Add a new metadata value to this line * - * @param key The metadata key (e.g. dc.contributor.author) + * @param key The metadata key (e.g. dc.contributor.author) * @param value The metadata value */ - public void add(String key, String value) - { + public void add(String key, String value) { // Create the array list if we need to - if (items.get(key) == null) - { + if (items.get(key) == null) { items.put(key, new ArrayList()); } // Store the item if it is not null - if (value != null) - { + if (value != null) { items.get(key).add(value); } } @@ -113,8 +117,7 @@ public class DSpaceCSVLine implements Serializable * @param key The metadata key * @return All the elements that match */ - public List get(String key) - { + public List get(String key) { // Return any relevant values return items.get(key); } @@ -124,12 +127,11 @@ public class DSpaceCSVLine implements Serializable * * @return The action (may be blank, 'withdraw', 'reinstate' or 'delete') */ - public String getAction() - { + public String getAction() { if (items.containsKey("action")) { ArrayList actions = items.get("action"); if (actions.size() > 0) { - return ((String)actions.get(0)).trim(); + return ((String) actions.get(0)).trim(); } } return ""; @@ -140,8 +142,7 @@ public class DSpaceCSVLine implements Serializable * * @return An enumeration of all the keys */ - public Set keys() - { + public Set keys() { // Return the keys return items.keySet(); } @@ -149,26 +150,23 @@ public class DSpaceCSVLine implements Serializable /** * 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 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 headings, String fieldSeparator, String valueSeparator) - { + protected String toCSV(List 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)); + bits.append(valueToCSV(items.get("collection"), valueSeparator)); // Add the rest of the elements - for (String heading : headings) - { + for (String heading : headings) { bits.append(fieldSeparator); List values = items.get(heading); - if (values != null && !"collection".equals(heading)) - { + if (values != null && !"collection".equals(heading)) { bits.append(valueToCSV(values, valueSeparator)); } } @@ -179,33 +177,26 @@ public class DSpaceCSVLine implements Serializable /** * Internal method to create a CSV formatted String joining a given set of elements * - * @param values The values to create the string from + * @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 values, String valueSeparator) - { + protected String valueToCSV(List values, String valueSeparator) { // Check there is some content - if (values == null) - { + if (values == null) { return ""; } // Get on with the work String s; - if (values.size() == 1) - { + if (values.size() == 1) { s = values.get(0); - } - else - { + } else { // Concatenate any fields together StringBuilder str = new StringBuilder(); - for (String value : values) - { - if (str.length() > 0) - { + for (String value : values) { + if (str.length() > 0) { str.append(valueSeparator); } diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExport.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExport.java index 9765511fb0..bc015ef5e0 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExport.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExport.java @@ -7,36 +7,46 @@ */ package org.dspace.app.bulkedit; -import com.google.common.collect.Iterators; -import org.apache.commons.cli.*; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; -import org.dspace.content.*; +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; -import java.util.ArrayList; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Metadata exporter to allow the batch export of metadata into a file * * @author Stuart Lewis */ -public class MetadataExport -{ - /** The items to export */ +public class MetadataExport { + /** + * The items to export + */ protected Iterator toExport; protected ItemService itemService; protected Context context; - /** Whether to export all metadata, or just normally edited metadata */ + /** + * Whether to export all metadata, or just normally edited metadata + */ protected boolean exportAll; protected MetadataExport() { @@ -46,12 +56,11 @@ public class MetadataExport /** * Set up a new metadata export * - * @param c The Context - * @param toExport The ItemIterator of items to 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 toExport, boolean exportAll) - { + public MetadataExport(Context c, Iterator toExport, boolean exportAll) { itemService = ContentServiceFactory.getInstance().getItemService(); // Store the export settings @@ -63,23 +72,19 @@ public class MetadataExport /** * Method to export a community (and sub-communities and collections) * - * @param c The Context - * @param toExport The Community to export + * @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) - { + public MetadataExport(Context c, Community toExport, boolean exportAll) { itemService = ContentServiceFactory.getInstance().getItemService(); - try - { + try { // Try to export the community this.toExport = buildFromCommunity(c, toExport, 0); this.exportAll = exportAll; this.context = c; - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { // Something went wrong... System.err.println("Error running exporter:"); sqle.printStackTrace(System.err); @@ -90,49 +95,43 @@ public class MetadataExport /** * Build an array list of item ids that are in a community (include sub-communities and collections) * - * @param context DSpace context + * @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 + * @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 buildFromCommunity(Context context, Community community, int indent) - throws SQLException - { + throws SQLException { // Add all the collections List collections = community.getCollections(); Iterator result = null; - for (Collection collection : collections) - { - for (int i = 0; i < indent; i++) - { + for (Collection collection : collections) { + for (int i = 0; i < indent; i++) { System.out.print(" "); } Iterator items = itemService.findByCollection(context, collection); - result = addItemsToResult(result,items); + result = addItemsToResult(result, items); } // Add all the sub-communities List communities = community.getSubcommunities(); - for (Community subCommunity : communities) - { - for (int i = 0; i < indent; i++) - { + for (Community subCommunity : communities) { + for (int i = 0; i < indent; i++) { System.out.print(" "); } Iterator items = buildFromCommunity(context, subCommunity, indent + 1); - result = addItemsToResult(result,items); + result = addItemsToResult(result, items); } return result; } private Iterator addItemsToResult(Iterator result, Iterator items) { - if(result == null) - { + if (result == null) { result = items; - }else{ + } else { result = Iterators.concat(result, items); } @@ -144,17 +143,14 @@ public class MetadataExport * * @return the exported CSV lines */ - public DSpaceCSV export() - { - try - { + 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()) - { + while (toExport.hasNext()) { Item item = toExport.next(); csv.addItem(item); context.uncacheEntity(item); @@ -163,9 +159,7 @@ public class MetadataExport context.setMode(originalMode); // Return the results return csv; - } - catch (Exception e) - { + } catch (Exception e) { // Something went wrong... System.err.println("Error exporting to CSV:"); e.printStackTrace(); @@ -176,11 +170,10 @@ public class MetadataExport /** * Print the help message * - * @param options The command line options the user gave + * @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) - { + private static void printHelp(Options options, int exitCode) { // print the help message HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("MetadataExport\n", options); @@ -190,13 +183,12 @@ public class MetadataExport } /** - * 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 - { + * 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(); @@ -204,30 +196,26 @@ public class MetadataExport 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("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 - { + try { line = parser.parse(options, argv); - } - catch (ParseException pe) - { + } catch (ParseException pe) { System.err.println("Error with commands."); printHelp(options, 1); System.exit(0); } - if (line.hasOption('h')) - { + if (line.hasOption('h')) { printHelp(options, 0); } // Check a filename is given - if (!line.hasOption('f')) - { + if (!line.hasOption('f')) { System.err.println("Required parameter -f missing!"); printHelp(options, 1); } @@ -247,42 +235,31 @@ public class MetadataExport ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance(); // Check we have an item OK ItemService itemService = contentServiceFactory.getItemService(); - if (!line.hasOption('i')) - { + if (!line.hasOption('i')) { System.out.println("Exporting whole repository WARNING: May take some time!"); exporter = new MetadataExport(c, itemService.findAll(c), exportAll); - } - else - { + } else { String handle = line.getOptionValue('i'); DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(c, handle); - if (dso == null) - { + 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) - { + if (dso.getType() == Constants.ITEM) { System.out.println("Exporting item '" + dso.getName() + "' (" + handle + ")"); List item = new ArrayList<>(); item.add((Item) dso); exporter = new MetadataExport(c, item.iterator(), exportAll); - } - else if (dso.getType() == Constants.COLLECTION) - { + } else if (dso.getType() == Constants.COLLECTION) { System.out.println("Exporting collection '" + dso.getName() + "' (" + handle + ")"); - Collection collection = (Collection)dso; + Collection collection = (Collection) dso; toExport = itemService.findByCollection(c, collection); exporter = new MetadataExport(c, toExport, exportAll); - } - else if (dso.getType() == Constants.COMMUNITY) - { + } else if (dso.getType() == Constants.COMMUNITY) { System.out.println("Exporting community '" + dso.getName() + "' (" + handle + ")"); - exporter = new MetadataExport(c, (Community)dso, exportAll); - } - else - { + exporter = new MetadataExport(c, (Community) dso, exportAll); + } else { System.err.println("Error identifying '" + handle + "'"); System.exit(1); } @@ -292,7 +269,7 @@ public class MetadataExport DSpaceCSV csv = exporter.export(); // Save the files to the file - csv.save(filename); + csv.save(filename); // Finish off and tidy up c.restoreAuthSystemState(); diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java index 997b1d1f9e..9f94506980 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java @@ -7,15 +7,35 @@ */ package org.dspace.app.bulkedit; -import org.dspace.authority.AuthorityValue; -import org.apache.commons.cli.*; -import org.apache.commons.lang.StringUtils; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +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.ParseException; +import org.apache.commons.cli.PosixParser; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.dspace.authority.AuthorityValue; import org.dspace.authority.factory.AuthorityServiceFactory; import org.dspace.authority.service.AuthorityValueService; -import org.dspace.content.*; +import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.WorkspaceItem; import org.dspace.content.authority.Choices; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; @@ -23,9 +43,8 @@ import org.dspace.content.service.InstallItemService; import org.dspace.content.service.ItemService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.ConfigurationManager; -import org.dspace.core.Context; import org.dspace.core.Constants; -import org.dspace.authorize.AuthorizeException; +import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.eperson.EPerson; import org.dspace.eperson.factory.EPersonServiceFactory; @@ -35,40 +54,44 @@ import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.WorkflowService; import org.dspace.workflow.factory.WorkflowServiceFactory; -import java.util.*; -import java.io.File; -import java.io.InputStreamReader; -import java.io.BufferedReader; -import java.io.IOException; -import java.sql.SQLException; - /** * Metadata importer to allow the batch import of metadata from a file * * @author Stuart Lewis */ -public class MetadataImport -{ - /** The Context */ +public class MetadataImport { + /** + * The Context + */ Context c; - /** The DSpaceCSV object we're processing */ + /** + * The DSpaceCSV object we're processing + */ DSpaceCSV csv; - /** The lines to import */ + /** + * The lines to import + */ List toImport; - /** The authority controlled fields */ + /** + * The authority controlled fields + */ protected static Set authorityControlled; - static - { + + static { setAuthorizedMetadataFields(); } - /** The prefix of the authority controlled field */ + /** + * The prefix of the authority controlled field + */ protected static final String AC_PREFIX = "authority.controlled."; - /** Logger */ + /** + * Logger + */ protected static final Logger log = Logger.getLogger(MetadataImport.class); protected final AuthorityValueService authorityValueService; @@ -83,11 +106,10 @@ public class MetadataImport * Create an instance of the metadata importer. Requires a context and an array of CSV lines * to examine. * - * @param c The context + * @param c The context * @param toImport An array of CSV lines to examine */ - public MetadataImport(Context c, DSpaceCSV toImport) - { + public MetadataImport(Context c, DSpaceCSV toImport) { // Store the import settings this.c = c; csv = toImport; @@ -104,37 +126,32 @@ public class MetadataImport * Run an import. The import can either be read-only to detect changes, or * can write changes as it goes. * - * @param change Whether or not to write the changes to the database - * @param useWorkflow Whether the workflows should be used when creating new items + * @param change Whether or not to write the changes to the database + * @param useWorkflow Whether the workflows should be used when creating new items * @param workflowNotify If the workflows should be used, whether to send notifications or not - * @param useTemplate Use collection template if create new item + * @param useTemplate Use collection template if create new item * @return An array of BulkEditChange elements representing the items that have changed - * * @throws MetadataImportException if something goes wrong */ public List runImport(boolean change, boolean useWorkflow, boolean workflowNotify, - boolean useTemplate) throws MetadataImportException - { + boolean useTemplate) throws MetadataImportException { // Store the changes ArrayList changes = new ArrayList(); // Make the changes - try - { + try { Context.Mode originalMode = c.getCurrentMode(); c.setMode(Context.Mode.BATCH_EDIT); // Process each change - for (DSpaceCSVLine line : toImport) - { + for (DSpaceCSVLine line : toImport) { // Get the DSpace item to compare with UUID id = line.getID(); // Is there an action column? - if (csv.hasActions() && (!"".equals(line.getAction())) && (id == null)) - { + if (csv.hasActions() && (!"".equals(line.getAction())) && (id == null)) { throw new MetadataImportException("'action' not allowed for new items!"); } @@ -143,12 +160,10 @@ public class MetadataImport Item item = null; // Is this a new item? - if (id != null) - { + if (id != null) { // Get the item item = itemService.find(c, id); - if (item == null) - { + if (item == null) { throw new MetadataImportException("Unknown item ID " + id); } @@ -157,11 +172,9 @@ public class MetadataImport // Has it moved collection? List collections = line.get("collection"); - if (collections != null) - { + if (collections != null) { // Sanity check we're not orphaning it - if (collections.size() == 0) - { + if (collections.size() == 0) { throw new MetadataImportException("Missing collection from item " + item.getHandle()); } List actualCollections = item.getCollections(); @@ -169,21 +182,16 @@ public class MetadataImport } // Iterate through each metadata element in the csv line - for (String md : line.keys()) - { + for (String md : line.keys()) { // Get the values we already have - if (!"id".equals(md)) - { + if (!"id".equals(md)) { // Get the values from the CSV String[] fromCSV = line.get(md).toArray(new String[line.get(md).size()]); // Remove authority unless the md is not authority controlled - if (!isAuthorityControlledField(md)) - { - for (int i=0; i -1) - { + if (pos > -1) { fromCSV[i] = fromCSV[i].substring(0, pos); } } @@ -194,94 +202,72 @@ public class MetadataImport } } - if (csv.hasActions()) - { + if (csv.hasActions()) { // Perform the action String action = line.getAction(); - if ("".equals(action)) - { + if ("".equals(action)) { // Do nothing - } - else if ("expunge".equals(action)) - { + } else if ("expunge".equals(action)) { // Does the configuration allow deletes? - if (!ConfigurationManager.getBooleanProperty("bulkedit", "allowexpunge", false)) - { + if (!ConfigurationManager.getBooleanProperty("bulkedit", "allowexpunge", false)) { throw new MetadataImportException("'expunge' action denied by configuration"); } // Remove the item - if (change) { - itemService.delete(c, item); - } - + if (change) { + itemService.delete(c, item); + } + whatHasChanged.setDeleted(); - } - else if ("withdraw".equals(action)) - { + } else if ("withdraw".equals(action)) { // Withdraw the item - if (!item.isWithdrawn()) - { - if (change) - { + if (!item.isWithdrawn()) { + if (change) { itemService.withdraw(c, item); } whatHasChanged.setWithdrawn(); } - } - else if ("reinstate".equals(action)) - { + } else if ("reinstate".equals(action)) { // Reinstate the item - if (item.isWithdrawn()) - { - if (change) - { + if (item.isWithdrawn()) { + if (change) { itemService.reinstate(c, item); } whatHasChanged.setReinstated(); } - } - else { + } else { // Unknown action! throw new MetadataImportException("Unknown action: " + action); } } // Only record if changes have been made - if (whatHasChanged.hasChanges()) - { + if (whatHasChanged.hasChanges()) { changes.add(whatHasChanged); } - } - else - { + } else { // This is marked as a new item, so no need to compare // First check a user is set, otherwise this can't happen - if (c.getCurrentUser() == null) - { - throw new MetadataImportException("When adding new items, a user must be specified with the -e option"); + if (c.getCurrentUser() == null) { + throw new MetadataImportException( + "When adding new items, a user must be specified with the -e option"); } // Iterate through each metadata element in the csv line BulkEditChange whatHasChanged = new BulkEditChange(); - for (String md : line.keys()) - { + for (String md : line.keys()) { // Get the values we already have - if (!"id".equals(md)) - { + if (!"id".equals(md)) { // Get the values from the CSV String[] fromCSV = line.get(md).toArray(new String[line.get(md).size()]); // Remove authority unless the md is not authority controlled - if (!isAuthorityControlledField(md)) - { - for (int i=0; i -1) - { + if (pos > -1) { fromCSV[i] = fromCSV[i].substring(0, pos); } } @@ -294,62 +280,55 @@ public class MetadataImport // Check it has an owning collection List collections = line.get("collection"); - if (collections == null) - { - throw new MetadataImportException("New items must have a 'collection' assigned in the form of a handle"); + if (collections == null) { + throw new MetadataImportException( + "New items must have a 'collection' assigned in the form of a handle"); } // Check collections are really collections ArrayList check = new ArrayList(); Collection collection; - for (String handle : collections) - { - try - { + for (String handle : collections) { + try { // Resolve the handle to the collection collection = (Collection) handleService.resolveToObject(c, handle); // Check it resolved OK - if (collection == null) - { - throw new MetadataImportException("'" + handle + "' is not a Collection! You must specify a valid collection for new items"); + if (collection == null) { + throw new MetadataImportException( + "'" + handle + "' is not a Collection! You must specify a valid collection for " + + "new items"); } // Check for duplicate - if (check.contains(collection)) - { - throw new MetadataImportException("Duplicate collection assignment detected in new item! " + handle); - } - else - { + if (check.contains(collection)) { + throw new MetadataImportException( + "Duplicate collection assignment detected in new item! " + handle); + } else { check.add(collection); } - } - catch (Exception ex) - { - throw new MetadataImportException("'" + handle + "' is not a Collection! You must specify a valid collection for new items", ex); + } catch (Exception ex) { + throw new MetadataImportException( + "'" + handle + "' is not a Collection! You must specify a valid collection for new " + + "items", + ex); } } // Record the addition to collections boolean first = true; - for (String handle : collections) - { + for (String handle : collections) { Collection extra = (Collection) handleService.resolveToObject(c, handle); - if (first) - { + if (first) { whatHasChanged.setOwningCollection(extra); - } - else - { + } else { whatHasChanged.registerNewMappedCollection(extra); } first = false; } // Create the new item? - if (change) - { + if (change) { // Create the item String collectionHandle = line.get("collection").get(0); collection = (Collection) handleService.resolveToObject(c, collectionHandle); @@ -357,37 +336,32 @@ public class MetadataImport item = wsItem.getItem(); // Add the metadata to the item - for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) - { + for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) { itemService.addMetadata(c, item, dcv.getSchema(), - dcv.getElement(), - dcv.getQualifier(), - dcv.getLanguage(), - dcv.getValue(), - dcv.getAuthority(), - dcv.getConfidence()); + dcv.getElement(), + dcv.getQualifier(), + dcv.getLanguage(), + dcv.getValue(), + dcv.getAuthority(), + dcv.getConfidence()); } // Should the workflow be used? - if(useWorkflow){ + if (useWorkflow) { WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService(); if (workflowNotify) { wfItem = workflowService.start(c, wsItem); } else { wfItem = workflowService.startWithoutNotify(c, wsItem); } - } - else - { + } else { // Install the item installItemService.installItem(c, wsItem); } // Add to extra collections - if (line.get("collection").size() > 0) - { - for (int i = 1; i < collections.size(); i++) - { + if (line.get("collection").size() > 0) { + for (int i = 1; i < collections.size(); i++) { String handle = collections.get(i); Collection extra = (Collection) handleService.resolveToObject(c, handle); collectionService.addItem(c, extra, item); @@ -412,13 +386,9 @@ public class MetadataImport } c.setMode(originalMode); - } - catch (MetadataImportException mie) - { + } catch (MetadataImportException mie) { throw mie; - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); } @@ -429,22 +399,21 @@ public class MetadataImport /** * Compare an item metadata with a line from CSV, and optionally update the item * - * @param item The current item metadata + * @param item The current item metadata * @param fromCSV The metadata from the CSV file - * @param change Whether or not to make the update - * @param md The element to compare + * @param change Whether or not to make the update + * @param md The element to compare * @param changes The changes object to populate - * @param line line in CSV file - * @throws SQLException if there is a problem accessing a Collection from the database, from its handle + * @param line line in CSV file + * @throws SQLException if there is a problem accessing a Collection from the database, from its handle * @throws AuthorizeException if there is an authorization problem with permissions */ protected void compare(Item item, String[] fromCSV, boolean change, - String md, BulkEditChange changes, DSpaceCSVLine line) throws SQLException, AuthorizeException - { + String md, BulkEditChange changes, DSpaceCSVLine line) + throws SQLException, AuthorizeException { // Log what metadata element we're looking at String all = ""; - for (String part : fromCSV) - { + for (String part : fromCSV) { all += part + ","; } all = all.substring(0, all.length()); @@ -452,16 +421,14 @@ public class MetadataImport "item_id=" + item.getID() + ",fromCSV=" + all)); // Don't compare collections or actions - if (("collection".equals(md)) || ("action".equals(md))) - { + if (("collection".equals(md)) || ("action".equals(md))) { return; } // Make a String array of the current values stored in this element // First, strip of language if it is there String language = null; - if (md.contains("[")) - { + if (md.contains("[")) { String[] bits = md.split("\\["); language = bits[1].substring(0, bits[1].length() - 1); } @@ -475,29 +442,26 @@ public class MetadataImport String schema = bits[0]; String element = bits[1]; // If there is a language on the element, strip if off - if (element.contains("[")) - { + if (element.contains("[")) { element = element.substring(0, element.indexOf('[')); } String qualifier = null; - if (bits.length > 2) - { + if (bits.length > 2) { qualifier = bits[2]; // If there is a language, strip if off - if (qualifier.contains("[")) - { + if (qualifier.contains("[")) { qualifier = qualifier.substring(0, qualifier.indexOf('[')); } } log.debug(LogManager.getHeader(c, "metadata_import", "item_id=" + item.getID() + ",fromCSV=" + all + - ",looking_for_schema=" + schema + - ",looking_for_element=" + element + - ",looking_for_qualifier=" + qualifier + - ",looking_for_language=" + language)); + ",looking_for_schema=" + schema + + ",looking_for_element=" + element + + ",looking_for_qualifier=" + qualifier + + ",looking_for_language=" + language)); String[] dcvalues; - if(fromAuthority==null) { + if (fromAuthority == null) { List current = itemService.getMetadata(item, schema, element, qualifier, language); dcvalues = new String[current.size()]; int i = 0; @@ -506,14 +470,15 @@ public class MetadataImport dcvalues[i] = dcv.getValue(); } else { dcvalues[i] = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority(); - dcvalues[i] += csv.getAuthoritySeparator() + (dcv.getConfidence() != -1 ? dcv.getConfidence() : Choices.CF_ACCEPTED); + dcvalues[i] += csv.getAuthoritySeparator() + (dcv.getConfidence() != -1 ? dcv + .getConfidence() : Choices.CF_ACCEPTED); } i++; log.debug(LogManager.getHeader(c, "metadata_import", - "item_id=" + item.getID() + ",fromCSV=" + all + - ",found=" + dcv.getValue())); + "item_id=" + item.getID() + ",fromCSV=" + all + + ",found=" + dcv.getValue())); } - }else{ + } else { dcvalues = line.get(md).toArray(new String[line.get(md).size()]); } @@ -521,9 +486,11 @@ public class MetadataImport // Compare from current->csv for (int v = 0; v < fromCSV.length; v++) { String value = fromCSV[v]; - BulkEditMetadataValue dcv = getBulkEditValueFromCSV(language, schema, element, qualifier, value, fromAuthority); - if (fromAuthority!=null) { - value = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority() + csv.getAuthoritySeparator() + dcv.getConfidence(); + BulkEditMetadataValue dcv = getBulkEditValueFromCSV(language, schema, element, qualifier, value, + fromAuthority); + if (fromAuthority != null) { + value = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority() + csv + .getAuthoritySeparator() + dcv.getConfidence(); fromCSV[v] = value; } @@ -536,93 +503,79 @@ public class MetadataImport } // Compare from csv->current - for (String value : dcvalues) - { + for (String value : dcvalues) { // Look to see if it should be removed BulkEditMetadataValue dcv = new BulkEditMetadataValue(); dcv.setSchema(schema); dcv.setElement(element); dcv.setQualifier(qualifier); dcv.setLanguage(language); - if (value == null || !value.contains(csv.getAuthoritySeparator())) + if (value == null || !value.contains(csv.getAuthoritySeparator())) { simplyCopyValue(value, dcv); - else - { + } else { String[] parts = value.split(csv.getAuthoritySeparator()); dcv.setValue(parts[0]); dcv.setAuthority(parts[1]); dcv.setConfidence((parts.length > 2 ? Integer.valueOf(parts[2]) : Choices.CF_ACCEPTED)); } - if ((value != null) && (!"".equals(value)) && (!contains(value, fromCSV)) && fromAuthority==null) - // fromAuthority==null: with the current implementation metadata values from external authority sources can only be used to add metadata, not to change or remove them - // because e.g. an author that is not in the column "ORCID:dc.contributor.author" could still be in the column "dc.contributor.author" so don't remove it - { + // fromAuthority==null: with the current implementation metadata values from external authority sources + // can only be used to add metadata, not to change or remove them + // because e.g. an author that is not in the column "ORCID:dc.contributor.author" could still be in the + // column "dc.contributor.author" so don't remove it + if ((value != null) && (!"".equals(value)) && (!contains(value, fromCSV)) && fromAuthority == null) { // Remove it log.debug(LogManager.getHeader(c, "metadata_import", "item_id=" + item.getID() + ",fromCSV=" + all + - ",removing_schema=" + schema + - ",removing_element=" + element + - ",removing_qualifier=" + qualifier + - ",removing_language=" + language)); + ",removing_schema=" + schema + + ",removing_element=" + element + + ",removing_qualifier=" + qualifier + + ",removing_language=" + language)); changes.registerRemove(dcv); } } // Update the item if it has changed if ((change) && - ((changes.getAdds().size() > 0) || (changes.getRemoves().size() > 0))) - { + ((changes.getAdds().size() > 0) || (changes.getRemoves().size() > 0))) { // Get the complete list of what values should now be in that element List list = changes.getComplete(); List values = new ArrayList(); List authorities = new ArrayList(); List confidences = new ArrayList(); - for (BulkEditMetadataValue value : list) - { - if ((qualifier == null) && (language == null)) - { + for (BulkEditMetadataValue value : list) { + if ((qualifier == null) && (language == null)) { if ((schema.equals(value.getSchema())) && (element.equals(value.getElement())) && - (value.getQualifier() == null) && - (value.getLanguage() == null)) - { + (value.getQualifier() == null) && + (value.getLanguage() == null)) { values.add(value.getValue()); authorities.add(value.getAuthority()); confidences.add(value.getConfidence()); } - } - else if (qualifier == null) - { + } else if (qualifier == null) { if ((schema.equals(value.getSchema())) && (element.equals(value.getElement())) && (language.equals(value.getLanguage())) && - (value.getQualifier() == null)) - { + (value.getQualifier() == null)) { values.add(value.getValue()); authorities.add(value.getAuthority()); confidences.add(value.getConfidence()); } - } - else if (language == null) - { + } else if (language == null) { if ((schema.equals(value.getSchema())) && (element.equals(value.getElement())) && (qualifier.equals(value.getQualifier())) && - (value.getLanguage() == null)) - { + (value.getLanguage() == null)) { values.add(value.getValue()); authorities.add(value.getAuthority()); confidences.add(value.getConfidence()); } - } - else - { + } else { if ((schema.equals(value.getSchema())) && (element.equals(value.getElement())) && (qualifier.equals(value.getQualifier())) && - (language.equals(value.getLanguage()))) - { + (language.equals(value.getLanguage()))) { values.add(value.getValue()); authorities.add(value.getAuthority()); confidences.add(value.getConfidence()); @@ -641,23 +594,22 @@ public class MetadataImport * Compare changes between an items owning collection and mapped collections * and what is in the CSV file * - * @param item The item in question - * @param collections The collection handles from the CSV file + * @param item The item in question + * @param collections The collection handles from the CSV file * @param actualCollections The Collections from the actual item - * @param bechange The bulkedit change object for this item - * @param change Whether or not to actuate a change - * - * @throws SQLException if there is a problem accessing a Collection from the database, from its handle - * @throws AuthorizeException if there is an authorization problem with permissions - * @throws IOException Can be thrown when moving items in communities + * @param bechange The bulkedit change object for this item + * @param change Whether or not to actuate a change + * @throws SQLException if there is a problem accessing a Collection from the database, from its handle + * @throws AuthorizeException if there is an authorization problem with permissions + * @throws IOException Can be thrown when moving items in communities * @throws MetadataImportException If something goes wrong to be reported back to the user */ protected void compare(Item item, - List collections, - List actualCollections, - BulkEditChange bechange, - boolean change) throws SQLException, AuthorizeException, IOException, MetadataImportException - { + List collections, + List actualCollections, + BulkEditChange bechange, + boolean change) + throws SQLException, AuthorizeException, IOException, MetadataImportException { // First, check the owning collection (as opposed to mapped collections) is the same of changed String oldOwner = item.getOwningCollection().getHandle(); String newOwner = collections.get(0); @@ -665,32 +617,28 @@ public class MetadataImport Collection newCollection = (Collection) handleService.resolveToObject(c, newOwner); // Check it resolved OK - if (newCollection == null) - { - throw new MetadataImportException("'" + newOwner + "' is not a Collection! You must specify a valid collection ID"); + if (newCollection == null) { + throw new MetadataImportException( + "'" + newOwner + "' is not a Collection! You must specify a valid collection ID"); } - if (!oldOwner.equals(newOwner)) - { + if (!oldOwner.equals(newOwner)) { // Register the old and new owning collections - bechange.changeOwningCollection(item.getOwningCollection(), (Collection) handleService.resolveToObject(c, newOwner)); + bechange.changeOwningCollection(item.getOwningCollection(), + (Collection) handleService.resolveToObject(c, newOwner)); } // Second, loop through the strings from the CSV of mapped collections boolean first = true; - for (String csvcollection : collections) - { + for (String csvcollection : collections) { // Ignore the first collection as this is the owning collection - if (!first) - { + if (!first) { // Look for it in the actual list of Collections boolean found = false; - for (Collection collection : actualCollections) - { + for (Collection collection : actualCollections) { if (collection.getID() != item.getOwningCollection().getID()) { // Is it there? - if (csvcollection.equals(collection.getHandle())) - { + if (csvcollection.equals(collection.getHandle())) { found = true; } } @@ -698,15 +646,13 @@ public class MetadataImport // Was it found? DSpaceObject dso = handleService.resolveToObject(c, csvcollection); - if ((dso == null) || (dso.getType() != Constants.COLLECTION)) - { + if ((dso == null) || (dso.getType() != Constants.COLLECTION)) { throw new MetadataImportException("Collection defined for item " + item.getID() + - " (" + item.getHandle() + ") is not a collection"); + " (" + item.getHandle() + ") is not a collection"); } - if (!found) - { + if (!found) { // Register the new mapped collection - Collection col = (Collection)dso; + Collection col = (Collection) dso; bechange.registerNewMappedCollection(col); } } @@ -714,23 +660,17 @@ public class MetadataImport } // Third, loop through the strings from the current item - for (Collection collection : actualCollections) - { + for (Collection collection : actualCollections) { // Look for it in the actual list of Collections boolean found = false; first = true; - for (String csvcollection : collections) - { + for (String csvcollection : collections) { // Don't check the owning collection - if ((first) && (collection.getID().equals(item.getOwningCollection().getID()))) - { + if ((first) && (collection.getID().equals(item.getOwningCollection().getID()))) { found = true; - } - else - { + } else { // Is it there? - if (!first && collection.getHandle().equals(csvcollection)) - { + if (!first && collection.getHandle().equals(csvcollection)) { found = true; } } @@ -738,51 +678,42 @@ public class MetadataImport } // Was it found? - if (!found) - { + if (!found) { // Record that it isn't there any more bechange.registerOldMappedCollection(collection); } } // Process the changes - if (change) - { + if (change) { // Remove old mapped collections - for (Collection collection : bechange.getOldMappedCollections()) - { + for (Collection collection : bechange.getOldMappedCollections()) { collectionService.removeItem(c, collection, item); } // Add to new owned collection - if (bechange.getNewOwningCollection() != null) - { + if (bechange.getNewOwningCollection() != null) { collectionService.addItem(c, bechange.getNewOwningCollection(), item); item.setOwningCollection(bechange.getNewOwningCollection()); itemService.update(c, item); } // Remove from old owned collection (if still a member) - if (bechange.getOldOwningCollection() != null) - { + if (bechange.getOldOwningCollection() != null) { boolean found = false; - for (Collection c : item.getCollections()) - { - if (c.getID().equals(bechange.getOldOwningCollection().getID())) - { + for (Collection c : item.getCollections()) { + if (c.getID().equals(bechange.getOldOwningCollection().getID())) { found = true; } } - if (found) - { + if (found) { collectionService.removeItem(c, bechange.getOldOwningCollection(), item); } } // Add to new mapped collections - for (Collection collection : bechange.getNewMappedCollections()) - { + for (Collection collection : bechange.getNewMappedCollections()) { collectionService.addItem(c, collection, item); } @@ -793,71 +724,66 @@ public class MetadataImport * Add an item metadata with a line from CSV, and optionally update the item * * @param fromCSV The metadata from the CSV file - * @param md The element to compare + * @param md The element to compare * @param changes The changes object to populate - * - * @throws SQLException when an SQL error has occurred (querying DSpace) + * @throws SQLException when an SQL error has occurred (querying DSpace) * @throws AuthorizeException If the user can't make the changes */ protected void add(String[] fromCSV, String md, BulkEditChange changes) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { // Don't add owning collection or action - if (("collection".equals(md)) || ("action".equals(md))) - { + if (("collection".equals(md)) || ("action".equals(md))) { return; } // Make a String array of the values // First, strip of language if it is there String language = null; - if (md.contains("[")) - { + if (md.contains("[")) { String[] bits = md.split("\\["); language = bits[1].substring(0, bits[1].length() - 1); } AuthorityValue fromAuthority = authorityValueService.getAuthorityValueType(md); if (md.indexOf(':') > 0) { - md = md.substring(md.indexOf(':')+1); + md = md.substring(md.indexOf(':') + 1); } String[] bits = md.split("\\."); String schema = bits[0]; String element = bits[1]; // If there is a language on the element, strip if off - if (element.contains("[")) - { + if (element.contains("[")) { element = element.substring(0, element.indexOf('[')); } String qualifier = null; - if (bits.length > 2) - { + if (bits.length > 2) { qualifier = bits[2]; // If there is a language, strip if off - if (qualifier.contains("[")) - { + if (qualifier.contains("[")) { qualifier = qualifier.substring(0, qualifier.indexOf('[')); } } // Add all the values - for (String value : fromCSV) - { - BulkEditMetadataValue dcv = getBulkEditValueFromCSV(language, schema, element, qualifier, value, fromAuthority); - if(fromAuthority!=null){ - value = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority() + csv.getAuthoritySeparator() + dcv.getConfidence(); + for (String value : fromCSV) { + BulkEditMetadataValue dcv = getBulkEditValueFromCSV(language, schema, element, qualifier, value, + fromAuthority); + if (fromAuthority != null) { + value = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority() + csv + .getAuthoritySeparator() + dcv.getConfidence(); } // Add it - if ((value != null) && (!"".equals(value))) - { + if ((value != null) && (!"".equals(value))) { changes.registerAdd(dcv); } } } - protected BulkEditMetadataValue getBulkEditValueFromCSV(String language, String schema, String element, String qualifier, String value, AuthorityValue fromAuthority) { + protected BulkEditMetadataValue getBulkEditValueFromCSV(String language, String schema, String element, + String qualifier, String value, + AuthorityValue fromAuthority) { // Look to see if it should be removed BulkEditMetadataValue dcv = new BulkEditMetadataValue(); dcv.setSchema(schema); @@ -904,17 +830,14 @@ public class MetadataImport /** * Method to find if a String occurs in an array of Strings * - * @param needle The String to look for + * @param needle The String to look for * @param haystack The array of Strings to search through * @return Whether or not it is contained */ - protected boolean contains(String needle, String[] haystack) - { + protected boolean contains(String needle, String[] haystack) { // Look for the needle in the haystack - for (String examine : haystack) - { - if (clean(examine).equals(clean(needle))) - { + for (String examine : haystack) { + if (clean(examine).equals(clean(needle))) { return true; } } @@ -927,14 +850,12 @@ public class MetadataImport * @param in The element to clean * @return The cleaned up element */ - protected String clean(String in) - { + protected String clean(String in) { // Check for nulls - if (in == null) - { + if (in == null) { return null; } - + // Remove newlines as different operating systems sometimes use different formats return in.replaceAll("\r\n", "").replaceAll("\n", "").trim(); } @@ -942,11 +863,10 @@ public class MetadataImport /** * Print the help message * - * @param options The command line options the user gave + * @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) - { + private static void printHelp(Options options, int exitCode) { // print the help message HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("MetatadataImport\n", options); @@ -961,12 +881,10 @@ public class MetadataImport * @param changed Whether or not the changes have been made * @return The number of items that have changed */ - private static int displayChanges(List changes, boolean changed) - { + private static int displayChanges(List changes, boolean changed) { // Display the changes int changeCounter = 0; - for (BulkEditChange change : changes) - { + for (BulkEditChange change : changes) { // Get the changes List adds = change.getAdds(); List removes = change.getRemoves(); @@ -975,27 +893,19 @@ public class MetadataImport if ((adds.size() > 0) || (removes.size() > 0) || (newCollections.size() > 0) || (oldCollections.size() > 0) || (change.getNewOwningCollection() != null) || (change.getOldOwningCollection() != null) || - (change.isDeleted()) || (change.isWithdrawn()) || (change.isReinstated())) - { + (change.isDeleted()) || (change.isWithdrawn()) || (change.isReinstated())) { // Show the item Item i = change.getItem(); System.out.println("-----------------------------------------------------------"); - if (!change.isNewItem()) - { + if (!change.isNewItem()) { System.out.println("Changes for item: " + i.getID() + " (" + i.getHandle() + ")"); - } - else - { + } else { System.out.print("New item: "); - if (i != null) - { - if (i.getHandle() != null) - { + if (i != null) { + if (i.getHandle() != null) { System.out.print(i.getID() + " (" + i.getHandle() + ")"); - } - else - { + } else { System.out.print(i.getID() + " (in workflow)"); } } @@ -1005,69 +915,48 @@ public class MetadataImport } // Show actions - if (change.isDeleted()) - { - if (changed) - { + if (change.isDeleted()) { + if (changed) { System.out.println(" - EXPUNGED!"); - } - else - { + } else { System.out.println(" - EXPUNGE!"); } } - if (change.isWithdrawn()) - { - if (changed) - { + if (change.isWithdrawn()) { + if (changed) { System.out.println(" - WITHDRAWN!"); - } - else - { + } else { System.out.println(" - WITHDRAW!"); } } - if (change.isReinstated()) - { - if (changed) - { + if (change.isReinstated()) { + if (changed) { System.out.println(" - REINSTATED!"); - } - else - { + } else { System.out.println(" - REINSTATE!"); } } - if (change.getNewOwningCollection() != null) - { + if (change.getNewOwningCollection() != null) { Collection c = change.getNewOwningCollection(); - if (c != null) - { + if (c != null) { String cHandle = c.getHandle(); String cName = c.getName(); - if (!changed) - { + if (!changed) { System.out.print(" + New owning collection (" + cHandle + "): "); - } - else - { + } else { System.out.print(" + New owning collection (" + cHandle + "): "); } System.out.println(cName); } c = change.getOldOwningCollection(); - if (c != null) - { + if (c != null) { String cHandle = c.getHandle(); String cName = c.getName(); - if (!changed) - { + if (!changed) { System.out.print(" + Old owning collection (" + cHandle + "): "); - } - else - { + } else { System.out.print(" + Old owning collection (" + cHandle + "): "); } System.out.println(cName); @@ -1075,60 +964,45 @@ public class MetadataImport } // Show new mapped collections - for (Collection c : newCollections) - { + for (Collection c : newCollections) { String cHandle = c.getHandle(); String cName = c.getName(); - if (!changed) - { + if (!changed) { System.out.print(" + Map to collection (" + cHandle + "): "); - } - else - { + } else { System.out.print(" + Mapped to collection (" + cHandle + "): "); } System.out.println(cName); } // Show old mapped collections - for (Collection c : oldCollections) - { + for (Collection c : oldCollections) { String cHandle = c.getHandle(); String cName = c.getName(); - if (!changed) - { + if (!changed) { System.out.print(" + Un-map from collection (" + cHandle + "): "); - } - else - { + } else { System.out.print(" + Un-mapped from collection (" + cHandle + "): "); } System.out.println(cName); } // Show additions - for (BulkEditMetadataValue metadataValue : adds) - { + for (BulkEditMetadataValue metadataValue : adds) { String md = metadataValue.getSchema() + "." + metadataValue.getElement(); - if (metadataValue.getQualifier() != null) - { + if (metadataValue.getQualifier() != null) { md += "." + metadataValue.getQualifier(); } - if (metadataValue.getLanguage() != null) - { + if (metadataValue.getLanguage() != null) { md += "[" + metadataValue.getLanguage() + "]"; } - if (!changed) - { + if (!changed) { System.out.print(" + Add (" + md + "): "); - } - else - { + } else { System.out.print(" + Added (" + md + "): "); } System.out.print(metadataValue.getValue()); - if (isAuthorityControlledField(md)) - { + if (isAuthorityControlledField(md)) { System.out.print(", authority = " + metadataValue.getAuthority()); System.out.print(", confidence = " + metadataValue.getConfidence()); } @@ -1136,28 +1010,21 @@ public class MetadataImport } // Show removals - for (BulkEditMetadataValue metadataValue : removes) - { + for (BulkEditMetadataValue metadataValue : removes) { String md = metadataValue.getSchema() + "." + metadataValue.getElement(); - if (metadataValue.getQualifier() != null) - { + if (metadataValue.getQualifier() != null) { md += "." + metadataValue.getQualifier(); } - if (metadataValue.getLanguage() != null) - { + if (metadataValue.getLanguage() != null) { md += "[" + metadataValue.getLanguage() + "]"; } - if (!changed) - { + if (!changed) { System.out.print(" - Remove (" + md + "): "); - } - else - { + } else { System.out.print(" - Removed (" + md + "): "); } System.out.print(metadataValue.getValue()); - if (isAuthorityControlledField(md)) - { + if (isAuthorityControlledField(md)) { System.out.print(", authority = " + metadataValue.getAuthority()); System.out.print(", confidence = " + metadataValue.getConfidence()); } @@ -1169,10 +1036,8 @@ public class MetadataImport /** * is the field is defined as authority controlled - * */ - private static boolean isAuthorityControlledField(String md) - { + private static boolean isAuthorityControlledField(String md) { String mdf = StringUtils.substringAfter(md, ":"); mdf = StringUtils.substringBefore(mdf, "["); return authorityControlled.contains(mdf); @@ -1180,30 +1045,25 @@ public class MetadataImport /** * Set authority controlled fields - * */ - private static void setAuthorizedMetadataFields() - { + private static void setAuthorizedMetadataFields() { authorityControlled = new HashSet(); Enumeration propertyNames = ConfigurationManager.getProperties().propertyNames(); - while(propertyNames.hasMoreElements()) - { + while (propertyNames.hasMoreElements()) { String key = ((String) propertyNames.nextElement()).trim(); if (key.startsWith(AC_PREFIX) - && ConfigurationManager.getBooleanProperty(key, false)) - { - authorityControlled.add(key.substring(AC_PREFIX.length())); + && ConfigurationManager.getBooleanProperty(key, false)) { + authorityControlled.add(key.substring(AC_PREFIX.length())); } } } /** - * main method to run the metadata exporter - * - * @param argv the command line arguments given - */ - public static void main(String[] argv) - { + * main method to run the metadata exporter + * + * @param argv the command line arguments given + */ + public static void main(String[] argv) { // Create an options object and populate it CommandLineParser parser = new PosixParser(); @@ -1211,33 +1071,31 @@ public class MetadataImport options.addOption("f", "file", true, "source file"); options.addOption("e", "email", true, "email address or user id of user (required if adding new items)"); - options.addOption("s", "silent", false, "silent operation - doesn't request confirmation of changes USE WITH CAUTION"); + options.addOption("s", "silent", false, + "silent operation - doesn't request confirmation of changes USE WITH CAUTION"); options.addOption("w", "workflow", false, "workflow - when adding new items, use collection workflow"); - options.addOption("n", "notify", false, "notify - when adding new items using a workflow, send notification emails"); - options.addOption("t", "template", false, "template - when adding new items, use the collection template (if it exists)"); + options.addOption("n", "notify", false, + "notify - when adding new items using a workflow, send notification emails"); + options.addOption("t", "template", false, + "template - when adding new items, use the collection template (if it exists)"); options.addOption("h", "help", false, "help"); // Parse the command line arguments CommandLine line; - try - { + try { line = parser.parse(options, argv); - } - catch (ParseException pe) - { + } catch (ParseException pe) { System.err.println("Error parsing command line arguments: " + pe.getMessage()); System.exit(1); return; } - if (line.hasOption('h')) - { + if (line.hasOption('h')) { printHelp(options, 0); } // Check a filename is given - if (!line.hasOption('f')) - { + if (!line.hasOption('f')) { System.err.println("Required parameter -f missing!"); printHelp(options, 1); } @@ -1245,66 +1103,52 @@ public class MetadataImport // Option to apply template to new items boolean useTemplate = false; - if (line.hasOption('t')) - { + if (line.hasOption('t')) { useTemplate = true; } // Options for workflows, and workflow notifications for new items boolean useWorkflow = false; - boolean workflowNotify = false; - if (line.hasOption('w')) - { + boolean workflowNotify = false; + if (line.hasOption('w')) { useWorkflow = true; - if (line.hasOption('n')) - { + if (line.hasOption('n')) { workflowNotify = true; } - } - else if (line.hasOption('n')) - { + } else if (line.hasOption('n')) { System.err.println("Invalid option 'n': (notify) can only be specified with the 'w' (workflow) option."); System.exit(1); } // Create a context Context c; - try - { + try { c = new Context(); c.turnOffAuthorisationSystem(); - } - catch (Exception e) - { + } catch (Exception e) { System.err.println("Unable to create a new DSpace Context: " + e.getMessage()); System.exit(1); return; } // Find the EPerson, assign to context - try - { - if (line.hasOption('e')) - { + try { + if (line.hasOption('e')) { EPerson eperson; String e = line.getOptionValue('e'); - if (e.indexOf('@') != -1) - { + if (e.indexOf('@') != -1) { eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(c, e); - } else - { + } else { eperson = EPersonServiceFactory.getInstance().getEPersonService().find(c, UUID.fromString(e)); } - if (eperson == null) - { + if (eperson == null) { System.out.println("Error, eperson cannot be found: " + e); System.exit(1); } c.setCurrentUser(eperson); } - } catch (Exception e) - { + } catch (Exception e) { System.err.println("Unable to find DSpace user: " + e.getMessage()); System.exit(1); return; @@ -1315,18 +1159,13 @@ public class MetadataImport // Read lines from the CSV file DSpaceCSV csv; - try - { + try { csv = new DSpaceCSV(new File(filename), c); - } - catch (MetadataImportInvalidHeadingException miihe) - { + } catch (MetadataImportInvalidHeadingException miihe) { System.err.println(miihe.getMessage()); System.exit(1); return; - } - catch (Exception e) - { + } catch (Exception e) { System.err.println("Error reading file: " + e.getMessage()); System.exit(1); return; @@ -1336,15 +1175,11 @@ public class MetadataImport MetadataImport importer = new MetadataImport(c, csv); List changes; - if (!line.hasOption('s')) - { + if (!line.hasOption('s')) { // See what has changed - try - { + try { changes = importer.runImport(false, useWorkflow, workflowNotify, useTemplate); - } - catch (MetadataImportException mie) - { + } catch (MetadataImportException mie) { System.err.println("Error: " + mie.getMessage()); System.exit(1); return; @@ -1354,52 +1189,36 @@ public class MetadataImport int changeCounter = displayChanges(changes, false); // If there were changes, ask if we should execute them - if (changeCounter > 0) - { - try - { + if (changeCounter > 0) { + try { // Ask the user if they want to make the changes System.out.println("\n" + changeCounter + " item(s) will be changed\n"); System.out.print("Do you want to make these changes? [y/n] "); String yn = (new BufferedReader(new InputStreamReader(System.in))).readLine(); - if ("y".equalsIgnoreCase(yn)) - { + if ("y".equalsIgnoreCase(yn)) { change = true; - } - else - { + } else { System.out.println("No data has been changed."); } - } - catch (IOException ioe) - { + } catch (IOException ioe) { System.err.println("Error: " + ioe.getMessage()); System.err.println("No changes have been made"); System.exit(1); } - } - else - { + } else { System.out.println("There were no changes detected"); } - } - else - { + } else { change = true; } - try - { + try { // If required, make the change - if (change) - { - try - { + if (change) { + try { // Make the changes changes = importer.runImport(true, useWorkflow, workflowNotify, useTemplate); - } - catch (MetadataImportException mie) - { + } catch (MetadataImportException mie) { System.err.println("Error: " + mie.getMessage()); System.exit(1); return; @@ -1415,9 +1234,7 @@ public class MetadataImport // Finsh off and tidy up c.restoreAuthSystemState(); c.complete(); - } - catch (Exception e) - { + } catch (Exception e) { c.abort(); System.err.println("Error committing changes to database: " + e.getMessage()); System.err.println("Aborting most recent changes."); diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportException.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportException.java index da359a7e0b..3353d78122 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportException.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportException.java @@ -12,26 +12,23 @@ package org.dspace.app.bulkedit; * * @author Stuart Lewis */ -public class MetadataImportException extends Exception -{ +public class MetadataImportException extends Exception { /** * Instantiate a new MetadataImportException * * @param message the error message */ - public MetadataImportException(String message) - { - super(message); + public MetadataImportException(String message) { + super(message); } /** * Instantiate a new MetadataImportException * - * @param message the error message + * @param message the error message * @param exception the root cause */ - public MetadataImportException(String message, Exception exception) - { - super(message, exception); + public MetadataImportException(String message, Exception exception) { + super(message, exception); } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportInvalidHeadingException.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportInvalidHeadingException.java index 29e3155a22..6781517b97 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportInvalidHeadingException.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportInvalidHeadingException.java @@ -12,39 +12,51 @@ package org.dspace.app.bulkedit; * * @author Stuart Lewis */ -public class MetadataImportInvalidHeadingException extends Exception -{ - /** The type of error (schema or element) */ +public class MetadataImportInvalidHeadingException extends Exception { + /** + * The type of error (schema or element) + */ private int type; - /** The bad heading */ + /** + * The bad heading + */ private String badHeading; - /** The column number */ + /** + * The column number + */ private int column; - /** Error with the schema */ + /** + * Error with the schema + */ public static final int SCHEMA = 0; - /** Error with the element */ + /** + * Error with the element + */ public static final int ELEMENT = 1; - /** Error with a missing header */ + /** + * Error with a missing header + */ public static final int MISSING = 98; - /** Error with the whole entry */ + /** + * 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 message the error message + * @param theType the type of the error * @param theColumn column number */ - public MetadataImportInvalidHeadingException(String message, int theType, int theColumn) - { + public MetadataImportInvalidHeadingException(String message, int theType, int theColumn) { super(message); badHeading = message; type = theType; @@ -54,10 +66,9 @@ public class MetadataImportInvalidHeadingException extends Exception /** * Get the type of the exception * - * @return the type of the exception + * @return the type of the exception */ - public String getType() - { + public String getType() { return "" + type; } @@ -66,8 +77,7 @@ public class MetadataImportInvalidHeadingException extends Exception * * @return the invalid heading */ - public String getBadHeader() - { + public String getBadHeader() { return badHeading; } @@ -76,8 +86,7 @@ public class MetadataImportInvalidHeadingException extends Exception * * @return the invalid column number */ - public int getColumn() - { + public int getColumn() { return column; } @@ -87,19 +96,14 @@ public class MetadataImportInvalidHeadingException extends Exception * @return The exception message */ @Override - public String getMessage() - { - if (type == SCHEMA) - { + public String getMessage() { + if (type == SCHEMA) { return "Unknown metadata schema in column " + column + ": " + badHeading; - } else if (type == ELEMENT) - { + } else if (type == ELEMENT) { return "Unknown metadata element in column " + column + ": " + badHeading; - } else if (type == MISSING) - { + } else if (type == MISSING) { return "Row with missing header: column " + column; - } else - { + } else { return "Bad metadata declaration in column" + column + ": " + badHeading; } } diff --git a/dspace-api/src/main/java/org/dspace/app/checker/ChecksumChecker.java b/dspace-api/src/main/java/org/dspace/app/checker/ChecksumChecker.java index 00ec210ad9..40cea2f786 100644 --- a/dspace-api/src/main/java/org/dspace/app/checker/ChecksumChecker.java +++ b/dspace-api/src/main/java/org/dspace/app/checker/ChecksumChecker.java @@ -9,7 +9,11 @@ package org.dspace.app.checker; import java.io.FileNotFoundException; import java.sql.SQLException; -import java.util.*; +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; @@ -20,7 +24,15 @@ 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.*; +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; @@ -28,15 +40,14 @@ import org.dspace.core.Context; import org.dspace.core.Utils; /** - * Command line access to the checksum checker. Options are listed in the + * 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 -{ +public final class ChecksumChecker { private static final Logger LOG = Logger.getLogger(ChecksumChecker.class); private static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); @@ -44,33 +55,32 @@ public final class ChecksumChecker /** * Blanked off constructor, this class should be used as a command line * tool. - * */ - private ChecksumChecker() - { + private ChecksumChecker() { } /** * Command line access to the checksum package. - * + * *
- *
-h
- *
Print help on command line options
- *
-l
- *
loop through bitstreams once
- *
-L
- *
loop continuously through bitstreams
- *
-d
- *
specify duration of process run
- *
-b
- *
specify bitstream IDs
- *
-a [handle_id]
- *
check anything by handle
- *
-e
- *
Report only errors in the logs
- *
-p
- *
Don't prune results before running checker
+ *
-h
+ *
Print help on command line options
+ *
-l
+ *
loop through bitstreams once
+ *
-L
+ *
loop continuously through bitstreams
+ *
-d
+ *
specify duration of process run
+ *
-b
+ *
specify bitstream IDs
+ *
-a [handle_id]
+ *
check anything by handle
+ *
-e
+ *
Report only errors in the logs
+ *
-p
+ *
Don't prune results before running checker
*
+ * * @param args the command line arguments given * @throws SQLException if error */ @@ -84,7 +94,7 @@ public final class ChecksumChecker options.addOption("l", "looping", false, "Loop once through bitstreams"); options.addOption("L", "continuous", false, - "Loop continuously through bitstreams"); + "Loop continuously through bitstreams"); options.addOption("h", "help", false, "Help"); options.addOption("d", "duration", true, "Checking duration"); options.addOption("c", "count", true, "Check count"); @@ -99,25 +109,21 @@ public final class ChecksumChecker 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')); + .withArgName("prune") + .hasOptionalArgs(1) + .withDescription( + "Prune old results (optionally using specified properties file for configuration)") + .create('p')); - try - { + try { line = parser.parse(options, args); - } - catch (ParseException e) - { + } catch (ParseException e) { LOG.fatal(e); System.exit(1); } // user asks for help - if (line.hasOption('h')) - { + if (line.hasOption('h')) { printHelp(options); } Context context = null; @@ -126,23 +132,19 @@ public final class ChecksumChecker // Prune stage - if (line.hasOption('p')) - { + if (line.hasOption('p')) { ResultsPruner rp = null; - try - { + try { rp = (line.getOptionValue('p') != null) ? ResultsPruner - .getPruner(context, line.getOptionValue('p')) : ResultsPruner - .getDefaultPruner(context); - } - catch (FileNotFoundException e) - { + .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."); + + " old results from the database."); } Date processStart = Calendar.getInstance().getTime(); @@ -151,77 +153,55 @@ public final class ChecksumChecker // process should loop infinitely through // most_recent_checksum table - if (line.hasOption('l')) - { + if (line.hasOption('l')) { dispatcher = new SimpleDispatcher(context, processStart, false); - } - else if (line.hasOption('L')) - { + } else if (line.hasOption('L')) { dispatcher = new SimpleDispatcher(context, processStart, true); - } - else if (line.hasOption('b')) - { + } else if (line.hasOption('b')) { // check only specified bitstream(s) String[] ids = line.getOptionValues('b'); List bitstreams = new ArrayList<>(ids.length); - for (int i = 0; i < ids.length; i++) - { - try - { + for (int i = 0; i < ids.length; i++) { + try { bitstreams.add(bitstreamService.find(context, UUID.fromString(ids[i]))); - } - catch (NumberFormatException nfe) - { + } catch (NumberFormatException nfe) { System.err.println("The following argument: " + ids[i] - + " is not an integer"); + + " is not an integer"); System.exit(0); } } dispatcher = new IteratorDispatcher(bitstreams.iterator()); - } - - else if (line.hasOption('a')) - { + } else if (line.hasOption('a')) { dispatcher = new HandleDispatcher(context, line.getOptionValue('a')); - } - else if (line.hasOption('d')) - { + } else if (line.hasOption('d')) { // run checker process for specified duration - try - { + try { dispatcher = new LimitedDurationDispatcher( - new SimpleDispatcher(context, processStart, true), new Date( - System.currentTimeMillis() - + Utils.parseDuration(line - .getOptionValue('d')))); - } - catch (Exception e) - { + 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); + + " as a duration: ", e); System.exit(0); } - } - else if (line.hasOption('c')) - { + } 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 - { + context, processStart, false), count); + } else { dispatcher = new LimitedCountDispatcher(new SimpleDispatcher( - context, processStart, false), 1); + context, processStart, false), 1); } ResultsLogger logger = new ResultsLogger(processStart); CheckerCommand checker = new CheckerCommand(context); // verbose reporting - if (line.hasOption('v')) - { + if (line.hasOption('v')) { checker.setReportVerbose(true); } @@ -240,21 +220,20 @@ public final class ChecksumChecker /** * Print the help options for the user - * + * * @param options that are available for the user */ - private static void printHelp(Options options) - { + 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"); + + "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"); + + "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"); diff --git a/dspace-api/src/main/java/org/dspace/app/configuration/APISpringLoader.java b/dspace-api/src/main/java/org/dspace/app/configuration/APISpringLoader.java index f2d84a045c..ce5865742b 100644 --- a/dspace-api/src/main/java/org/dspace/app/configuration/APISpringLoader.java +++ b/dspace-api/src/main/java/org/dspace/app/configuration/APISpringLoader.java @@ -7,12 +7,12 @@ */ package org.dspace.app.configuration; -import org.dspace.kernel.config.SpringLoader; -import org.dspace.services.ConfigurationService; - 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) */ @@ -32,7 +32,7 @@ public class APISpringLoader implements SpringLoader { try { - return new String[]{new File(filePath.toString()).toURI().toURL().toString() + XML_SUFFIX}; + return new String[] {new File(filePath.toString()).toURI().toURL().toString() + XML_SUFFIX}; } catch (MalformedURLException e) { return new String[0]; } diff --git a/dspace-api/src/main/java/org/dspace/app/harvest/Harvest.java b/dspace-api/src/main/java/org/dspace/app/harvest/Harvest.java index 09e43f160e..3b324f2763 100644 --- a/dspace-api/src/main/java/org/dspace/app/harvest/Harvest.java +++ b/dspace-api/src/main/java/org/dspace/app/harvest/Harvest.java @@ -7,7 +7,17 @@ */ package org.dspace.app.harvest; -import org.apache.commons.cli.*; +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; @@ -27,27 +37,21 @@ import org.dspace.harvest.OAIHarvester; import org.dspace.harvest.factory.HarvestServiceFactory; import org.dspace.harvest.service.HarvestedCollectionService; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; - /** - * Test class for harvested collections. + * Test class for harvested collections. * * @author Alexey Maslov */ -public class Harvest -{ +public class Harvest { private static Context context; - private static final HarvestedCollectionService harvestedCollectionService = HarvestServiceFactory.getInstance().getHarvestedCollectionService(); + private static final HarvestedCollectionService harvestedCollectionService = + HarvestServiceFactory.getInstance().getHarvestedCollectionService(); private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final CollectionService collectionService = + ContentServiceFactory.getInstance().getCollectionService(); - public static void main(String[] argv) throws Exception - { + public static void main(String[] argv) throws Exception { // create an options object and populate it CommandLineParser parser = new PosixParser(); @@ -61,47 +65,50 @@ public class Harvest 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"); + "eperson"); options.addOption("c", "collection", true, - "harvesting collection (handle or id)"); + "harvesting collection (handle or id)"); options.addOption("t", "type", true, - "type of harvesting (0 for none)"); + "type of harvesting (0 for none)"); options.addOption("a", "address", true, - "address of the OAI-PMH server"); + "address of the OAI-PMH server"); options.addOption("i", "oai_set_id", true, - "id of the PMH set representing the harvested collection"); + "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"); + "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 command = null; String eperson = null; String collection = null; String oaiSource = null; String oaiSetID = null; String metadataKey = null; int harvestType = 0; - - if (line.hasOption('h')) - { + + 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( + "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); } @@ -131,7 +138,7 @@ public class Harvest command = "purgeAll"; } - + if (line.hasOption('e')) { eperson = line.getOptionValue('e'); } @@ -152,106 +159,87 @@ public class Harvest 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) - { + if (command == null) { System.out - .println("Error - no parameters specified (run with -h flag for details)"); + .println("Error - no parameters specified (run with -h flag for details)"); System.exit(1); - } - // Run a single harvest cycle on a collection using saved settings. - else if ("run".equals(command)) - { - if (collection == null || eperson == null) - { + } 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"); + .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); - } - // start the harvest loop - else if ("start".equals(command)) - { + } else if ("start".equals(command)) { + // start the harvest loop startHarvester(); - } - // reset harvesting status - else if ("reset".equals(command)) - { + } else if ("reset".equals(command)) { + // reset harvesting status resetHarvesting(); - } - // purge all collections that are set up for harvesting (obviously for testing purposes only) - else if ("purgeAll".equals(command)) - { - if (eperson == null) - { + } 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"); + .println("Error - an eperson must be provided"); System.out.println(" (run with -h flag for details)"); System.exit(1); } List 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()); + 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(); - } - // Delete all items in a collection. Useful for testing fresh harvests. - else if ("purge".equals(command)) - { - if (collection == null || eperson == null) - { + } 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"); + .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 - } - // Configure a collection with the three main settings - else if ("config".equals(command)) - { - if (collection == null) - { + } 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) - { + 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"); + 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) - { + } 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); @@ -260,10 +248,10 @@ public class Harvest 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. + * the collection, if not, bail out. */ private Collection resolveCollection(String collectionID) { @@ -272,47 +260,39 @@ public class Harvest try { // is the ID a handle? - if (collectionID != null) - { - if (collectionID.indexOf('/') != -1) - { + 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) - { + if (dso == null || dso.getType() != Constants.COLLECTION) { targetCollection = null; - } - else - { + } else { targetCollection = (Collection) dso; } - } - // not a handle, try and treat it as an integer collection - // database ID - else - { - System.out.println("Looking up by id: " + collectionID + ", parsed as '" + Integer.parseInt(collectionID) + "', " + "in context: " + context); + } 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) - { + if (targetCollection == null) { System.out.println("Cannot resolve " + collectionID + " to collection"); System.exit(1); } - } - catch (SQLException se) { + } catch (SQLException se) { se.printStackTrace(); } return targetCollection; } - - - private void configureCollection(String collectionID, int type, String oaiSource, String oaiSetId, String mdConfigId) { + + + private void configureCollection(String collectionID, int type, String oaiSource, String oaiSetId, + String mdConfigId) { System.out.println("Running: configure collection"); Collection collection = resolveCollection(collectionID); @@ -330,55 +310,52 @@ public class Harvest harvestedCollectionService.update(context, hc); context.restoreAuthSystemState(); context.complete(); - } - catch (Exception e) { + } catch (Exception e) { System.out.println("Changes could not be committed"); e.printStackTrace(); System.exit(1); - } - finally { - if (context != null) - { + } 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); + System.out.println( + "Purging collection of all items and resetting last_harvested and harvest_message: " + collectionID); Collection collection = resolveCollection(collectionID); - try - { + try { EPerson eperson = ePersonService.findByEmail(context, email); context.setCurrentUser(eperson); context.turnOffAuthorisationSystem(); ItemService itemService = ContentServiceFactory.getInstance().getItemService(); Iterator it = itemService.findByCollection(context, collection); - int i=0; + 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); + 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); @@ -386,20 +363,18 @@ public class Harvest } context.restoreAuthSystemState(); context.dispatchEvents(); - } - catch (Exception e) { + } catch (Exception e) { System.out.println("Changes could not be committed"); e.printStackTrace(); System.exit(1); - } - finally { + } finally { context.restoreAuthSystemState(); } } - - + + /** - * Run a single harvest cycle on the specified collection under the authorization of the supplied EPerson + * Run a single harvest cycle on the specified collection under the authorization of the supplied EPerson */ private void runHarvest(String collectionID, String email) { System.out.println("Running: a harvest cycle on " + collectionID); @@ -411,8 +386,7 @@ public class Harvest HarvestedCollection hc = harvestedCollectionService.find(context, collection); harvester = new OAIHarvester(context, collection, hc); System.out.println("success. "); - } - catch (HarvestingException hex) { + } catch (HarvestingException hex) { System.out.print("failed. "); System.out.println(hex.getMessage()); throw new IllegalStateException("Unable to harvest", hex); @@ -429,14 +403,11 @@ public class Harvest context.setCurrentUser(eperson); harvester.runHarvest(); context.complete(); - } - catch (SQLException e) { + } catch (SQLException e) { throw new IllegalStateException("Failed to run harvester", e); - } - catch (AuthorizeException e) { + } catch (AuthorizeException e) { throw new IllegalStateException("Failed to run harvester", e); - } - catch (IOException e) { + } catch (IOException e) { throw new IllegalStateException("Failed to run harvester", e); } @@ -444,24 +415,22 @@ public class Harvest } /** - * Resets harvest_status and harvest_start_time flags for all collections that have a row in the harvested_collections table + * 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 - { + try { List harvestedCollections = harvestedCollectionService.findAll(context); - for (HarvestedCollection harvestedCollection : harvestedCollections) - { + 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) { + } catch (Exception ex) { System.out.println("failed. "); ex.printStackTrace(); } @@ -470,15 +439,12 @@ public class Harvest /** * Starts up the harvest scheduler. Terminating this process will stop the scheduler. */ - private static void startHarvester() - { - try - { + private static void startHarvester() { + try { System.out.print("Starting harvest loop... "); HarvestServiceFactory.getInstance().getHarvestSchedulingService().startNewScheduler(); System.out.println("running. "); - } - catch (Exception ex) { + } catch (Exception ex) { ex.printStackTrace(); } } @@ -486,34 +452,33 @@ public class Harvest /** * See if the responder is alive and working. * - * @param server address of the responder's host. - * @param set name of an item set. + * @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) - { + private static void pingResponder(String server, String set, String metadataFormat) { List errors; System.out.print("Testing basic PMH access: "); errors = OAIHarvester.verifyOAIharvester(server, set, - (null != metadataFormat) ? metadataFormat : "dc", false); - if (errors.isEmpty()) + (null != metadataFormat) ? metadataFormat : "dc", false); + if (errors.isEmpty()) { System.out.println("OK"); - else - { - for (String error : errors) + } 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()) + (null != metadataFormat) ? metadataFormat : "dc", true); + if (errors.isEmpty()) { System.out.println("OK"); - else - { - for (String error : errors) + } else { + for (String error : errors) { System.err.println(error); + } } } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportCLITool.java b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportCLITool.java index 973f60346b..760a6fc9e5 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportCLITool.java +++ b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportCLITool.java @@ -7,7 +7,17 @@ */ package org.dspace.app.itemexport; -import org.apache.commons.cli.*; +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; @@ -20,8 +30,6 @@ import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; -import java.util.*; - /** * Item exporter to create simple AIPs for DSpace content. Currently exports * individual items, or entire collections. For instructions on use, see @@ -45,17 +53,21 @@ import java.util.*; */ public class ItemExportCLITool { - protected static ItemExportService itemExportService = ItemExportServiceFactory.getInstance().getItemExportService(); + 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 - { + public static void main(String[] argv) throws Exception { // create an options object and populate it CommandLineParser parser = new PosixParser(); @@ -64,10 +76,11 @@ public class ItemExportCLITool { 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)"); + "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"); + "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"); @@ -86,175 +99,140 @@ public class ItemExportCLITool { Item myItem = null; Collection mycollection = null; - if (line.hasOption('h')) - { + 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"); + .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"); + .println("singleitem: ItemExport -t ITEM -i ID -d dest -n number"); System.exit(0); } - if (line.hasOption('t')) // type - { + if (line.hasOption('t')) { // type typeString = line.getOptionValue('t'); - if ("ITEM".equals(typeString)) - { + if ("ITEM".equals(typeString)) { myType = Constants.ITEM; - } - else if ("COLLECTION".equals(typeString)) - { + } else if ("COLLECTION".equals(typeString)) { myType = Constants.COLLECTION; } } - if (line.hasOption('i')) // id - { + if (line.hasOption('i')) { // id myIDString = line.getOptionValue('i'); } - if (line.hasOption('d')) // dest - { + if (line.hasOption('d')) { // dest destDirName = line.getOptionValue('d'); } - if (line.hasOption('n')) // number - { + if (line.hasOption('n')) { // number seqStart = Integer.parseInt(line.getOptionValue('n')); } boolean migrate = false; - if (line.hasOption('m')) // number - { + if (line.hasOption('m')) { // number migrate = true; } boolean zip = false; String zipFileName = ""; - if (line.hasOption('z')) - { + if (line.hasOption('z')) { zip = true; zipFileName = line.getOptionValue('z'); } boolean excludeBitstreams = false; - if (line.hasOption('x')) - { - excludeBitstreams = true; + if (line.hasOption('x')) { + excludeBitstreams = true; } // now validate the args - if (myType == -1) - { + if (myType == -1) { System.out - .println("type must be either COLLECTION or ITEM (-h for help)"); + .println("type must be either COLLECTION or ITEM (-h for help)"); System.exit(1); } - if (destDirName == null) - { + if (destDirName == null) { System.out - .println("destination directory must be set (-h for help)"); + .println("destination directory must be set (-h for help)"); System.exit(1); } - if (seqStart == -1) - { + if (seqStart == -1) { System.out - .println("sequence start number must be set (-h for help)"); + .println("sequence start number must be set (-h for help)"); System.exit(1); } - if (myIDString == null) - { + if (myIDString == null) { System.out - .println("ID must be set to either a database ID or a handle (-h for help)"); + .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) - { + if (myType == Constants.ITEM) { // first, is myIDString a handle? - if (myIDString.indexOf('/') != -1) - { + if (myIDString.indexOf('/') != -1) { myItem = (Item) handleService.resolveToObject(c, myIDString); - if ((myItem == null) || (myItem.getType() != Constants.ITEM)) - { + if ((myItem == null) || (myItem.getType() != Constants.ITEM)) { myItem = null; } - } - else - { + } else { myItem = itemService.find(c, UUID.fromString(myIDString)); } - if (myItem == null) - { + if (myItem == null) { System.out - .println("Error, item cannot be found: " + myIDString); + .println("Error, item cannot be found: " + myIDString); } - } - else - { - if (myIDString.indexOf('/') != -1) - { + } else { + if (myIDString.indexOf('/') != -1) { // has a / must be a handle mycollection = (Collection) handleService.resolveToObject(c, - myIDString); + myIDString); // ensure it's a collection if ((mycollection == null) - || (mycollection.getType() != Constants.COLLECTION)) - { + || (mycollection.getType() != Constants.COLLECTION)) { mycollection = null; } - } - else if (myIDString != null) - { + } else if (myIDString != null) { mycollection = collectionService.find(c, UUID.fromString(myIDString)); } - if (mycollection == null) - { + if (mycollection == null) { System.out.println("Error, collection cannot be found: " - + myIDString); + + myIDString); System.exit(1); } } - if (zip) - { + if (zip) { Iterator items; - if (myItem != null) - { + if (myItem != null) { List myItems = new ArrayList<>(); myItems.add(myItem); items = myItems.iterator(); - } - else - { + } 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) - { + } else { + if (myItem != null) { // it's only a single item - itemExportService.exportItem(c, Collections.singletonList(myItem).iterator(), destDirName, seqStart, migrate, excludeBitstreams); - } - else - { + 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 diff --git a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportException.java b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportException.java index 4032abad6a..4b1def6dee 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportException.java +++ b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportException.java @@ -10,20 +10,17 @@ package org.dspace.app.itemexport; /** * An exception that can be thrown when error occur during item export */ -public class ItemExportException extends Exception -{ +public class ItemExportException extends Exception { public static final int EXPORT_TOO_LARGE = 0; private int reason; - public ItemExportException(int r, String message) - { + public ItemExportException(int r, String message) { super(message); reason = r; } - public int getReason() - { + public int getReason() { return reason; } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java index 7a8bbcfa38..170aa0c620 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java @@ -7,28 +7,58 @@ */ package org.dspace.app.itemexport; +import java.io.BufferedOutputStream; +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.PrintWriter; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.UUID; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import javax.mail.MessagingException; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.itemexport.service.ItemExportService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; -import org.dspace.core.*; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; +import org.dspace.core.LogManager; +import org.dspace.core.Utils; import org.dspace.eperson.EPerson; import org.dspace.eperson.service.EPersonService; import org.dspace.handle.service.HandleService; import org.springframework.beans.factory.annotation.Autowired; -import javax.mail.MessagingException; -import java.io.*; -import java.sql.SQLException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - /** * Item exporter to create simple AIPs for DSpace content. Currently exports * individual items, or entire collections. For instructions on use, see @@ -50,8 +80,7 @@ import java.util.zip.ZipOutputStream; * @author David Little * @author Jay Paz */ -public class ItemExportServiceImpl implements ItemExportService -{ +public class ItemExportServiceImpl implements ItemExportService { protected final int SUBDIR_LIMIT = 0; @Autowired(required = true) @@ -66,20 +95,20 @@ public class ItemExportServiceImpl implements ItemExportService protected HandleService handleService; - /** log4j logger */ + /** + * log4j logger + */ private Logger log = Logger.getLogger(ItemExportServiceImpl.class); - protected ItemExportServiceImpl() - { + protected ItemExportServiceImpl() { } @Override public void exportItem(Context c, Iterator i, - String destDirName, int seqStart, boolean migrate, - boolean excludeBitstreams) throws Exception - { + String destDirName, int seqStart, boolean migrate, + boolean excludeBitstreams) throws Exception { int mySequenceNumber = seqStart; int counter = SUBDIR_LIMIT - 1; int subDirSuffix = 0; @@ -87,27 +116,22 @@ public class ItemExportServiceImpl implements ItemExportService String subdir = ""; File dir; - if (SUBDIR_LIMIT > 0) - { + if (SUBDIR_LIMIT > 0) { dir = new File(destDirName); - if (!dir.isDirectory()) - { + if (!dir.isDirectory()) { throw new IOException(destDirName + " is not a directory."); } } System.out.println("Beginning export"); - while (i.hasNext()) - { - if (SUBDIR_LIMIT > 0 && ++counter == SUBDIR_LIMIT) - { + while (i.hasNext()) { + if (SUBDIR_LIMIT > 0 && ++counter == SUBDIR_LIMIT) { subdir = Integer.valueOf(subDirSuffix++).toString(); fullPath = destDirName + File.separatorChar + subdir; counter = 0; - if (!new File(fullPath).mkdirs()) - { + if (!new File(fullPath).mkdirs()) { throw new IOException("Error, can't make dir " + fullPath); } } @@ -121,44 +145,35 @@ public class ItemExportServiceImpl implements ItemExportService } protected void exportItem(Context c, Item myItem, String destDirName, - int seqStart, boolean migrate, boolean excludeBitstreams) throws Exception - { + int seqStart, boolean migrate, boolean excludeBitstreams) throws Exception { File destDir = new File(destDirName); - if (destDir.exists()) - { + if (destDir.exists()) { // now create a subdirectory File itemDir = new File(destDir + "/" + seqStart); - - System.out.println("Exporting Item " + myItem.getID() + - (myItem.getHandle() != null ? ", handle " + myItem.getHandle() : "") + - " to " + itemDir); - if (itemDir.exists()) - { + System.out.println("Exporting Item " + myItem.getID() + + (myItem.getHandle() != null ? ", handle " + myItem.getHandle() : "") + + " to " + itemDir); + + if (itemDir.exists()) { throw new Exception("Directory " + destDir + "/" + seqStart - + " already exists!"); + + " already exists!"); } - if (itemDir.mkdir()) - { + if (itemDir.mkdir()) { // make it this far, now start exporting writeMetadata(c, myItem, itemDir, migrate); writeBitstreams(c, myItem, itemDir, excludeBitstreams); - if (!migrate) - { + if (!migrate) { writeHandle(c, myItem, itemDir); } - } - else - { + } else { throw new Exception("Error, can't make dir " + itemDir); } - } - else - { + } else { throw new Exception("Error, directory " + destDirName - + " doesn't exist!"); + + " doesn't exist!"); } } @@ -166,48 +181,42 @@ public class ItemExportServiceImpl implements ItemExportService * Discover the different schemas in use and output a separate metadata XML * file for each schema. * - * @param c DSpace context - * @param i DSpace Item + * @param c DSpace context + * @param i DSpace Item * @param destDir destination directory * @param migrate Whether to use the migrate option or not * @throws Exception if error */ protected void writeMetadata(Context c, Item i, File destDir, boolean migrate) - throws Exception - { + throws Exception { Set schemas = new HashSet(); List dcValues = itemService.getMetadata(i, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue metadataValue : dcValues) - { + for (MetadataValue metadataValue : dcValues) { schemas.add(metadataValue.getMetadataField().getMetadataSchema().getName()); } // Save each of the schemas into it's own metadata file - for (String schema : schemas) - { + for (String schema : schemas) { writeMetadata(c, schema, i, destDir, migrate); } } /** * output the item's dublin core into the item directory - * @param c DSpace context - * @param schema schema - * @param i DSpace Item + * + * @param c DSpace context + * @param schema schema + * @param i DSpace Item * @param destDir destination directory * @param migrate Whether to use the migrate option or not * @throws Exception if error */ protected void writeMetadata(Context c, String schema, Item i, - File destDir, boolean migrate) throws Exception - { + File destDir, boolean migrate) throws Exception { String filename; - if (schema.equals(MetadataSchema.DC_SCHEMA)) - { + if (schema.equals(MetadataSchema.DC_SCHEMA)) { filename = "dublin_core.xml"; - } - else - { + } else { filename = "metadata_" + schema + ".xml"; } @@ -215,17 +224,16 @@ public class ItemExportServiceImpl implements ItemExportService System.out.println("Attempting to create file " + outFile); - if (outFile.createNewFile()) - { + if (outFile.createNewFile()) { BufferedOutputStream out = new BufferedOutputStream( - new FileOutputStream(outFile)); + new FileOutputStream(outFile)); List dcorevalues = itemService.getMetadata(i, schema, Item.ANY, Item.ANY, - Item.ANY); + Item.ANY); // XML preamble byte[] utf8 = "\n" - .getBytes("UTF-8"); + .getBytes("UTF-8"); out.write(utf8, 0, utf8.length); String dcTag = "\n"; @@ -235,56 +243,48 @@ public class ItemExportServiceImpl implements ItemExportService String dateIssued = null; String dateAccessioned = null; - for (MetadataValue dcv : dcorevalues) - { + for (MetadataValue dcv : dcorevalues) { MetadataField metadataField = dcv.getMetadataField(); String qualifier = metadataField.getQualifier(); - if (qualifier == null) - { + if (qualifier == null) { qualifier = "none"; } String language = dcv.getLanguage(); - if (language != null) - { + if (language != null) { language = " language=\"" + language + "\""; - } - else - { + } else { language = ""; } utf8 = (" " - + Utils.addEntities(dcv.getValue()) + "\n") - .getBytes("UTF-8"); + + "qualifier=\"" + qualifier + "\"" + + language + ">" + + Utils.addEntities(dcv.getValue()) + "\n") + .getBytes("UTF-8"); if ((!migrate) || (migrate && !( - ("date".equals(metadataField.getElement()) && "issued".equals(qualifier)) || - ("date".equals(metadataField.getElement()) && "accessioned".equals(qualifier)) || - ("date".equals(metadataField.getElement()) && "available".equals(qualifier)) || - ("identifier".equals(metadataField.getElement()) && "uri".equals(qualifier) && - (dcv.getValue() != null && dcv.getValue().startsWith("http://hdl.handle.net/" + - handleService.getPrefix() + "/"))) || - ("description".equals(metadataField.getElement()) && "provenance".equals(qualifier)) || - ("format".equals(metadataField.getElement()) && "extent".equals(qualifier)) || - ("format".equals(metadataField.getElement()) && "mimetype".equals(qualifier))))) - { + ("date".equals(metadataField.getElement()) && "issued".equals(qualifier)) || + ("date".equals(metadataField.getElement()) && "accessioned".equals(qualifier)) || + ("date".equals(metadataField.getElement()) && "available".equals(qualifier)) || + ("identifier".equals(metadataField.getElement()) && "uri".equals(qualifier) && + (dcv.getValue() != null && dcv.getValue().startsWith( + handleService.getCanonicalPrefix() + handleService.getPrefix() + "/"))) || + ("description".equals(metadataField.getElement()) && "provenance".equals(qualifier)) || + ("format".equals(metadataField.getElement()) && "extent".equals(qualifier)) || + ("format".equals(metadataField.getElement()) && "mimetype".equals(qualifier))))) { out.write(utf8, 0, utf8.length); } // Store the date issued and accession to see if they are different // because we need to keep date.issued if they are, when migrating - if (("date".equals(metadataField.getElement()) && "issued".equals(qualifier))) - { + if (("date".equals(metadataField.getElement()) && "issued".equals(qualifier))) { dateIssued = dcv.getValue(); } - if (("date".equals(metadataField.getElement()) && "accessioned".equals(qualifier))) - { + if (("date".equals(metadataField.getElement()) && "accessioned".equals(qualifier))) { dateAccessioned = dcv.getValue(); } } @@ -293,12 +293,11 @@ public class ItemExportServiceImpl implements ItemExportService if ((migrate) && (dateIssued != null) && (dateAccessioned != null) && - (!dateIssued.equals(dateAccessioned))) - { + (!dateIssued.equals(dateAccessioned))) { utf8 = (" " - + Utils.addEntities(dateIssued) + "\n") - .getBytes("UTF-8"); + + "qualifier=\"issued\">" + + Utils.addEntities(dateIssued) + "\n") + .getBytes("UTF-8"); out.write(utf8, 0, utf8.length); } @@ -306,44 +305,38 @@ public class ItemExportServiceImpl implements ItemExportService out.write(utf8, 0, utf8.length); out.close(); - } - else - { + } else { throw new Exception("Cannot create dublin_core.xml in " + destDir); } } /** * create the file 'handle' which contains the handle assigned to the item - * @param c DSpace Context - * @param i DSpace Item + * + * @param c DSpace Context + * @param i DSpace Item * @param destDir destination directory * @throws Exception if error */ protected void writeHandle(Context c, Item i, File destDir) - throws Exception - { - if (i.getHandle() == null) - { + throws Exception { + if (i.getHandle() == null) { return; } String filename = "handle"; File outFile = new File(destDir, filename); - if (outFile.createNewFile()) - { + if (outFile.createNewFile()) { PrintWriter out = new PrintWriter(new FileWriter(outFile)); out.println(i.getHandle()); // close the contents file out.close(); - } - else - { + } else { throw new Exception("Cannot create file " + filename + " in " - + destDir); + + destDir); } } @@ -353,24 +346,18 @@ public class ItemExportServiceImpl implements ItemExportService * However, the export directory will contain actual copies of the content * files being exported. * - * @param c - * the DSpace context - * @param i - * the item being exported - * @param destDir - * the item's export directory - * @param excludeBitstreams - * whether to exclude bitstreams + * @param c the DSpace context + * @param i the item being exported + * @param destDir the item's export directory + * @param excludeBitstreams whether to exclude bitstreams * @throws Exception if error - * if there is any problem writing to the export directory + * if there is any problem writing to the export directory */ protected void writeBitstreams(Context c, Item i, File destDir, - boolean excludeBitstreams) throws Exception - { + boolean excludeBitstreams) throws Exception { File outFile = new File(destDir, "contents"); - if (outFile.createNewFile()) - { + if (outFile.createNewFile()) { PrintWriter out = new PrintWriter(new FileWriter(outFile)); List bundles = i.getBundles(); @@ -405,9 +392,9 @@ public class ItemExportServiceImpl implements ItemExportService while (!excludeBitstreams && !isDone) { if (myName.contains(File.separator)) { String dirs = myName.substring(0, myName - .lastIndexOf(File.separator)); + .lastIndexOf(File.separator)); File fdirs = new File(destDir + File.separator - + dirs); + + dirs); if (!fdirs.exists() && !fdirs.mkdirs()) { log.error("Unable to create destination directory"); } @@ -416,7 +403,7 @@ public class ItemExportServiceImpl implements ItemExportService File fout = new File(destDir, myName); if (fout.createNewFile()) { - InputStream is = bitstreamService.retrieve(c, bitstream); + InputStream is = bitstreamService.retrieve(c, bitstream); FileOutputStream fos = new FileOutputStream(fout); Utils.bufferedCopy(is, fos); // close streams @@ -433,50 +420,44 @@ public class ItemExportServiceImpl implements ItemExportService myPrefix++; } } - + // write the manifest file entry if (bitstreamService.isRegisteredBitstream(bitstream)) { out.println("-r -s " + bitstream.getStoreNumber() - + " -f " + myName + - "\tbundle:" + bundleName + - primary + description); + + " -f " + myName + + "\tbundle:" + bundleName + + primary + description); } else { out.println(myName + "\tbundle:" + bundleName + - primary + description); + primary + description); } - + } } // close the contents file out.close(); - } - else - { + } else { throw new Exception("Cannot create contents in " + destDir); } } @Override public void exportAsZip(Context context, Iterator items, - String destDirName, String zipFileName, - int seqStart, boolean migrate, - boolean excludeBitstreams) throws Exception - - { + String destDirName, String zipFileName, + int seqStart, boolean migrate, + boolean excludeBitstreams) throws Exception { String workDir = getExportWorkDirectory() + - System.getProperty("file.separator") + - zipFileName; + System.getProperty("file.separator") + + zipFileName; File wkDir = new File(workDir); - if (!wkDir.exists() && !wkDir.mkdirs()) - { + if (!wkDir.exists() && !wkDir.mkdirs()) { log.error("Unable to create working direcory"); } File dnDir = new File(destDirName); - if (!dnDir.exists() && !dnDir.mkdirs()) - { + if (!dnDir.exists() && !dnDir.mkdirs()) { log.error("Unable to create destination directory"); } @@ -489,28 +470,25 @@ public class ItemExportServiceImpl implements ItemExportService @Override public void createDownloadableExport(DSpaceObject dso, - Context context, boolean migrate) throws Exception - { + Context context, boolean migrate) throws Exception { EPerson eperson = context.getCurrentUser(); ArrayList list = new ArrayList(1); list.add(dso); processDownloadableExport(list, context, eperson == null ? null - : eperson.getEmail(), migrate); + : eperson.getEmail(), migrate); } @Override public void createDownloadableExport(List dsObjects, - Context context, boolean migrate) throws Exception - { + Context context, boolean migrate) throws Exception { EPerson eperson = context.getCurrentUser(); processDownloadableExport(dsObjects, context, eperson == null ? null - : eperson.getEmail(), migrate); + : eperson.getEmail(), migrate); } @Override public void createDownloadableExport(DSpaceObject dso, - Context context, String additionalEmail, boolean migrate) throws Exception - { + Context context, String additionalEmail, boolean migrate) throws Exception { ArrayList list = new ArrayList(1); list.add(dso); processDownloadableExport(list, context, additionalEmail, migrate); @@ -518,8 +496,7 @@ public class ItemExportServiceImpl implements ItemExportService @Override public void createDownloadableExport(List dsObjects, - Context context, String additionalEmail, boolean migrate) throws Exception - { + Context context, String additionalEmail, boolean migrate) throws Exception { processDownloadableExport(dsObjects, context, additionalEmail, migrate); } @@ -528,18 +505,15 @@ public class ItemExportServiceImpl implements ItemExportService * Collection It then kicks off a new Thread to export the items, zip the * export directory and send confirmation email * - * @param dsObjects - * - List of dspace objects to process - * @param context - * - the dspace context - * @param additionalEmail - * - email address to cc in addition the the current user email - * @param toMigrate Whether to use the migrate option or not + * @param dsObjects - List of dspace objects to process + * @param context - the dspace context + * @param additionalEmail - email address to cc in addition the the current user email + * @param toMigrate Whether to use the migrate option or not * @throws Exception if error */ protected void processDownloadableExport(List dsObjects, - Context context, final String additionalEmail, boolean toMigrate) throws Exception - { + Context context, final String additionalEmail, boolean toMigrate) + throws Exception { final EPerson eperson = context.getCurrentUser(); final boolean migrate = toMigrate; @@ -553,103 +527,78 @@ public class ItemExportServiceImpl implements ItemExportService // it will be checked against the config file entry double size = 0; final HashMap> itemsMap = new HashMap<>(); - for (DSpaceObject dso : dsObjects) - { - if (dso.getType() == Constants.COMMUNITY) - { + for (DSpaceObject dso : dsObjects) { + if (dso.getType() == Constants.COMMUNITY) { Community community = (Community) dso; // get all the collections in the community List collections = communityService.getAllCollections(context, community); - for (Collection collection : collections) - { + for (Collection collection : collections) { ArrayList items = new ArrayList<>(); // get all the items in each collection Iterator iitems = itemService.findByCollection(context, collection); - try - { - while (iitems.hasNext()) - { + try { + while (iitems.hasNext()) { Item item = iitems.next(); // get all the bundles in the item List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { // get all the bitstreams in each bundle List bitstreams = bundle.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { // add up the size - size += bitstream.getSize(); + size += bitstream.getSizeBytes(); } } items.add(item.getID()); } - } - finally - { - if (items.size() > 0) - { - itemsMap.put("collection_"+collection.getID(), items); + } finally { + if (items.size() > 0) { + itemsMap.put("collection_" + collection.getID(), items); } } } - } - else if (dso.getType() == Constants.COLLECTION) - { + } else if (dso.getType() == Constants.COLLECTION) { Collection collection = (Collection) dso; ArrayList items = new ArrayList<>(); // get all the items in the collection Iterator iitems = itemService.findByCollection(context, collection); - try - { - while (iitems.hasNext()) - { + try { + while (iitems.hasNext()) { Item item = iitems.next(); // get all thebundles in the item List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { // get all the bitstreams in the bundle List bitstreams = bundle.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { // add up the size - size += bitstream.getSize(); + size += bitstream.getSizeBytes(); } } items.add(item.getID()); } - } - finally - { - if (items.size() > 0) - { - itemsMap.put("collection_"+collection.getID(), items); + } finally { + if (items.size() > 0) { + itemsMap.put("collection_" + collection.getID(), items); } } - } - else if (dso.getType() == Constants.ITEM) - { + } else if (dso.getType() == Constants.ITEM) { Item item = (Item) dso; // get all the bundles in the item List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { // get all the bitstreams in the bundle List bitstreams = bundle.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { // add up the size - size += bitstream.getSize(); + size += bitstream.getSizeBytes(); } } ArrayList items = new ArrayList<>(); items.add(item.getID()); - itemsMap.put("item_"+item.getID(), items); - } - else - { + itemsMap.put("item_" + item.getID(), items); + } else { // nothing to do just ignore this type of DSpaceObject } } @@ -657,58 +606,48 @@ public class ItemExportServiceImpl implements ItemExportService // check the size of all the bitstreams against the configuration file // entry if it exists String megaBytes = ConfigurationManager - .getProperty("org.dspace.app.itemexport.max.size"); - if (megaBytes != null) - { + .getProperty("org.dspace.app.itemexport.max.size"); + if (megaBytes != null) { float maxSize = 0; - try - { + try { maxSize = Float.parseFloat(megaBytes); - } - catch (Exception e) - { + } catch (Exception e) { // ignore...configuration entry may not be present } - if (maxSize > 0 && maxSize < (size / 1048576.00)) - { // a megabyte + if (maxSize > 0 && maxSize < (size / 1048576.00)) { // a megabyte throw new ItemExportException(ItemExportException.EXPORT_TOO_LARGE, - "The overall size of this export is too large. Please contact your administrator for more information."); + "The overall size of this export is too large. Please contact your " + + "administrator for more information."); } } // if we have any items to process then kick off anonymous thread - if (itemsMap.size() > 0) - { - Thread go = new Thread() - { + if (itemsMap.size() > 0) { + Thread go = new Thread() { @Override - public void run() - { + public void run() { Context context = null; Iterator iitems = null; - try - { + try { // create a new dspace context context = new Context(); // ignore auths context.turnOffAuthorisationSystem(); String fileName = assembleFileName("item", eperson, - new Date()); + new Date()); String workParentDir = getExportWorkDirectory() - + System.getProperty("file.separator") - + fileName; + + System.getProperty("file.separator") + + fileName; String downloadDir = getExportDownloadDirectory(eperson); File dnDir = new File(downloadDir); - if (!dnDir.exists() && !dnDir.mkdirs()) - { + if (!dnDir.exists() && !dnDir.mkdirs()) { log.error("Unable to create download directory"); } Iterator iter = itemsMap.keySet().iterator(); - while(iter.hasNext()) - { + while (iter.hasNext()) { String keyName = iter.next(); List uuids = itemsMap.get(keyName); List items = new ArrayList(); @@ -717,13 +656,12 @@ public class ItemExportServiceImpl implements ItemExportService } iitems = items.iterator(); - String workDir = workParentDir - + System.getProperty("file.separator") - + keyName; + String workDir = workParentDir + + System.getProperty("file.separator") + + keyName; File wkDir = new File(workDir); - if (!wkDir.exists() && !wkDir.mkdirs()) - { + if (!wkDir.exists() && !wkDir.mkdirs()) { log.error("Unable to create working directory"); } @@ -734,34 +672,27 @@ public class ItemExportServiceImpl implements ItemExportService // now zip up the export directory created above zip(workParentDir, downloadDir - + System.getProperty("file.separator") - + fileName + ".zip"); + + System.getProperty("file.separator") + + fileName + ".zip"); // email message letting user know the file is ready for // download emailSuccessMessage(context, eperson, fileName + ".zip"); // return to enforcing auths context.restoreAuthSystemState(); - } - catch (Exception e1) - { - try - { + } catch (Exception e1) { + try { emailErrorMessage(eperson, e1.getMessage()); - } - catch (Exception e) - { + } catch (Exception e) { // wont throw here } throw new IllegalStateException(e1); - } - finally - { + } finally { // Make sure the database connection gets closed in all conditions. - try { - context.complete(); - } catch (SQLException sqle) { - context.abort(); - } + try { + context.complete(); + } catch (SQLException sqle) { + context.abort(); + } } } @@ -769,9 +700,7 @@ public class ItemExportServiceImpl implements ItemExportService go.isDaemon(); go.start(); - } - else - { + } else { Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); emailErrorMessage(eperson, I18nUtil.getMessage("org.dspace.app.itemexport.no-result", supportedLocale)); } @@ -779,8 +708,7 @@ public class ItemExportServiceImpl implements ItemExportService @Override public String assembleFileName(String type, EPerson eperson, - Date date) throws Exception - { + Date date) throws Exception { // to format the date SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MMM_dd"); String downloadDir = getExportDownloadDirectory(eperson); @@ -788,13 +716,12 @@ public class ItemExportServiceImpl implements ItemExportService int count = 1; boolean exists = true; String fileName = null; - while (exists) - { + while (exists) { fileName = type + "_export_" + sdf.format(date) + "_" + count + "_" - + eperson.getID(); + + eperson.getID(); exists = new File(downloadDir - + System.getProperty("file.separator") + fileName + ".zip") - .exists(); + + System.getProperty("file.separator") + fileName + ".zip") + .exists(); count++; } return fileName; @@ -802,18 +729,15 @@ public class ItemExportServiceImpl implements ItemExportService @Override public String getExportDownloadDirectory(EPerson ePerson) - throws Exception - { + throws Exception { String downloadDir = ConfigurationManager - .getProperty("org.dspace.app.itemexport.download.dir"); - if (downloadDir == null) - { + .getProperty("org.dspace.app.itemexport.download.dir"); + if (downloadDir == null) { throw new Exception( - "A dspace.cfg entry for 'org.dspace.app.itemexport.download.dir' does not exist."); + "A dspace.cfg entry for 'org.dspace.app.itemexport.download.dir' does not exist."); } File result = new File(downloadDir + System.getProperty("file.separator") + ePerson.getID()); - if(!result.exists() && ePerson.getLegacyId()!=null) - { + if (!result.exists() && ePerson.getLegacyId() != null) { //Check for the old identifier result = new File(downloadDir + System.getProperty("file.separator") + ePerson.getLegacyId()); } @@ -822,51 +746,43 @@ public class ItemExportServiceImpl implements ItemExportService } @Override - public String getExportWorkDirectory() throws Exception - { + public String getExportWorkDirectory() throws Exception { String exportDir = ConfigurationManager - .getProperty("org.dspace.app.itemexport.work.dir"); - if (exportDir == null) - { + .getProperty("org.dspace.app.itemexport.work.dir"); + if (exportDir == null) { throw new Exception( - "A dspace.cfg entry for 'org.dspace.app.itemexport.work.dir' does not exist."); + "A dspace.cfg entry for 'org.dspace.app.itemexport.work.dir' does not exist."); } return exportDir; } @Override public InputStream getExportDownloadInputStream(String fileName, - EPerson eperson) throws Exception - { + EPerson eperson) throws Exception { File file = new File(getExportDownloadDirectory(eperson) - + System.getProperty("file.separator") + fileName); - if (file.exists()) - { + + System.getProperty("file.separator") + fileName); + if (file.exists()) { return new FileInputStream(file); - } - else - { + } else { return null; } } @Override - public long getExportFileSize(Context context, String fileName) throws Exception - { + public long getExportFileSize(Context context, String fileName) throws Exception { String strID = fileName.substring(fileName.lastIndexOf('_') + 1, - fileName.lastIndexOf('.')); + fileName.lastIndexOf('.')); EPerson ePerson = getEPersonFromString(context, strID); File file = new File( - getExportDownloadDirectory(ePerson) - + System.getProperty("file.separator") + fileName); - if (!file.exists() || !file.isFile()) - { + getExportDownloadDirectory(ePerson) + + System.getProperty("file.separator") + fileName); + if (!file.exists() || !file.isFile()) { throw new FileNotFoundException("The file " - + getExportDownloadDirectory(ePerson) - + System.getProperty("file.separator") + fileName - + " does not exist."); + + getExportDownloadDirectory(ePerson) + + System.getProperty("file.separator") + fileName + + " does not exist."); } return file.length(); @@ -874,17 +790,18 @@ public class ItemExportServiceImpl implements ItemExportService /** * Attempt to find an EPerson based on string ID + * * @param context DSpace context - * @param strID string identifier + * @param strID string identifier * @return EPerson object (if found) * @throws SQLException if database error */ protected EPerson getEPersonFromString(Context context, String strID) throws SQLException { EPerson eperson; - try{ + try { UUID ePersonId = UUID.fromString(strID); eperson = ePersonService.find(context, ePersonId); - }catch (Exception e){ + } catch (Exception e) { eperson = ePersonService.findByLegacyId(context, Integer.parseInt(strID)); } return eperson; @@ -892,45 +809,37 @@ public class ItemExportServiceImpl implements ItemExportService @Override public long getExportFileLastModified(Context context, String fileName) - throws Exception - { + throws Exception { String strID = fileName.substring(fileName.lastIndexOf('_') + 1, - fileName.lastIndexOf('.')); + fileName.lastIndexOf('.')); EPerson ePerson = getEPersonFromString(context, strID); File file = new File( - getExportDownloadDirectory(ePerson) - + System.getProperty("file.separator") + fileName); - if (!file.exists() || !file.isFile()) - { + getExportDownloadDirectory(ePerson) + + System.getProperty("file.separator") + fileName); + if (!file.exists() || !file.isFile()) { throw new FileNotFoundException("The file " - + getExportDownloadDirectory(ePerson) - + System.getProperty("file.separator") + fileName - + " does not exist."); + + getExportDownloadDirectory(ePerson) + + System.getProperty("file.separator") + fileName + + " does not exist."); } return file.lastModified(); } @Override - public boolean canDownload(Context context, String fileName) - { + public boolean canDownload(Context context, String fileName) { EPerson eperson = context.getCurrentUser(); - if (eperson == null) - { + if (eperson == null) { return false; } String strID = fileName.substring(fileName.lastIndexOf('_') + 1, - fileName.lastIndexOf('.')); - try - { - if (strID.equals(eperson.getID().toString())) - { + fileName.lastIndexOf('.')); + try { + if (strID.equals(eperson.getID().toString())) { return true; } - } - catch (Exception e) - { + } catch (Exception e) { return false; } return false; @@ -938,26 +847,21 @@ public class ItemExportServiceImpl implements ItemExportService @Override public List getExportsAvailable(EPerson eperson) - throws Exception - { + throws Exception { File downloadDir = new File(getExportDownloadDirectory(eperson)); - if (!downloadDir.exists() || !downloadDir.isDirectory()) - { + if (!downloadDir.exists() || !downloadDir.isDirectory()) { return null; } List fileNames = new ArrayList(); - for (String fileName : downloadDir.list()) - { - if (fileName.contains("export") && fileName.endsWith(".zip")) - { + for (String fileName : downloadDir.list()) { + if (fileName.contains("export") && fileName.endsWith(".zip")) { fileNames.add(fileName); } } - if (fileNames.size() > 0) - { + if (fileNames.size() > 0) { return fileNames; } @@ -965,23 +869,18 @@ public class ItemExportServiceImpl implements ItemExportService } @Override - public void deleteOldExportArchives(EPerson eperson) throws Exception - { + public void deleteOldExportArchives(EPerson eperson) throws Exception { int hours = ConfigurationManager - .getIntProperty("org.dspace.app.itemexport.life.span.hours"); + .getIntProperty("org.dspace.app.itemexport.life.span.hours"); Calendar now = Calendar.getInstance(); now.setTime(new Date()); now.add(Calendar.HOUR, (-hours)); File downloadDir = new File(getExportDownloadDirectory(eperson)); - if (downloadDir.exists()) - { + if (downloadDir.exists()) { File[] files = downloadDir.listFiles(); - for (File file : files) - { - if (file.lastModified() < now.getTimeInMillis()) - { - if (!file.delete()) - { + for (File file : files) { + if (file.lastModified() < now.getTimeInMillis()) { + if (!file.delete()) { log.error("Unable to delete export file"); } } @@ -991,37 +890,29 @@ public class ItemExportServiceImpl implements ItemExportService } @Override - public void deleteOldExportArchives() throws Exception - { + public void deleteOldExportArchives() throws Exception { int hours = ConfigurationManager.getIntProperty("org.dspace.app.itemexport.life.span.hours"); Calendar now = Calendar.getInstance(); now.setTime(new Date()); now.add(Calendar.HOUR, (-hours)); File downloadDir = new File(ConfigurationManager.getProperty("org.dspace.app.itemexport.download.dir")); - if (downloadDir.exists()) - { + if (downloadDir.exists()) { // Get a list of all the sub-directories, potentially one for each ePerson. File[] dirs = downloadDir.listFiles(); - for (File dir : dirs) - { + for (File dir : dirs) { // For each sub-directory delete any old files. File[] files = dir.listFiles(); - for (File file : files) - { - if (file.lastModified() < now.getTimeInMillis()) - { - if (!file.delete()) - { + for (File file : files) { + if (file.lastModified() < now.getTimeInMillis()) { + if (!file.delete()) { log.error("Unable to delete old files"); } } } // If the directory is now empty then we delete it too. - if (dir.listFiles().length == 0) - { - if (!dir.delete()) - { + if (dir.listFiles().length == 0) { + if (!dir.delete()) { log.error("Unable to delete directory"); } } @@ -1033,10 +924,8 @@ public class ItemExportServiceImpl implements ItemExportService @Override public void emailSuccessMessage(Context context, EPerson eperson, - String fileName) throws MessagingException - { - try - { + String fileName) throws MessagingException { + try { Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "export_success")); email.addRecipient(eperson.getEmail()); @@ -1044,20 +933,16 @@ public class ItemExportServiceImpl implements ItemExportService email.addArgument(ConfigurationManager.getProperty("org.dspace.app.itemexport.life.span.hours")); email.send(); - } - catch (Exception e) - { + } catch (Exception e) { log.warn(LogManager.getHeader(context, "emailSuccessMessage", "cannot notify user of export"), e); } } @Override public void emailErrorMessage(EPerson eperson, String error) - throws MessagingException - { + throws MessagingException { log.warn("An error occurred during item export, the user will be notified. " + error); - try - { + try { Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "export_error")); email.addRecipient(eperson.getEmail()); @@ -1065,28 +950,22 @@ public class ItemExportServiceImpl implements ItemExportService email.addArgument(ConfigurationManager.getProperty("dspace.url") + "/feedback"); email.send(); - } - catch (Exception e) - { + } catch (Exception e) { log.warn("error during item export error notification", e); } } @Override - public void zip(String strSource, String target) throws Exception - { + public void zip(String strSource, String target) throws Exception { ZipOutputStream cpZipOutputStream = null; String tempFileName = target + "_tmp"; - try - { + try { File cpFile = new File(strSource); - if (!cpFile.isFile() && !cpFile.isDirectory()) - { + if (!cpFile.isFile() && !cpFile.isDirectory()) { return; } File targetFile = new File(tempFileName); - if (!targetFile.createNewFile()) - { + if (!targetFile.createNewFile()) { log.warn("Target file already exists: " + targetFile.getName()); } @@ -1102,53 +981,42 @@ public class ItemExportServiceImpl implements ItemExportService System.gc(); deleteDirectory(cpFile); - if (!targetFile.renameTo(new File(target))) - { + if (!targetFile.renameTo(new File(target))) { log.error("Unable to rename file"); } - } - finally - { - if (cpZipOutputStream != null) - { + } finally { + if (cpZipOutputStream != null) { cpZipOutputStream.close(); } } } /** - * - * @param cpFile file - * @param strSource source location - * @param strTarget target location + * @param cpFile file + * @param strSource source location + * @param strTarget target location * @param cpZipOutputStream current zip outputstream * @throws Exception if error */ protected void zipFiles(File cpFile, String strSource, - String strTarget, ZipOutputStream cpZipOutputStream) - throws Exception - { + String strTarget, ZipOutputStream cpZipOutputStream) + throws Exception { int byteCount; final int DATA_BLOCK_SIZE = 2048; FileInputStream cpFileInputStream = null; - if (cpFile.isDirectory()) - { + if (cpFile.isDirectory()) { File[] fList = cpFile.listFiles(); for (File aFList : fList) { zipFiles(aFList, strSource, strTarget, cpZipOutputStream); } - } - else - { - try - { - if (cpFile.getAbsolutePath().equalsIgnoreCase(strTarget)) - { + } else { + try { + if (cpFile.getAbsolutePath().equalsIgnoreCase(strTarget)) { return; } String strAbsPath = cpFile.getPath(); String strZipEntryName = strAbsPath.substring(strSource - .length() + 1, strAbsPath.length()); + .length() + 1, strAbsPath.length()); // byte[] b = new byte[ (int)(cpFile.length()) ]; @@ -1159,17 +1027,13 @@ public class ItemExportServiceImpl implements ItemExportService byte[] b = new byte[DATA_BLOCK_SIZE]; while ((byteCount = cpFileInputStream.read(b, 0, - DATA_BLOCK_SIZE)) != -1) - { + DATA_BLOCK_SIZE)) != -1) { cpZipOutputStream.write(b, 0, byteCount); } // cpZipOutputStream.write(b, 0, (int)cpFile.length()); - } - finally - { - if (cpFileInputStream != null) - { + } finally { + if (cpFileInputStream != null) { cpFileInputStream.close(); } cpZipOutputStream.closeEntry(); @@ -1179,13 +1043,12 @@ public class ItemExportServiceImpl implements ItemExportService /** * Delete a directory + * * @param path directory path * @return true if successful, false otherwise */ - protected boolean deleteDirectory(File path) - { - if (path.exists()) - { + protected boolean deleteDirectory(File path) { + if (path.exists()) { File[] files = path.listFiles(); for (File file : files) { if (file.isDirectory()) { diff --git a/dspace-api/src/main/java/org/dspace/app/itemexport/factory/ItemExportServiceFactory.java b/dspace-api/src/main/java/org/dspace/app/itemexport/factory/ItemExportServiceFactory.java index c1b3b07d3d..a6020c5c9d 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemexport/factory/ItemExportServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/app/itemexport/factory/ItemExportServiceFactory.java @@ -11,7 +11,8 @@ 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 + * Abstract factory to get services for the itemexport package, use ItemExportServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -19,7 +20,8 @@ public abstract class ItemExportServiceFactory { public abstract ItemExportService getItemExportService(); - public static ItemExportServiceFactory getInstance(){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("itemExportServiceFactory", ItemExportServiceFactory.class); + public static ItemExportServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("itemExportServiceFactory", ItemExportServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemexport/factory/ItemExportServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/app/itemexport/factory/ItemExportServiceFactoryImpl.java index 058accba4a..840d023cb9 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemexport/factory/ItemExportServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemexport/factory/ItemExportServiceFactoryImpl.java @@ -11,7 +11,8 @@ 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 + * Factory implementation to get services for the itemexport package, use ItemExportServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/app/itemexport/service/ItemExportService.java b/dspace-api/src/main/java/org/dspace/app/itemexport/service/ItemExportService.java index e93a2f22b2..7dedc9950b 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemexport/service/ItemExportService.java +++ b/dspace-api/src/main/java/org/dspace/app/itemexport/service/ItemExportService.java @@ -7,16 +7,16 @@ */ package org.dspace.app.itemexport.service; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; -import org.dspace.core.Context; -import org.dspace.eperson.EPerson; - -import javax.mail.MessagingException; 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 @@ -47,122 +47,109 @@ public interface ItemExportService { public static final String COMPRESSED_EXPORT_MIME_TYPE = "application/zip"; public void exportItem(Context c, Iterator i, - String destDirName, int seqStart, boolean migrate, - boolean excludeBitstreams) throws Exception; + 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 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 items, - String destDirName, String zipFileName, - int seqStart, boolean migrate, - boolean excludeBitstreams) throws Exception; + 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 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; + 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 + * @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 dsObjects, - Context context, boolean migrate) throws Exception; + 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 + * @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; + 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 + * @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 dsObjects, - Context context, String additionalEmail, boolean migrate) throws Exception; + 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 + * @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' + * 'export_yyy_MMM_dd_count_epersonID' * @throws Exception if error */ public String assembleFileName(String type, EPerson eperson, - Date date) throws Exception; + 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 + * @param ePerson - the eperson who requested export archive * @return String representing a directory in the form of - * org.dspace.app.itemexport.download.dir/epersonID + * org.dspace.app.itemexport.download.dir/epersonID * @throws Exception if error */ public String getExportDownloadDirectory(EPerson ePerson) - throws Exception; + 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 + * org.dspace.app.itemexport.work.dir * @throws Exception if error */ public String getExportWorkDirectory() throws Exception; @@ -170,49 +157,43 @@ public interface ItemExportService { /** * 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 + * @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; + 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. - * @throws Exception if error + * @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. + * @param context DSpace context + * @param fileName name of the file to get the size. * @return date as long - * @see java.io.File#lastModified() * @throws Exception if error + * @see java.io.File#lastModified() */ public long getExportFileLastModified(Context context, String fileName) - throws Exception; + 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 + * @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); @@ -223,19 +204,18 @@ public interface ItemExportService { * * @param eperson EPerson object * @return a list of file names representing export archives that have been - * processed + * processed * @throws Exception if error */ public List getExportsAvailable(EPerson eperson) - throws Exception; + 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 + * @param eperson - the eperson to clean up * @throws Exception if error */ public void deleteOldExportArchives(EPerson eperson) throws Exception; @@ -256,17 +236,14 @@ public interface ItemExportService { * 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 + * @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; + String fileName) throws MessagingException; /** * Since the archive is created in a new thread we are unable to communicate @@ -274,19 +251,18 @@ public interface ItemExportService { * 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 + * @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; + throws MessagingException; /** * Zip source to target + * * @param strSource source file - * @param target target file + * @param target target file * @throws Exception if error */ public void zip(String strSource, String target) throws Exception; diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/BTEBatchImportService.java b/dspace-api/src/main/java/org/dspace/app/itemimport/BTEBatchImportService.java index df2a63eaa9..c8419a2fae 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/BTEBatchImportService.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/BTEBatchImportService.java @@ -7,99 +7,100 @@ */ package org.dspace.app.itemimport; -import gr.ekt.bte.core.DataLoader; -import gr.ekt.bte.core.TransformationEngine; -import gr.ekt.bte.dataloader.FileDataLoader; - 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 -{ +public class BTEBatchImportService { - TransformationEngine transformationEngine; + TransformationEngine transformationEngine; Map dataLoaders = new HashMap(); - Map outputMap = new HashMap(); - + Map outputMap = new HashMap(); + /** * Default constructor */ - public BTEBatchImportService() - { + public BTEBatchImportService() { super(); } /** * Setter method for dataLoaders parameter + * * @param dataLoaders map of data loaders */ - public void setDataLoaders(Map dataLoaders) - { + public void setDataLoaders(Map dataLoaders) { this.dataLoaders = dataLoaders; } /** * Get data loaders + * * @return the map of DataLoaders */ - public Map getDataLoaders() - { + public Map getDataLoaders() { return dataLoaders; } /** * Get output map + * * @return the outputMapping */ - public Map getOutputMap() { - return outputMap; - } + public Map getOutputMap() { + return outputMap; + } - /** - * Setter method for the outputMapping - * @param outputMap the output mapping - */ - public void setOutputMap(Map outputMap) { - this.outputMap = outputMap; - } + /** + * Setter method for the outputMapping + * + * @param outputMap the output mapping + */ + public void setOutputMap(Map outputMap) { + this.outputMap = outputMap; + } - /** - * Get transformation engine - * @return transformation engine - */ - public TransformationEngine getTransformationEngine() { - return transformationEngine; - } + /** + * 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 getFileDataLoaders(){ - List result = new ArrayList(); - - for (String key : dataLoaders.keySet()){ - DataLoader dl = dataLoaders.get(key); - if (dl instanceof FileDataLoader){ - result.add(key); - } - } - return result; - } -} \ No newline at end of file + /** + * 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 getFileDataLoaders() { + List result = new ArrayList(); + + for (String key : dataLoaders.keySet()) { + DataLoader dl = dataLoaders.get(key); + if (dl instanceof FileDataLoader) { + result.add(key); + } + } + return result; + } +} diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/BatchUpload.java b/dspace-api/src/main/java/org/dspace/app/itemimport/BatchUpload.java index 58e40c6ab9..c574112159 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/BatchUpload.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/BatchUpload.java @@ -20,198 +20,210 @@ 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 handlesImported = new ArrayList(); - private String errorMsg = ""; - private String errorMsgHTML = ""; - - /** - * Initialize with directory - * @param dirPath directory path - */ - public BatchUpload(String dirPath) { - - this.initializeWithFile(new File(dirPath)); - - } + private Date date; + private File dir; + private boolean successful; + private int itemsImported; + private int totalItems = 0; + private List handlesImported = new ArrayList(); + private String errorMsg = ""; + private String errorMsgHTML = ""; - /** - * Initialize with directory - * @param dir directory path - */ - public BatchUpload(File dir) { - - this.initializeWithFile(dir); - - } + /** + * Initialize with directory + * + * @param dirPath directory path + */ + public BatchUpload(String dirPath) { - /** - * 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); - } + this.initializeWithFile(new File(dirPath)); - 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 += "" + lineRead + "
"; - } - else if (lineRead.startsWith("Caused by")){ - this.errorMsgHTML += "" + lineRead + "
"; - } - else { - this.errorMsgHTML += lineRead + "
"; - } - } - reader.close(); - } + } - /** - * Get date - * @return Date - */ - public Date getDate() { - return date; - } + /** + * Initialize with directory + * + * @param dir directory path + */ + public BatchUpload(File dir) { - /** - * Get path to directory - * @return directory - */ - public File getDir() { - return dir; - } + this.initializeWithFile(dir); - /** - * Whether successulf - * @return true or false - */ - public boolean isSuccessful() { - return successful; - } + } - /** - * Get items imported - * @return number of items - */ - public int getItemsImported() { - return itemsImported; - } + /** + * Initialize with directory + * + * @param dir directory path + */ + private void initializeWithFile(File dir) { - /** - * 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); - } + this.dir = dir; - /** - * Get handles of imported files - * @return list of handles - */ - public List getHandlesImported() { - return handlesImported; - } + String dirName = dir.getName(); + long timeMillis = Long.parseLong(dirName); + Calendar calendar = new GregorianCalendar(); + calendar.setTimeInMillis(timeMillis); + this.date = calendar.getTime(); - /** - * Get error message - * @return error message - */ - public String getErrorMsg() { - return errorMsg; - } + try { + this.itemsImported = countLines(dir + File.separator + "mapfile"); + } catch (IOException e) { + e.printStackTrace(); + } - /** - * Get error message as HTML - * @return error message string as HTML - */ - public String getErrorMsgHTML() { - return errorMsgHTML; - } + 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 += "" + lineRead + "
"; + } else if (lineRead.startsWith("Caused by")) { + this.errorMsgHTML += "" + lineRead + "
"; + } else { + this.errorMsgHTML += lineRead + "
"; + } + } + 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 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; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java index d4339e11a2..28ae816607 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java @@ -7,7 +7,17 @@ */ package org.dspace.app.itemimport; -import org.apache.commons.cli.*; +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; @@ -21,12 +31,6 @@ import org.dspace.eperson.service.EPersonService; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; -import java.io.File; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; - /** * Import items into DSpace. The conventional use is upload files by copying * them. DSpace writes the item's bitstreams into its assetstore. Metadata is @@ -47,12 +51,17 @@ public class ItemImportCLITool { private static boolean template = false; - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final CollectionService collectionService = ContentServiceFactory.getInstance() + .getCollectionService(); private static final EPersonService epersonService = EPersonServiceFactory.getInstance().getEPersonService(); private static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - public static void main(String[] argv) throws Exception - { + /** + * Default constructor + */ + private ItemImportCLITool() { } + + public static void main(String[] argv) throws Exception { Date startTime = new Date(); int status = 0; @@ -66,24 +75,24 @@ public class ItemImportCLITool { 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"); + "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"); + "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"); + "email of eperson doing importing"); options.addOption("w", "workflow", false, - "send submission through collection's workflow"); + "send submission through collection's workflow"); options.addOption("n", "notify", false, - "if sending submissions through the workflow, send notification emails"); + "if sending submissions through the workflow, send notification emails"); options.addOption("t", "test", false, - "test run - do not actually import items"); + "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)"); + "resume a failed import (add only)"); options.addOption("q", "quiet", false, "don't display metadata"); options.addOption("h", "help", false, "help"); @@ -106,15 +115,19 @@ public class ItemImportCLITool { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("ItemImport\n", options); System.out - .println("\nadding items: ItemImport -a -e eperson -c collection -s sourcedir -m mapfile"); + .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"); + .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"); + .println("replacing items: ItemImport -r -e eperson -c collection -s sourcedir -m mapfile"); System.out - .println("deleting items: ItemImport -d -e eperson -m mapfile"); + .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."); + .println( + "If multiple collections are specified, the first collection will be the one that owns the " + + "item."); System.exit(0); } @@ -155,30 +168,26 @@ public class ItemImportCLITool { template = true; } - if (line.hasOption('s')) // source - { + if (line.hasOption('s')) { // source sourcedir = line.getOptionValue('s'); } - if (line.hasOption('m')) // mapfile - { + if (line.hasOption('m')) { // mapfile mapfile = line.getOptionValue('m'); } - if (line.hasOption('e')) // eperson - { + if (line.hasOption('e')) { // eperson eperson = line.getOptionValue('e'); } - if (line.hasOption('c')) // collections - { + 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"); + .println("**Resume import** - attempting to import items not already imported"); } if (line.hasOption('q')) { @@ -198,26 +207,26 @@ public class ItemImportCLITool { // 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)"); + .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"); + .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"); + .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"); + .println("Error - an eperson to do the importing must be specified"); System.out.println(" (run with -h flag for details)"); System.exit(1); } @@ -227,18 +236,19 @@ public class ItemImportCLITool { 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 + //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"); + .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"); + .println("Error - an eperson to do the importing must be specified"); System.out.println(" (run with -h flag for details)"); System.exit(1); } @@ -250,14 +260,16 @@ public class ItemImportCLITool { 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"); + .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"); + .println("Error - an eperson to do the importing must be specified"); System.exit(1); } @@ -270,7 +282,7 @@ public class ItemImportCLITool { // 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"); + .println("Error - resume option only works with the --add or the --add-bte commands"); System.exit(1); } @@ -280,9 +292,9 @@ public class ItemImportCLITool { if (!isResume && "add".equals(command) && myFile.exists()) { System.out.println("Error - the mapfile " + mapfile - + " already exists."); + + " already exists."); System.out - .println("Either delete it or use --resume if attempting to resume an aborted import."); + .println("Either delete it or use --resume if attempting to resume an aborted import."); System.exit(1); } @@ -330,24 +342,22 @@ public class ItemImportCLITool { // string has a / so it must be a handle - try and resolve // it mycollections.add((Collection) handleService - .resolveToObject(c, collections[i])); + .resolveToObject(c, collections[i])); // resolved, now make sure it's a collection if ((mycollections.get(i) == null) - || (mycollections.get(i).getType() != Constants.COLLECTION)) { + || (mycollections.get(i).getType() != Constants.COLLECTION)) { mycollections.set(i, null); } - } - // not a handle, try and treat it as an integer collection - // database ID - else if (collections[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"); + + collections[i] + " to collection"); } // print progress info @@ -358,7 +368,7 @@ public class ItemImportCLITool { } System.out.println(owningPrefix + " Collection: " - + mycollections.get(i).getName()); + + mycollections.get(i).getName()); } } // end of validating collections @@ -394,11 +404,13 @@ public class ItemImportCLITool { try { if (zip) { System.gc(); - System.out.println("Deleting temporary zip directory: " + myloader.getTempWorkDirFile().getAbsolutePath()); + 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()); + System.out.println("Unable to delete temporary zip archive location: " + myloader.getTempWorkDirFile() + .getAbsolutePath()); } @@ -409,7 +421,9 @@ public class ItemImportCLITool { 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.out.println( + "Elapsed time: " + ((endTime.getTime() - startTime.getTime()) / 1000) + " secs (" + (endTime + .getTime() - startTime.getTime()) + " msecs)"); } System.exit(status); diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 786c3cd632..829594f448 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -7,6 +7,44 @@ */ package org.dspace.app.itemimport; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.URL; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TreeMap; +import java.util.UUID; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import javax.mail.MessagingException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + import gr.ekt.bte.core.DataLoader; import gr.ekt.bte.core.TransformationEngine; import gr.ekt.bte.core.TransformationResult; @@ -14,7 +52,7 @@ import gr.ekt.bte.core.TransformationSpec; import gr.ekt.bte.dataloader.FileDataLoader; import gr.ekt.bteio.generators.DSpaceOutputGenerator; import gr.ekt.bteio.loaders.OAIPMHDataLoader; -import org.apache.commons.collections.ComparatorUtils; +import org.apache.commons.collections4.ComparatorUtils; import org.apache.commons.io.FileDeleteStrategy; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.RandomStringUtils; @@ -28,10 +66,30 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.ResourcePolicyService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; import org.dspace.content.Collection; -import org.dspace.content.service.*; -import org.dspace.core.*; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataSchema; +import org.dspace.content.WorkspaceItem; +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.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; +import org.dspace.core.LogManager; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.service.EPersonService; @@ -48,19 +106,6 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import javax.mail.MessagingException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; -import java.io.*; -import java.net.URL; -import java.sql.SQLException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - /** * Import items into DSpace. The conventional use is upload files by copying @@ -78,8 +123,7 @@ import java.util.zip.ZipFile; * Modified by David Little, UCSD Libraries 12/21/04 to * allow the registration of files (bitstreams) into DSpace. */ -public class ItemImportServiceImpl implements ItemImportService, InitializingBean -{ +public class ItemImportServiceImpl implements ItemImportService, InitializingBean { private final Logger log = Logger.getLogger(ItemImportServiceImpl.class); @Autowired(required = true) @@ -125,7 +169,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea public void afterPropertiesSet() throws Exception { //Ensure tempWorkDir exists File tempWorkDirFile = new File(tempWorkDir); - if (!tempWorkDirFile.exists()){ + if (!tempWorkDirFile.exists()) { boolean success = tempWorkDirFile.mkdir(); if (success) { log.info("Created org.dspace.app.batchitemimport.work.dir of: " + tempWorkDir); @@ -139,112 +183,116 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea protected FilenameFilter metadataFileFilter = new LocalSchemaFilenameFilter(); // File listing filter to check for folders - protected FilenameFilter directoryFilter = new FilenameFilter() - { + protected FilenameFilter directoryFilter = new FilenameFilter() { @Override - public boolean accept(File dir, String n) - { + public boolean accept(File dir, String n) { File item = new File(dir.getAbsolutePath() + File.separatorChar + n); return item.isDirectory(); } }; - - protected ItemImportServiceImpl(){ + + protected ItemImportServiceImpl() { //Protected consumer to ensure that we use spring to create a bean, NEVER make this public } - - /** * In this method, the BTE is instantiated. THe workflow generates the DSpace files * necessary for the upload, and the default item import method is called - * @param c The contect + * + * @param c The contect * @param mycollections The collections the items are inserted to - * @param sourceDir The filepath to the file to read data from - * @param mapFile The filepath to mapfile to be generated - * @param template whether to use collection template item as starting point - * @param inputType The type of the input data (bibtex, csv, etc.) - * @param workingDir The path to create temporary files (for command line or UI based) + * @param sourceDir The filepath to the file to read data from + * @param mapFile The filepath to mapfile to be generated + * @param template whether to use collection template item as starting point + * @param inputType The type of the input data (bibtex, csv, etc.) + * @param workingDir The path to create temporary files (for command line or UI based) * @throws Exception if error occurs */ @Override public void addBTEItems(Context c, List mycollections, - String sourceDir, String mapFile, boolean template, String inputType, String workingDir) throws Exception - { - //Determine the folder where BTE will output the results - String outputFolder = null; - if (workingDir == null){ //This indicates a command line import, create a random path - File importDir = new File(ConfigurationManager.getProperty("org.dspace.app.batchitemimport.work.dir")); - if (!importDir.exists()){ - boolean success = importDir.mkdir(); - if (!success) { - log.info("Cannot create batch import directory!"); - throw new Exception("Cannot create batch import directory!"); - } + String sourceDir, String mapFile, boolean template, String inputType, String workingDir) + throws Exception { + //Determine the folder where BTE will output the results + String outputFolder = null; + if (workingDir == null) { //This indicates a command line import, create a random path + File importDir = new File(ConfigurationManager.getProperty("org.dspace.app.batchitemimport.work.dir")); + if (!importDir.exists()) { + boolean success = importDir.mkdir(); + if (!success) { + log.info("Cannot create batch import directory!"); + throw new Exception("Cannot create batch import directory!"); + } } //Get a random folder in case two admins batch import data at the same time - outputFolder = importDir + File.separator + generateRandomFilename(true); - } - else { //This indicates a UI import, working dir is preconfigured - outputFolder = workingDir; - } + outputFolder = importDir + File.separator + generateRandomFilename(true); + } else { //This indicates a UI import, working dir is preconfigured + outputFolder = workingDir; + } - BTEBatchImportService dls = new DSpace().getSingletonService(BTEBatchImportService.class); + BTEBatchImportService dls = new DSpace().getSingletonService(BTEBatchImportService.class); DataLoader dataLoader = dls.getDataLoaders().get(inputType); Map outputMap = dls.getOutputMap(); TransformationEngine te = dls.getTransformationEngine(); - if (dataLoader==null){ - System.out.println("ERROR: The key used in -i parameter must match a valid DataLoader in the BTE Spring XML configuration file!"); + if (dataLoader == null) { + System.out.println( + "ERROR: The key used in -i parameter must match a valid DataLoader in the BTE Spring XML " + + "configuration file!"); return; } - if (outputMap==null){ - System.out.println("ERROR: The key used in -i parameter must match a valid outputMapping in the BTE Spring XML configuration file!"); + if (outputMap == null) { + System.out.println( + "ERROR: The key used in -i parameter must match a valid outputMapping in the BTE Spring XML " + + "configuration file!"); return; } - if (dataLoader instanceof FileDataLoader){ + if (dataLoader instanceof FileDataLoader) { FileDataLoader fdl = (FileDataLoader) dataLoader; if (!StringUtils.isBlank(sourceDir)) { - System.out.println("INFO: Dataloader will load data from the file specified in the command prompt (and not from the Spring XML configuration file)"); + System.out.println( + "INFO: Dataloader will load data from the file specified in the command prompt (and not from the " + + "Spring XML configuration file)"); fdl.setFilename(sourceDir); } - } - else if (dataLoader instanceof OAIPMHDataLoader){ + } else if (dataLoader instanceof OAIPMHDataLoader) { OAIPMHDataLoader fdl = (OAIPMHDataLoader) dataLoader; System.out.println(sourceDir); - if (!StringUtils.isBlank(sourceDir)){ - System.out.println("INFO: Dataloader will load data from the address specified in the command prompt (and not from the Spring XML configuration file)"); + if (!StringUtils.isBlank(sourceDir)) { + System.out.println( + "INFO: Dataloader will load data from the address specified in the command prompt (and not from " + + "the Spring XML configuration file)"); fdl.setServerAddress(sourceDir); } } - if (dataLoader!=null){ - System.out.println("INFO: Dataloader " + dataLoader.toString()+" will be used for the import!"); + if (dataLoader != null) { + System.out.println("INFO: Dataloader " + dataLoader.toString() + " will be used for the import!"); - te.setDataLoader(dataLoader); + te.setDataLoader(dataLoader); - DSpaceOutputGenerator outputGenerator = new DSpaceOutputGenerator(outputMap); - outputGenerator.setOutputDirectory(outputFolder); + DSpaceOutputGenerator outputGenerator = new DSpaceOutputGenerator(outputMap); + outputGenerator.setOutputDirectory(outputFolder); - te.setOutputGenerator(outputGenerator); + te.setOutputGenerator(outputGenerator); - try { - TransformationResult res = te.transform(new TransformationSpec()); - List output = res.getOutput(); - outputGenerator.writeOutput(output); - } catch (Exception e) { - System.err.println("Exception"); - e.printStackTrace(); - throw e; - } - addItems(c, mycollections, outputFolder, mapFile, template); + try { + TransformationResult res = te.transform(new TransformationSpec()); + List output = res.getOutput(); + outputGenerator.writeOutput(output); + } catch (Exception e) { + System.err.println("Exception"); + e.printStackTrace(); + throw e; + } + addItems(c, mycollections, outputFolder, mapFile, template); } } @Override - public void addItemsAtomic(Context c, List mycollections, String sourceDir, String mapFile, boolean template) throws Exception { + public void addItemsAtomic(Context c, List mycollections, String sourceDir, String mapFile, + boolean template) throws Exception { try { addItems(c, mycollections, sourceDir, mapFile, template); } catch (Exception addException) { @@ -257,8 +305,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea @Override public void addItems(Context c, List mycollections, - String sourceDir, String mapFile, boolean template) throws Exception - { + String sourceDir, String mapFile, boolean template) throws Exception { // create the mapfile File outFile = null; PrintWriter mapOut = null; @@ -272,17 +319,14 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea log.debug("Generating mapfile: " + mapFile); boolean directoryFileCollections = false; - if (mycollections == null) - { + if (mycollections == null) { directoryFileCollections = true; } - if (!isTest) - { + if (!isTest) { // get the directory names of items to skip (will be in keys of // hash) - if (isResume) - { + if (isResume) { skipItems = readMapFile(mapFile); } @@ -290,8 +334,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea outFile = new File(mapFile); mapOut = new PrintWriter(new FileWriter(outFile, isResume)); - if (mapOut == null) - { + if (mapOut == null) { throw new Exception("can't open mapfile: " + mapFile); } } @@ -299,8 +342,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // open and process the source directory File d = new java.io.File(sourceDir); - if (d == null || !d.isDirectory()) - { + if (d == null || !d.isDirectory()) { throw new Exception("Error, cannot open source directory " + sourceDir); } @@ -308,42 +350,36 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea Arrays.sort(dircontents, ComparatorUtils.naturalComparator()); - for (int i = 0; i < dircontents.length; i++) - { - if (skipItems.containsKey(dircontents[i])) - { - System.out.println("Skipping import of " + dircontents[i]); - } - else - { - List clist; - if (directoryFileCollections) { - String path = sourceDir + File.separatorChar + dircontents[i]; - try { - List cols = processCollectionFile(c, path, "collections"); - if (cols == null) { - System.out.println("No collections specified for item " + dircontents[i] + ". Skipping."); + for (int i = 0; i < dircontents.length; i++) { + if (skipItems.containsKey(dircontents[i])) { + System.out.println("Skipping import of " + dircontents[i]); + } else { + List clist; + if (directoryFileCollections) { + String path = sourceDir + File.separatorChar + dircontents[i]; + try { + List cols = processCollectionFile(c, path, "collections"); + if (cols == null) { + System.out + .println("No collections specified for item " + dircontents[i] + ". Skipping."); + continue; + } + clist = cols; + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage() + " Skipping."); continue; } - clist = cols; - } - catch (IllegalArgumentException e) - { - System.out.println(e.getMessage() + " Skipping." ); - continue; + } else { + clist = mycollections; } + Item item = addItem(c, clist, sourceDir, dircontents[i], mapOut, template); + c.uncacheEntity(item); + System.out.println(i + " " + dircontents[i]); } - else - { - clist = mycollections; - } - Item item =addItem(c, clist, sourceDir, dircontents[i], mapOut, template);c.uncacheEntity(item); - System.out.println(i + " " + dircontents[i]); } - } } finally { - if(mapOut!=null) { + if (mapOut != null) { mapOut.flush(); mapOut.close(); } @@ -352,15 +388,13 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea @Override public void replaceItems(Context c, List mycollections, - String sourceDir, String mapFile, boolean template) throws Exception - { + String sourceDir, String mapFile, boolean template) throws Exception { // verify the source directory File d = new java.io.File(sourceDir); - if (d == null || !d.isDirectory()) - { + if (d == null || !d.isDirectory()) { throw new Exception("Error, cannot open source directory " - + sourceDir); + + sourceDir); } // read in HashMap first, to get list of handles & source dirs @@ -368,23 +402,19 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // for each handle, re-import the item, discard the new handle // and re-assign the old handle - for (Map.Entry mapEntry : myHash.entrySet()) - { + for (Map.Entry mapEntry : myHash.entrySet()) { // get the old handle String newItemName = mapEntry.getKey(); String oldHandle = mapEntry.getValue(); Item oldItem = null; - if (oldHandle.indexOf('/') != -1) - { + if (oldHandle.indexOf('/') != -1) { System.out.println("\tReplacing: " + oldHandle); // add new item, locate old one oldItem = (Item) handleService.resolveToObject(c, oldHandle); - } - else - { + } else { oldItem = itemService.findByIdOrLegacyId(c, oldHandle); } @@ -401,8 +431,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea File handleFile = new File(sourceDir + File.separatorChar + newItemName + File.separatorChar + "handle"); PrintWriter handleOut = new PrintWriter(new FileWriter(handleFile, true)); - if (handleOut == null) - { + if (handleOut == null) { throw new Exception("can't open handle file: " + handleFile.getCanonicalPath()); } @@ -417,8 +446,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } @Override - public void deleteItems(Context c, String mapFile) throws Exception - { + public void deleteItems(Context c, String mapFile) throws Exception { System.out.println("Deleting items listed in mapfile: " + mapFile); // read in the mapfile @@ -427,18 +455,14 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // now delete everything that appeared in the mapFile Iterator i = myhash.keySet().iterator(); - while (i.hasNext()) - { + while (i.hasNext()) { String itemID = myhash.get(i.next()); - if (itemID.indexOf('/') != -1) - { + if (itemID.indexOf('/') != -1) { String myhandle = itemID; System.out.println("Deleting item " + myhandle); deleteItem(c, myhandle); - } - else - { + } else { // it's an ID Item myitem = itemService.findByIdOrLegacyId(c, itemID); System.out.println("Deleting item " + itemID); @@ -450,18 +474,18 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea /** * item? try and add it to the archive. - * @param c current Context + * + * @param c current Context * @param mycollections - add item to these Collections. - * @param path - directory containing the item directories. - * @param itemname handle - non-null means we have a pre-defined handle already - * @param mapOut - mapfile we're writing - * @param template whether to use collection template item as starting point + * @param path - directory containing the item directories. + * @param itemname handle - non-null means we have a pre-defined handle already + * @param mapOut - mapfile we're writing + * @param template whether to use collection template item as starting point * @return Item * @throws Exception if error occurs */ protected Item addItem(Context c, List mycollections, String path, - String itemname, PrintWriter mapOut, boolean template) throws Exception - { + String itemname, PrintWriter mapOut, boolean template) throws Exception { String mapOutputString = null; System.out.println("Adding item from directory " + itemname); @@ -472,28 +496,25 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea WorkspaceItem wi = null; WorkflowItem wfi = null; - if (!isTest) - { + if (!isTest) { wi = workspaceItemService.create(c, mycollections.iterator().next(), template); myitem = wi.getItem(); } // now fill out dublin core for item loadMetadata(c, myitem, path + File.separatorChar + itemname - + File.separatorChar); + + File.separatorChar); // and the bitstreams from the contents file // process contents file, add bistreams and bundles, return any // non-standard permissions List options = processContentsFile(c, myitem, path - + File.separatorChar + itemname, "contents"); + + File.separatorChar + itemname, "contents"); - if (useWorkflow) - { + if (useWorkflow) { // don't process handle file // start up a workflow - if (!isTest) - { + if (!isTest) { // Should we send a workflow alert email or not? if (useWorkflowSendEmail) { wfi = workflowService.start(c, wi); @@ -504,16 +525,13 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // send ID to the mapfile mapOutputString = itemname + " " + myitem.getID(); } - } - else - { + } else { // only process handle file if not using workflow system String myhandle = processHandleFile(c, myitem, path - + File.separatorChar + itemname, "handle"); + + File.separatorChar + itemname, "handle"); // put item in system - if (!isTest) - { + if (!isTest) { try { installItemService.installItem(c, wi, myhandle); } catch (Exception e) { @@ -529,28 +547,23 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } // set permissions if specified in contents file - if (options.size() > 0) - { + if (options.size() > 0) { System.out.println("Processing options"); processOptions(c, myitem, options); } } // now add to multiple collections if requested - if (mycollections.size() > 1) - { - for (int i = 1; i < mycollections.size(); i++) - { - if (!isTest) - { + if (mycollections.size() > 1) { + for (int i = 1; i < mycollections.size(); i++) { + if (!isTest) { collectionService.addItem(c, mycollections.get(i), myitem); } } } // made it this far, everything is fine, commit transaction - if (mapOut != null) - { + if (mapOut != null) { mapOut.println(mapOutputString); } @@ -562,10 +575,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } // remove, given the actual item - protected void deleteItem(Context c, Item myitem) throws Exception - { - if (!isTest) - { + protected void deleteItem(Context c, Item myitem) throws Exception { + if (!isTest) { ArrayList removeList = new ArrayList<>(); List collections = myitem.getCollections(); @@ -582,18 +593,14 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } // remove, given a handle - protected void deleteItem(Context c, String myhandle) throws Exception - { + protected void deleteItem(Context c, String myhandle) throws Exception { // bit of a hack - to remove an item, you must remove it // from all collections it's a part of, then it will be removed Item myitem = (Item) handleService.resolveToObject(c, myhandle); - if (myitem == null) - { + if (myitem == null) { System.out.println("Error - cannot locate item - already deleted?"); - } - else - { + } else { deleteItem(c, myitem); c.uncacheEntity(myitem); } @@ -603,50 +610,38 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // utility methods //////////////////////////////////// // read in the map file and generate a hashmap of (file,handle) pairs - protected Map readMapFile(String filename) throws Exception - { + protected Map readMapFile(String filename) throws Exception { Map myHash = new HashMap<>(); BufferedReader is = null; - try - { + try { is = new BufferedReader(new FileReader(filename)); String line; - while ((line = is.readLine()) != null) - { + while ((line = is.readLine()) != null) { String myFile; String myHandle; // a line should be archive filenamehandle StringTokenizer st = new StringTokenizer(line); - if (st.hasMoreTokens()) - { + if (st.hasMoreTokens()) { myFile = st.nextToken(); - } - else - { + } else { throw new Exception("Bad mapfile line:\n" + line); } - if (st.hasMoreTokens()) - { + if (st.hasMoreTokens()) { myHandle = st.nextToken(); - } - else - { + } else { throw new Exception("Bad mapfile line:\n" + line); } myHash.put(myFile, myHandle); } - } - finally - { - if (is != null) - { + } finally { + if (is != null) { is.close(); } } @@ -656,25 +651,22 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // Load all metadata schemas into the item. protected void loadMetadata(Context c, Item myitem, String path) - throws SQLException, IOException, ParserConfigurationException, - SAXException, TransformerException, AuthorizeException - { + throws SQLException, IOException, ParserConfigurationException, + SAXException, TransformerException, AuthorizeException { // Load the dublin core metadata loadDublinCore(c, myitem, path + "dublin_core.xml"); // Load any additional metadata schemas File folder = new File(path); File file[] = folder.listFiles(metadataFileFilter); - for (int i = 0; i < file.length; i++) - { + for (int i = 0; i < file.length; i++) { loadDublinCore(c, myitem, file[i].getAbsolutePath()); } } protected void loadDublinCore(Context c, Item myitem, String filename) - throws SQLException, IOException, ParserConfigurationException, - SAXException, TransformerException, AuthorizeException - { + throws SQLException, IOException, ParserConfigurationException, + SAXException, TransformerException, AuthorizeException { Document document = loadXML(filename); // Get the schema, for backward compatibility we will default to the @@ -683,44 +675,36 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String schema; NodeList metadata = XPathAPI.selectNodeList(document, "/dublin_core"); Node schemaAttr = metadata.item(0).getAttributes().getNamedItem( - "schema"); - if (schemaAttr == null) - { + "schema"); + if (schemaAttr == null) { schema = MetadataSchema.DC_SCHEMA; - } - else - { + } else { schema = schemaAttr.getNodeValue(); } // Get the nodes corresponding to formats NodeList dcNodes = XPathAPI.selectNodeList(document, - "/dublin_core/dcvalue"); + "/dublin_core/dcvalue"); - if (!isQuiet) - { + if (!isQuiet) { System.out.println("\tLoading dublin core from " + filename); } // Add each one as a new format to the registry - for (int i = 0; i < dcNodes.getLength(); i++) - { + for (int i = 0; i < dcNodes.getLength(); i++) { Node n = dcNodes.item(i); addDCValue(c, myitem, schema, n); } } - protected void addDCValue(Context c, Item i, String schema, Node n) throws TransformerException, SQLException, AuthorizeException - { + protected void addDCValue(Context c, Item i, String schema, Node n) + throws TransformerException, SQLException, AuthorizeException { String value = getStringValue(n); //n.getNodeValue(); // compensate for empty value getting read as "null", which won't display - if (value == null) - { + if (value == null) { value = ""; - } - else - { - value = value.trim(); + } else { + value = value.trim(); } // //getElementData(n, "element"); String element = getAttributeValue(n, "element"); @@ -728,43 +712,37 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // //getElementData(n, // "qualifier"); String language = getAttributeValue(n, "language"); - if (language != null) - { + if (language != null) { language = language.trim(); } - if (!isQuiet) - { + if (!isQuiet) { System.out.println("\tSchema: " + schema + " Element: " + element + " Qualifier: " + qualifier - + " Value: " + value); + + " Value: " + value); } - if ("none".equals(qualifier) || "".equals(qualifier)) - { + if ("none".equals(qualifier) || "".equals(qualifier)) { qualifier = null; } // only add metadata if it is no test and there is an actual value - if (!isTest && !value.equals("")) - { + if (!isTest && !value.equals("")) { itemService.addMetadata(c, i, schema, element, qualifier, language, value); - } - else - { + } else { // If we're just test the import, let's check that the actual metadata field exists. - MetadataSchema foundSchema = metadataSchemaService.find(c,schema); + MetadataSchema foundSchema = metadataSchemaService.find(c, schema); - if (foundSchema == null) - { - System.out.println("ERROR: schema '"+schema+"' was not found in the registry."); - return; - } + if (foundSchema == null) { + System.out.println("ERROR: schema '" + schema + "' was not found in the registry."); + return; + } - MetadataField foundField = metadataFieldService.findByElement(c, foundSchema, element, qualifier); + MetadataField foundField = metadataFieldService.findByElement(c, foundSchema, element, qualifier); - if (foundField == null) - { - System.out.println("ERROR: Metadata field: '"+schema+"."+element+"."+qualifier+"' was not found in the registry."); - return; + if (foundField == null) { + System.out.println( + "ERROR: Metadata field: '" + schema + "." + element + "." + qualifier + "' was not found in the " + + "registry."); + return; } } } @@ -775,61 +753,49 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea * which the item should be inserted. If it does not exist or it * is empty return null. * - * @param c The context - * @param path The path to the data directory for this item + * @param c The context + * @param path The path to the data directory for this item * @param filename The collections file filename. Should be "collections" * @return A list of collections in which to insert the item or null - * @throws IOException if IO error + * @throws IOException if IO error * @throws SQLException if database error */ - protected List processCollectionFile(Context c, String path, String filename) throws IOException, SQLException - { + protected List processCollectionFile(Context c, String path, String filename) + throws IOException, SQLException { File file = new File(path + File.separatorChar + filename); ArrayList collections = new ArrayList<>(); List result = null; System.out.println("Processing collections file: " + filename); - if(file.exists()) - { + if (file.exists()) { BufferedReader br = null; - try - { + try { br = new BufferedReader(new FileReader(file)); String line = null; - while ((line = br.readLine()) != null) - { + while ((line = br.readLine()) != null) { DSpaceObject obj = null; - if (line.indexOf('/') != -1) - { + if (line.indexOf('/') != -1) { obj = handleService.resolveToObject(c, line); - if (obj == null || obj.getType() != Constants.COLLECTION) - { + if (obj == null || obj.getType() != Constants.COLLECTION) { obj = null; } - } - else - { + } else { obj = collectionService.find(c, UUID.fromString(line)); } if (obj == null) { throw new IllegalArgumentException("Cannot resolve " + line + " to a collection."); } - collections.add((Collection)obj); + collections.add((Collection) obj); } result = collections; - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { System.out.println("No collections file found."); - } - finally - { - if (br != null) - { + } finally { + if (br != null) { try { br.close(); } catch (IOException e) { @@ -844,23 +810,21 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea /** * Read in the handle file contents or return null if empty or doesn't exist - * @param c DSpace context - * @param i DSpace item - * @param path path to handle file + * + * @param c DSpace context + * @param i DSpace item + * @param path path to handle file * @param filename name of file * @return handle file contents or null if doesn't exist */ - protected String processHandleFile(Context c, Item i, String path, String filename) - { + protected String processHandleFile(Context c, Item i, String path, String filename) { File file = new File(path + File.separatorChar + filename); String result = null; System.out.println("Processing handle file: " + filename); - if (file.exists()) - { + if (file.exists()) { BufferedReader is = null; - try - { + try { is = new BufferedReader(new FileReader(file)); // result gets contents of file, or null @@ -868,34 +832,22 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea System.out.println("read handle: '" + result + "'"); - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { // probably no handle file, just return null System.out.println("It appears there is no handle file -- generating one"); - } - catch (IOException e) - { + } catch (IOException e) { // probably no handle file, just return null System.out.println("It appears there is no handle file -- generating one"); - } - finally - { - if (is != null) - { - try - { + } finally { + if (is != null) { + try { is.close(); - } - catch (IOException e1) - { + } catch (IOException e1) { System.err.println("Non-critical problem releasing resources."); } } } - } - else - { + } else { // probably no handle file, just return null System.out.println("It appears there is no handle file -- generating one"); } @@ -907,92 +859,73 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea * Given a contents file and an item, stuffing it with bitstreams from the * contents file Returns a List of Strings with lines from the contents * file that request non-default bitstream permission - * @param c DSpace Context - * @param i DSpace item - * @param path path as string + * + * @param c DSpace Context + * @param i DSpace item + * @param path path as string * @param filename file name * @return List of Strings - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ protected List processContentsFile(Context c, Item i, String path, - String filename) throws SQLException, IOException, - AuthorizeException - { + String filename) throws SQLException, IOException, + AuthorizeException { File contentsFile = new File(path + File.separatorChar + filename); String line = ""; List options = new ArrayList<>(); System.out.println("\tProcessing contents file: " + contentsFile); - if (contentsFile.exists()) - { + if (contentsFile.exists()) { BufferedReader is = null; - try - { + try { is = new BufferedReader(new FileReader(contentsFile)); - while ((line = is.readLine()) != null) - { - if ("".equals(line.trim())) - { + while ((line = is.readLine()) != null) { + if ("".equals(line.trim())) { continue; } - // 1) registered into dspace (leading -r) + // 1) registered into dspace (leading -r) // 2) imported conventionally into dspace (no -r) - if (line.trim().startsWith("-r ")) - { + if (line.trim().startsWith("-r ")) { // line should be one of these two: // -r -s n -f filepath // -r -s n -f filepath\tbundle:bundlename // where - // n is the assetstore number - // filepath is the path of the file to be registered - // bundlename is an optional bundle name + // n is the assetstore number + // filepath is the path of the file to be registered + // bundlename is an optional bundle name String sRegistrationLine = line.trim(); int iAssetstore = -1; String sFilePath = null; String sBundle = null; StringTokenizer tokenizer = new StringTokenizer(sRegistrationLine); - while (tokenizer.hasMoreTokens()) - { + while (tokenizer.hasMoreTokens()) { String sToken = tokenizer.nextToken(); - if ("-r".equals(sToken)) - { + if ("-r".equals(sToken)) { continue; - } - else if ("-s".equals(sToken) && tokenizer.hasMoreTokens()) - { - try - { + } else if ("-s".equals(sToken) && tokenizer.hasMoreTokens()) { + try { iAssetstore = Integer.parseInt(tokenizer.nextToken()); - } - catch (NumberFormatException e) - { + } catch (NumberFormatException e) { // ignore - iAssetstore remains -1 } - } - else if ("-f".equals(sToken) && tokenizer.hasMoreTokens()) - { + } else if ("-f".equals(sToken) && tokenizer.hasMoreTokens()) { sFilePath = tokenizer.nextToken(); - } - else if (sToken.startsWith("bundle:")) - { + } else if (sToken.startsWith("bundle:")) { sBundle = sToken.substring(7); - } - else - { + } else { // unrecognized token - should be no problem } } // while - if (iAssetstore == -1 || sFilePath == null) - { + if (iAssetstore == -1 || sFilePath == null) { System.out.println("\tERROR: invalid contents file line"); System.out.println("\t\tSkipping line: " - + sRegistrationLine); + + sRegistrationLine); continue; } @@ -1001,40 +934,34 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String descriptionMarker = "\tdescription:"; int dMarkerIndex = line.indexOf(descriptionMarker); int dEndIndex = 0; - if (dMarkerIndex > 0) - { - dEndIndex = line.indexOf("\t", dMarkerIndex + 1); - if (dEndIndex == -1) - { - dEndIndex = line.length(); - } - descriptionExists = true; + if (dMarkerIndex > 0) { + dEndIndex = line.indexOf("\t", dMarkerIndex + 1); + if (dEndIndex == -1) { + dEndIndex = line.length(); + } + descriptionExists = true; } String sDescription = ""; - if (descriptionExists) - { - sDescription = line.substring(dMarkerIndex, dEndIndex); - sDescription = sDescription.replaceFirst("description:", ""); + if (descriptionExists) { + sDescription = line.substring(dMarkerIndex, dEndIndex); + sDescription = sDescription.replaceFirst("description:", ""); } registerBitstream(c, i, iAssetstore, sFilePath, sBundle, sDescription); System.out.println("\tRegistering Bitstream: " + sFilePath - + "\tAssetstore: " + iAssetstore - + "\tBundle: " + sBundle - + "\tDescription: " + sDescription); - continue; // process next line in contents file + + "\tAssetstore: " + iAssetstore + + "\tBundle: " + sBundle + + "\tDescription: " + sDescription); + continue; // process next line in contents file } int bitstreamEndIndex = line.indexOf('\t'); - if (bitstreamEndIndex == -1) - { + if (bitstreamEndIndex == -1) { // no extra info processContentFileEntry(c, i, path, line, null, false); System.out.println("\tBitstream: " + line); - } - else - { + } else { String bitstreamName = line.substring(0, bitstreamEndIndex); @@ -1046,11 +973,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String bundleMarker = "\tbundle:"; int bMarkerIndex = line.indexOf(bundleMarker); int bEndIndex = 0; - if (bMarkerIndex > 0) - { + if (bMarkerIndex > 0) { bEndIndex = line.indexOf("\t", bMarkerIndex + 1); - if (bEndIndex == -1) - { + if (bEndIndex == -1) { bEndIndex = line.length(); } bundleExists = true; @@ -1060,11 +985,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String permissionsMarker = "\tpermissions:"; int pMarkerIndex = line.indexOf(permissionsMarker); int pEndIndex = 0; - if (pMarkerIndex > 0) - { + if (pMarkerIndex > 0) { pEndIndex = line.indexOf("\t", pMarkerIndex + 1); - if (pEndIndex == -1) - { + if (pEndIndex == -1) { pEndIndex = line.length(); } permissionsExist = true; @@ -1074,11 +997,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String descriptionMarker = "\tdescription:"; int dMarkerIndex = line.indexOf(descriptionMarker); int dEndIndex = 0; - if (dMarkerIndex > 0) - { + if (dMarkerIndex > 0) { dEndIndex = line.indexOf("\t", dMarkerIndex + 1); - if (dEndIndex == -1) - { + if (dEndIndex == -1) { dEndIndex = line.length(); } descriptionExists = true; @@ -1088,65 +1009,52 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String primaryBitstreamMarker = "\tprimary:true"; boolean primary = false; String primaryStr = ""; - if (line.contains(primaryBitstreamMarker)) - { + if (line.contains(primaryBitstreamMarker)) { primary = true; primaryStr = "\t **Setting as primary bitstream**"; } - if (bundleExists) - { + if (bundleExists) { String bundleName = line.substring(bMarkerIndex - + bundleMarker.length(), bEndIndex).trim(); + + bundleMarker.length(), bEndIndex).trim(); processContentFileEntry(c, i, path, bitstreamName, bundleName, primary); System.out.println("\tBitstream: " + bitstreamName + - "\tBundle: " + bundleName + - primaryStr); - } - else - { + "\tBundle: " + bundleName + + primaryStr); + } else { processContentFileEntry(c, i, path, bitstreamName, null, primary); System.out.println("\tBitstream: " + bitstreamName + primaryStr); } - if (permissionsExist || descriptionExists) - { + if (permissionsExist || descriptionExists) { String extraInfo = bitstreamName; - if (permissionsExist) - { + if (permissionsExist) { extraInfo = extraInfo - + line.substring(pMarkerIndex, pEndIndex); + + line.substring(pMarkerIndex, pEndIndex); } - if (descriptionExists) - { + if (descriptionExists) { extraInfo = extraInfo - + line.substring(dMarkerIndex, dEndIndex); + + line.substring(dMarkerIndex, dEndIndex); } options.add(extraInfo); } } } - } - finally - { - if (is != null) - { + } finally { + if (is != null) { is.close(); } } - } - else - { + } else { File dir = new File(path); String[] dirListing = dir.list(); - for (String fileName : dirListing) - { - if (!"dublin_core.xml".equals(fileName) && !fileName.equals("handle") && !metadataFileFilter.accept(dir, fileName)) - { + for (String fileName : dirListing) { + if (!"dublin_core.xml".equals(fileName) && !fileName.equals("handle") && !metadataFileFilter + .accept(dir, fileName)) { throw new FileNotFoundException("No contents file found"); } } @@ -1159,56 +1067,48 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea /** * each entry represents a bitstream.... - * @param c DSpace Context - * @param i Dspace Item - * @param path path to file - * @param fileName file name + * + * @param c DSpace Context + * @param i Dspace Item + * @param path path to file + * @param fileName file name * @param bundleName bundle name - * @param primary if primary bitstream - * @throws SQLException if database error - * @throws IOException if IO error + * @param primary if primary bitstream + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ protected void processContentFileEntry(Context c, Item i, String path, - String fileName, String bundleName, boolean primary) throws SQLException, - IOException, AuthorizeException - { + String fileName, String bundleName, boolean primary) throws SQLException, + IOException, AuthorizeException { String fullpath = path + File.separatorChar + fileName; // get an input stream BufferedInputStream bis = new BufferedInputStream(new FileInputStream( - fullpath)); + fullpath)); Bitstream bs = null; String newBundleName = bundleName; - if (bundleName == null) - { + if (bundleName == null) { // is it license.txt? - if ("license.txt".equals(fileName)) - { + if ("license.txt".equals(fileName)) { newBundleName = "LICENSE"; - } - else - { + } else { // call it ORIGINAL newBundleName = "ORIGINAL"; } } - if (!isTest) - { + if (!isTest) { // find the bundle List bundles = itemService.getBundles(i, newBundleName); Bundle targetBundle = null; - if (bundles.size() < 1) - { + if (bundles.size() < 1) { // not found, create a new one targetBundle = bundleService.create(c, i, newBundleName); - } - else - { + } else { // put bitstreams into first bundle targetBundle = bundles.iterator().next(); } @@ -1225,8 +1125,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea bitstreamService.setFormat(c, bs, bf); // Is this a the primary bitstream? - if (primary) - { + if (primary) { targetBundle.setPrimaryBitstreamID(bs); bundleService.update(c, targetBundle); } @@ -1240,100 +1139,89 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea /** * Register the bitstream file into DSpace * - * @param c DSpace Context - * @param i DSpace Item - * @param assetstore assetstore number + * @param c DSpace Context + * @param i DSpace Item + * @param assetstore assetstore number * @param bitstreamPath the full filepath expressed in the contents file - * @param bundleName bundle name - * @param description bitstream description - * @throws SQLException if database error - * @throws IOException if IO error + * @param bundleName bundle name + * @param description bitstream description + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ protected void registerBitstream(Context c, Item i, int assetstore, - String bitstreamPath, String bundleName, String description ) - throws SQLException, IOException, AuthorizeException - { + String bitstreamPath, String bundleName, String description) + throws SQLException, IOException, AuthorizeException { // TODO validate assetstore number // TODO make sure the bitstream is there Bitstream bs = null; String newBundleName = bundleName; - if (StringUtils.isBlank(bundleName)) - { + if (StringUtils.isBlank(bundleName)) { // is it license.txt? - if (bitstreamPath.endsWith("license.txt")) - { + if (bitstreamPath.endsWith("license.txt")) { newBundleName = "LICENSE"; - } - else - { + } else { // call it ORIGINAL newBundleName = "ORIGINAL"; } } - if(!isTest) - { - // find the bundle - List bundles = itemService.getBundles(i, newBundleName); - Bundle targetBundle = null; + if (!isTest) { + // find the bundle + List bundles = itemService.getBundles(i, newBundleName); + Bundle targetBundle = null; - if( bundles.size() < 1 ) - { - // not found, create a new one - targetBundle = bundleService.create(c, i, newBundleName); - } - else - { - // put bitstreams into first bundle - targetBundle = bundles.iterator().next(); - } + if (bundles.size() < 1) { + // not found, create a new one + targetBundle = bundleService.create(c, i, newBundleName); + } else { + // put bitstreams into first bundle + targetBundle = bundles.iterator().next(); + } - // now add the bitstream - bs = bitstreamService.register(c, targetBundle, assetstore, bitstreamPath); + // now add the bitstream + bs = bitstreamService.register(c, targetBundle, assetstore, bitstreamPath); - // set the name to just the filename - int iLastSlash = bitstreamPath.lastIndexOf('/'); - bs.setName(c, bitstreamPath.substring(iLastSlash + 1)); + // set the name to just the filename + int iLastSlash = bitstreamPath.lastIndexOf('/'); + bs.setName(c, bitstreamPath.substring(iLastSlash + 1)); - // Identify the format - // FIXME - guessing format guesses license.txt incorrectly as a text file format! - BitstreamFormat bf = bitstreamFormatService.guessFormat(c, bs); + // Identify the format + // FIXME - guessing format guesses license.txt incorrectly as a text file format! + BitstreamFormat bf = bitstreamFormatService.guessFormat(c, bs); bitstreamService.setFormat(c, bs, bf); - bs.setDescription(c, description); + bs.setDescription(c, description); bitstreamService.update(c, bs); } } /** - * * Process the Options to apply to the Item. The options are tab delimited * * Options: - * {@code - * 48217870-MIT.pdf permissions: -r 'MIT Users' description: Full printable version (MIT only) - * permissions:[r|w]-['group name'] - * description: 'the description of the file' - * } - * where: - * {@code - * [r|w] (meaning: read|write) - * ['MIT Users'] (the group name) - * } - * @param c DSpace Context - * @param myItem DSpace Item + * {@code + * 48217870-MIT.pdf permissions: -r 'MIT Users' description: Full printable version (MIT only) + * permissions:[r|w]-['group name'] + * description: 'the description of the file' + * } + * where: + * {@code + * [r|w] (meaning: read|write) + * ['MIT Users'] (the group name) + * } + * + * @param c DSpace Context + * @param myItem DSpace Item * @param options List of option strings - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ protected void processOptions(Context c, Item myItem, List options) - throws SQLException, AuthorizeException - { - for (String line : options) - { + throws SQLException, AuthorizeException { + for (String line : options) { System.out.println("\tprocessing " + line); boolean permissionsExist = false; @@ -1342,11 +1230,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String permissionsMarker = "\tpermissions:"; int pMarkerIndex = line.indexOf(permissionsMarker); int pEndIndex = 0; - if (pMarkerIndex > 0) - { + if (pMarkerIndex > 0) { pEndIndex = line.indexOf("\t", pMarkerIndex + 1); - if (pEndIndex == -1) - { + if (pEndIndex == -1) { pEndIndex = line.length(); } permissionsExist = true; @@ -1355,11 +1241,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String descriptionMarker = "\tdescription:"; int dMarkerIndex = line.indexOf(descriptionMarker); int dEndIndex = 0; - if (dMarkerIndex > 0) - { + if (dMarkerIndex > 0) { dEndIndex = line.indexOf("\t", dMarkerIndex + 1); - if (dEndIndex == -1) - { + if (dEndIndex == -1) { dEndIndex = line.length(); } descriptionExists = true; @@ -1371,10 +1255,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea int actionID = -1; String groupName = ""; Group myGroup = null; - if (permissionsExist) - { + if (permissionsExist) { String thisPermission = line.substring(pMarkerIndex - + permissionsMarker.length(), pEndIndex); + + permissionsMarker.length(), pEndIndex); // get permission type ("read" or "write") int pTypeIndex = thisPermission.indexOf('-'); @@ -1385,92 +1268,71 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // if not in single quotes, assume everything after type flag is // group name - if (groupIndex == -1) - { + if (groupIndex == -1) { groupIndex = thisPermission.indexOf(' ', pTypeIndex); groupEndIndex = thisPermission.length(); } groupName = thisPermission.substring(groupIndex + 1, - groupEndIndex); + groupEndIndex); - if (thisPermission.toLowerCase().charAt(pTypeIndex + 1) == 'r') - { + if (thisPermission.toLowerCase().charAt(pTypeIndex + 1) == 'r') { actionID = Constants.READ; - } - else if (thisPermission.toLowerCase().charAt(pTypeIndex + 1) == 'w') - { + } else if (thisPermission.toLowerCase().charAt(pTypeIndex + 1) == 'w') { actionID = Constants.WRITE; } - try - { + try { myGroup = groupService.findByName(c, groupName); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { System.out.println("SQL Exception finding group name: " - + groupName); + + groupName); // do nothing, will check for null group later } } String thisDescription = ""; - if (descriptionExists) - { + if (descriptionExists) { thisDescription = line.substring( - dMarkerIndex + descriptionMarker.length(), dEndIndex) - .trim(); + dMarkerIndex + descriptionMarker.length(), dEndIndex) + .trim(); } Bitstream bs = null; boolean notfound = true; - if (!isTest) - { + if (!isTest) { // find bitstream List bitstreams = itemService.getNonInternalBitstreams(c, myItem); - for (int j = 0; j < bitstreams.size() && notfound; j++) - { - if (bitstreams.get(j).getName().equals(bitstreamName)) - { + for (int j = 0; j < bitstreams.size() && notfound; j++) { + if (bitstreams.get(j).getName().equals(bitstreamName)) { bs = bitstreams.get(j); notfound = false; } } } - if (notfound && !isTest) - { + if (notfound && !isTest) { // this should never happen System.out.println("\tdefault permissions set for " - + bitstreamName); - } - else if (!isTest) - { - if (permissionsExist) - { - if (myGroup == null) - { + + bitstreamName); + } else if (!isTest) { + if (permissionsExist) { + if (myGroup == null) { System.out.println("\t" + groupName - + " not found, permissions set to default"); - } - else if (actionID == -1) - { + + " not found, permissions set to default"); + } else if (actionID == -1) { System.out - .println("\tinvalid permissions flag, permissions set to default"); - } - else - { + .println("\tinvalid permissions flag, permissions set to default"); + } else { System.out.println("\tSetting special permissions for " - + bitstreamName); + + bitstreamName); setPermission(c, myGroup, actionID, bs); } } - if (descriptionExists) - { + if (descriptionExists) { System.out.println("\tSetting description for " - + bitstreamName); + + bitstreamName); bs.setDescription(c, thisDescription); bitstreamService.update(c, bs); } @@ -1481,19 +1343,17 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea /** * Set the Permission on a Bitstream. * - * @param c DSpace Context - * @param g Dspace Group + * @param c DSpace Context + * @param g Dspace Group * @param actionID action identifier - * @param bs Bitstream - * @see org.dspace.core.Constants - * @throws SQLException if database error + * @param bs Bitstream + * @throws SQLException if database error * @throws AuthorizeException if authorization error + * @see org.dspace.core.Constants */ protected void setPermission(Context c, Group g, int actionID, Bitstream bs) - throws SQLException, AuthorizeException - { - if (!isTest) - { + throws SQLException, AuthorizeException { + if (!isTest) { // remove the default policy authorizeService.removeAllPolicies(c, bs); @@ -1505,15 +1365,10 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea rp.setGroup(g); resourcePolicyService.update(c, rp); - } - else - { - if (actionID == Constants.READ) - { + } else { + if (actionID == Constants.READ) { System.out.println("\t\tpermissions: READ for " + g.getName()); - } - else if (actionID == Constants.WRITE) - { + } else if (actionID == Constants.WRITE) { System.out.println("\t\tpermissions: WRITE for " + g.getName()); } } @@ -1521,22 +1376,21 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } // XML utility methods + /** * Lookup an attribute from a DOM node. - * @param n node + * + * @param n node * @param name attribute name * @return attribute value */ - private String getAttributeValue(Node n, String name) - { + private String getAttributeValue(Node n, String name) { NamedNodeMap nm = n.getAttributes(); - for (int i = 0; i < nm.getLength(); i++) - { + for (int i = 0; i < nm.getLength(); i++) { Node node = nm.item(i); - if (name.equals(node.getNodeName())) - { + if (name.equals(node.getNodeName())) { return node.getNodeValue(); } } @@ -1547,19 +1401,17 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea /** * Return the String value of a Node. + * * @param node node * @return string value */ - protected String getStringValue(Node node) - { + protected String getStringValue(Node node) { String value = node.getNodeValue(); - if (node.hasChildNodes()) - { + if (node.hasChildNodes()) { Node first = node.getFirstChild(); - if (first.getNodeType() == Node.TEXT_NODE) - { + if (first.getNodeType() == Node.TEXT_NODE) { return first.getNodeValue(); } } @@ -1570,43 +1422,34 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea /** * Load in the XML from file. * - * @param filename - * the filename to load from - * + * @param filename the filename to load from * @return the DOM representation of the XML file - * @throws IOException if IO error + * @throws IOException if IO error * @throws ParserConfigurationException if config error - * @throws SAXException if XML error + * @throws SAXException if XML error */ protected Document loadXML(String filename) throws IOException, - ParserConfigurationException, SAXException - { + ParserConfigurationException, SAXException { DocumentBuilder builder = DocumentBuilderFactory.newInstance() - .newDocumentBuilder(); + .newDocumentBuilder(); return builder.parse(new File(filename)); } /** * Delete a directory and its child files and directories + * * @param path The directory to delete * @return Whether the deletion was successful or not */ - protected boolean deleteDirectory(File path) - { - if (path.exists()) - { + protected boolean deleteDirectory(File path) { + if (path.exists()) { File[] files = path.listFiles(); - for (int i = 0; i < files.length; i++) - { - if (files[i].isDirectory()) - { + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { deleteDirectory(files[i]); - } - else - { - if (!files[i].delete()) - { + } else { + if (!files[i].delete()) { log.error("Unable to delete file: " + files[i].getName()); } } @@ -1619,37 +1462,35 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea @Override public String unzip(File zipfile) throws IOException { - return unzip(zipfile, null); + return unzip(zipfile, null); } - + @Override public String unzip(File zipfile, String destDir) throws IOException { // 2 // does the zip file exist and can we write to the temp directory - if (!zipfile.canRead()) - { + if (!zipfile.canRead()) { log.error("Zip file '" + zipfile.getAbsolutePath() + "' does not exist, or is not readable."); } String destinationDir = destDir; - if (destinationDir == null){ - destinationDir = tempWorkDir; + if (destinationDir == null) { + destinationDir = tempWorkDir; } File tempdir = new File(destinationDir); - if (!tempdir.isDirectory()) - { + if (!tempdir.isDirectory()) { log.error("'" + ConfigurationManager.getProperty("org.dspace.app.itemexport.work.dir") + - "' as defined by the key 'org.dspace.app.itemexport.work.dir' in dspace.cfg " + - "is not a valid directory"); + "' as defined by the key 'org.dspace.app.itemexport.work.dir' in dspace.cfg " + + "is not a valid directory"); } - if (!tempdir.exists() && !tempdir.mkdirs()) - { + if (!tempdir.exists() && !tempdir.mkdirs()) { log.error("Unable to create temporary directory: " + tempdir.getAbsolutePath()); } String sourcedir = destinationDir + System.getProperty("file.separator") + zipfile.getName(); - String zipDir = destinationDir + System.getProperty("file.separator") + zipfile.getName() + System.getProperty("file.separator"); + String zipDir = destinationDir + System.getProperty("file.separator") + zipfile.getName() + System + .getProperty("file.separator"); // 3 @@ -1657,32 +1498,24 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea ZipFile zf = new ZipFile(zipfile); ZipEntry entry; Enumeration entries = zf.entries(); - while (entries.hasMoreElements()) - { + while (entries.hasMoreElements()) { entry = entries.nextElement(); - if (entry.isDirectory()) - { - if (!new File(zipDir + entry.getName()).mkdirs()) - { + if (entry.isDirectory()) { + if (!new File(zipDir + entry.getName()).mkdirs()) { log.error("Unable to create contents directory: " + zipDir + entry.getName()); } - } - else - { + } else { System.out.println("Extracting file: " + entry.getName()); log.info("Extracting file: " + entry.getName()); int index = entry.getName().lastIndexOf('/'); - if (index == -1) - { + if (index == -1) { // Was it created on Windows instead? index = entry.getName().lastIndexOf('\\'); } - if (index > 0) - { + if (index > 0) { File dir = new File(zipDir + entry.getName().substring(0, index)); - if (!dir.exists() && !dir.mkdirs()) - { + if (!dir.exists() && !dir.mkdirs()) { log.error("Unable to create directory: " + dir.getAbsolutePath()); } @@ -1695,8 +1528,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea //regex supports either windows or *nix file paths String[] entryChunks = entry.getName().split("/|\\\\"); - if(entryChunks.length > 2) { - if(StringUtils.equals(sourceDirForZip, sourcedir)) { + if (entryChunks.length > 2) { + if (StringUtils.equals(sourceDirForZip, sourcedir)) { sourceDirForZip = sourcedir + "/" + entryChunks[0]; } } @@ -1707,9 +1540,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea int len; InputStream in = zf.getInputStream(entry); BufferedOutputStream out = new BufferedOutputStream( - new FileOutputStream(zipDir + entry.getName())); - while((len = in.read(buffer)) >= 0) - { + new FileOutputStream(zipDir + entry.getName())); + while ((len = in.read(buffer)) >= 0) { out.write(buffer, 0, len); } in.close(); @@ -1719,8 +1551,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea //Close zip file zf.close(); - - if(!StringUtils.equals(sourceDirForZip, sourcedir)) { + + if (!StringUtils.equals(sourceDirForZip, sourcedir)) { sourcedir = sourceDirForZip; System.out.println("Set sourceDir using path inside of Zip: " + sourcedir); log.info("Set sourceDir using path inside of Zip: " + sourcedir); @@ -1734,67 +1566,67 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea File zipfile = new File(sourcedir + File.separator + zipfilename); return unzip(zipfile); } - + /** * Generate a random filename based on current time + * * @param hidden set to add . as a prefix to make the file hidden * @return the filename */ - protected String generateRandomFilename(boolean hidden) - { - String filename = String.format("%s", RandomStringUtils.randomAlphanumeric(8)); + protected String generateRandomFilename(boolean hidden) { + String filename = String.format("%s", RandomStringUtils.randomAlphanumeric(8)); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmm"); String datePart = sdf.format(new Date()); - filename = datePart+"_"+filename; + filename = datePart + "_" + filename; return filename; } /** - * - * Given a local file or public URL to a zip file that has the Simple Archive Format, this method imports the contents to DSpace - * @param filepath The filepath to local file or the public URL of the zip file + * Given a local file or public URL to a zip file that has the Simple Archive Format, this method imports the + * contents to DSpace + * + * @param filepath The filepath to local file or the public URL of the zip file * @param owningCollection The owning collection the items will belong to * @param otherCollections 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 + * @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 */ @Override - public void processUIImport(String filepath, Collection owningCollection, String[] otherCollections, String resumeDir, String inputType, Context context, final boolean template) throws Exception - { - final EPerson oldEPerson = context.getCurrentUser(); - final String[] theOtherCollections = otherCollections; - final Collection theOwningCollection = owningCollection; - final String theFilePath = filepath; - final String theInputType = inputType; - final String theResumeDir = resumeDir; + public void processUIImport(String filepath, Collection owningCollection, String[] otherCollections, + String resumeDir, String inputType, Context context, final boolean template) + throws Exception { + final EPerson oldEPerson = context.getCurrentUser(); + final String[] theOtherCollections = otherCollections; + final Collection theOwningCollection = owningCollection; + final String theFilePath = filepath; + final String theInputType = inputType; + final String theResumeDir = resumeDir; final boolean useTemplateItem = template; - - Thread go = new Thread() - { - @Override - public void run() - { - Context context = null; - String importDir = null; - EPerson eperson = null; - - try { - - // create a new dspace context - context = new Context(); - eperson = ePersonService.find(context, oldEPerson.getID()); - context.setCurrentUser(eperson); - context.turnOffAuthorisationSystem(); - - boolean isResume = theResumeDir!=null; - - List collectionList = new ArrayList<>(); - if (theOtherCollections != null) { + Thread go = new Thread() { + @Override + public void run() { + Context context = null; + + String importDir = null; + EPerson eperson = null; + + try { + + // create a new dspace context + context = new Context(); + eperson = ePersonService.find(context, oldEPerson.getID()); + context.setCurrentUser(eperson); + context.turnOffAuthorisationSystem(); + + boolean isResume = theResumeDir != null; + + List collectionList = new ArrayList<>(); + if (theOtherCollections != null) { for (String colID : theOtherCollections) { UUID colId = UUID.fromString(colID); if (!theOwningCollection.getID().equals(colId)) { @@ -1806,164 +1638,160 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } } - importDir = ConfigurationManager.getProperty("org.dspace.app.batchitemimport.work.dir") + File.separator + "batchuploads" + File.separator + context.getCurrentUser().getID() + File.separator + (isResume?theResumeDir:(new GregorianCalendar()).getTimeInMillis()); - File importDirFile = new File(importDir); - if (!importDirFile.exists()){ - boolean success = importDirFile.mkdirs(); - if (!success) { - log.info("Cannot create batch import directory!"); - throw new Exception("Cannot create batch import directory!"); - } - } - - String dataPath = null; - String dataDir = null; - - if (theInputType.equals("saf")){ //In case of Simple Archive Format import (from remote url) - dataPath = importDirFile + File.separator + "data.zip"; - dataDir = importDirFile + File.separator + "data_unzipped2" + File.separator; - } - else if (theInputType.equals("safupload")){ //In case of Simple Archive Format import (from upload file) - FileUtils.copyFileToDirectory(new File(theFilePath), importDirFile); - dataPath = importDirFile + File.separator + (new File(theFilePath)).getName(); - dataDir = importDirFile + File.separator + "data_unzipped2" + File.separator; - } - else { // For all other imports - dataPath = importDirFile + File.separator + (new File(theFilePath)).getName(); - dataDir = importDirFile + File.separator + "data" + File.separator; - } - - //Clear these files, if a resume - if (isResume){ - if (!theInputType.equals("safupload")) { - (new File(dataPath)).delete(); - } - (new File(importDirFile + File.separator + "error.txt")).delete(); - FileDeleteStrategy.FORCE.delete(new File(dataDir)); - FileDeleteStrategy.FORCE.delete(new File(importDirFile + File.separator + "data_unzipped" + File.separator)); - } + importDir = ConfigurationManager.getProperty( + "org.dspace.app.batchitemimport.work.dir") + File.separator + "batchuploads" + File.separator + + context + .getCurrentUser() + .getID() + File.separator + (isResume ? theResumeDir : (new GregorianCalendar()) + .getTimeInMillis()); + File importDirFile = new File(importDir); + if (!importDirFile.exists()) { + boolean success = importDirFile.mkdirs(); + if (!success) { + log.info("Cannot create batch import directory!"); + throw new Exception("Cannot create batch import directory!"); + } + } - //In case of Simple Archive Format import we need an extra effort to download the zip file and unzip it - String sourcePath = null; - if (theInputType.equals("saf")){ - OutputStream os = new FileOutputStream(dataPath); + String dataPath = null; + String dataDir = null; - byte[] b = new byte[2048]; - int length; + if (theInputType.equals("saf")) { //In case of Simple Archive Format import (from remote url) + dataPath = importDirFile + File.separator + "data.zip"; + dataDir = importDirFile + File.separator + "data_unzipped2" + File.separator; + } else if (theInputType + .equals("safupload")) { //In case of Simple Archive Format import (from upload file) + FileUtils.copyFileToDirectory(new File(theFilePath), importDirFile); + dataPath = importDirFile + File.separator + (new File(theFilePath)).getName(); + dataDir = importDirFile + File.separator + "data_unzipped2" + File.separator; + } else { // For all other imports + dataPath = importDirFile + File.separator + (new File(theFilePath)).getName(); + dataDir = importDirFile + File.separator + "data" + File.separator; + } - InputStream is = new URL(theFilePath).openStream(); - while ((length = is.read(b)) != -1) { - os.write(b, 0, length); - } + //Clear these files, if a resume + if (isResume) { + if (!theInputType.equals("safupload")) { + (new File(dataPath)).delete(); + } + (new File(importDirFile + File.separator + "error.txt")).delete(); + FileDeleteStrategy.FORCE.delete(new File(dataDir)); + FileDeleteStrategy.FORCE + .delete(new File(importDirFile + File.separator + "data_unzipped" + File.separator)); + } - is.close(); - os.close(); + //In case of Simple Archive Format import we need an extra effort to download the zip file and + // unzip it + String sourcePath = null; + if (theInputType.equals("saf")) { + OutputStream os = new FileOutputStream(dataPath); - sourcePath = unzip(new File(dataPath), dataDir); - - //Move files to the required folder - FileUtils.moveDirectory(new File(sourcePath), new File(importDirFile + File.separator + "data_unzipped" + File.separator)); - FileDeleteStrategy.FORCE.delete(new File(dataDir)); - dataDir = importDirFile + File.separator + "data_unzipped" + File.separator; - } - else if (theInputType.equals("safupload")){ - sourcePath = unzip(new File(dataPath), dataDir); - //Move files to the required folder - FileUtils.moveDirectory(new File(sourcePath), new File(importDirFile + File.separator + "data_unzipped" + File.separator)); - FileDeleteStrategy.FORCE.delete(new File(dataDir)); - dataDir = importDirFile + File.separator + "data_unzipped" + File.separator; - } - - //Create mapfile path - String mapFilePath = importDirFile + File.separator + "mapfile"; - - List finalCollections = null; - if (theOwningCollection != null){ + byte[] b = new byte[2048]; + int length; + + InputStream is = new URL(theFilePath).openStream(); + while ((length = is.read(b)) != -1) { + os.write(b, 0, length); + } + + is.close(); + os.close(); + + sourcePath = unzip(new File(dataPath), dataDir); + + //Move files to the required folder + FileUtils.moveDirectory(new File(sourcePath), new File( + importDirFile + File.separator + "data_unzipped" + File.separator)); + FileDeleteStrategy.FORCE.delete(new File(dataDir)); + dataDir = importDirFile + File.separator + "data_unzipped" + File.separator; + } else if (theInputType.equals("safupload")) { + sourcePath = unzip(new File(dataPath), dataDir); + //Move files to the required folder + FileUtils.moveDirectory(new File(sourcePath), new File( + importDirFile + File.separator + "data_unzipped" + File.separator)); + FileDeleteStrategy.FORCE.delete(new File(dataDir)); + dataDir = importDirFile + File.separator + "data_unzipped" + File.separator; + } + + //Create mapfile path + String mapFilePath = importDirFile + File.separator + "mapfile"; + + List finalCollections = null; + if (theOwningCollection != null) { finalCollections = new ArrayList<>(); - finalCollections.add(theOwningCollection); + finalCollections.add(theOwningCollection); finalCollections.addAll(collectionList); - } - - setResume(isResume); - - if (theInputType.equals("saf") || theInputType.equals("safupload")){ //In case of Simple Archive Format import - addItems(context, finalCollections, dataDir, mapFilePath, template); - } - else { // For all other imports (via BTE) - addBTEItems(context, finalCollections, theFilePath, mapFilePath, useTemplateItem, theInputType, dataDir); - } - - // email message letting user know the file is ready for + } + + setResume(isResume); + + if (theInputType.equals("saf") || theInputType + .equals("safupload")) { //In case of Simple Archive Format import + addItems(context, finalCollections, dataDir, mapFilePath, template); + } else { // For all other imports (via BTE) + addBTEItems(context, finalCollections, theFilePath, mapFilePath, useTemplateItem, theInputType, + dataDir); + } + + // email message letting user know the file is ready for // download emailSuccessMessage(context, eperson, mapFilePath); - - context.complete(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + context.complete(); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); String exceptionString = ExceptionUtils.getStackTrace(e); - try - { - File importDirFile = new File(importDir+File.separator+"error.txt"); - PrintWriter errorWriter = new PrintWriter(importDirFile); - errorWriter.print(exceptionString); - errorWriter.close(); - + try { + File importDirFile = new File(importDir + File.separator + "error.txt"); + PrintWriter errorWriter = new PrintWriter(importDirFile); + errorWriter.print(exceptionString); + errorWriter.close(); + emailErrorMessage(eperson, exceptionString); throw new Exception(e.getMessage()); - } - catch (Exception e2) - { + } catch (Exception e2) { // wont throw here } - } - - finally - { + } finally { // Make sure the database connection gets closed in all conditions. - try { - context.complete(); - } catch (SQLException sqle) { - context.abort(); - } + try { + context.complete(); + } catch (SQLException sqle) { + context.abort(); + } } - } + } - }; + }; - go.isDaemon(); - go.start(); - - } + go.isDaemon(); + go.start(); + + } @Override public void emailSuccessMessage(Context context, EPerson eperson, - String fileName) throws MessagingException - { - try - { + String fileName) throws MessagingException { + try { Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "bte_batch_import_success")); email.addRecipient(eperson.getEmail()); email.addArgument(fileName); email.send(); - } - catch (Exception e) - { + } catch (Exception e) { log.warn(LogManager.getHeader(context, "emailSuccessMessage", "cannot notify user of import"), e); } } @Override public void emailErrorMessage(EPerson eperson, String error) - throws MessagingException - { + throws MessagingException { log.warn("An error occurred during item import, the user will be notified. " + error); - try - { + try { Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "bte_batch_import_error")); email.addRecipient(eperson.getEmail()); @@ -1971,38 +1799,32 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea email.addArgument(ConfigurationManager.getProperty("dspace.url") + "/feedback"); email.send(); - } - catch (Exception e) - { + } catch (Exception e) { log.warn("error during item import error notification", e); } } - + @Override public List getImportsAvailable(EPerson eperson) - throws Exception - { + throws Exception { File uploadDir = new File(getImportUploadableDirectory(eperson)); - if (!uploadDir.exists() || !uploadDir.isDirectory()) - { + if (!uploadDir.exists() || !uploadDir.isDirectory()) { return null; } Map fileNames = new TreeMap<>(); - for (String fileName : uploadDir.list()) - { + for (String fileName : uploadDir.list()) { File file = new File(uploadDir + File.separator + fileName); - if (file.isDirectory()){ - - BatchUpload upload = new BatchUpload(file); - - fileNames.put(upload.getDir().getName(), upload); + if (file.isDirectory()) { + + BatchUpload upload = new BatchUpload(file); + + fileNames.put(upload.getDir().getName(), upload); } } - if (fileNames.size() > 0) - { + if (fileNames.size() > 0) { return new ArrayList<>(fileNames.values()); } @@ -2011,19 +1833,16 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea @Override public String getImportUploadableDirectory(EPerson ePerson) - throws Exception - { + throws Exception { String uploadDir = ConfigurationManager.getProperty("org.dspace.app.batchitemimport.work.dir"); - if (uploadDir == null) - { + if (uploadDir == null) { throw new Exception( - "A dspace.cfg entry for 'org.dspace.app.batchitemimport.work.dir' does not exist."); + "A dspace.cfg entry for 'org.dspace.app.batchitemimport.work.dir' does not exist."); } String uploadDirBasePath = uploadDir + File.separator + "batchuploads" + File.separator; //Check for backwards compatibility with the old identifier File uploadDirectory = new File(uploadDirBasePath + ePerson.getLegacyId()); - if(!uploadDirectory.exists()) - { + if (!uploadDirectory.exists()) { uploadDirectory = new File(uploadDirBasePath + ePerson.getID()); } @@ -2032,16 +1851,15 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } @Override - public void deleteBatchUpload(Context c, String uploadId) throws Exception - { - String uploadDir = null; - String mapFilePath = null; + public void deleteBatchUpload(Context c, String uploadId) throws Exception { + String uploadDir = null; + String mapFilePath = null; - uploadDir = getImportUploadableDirectory(c.getCurrentUser()) + File.separator + uploadId; - mapFilePath = uploadDir + File.separator + "mapfile"; - - this.deleteItems(c, mapFilePath); - FileDeleteStrategy.FORCE.delete(new File(uploadDir)); + uploadDir = getImportUploadableDirectory(c.getCurrentUser()) + File.separator + uploadId; + mapFilePath = uploadDir + File.separator + "mapfile"; + + this.deleteItems(c, mapFilePath); + FileDeleteStrategy.FORCE.delete(new File(uploadDir)); } @Override @@ -2051,20 +1869,20 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea @Override public File getTempWorkDirFile() - throws IOException - { + throws IOException { File tempDirFile = new File(getTempWorkDir()); - if(!tempDirFile.exists()) { + if (!tempDirFile.exists()) { boolean success = tempDirFile.mkdirs(); - if (!success) - { + if (!success) { throw new IOException("Work directory " - + tempDirFile.getAbsolutePath() - + " could not be created."); + + tempDirFile.getAbsolutePath() + + " could not be created."); + } else { + log.debug("Created directory " + tempDirFile.getAbsolutePath()); } - else log.debug("Created directory " + tempDirFile.getAbsolutePath()); + } else { + log.debug("Work directory exists: " + tempDirFile.getAbsolutePath()); } - else log.debug("Work directory exists: " + tempDirFile.getAbsolutePath()); return tempDirFile; } diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/factory/ItemImportServiceFactory.java b/dspace-api/src/main/java/org/dspace/app/itemimport/factory/ItemImportServiceFactory.java index 6a66e8f0a5..486a6b993e 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/factory/ItemImportServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/factory/ItemImportServiceFactory.java @@ -11,7 +11,8 @@ 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 + * Abstract factory to get services for the itemimport package, use ItemImportService.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -19,7 +20,8 @@ public abstract class ItemImportServiceFactory { public abstract ItemImportService getItemImportService(); - public static ItemImportServiceFactory getInstance(){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("itemImportServiceFactory", ItemImportServiceFactory.class); + public static ItemImportServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("itemImportServiceFactory", ItemImportServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/factory/ItemImportServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/factory/ItemImportServiceFactoryImpl.java index b1be4c4255..c344c0b2ad 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/factory/ItemImportServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/factory/ItemImportServiceFactoryImpl.java @@ -11,7 +11,8 @@ 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 + * Factory implementation to get services for the itemimport package, use ItemImportService.getInstance() to retrieve + * an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java b/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java index 966c06f36a..296f6a1e9c 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java @@ -7,16 +7,16 @@ */ 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 javax.mail.MessagingException; -import java.io.File; -import java.io.IOException; -import java.util.List; - /** * Import items into DSpace. The conventional use is upload files by copying * them. DSpace writes the item's bitstreams into its assetstore. Metadata is @@ -37,30 +37,32 @@ public interface ItemImportService { /** - * - * @param c DSpace Context + * @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 + * @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 mycollections, String sourceDir, String mapFile, boolean template) throws Exception; + public void addItemsAtomic(Context c, List mycollections, String sourceDir, String mapFile, + boolean template) throws Exception; /** * Add items - * @param c DSpace Context + * + * @param c DSpace Context * @param mycollections List of Collections - * @param sourceDir source location - * @param mapFile map file - * @param template whether to use template item + * @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 mycollections, - String sourceDir, String mapFile, boolean template) throws Exception; + String sourceDir, String mapFile, boolean template) throws Exception; /** * Unzip a file + * * @param zipfile file * @return unzip location * @throws IOException if error @@ -69,6 +71,7 @@ public interface ItemImportService { /** * Unzip a file to a destination + * * @param zipfile file * @param destDir destination directory * @return unzip location @@ -78,7 +81,8 @@ public interface ItemImportService { /** * Unzip a file in a specific source directory - * @param sourcedir source directory + * + * @param sourcedir source directory * @param zipfilename file name * @return unzip location * @throws IOException if error @@ -86,18 +90,19 @@ public interface ItemImportService { 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 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 + * @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; + 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 @@ -105,16 +110,13 @@ public interface ItemImportService { * 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 + * @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; + String fileName) throws MessagingException; /** * Since the BTE batch import is done in a new thread we are unable to communicate @@ -122,37 +124,38 @@ public interface ItemImportService { * 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 + * @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; + throws MessagingException; /** * Get imports available for a person + * * @param eperson EPerson object * @return List of batch uploads * @throws Exception if error */ public List getImportsAvailable(EPerson eperson) - throws Exception; + throws Exception; /** * Get import upload directory + * * @param ePerson EPerson object * @return directory - * @throws Exception if error + * @throws Exception if error */ public String getImportUploadableDirectory(EPerson ePerson) - throws Exception; + throws Exception; /** * Delete a batch by ID - * @param c DSpace Context + * + * @param c DSpace Context * @param uploadId identifier * @throws Exception if error */ @@ -160,18 +163,21 @@ public interface ItemImportService { /** * Replace items - * @param c DSpace Context + * + * @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 sourcedir source directory + * @param mapfile map file + * @param template whether to use template item * @throws Exception if error */ - public void replaceItems(Context c, List mycollections, String sourcedir, String mapfile, boolean template) throws Exception; + public void replaceItems(Context c, List mycollections, String sourcedir, String mapfile, + boolean template) throws Exception; /** * Delete items via mapfile - * @param c DSpace Context + * + * @param c DSpace Context * @param mapfile map file * @throws Exception if error */ @@ -179,25 +185,29 @@ public interface ItemImportService { /** * Add items - * @param c DSpace Context + * + * @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 + * @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 mycollections, String sourcedir, String mapfile, boolean template, String bteInputType, String workingDir) throws Exception; + public void addBTEItems(Context c, List 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. */ @@ -210,18 +220,21 @@ public interface ItemImportService { /** * Set test flag - * @param isTest true or false + * + * @param isTest true or false */ public void setTest(boolean isTest); /** * Set resume flag - * @param isResume true or false + * + * @param isResume true or false */ public void setResume(boolean isResume); /** * Set use workflow + * * @param useWorkflow whether to enable workflow */ public void setUseWorkflow(boolean useWorkflow); @@ -233,6 +246,7 @@ public interface ItemImportService { /** * Set quiet flag + * * @param isQuiet true or false */ public void setQuiet(boolean isQuiet); diff --git a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingAvailabilityBitstreamStrategy.java b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingAvailabilityBitstreamStrategy.java index 45c63660bd..cd08ad032c 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingAvailabilityBitstreamStrategy.java +++ b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingAvailabilityBitstreamStrategy.java @@ -23,75 +23,71 @@ 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; + 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 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 { + public ItemMarkingAvailabilityBitstreamStrategy() { + + } + + @Override + public ItemMarkingInfo getItemMarkingInfo(Context context, Item item) + throws SQLException { + + List 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 = ""; + + + String bsLink = ""; bsLink = bsLink + "bitstream/" - + item.getHandle() + "/" - + bitstream.getSequenceID() + "/"; - + + item.getHandle() + "/" + + bitstream.getSequenceID() + "/"; + try { - bsLink = bsLink + Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING); - } catch (UnsupportedEncodingException e) { - - e.printStackTrace(); - } - - signInfo.setLink(bsLink); - - return signInfo; - } - } - } + bsLink = bsLink + Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING); + } catch (UnsupportedEncodingException e) { - public void setAvailableImageName(String availableImageName) { - this.availableImageName = availableImageName; - } + e.printStackTrace(); + } - public void setNonAvailableImageName(String nonAvailableImageName) { - this.nonAvailableImageName = nonAvailableImageName; - } + signInfo.setLink(bsLink); + + return signInfo; + } + } + } + + public void setAvailableImageName(String availableImageName) { + this.availableImageName = availableImageName; + } + + public void setNonAvailableImageName(String nonAvailableImageName) { + this.nonAvailableImageName = nonAvailableImageName; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingCollectionStrategy.java b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingCollectionStrategy.java index deaee2a748..5fcf045c87 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingCollectionStrategy.java +++ b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingCollectionStrategy.java @@ -18,33 +18,32 @@ 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 mapping = new HashMap(); - - public ItemMarkingCollectionStrategy() { - } + Map mapping = new HashMap(); - @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 ItemMarkingCollectionStrategy() { + } - public void setMapping(Map mapping) { - this.mapping = mapping; - } + @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 mapping) { + this.mapping = mapping; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingExtractor.java b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingExtractor.java index 3a036e81a5..ecbd952541 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingExtractor.java +++ b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingExtractor.java @@ -14,11 +14,10 @@ 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; + public ItemMarkingInfo getItemMarkingInfo(Context context, Item item) + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingInfo.java b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingInfo.java index 3ca671f7ce..297df6a939 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingInfo.java +++ b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingInfo.java @@ -9,49 +9,48 @@ 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; + private String imageName; + private String classInfo; + private String tooltip; + private String link; - public ItemMarkingInfo() { - super(); - } + public ItemMarkingInfo() { + super(); + } - public String getImageName() { - return imageName; - } + public String getImageName() { + return imageName; + } - public void setImageName(String imageName) { - this.imageName = imageName; - } + public void setImageName(String imageName) { + this.imageName = imageName; + } - public String getTooltip() { - return tooltip; - } + public String getTooltip() { + return tooltip; + } - public void setTooltip(String tooltip) { - this.tooltip = tooltip; - } - - public String getLink() { - return link; - } + public void setTooltip(String tooltip) { + this.tooltip = tooltip; + } - public void setLink(String link) { - this.link = link; - } - - public String getClassInfo() { - return classInfo; - } + public String getLink() { + return link; + } - public void setClassInfo(String classInfo) { - this.classInfo = classInfo; - } + public void setLink(String link) { + this.link = link; + } + + public String getClassInfo() { + return classInfo; + } + + public void setClassInfo(String classInfo) { + this.classInfo = classInfo; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingMetadataStrategy.java b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingMetadataStrategy.java index 6e637ee10c..3573e0c2bc 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingMetadataStrategy.java +++ b/dspace-api/src/main/java/org/dspace/app/itemmarking/ItemMarkingMetadataStrategy.java @@ -22,46 +22,43 @@ 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 mapping = new HashMap(); - - public ItemMarkingMetadataStrategy() { - } + private String metadataField; + Map mapping = new HashMap(); - @Override - public ItemMarkingInfo getItemMarkingInfo(Context context, Item item) - throws SQLException { - - if (metadataField != null && mapping!=null) - { - List 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 ItemMarkingMetadataStrategy() { + } - public void setMetadataField(String metadataField) { - this.metadataField = metadataField; - } + @Override + public ItemMarkingInfo getItemMarkingInfo(Context context, Item item) + throws SQLException { - public void setMapping(Map mapping) { - this.mapping = mapping; - } + if (metadataField != null && mapping != null) { + List 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 mapping) { + this.mapping = mapping; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/ActionManager.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/ActionManager.java index 6a5579a958..a79566d69b 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/ActionManager.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/ActionManager.java @@ -12,80 +12,70 @@ 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. - * - * + * 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 { - - protected Map, UpdateAction> registry - = new LinkedHashMap, 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 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 iterator() - { - return new Iterator() - { - private Iterator> 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(); - } - }; - - } + + protected Map, UpdateAction> registry + = new LinkedHashMap, 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 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 iterator() { + return new Iterator() { + private Iterator> 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(); + } + }; + + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/AddBitstreamsAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/AddBitstreamsAction.java index d78c73693b..e9693fb3d1 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/AddBitstreamsAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/AddBitstreamsAction.java @@ -19,7 +19,11 @@ 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.*; +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; @@ -29,201 +33,176 @@ 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 - * - * + * 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 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 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 fileList = new ArrayList(); - 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++; - } - } + 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 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 fileList = new ArrayList(); + 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); - 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")) - { + if (ce.bundlename == null) { // should be required but default convention established + if (ce.filename.equals("license.txt")) { newBundleName = "LICENSE"; - } - else - { + } else { newBundleName = "ORIGINAL"; } } ItemUpdate.pr(" Bitstream " + ce.filename + " to be added to bundle: " + newBundleName); - - if (!isTest) - { - // find the bundle - List 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 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 (!isTest) { + // find the bundle + List bundles = itemService.getBundles(item, newBundleName); + Bundle targetBundle = null; - 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) - { + 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 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 + } + } + + //update after all changes are applied bitstreamService.update(context, bs); - - if (!suppressUndo) - { - itarch.addUndoDeleteContents(bs.getID()); - } - return targetBundle.getName(); + + if (!suppressUndo) { + itarch.addUndoDeleteContents(bs.getID()); + } + return targetBundle.getName(); } - return ""; + return ""; } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/AddMetadataAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/AddMetadataAction.java index 74aa8525b1..89c24b07d5 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/AddMetadataAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/AddMetadataAction.java @@ -11,119 +11,107 @@ import java.sql.SQLException; import java.util.List; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.MetadataValue; 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 - * + * Action to add metadata to item */ public class AddMetadataAction extends UpdateMetadataAction { - protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + 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 + /** + * 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 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) - { + 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 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 - } - } - } - } + 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 + } + } + } + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilter.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilter.java index dd1cfccd7e..31d3014b6a 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilter.java @@ -7,55 +7,49 @@ */ package org.dspace.app.itemupdate; -import java.io.IOException; -import java.util.Properties; -import java.io.InputStream; 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. - * + * 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; + protected Properties props = null; - try - { + /** + * 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) - { + } finally { + if (in != null) { in.close(); } } - } - + } + } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterByBundleName.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterByBundleName.java index e24ea0c42b..885465cd7d 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterByBundleName.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterByBundleName.java @@ -14,55 +14,44 @@ import org.dspace.content.Bitstream; import org.dspace.content.Bundle; /** - * BitstreamFilter implementation to filter by bundle name - * + * BitstreamFilter implementation to filter by bundle name */ public class BitstreamFilterByBundleName extends BitstreamFilter { - protected String bundleName; - - public BitstreamFilterByBundleName() - { - //empty - } + 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 bundles = bitstream.getBundles(); + for (Bundle b : bundles) { + if (b.getName().equals(bundleName)) { + return true; + } + } + } catch (SQLException e) { + throw new BitstreamFilterException(e); + } + return false; + } - /** - * Filter bitstream based on bundle name found in properties file - * - * @param bitstream Bitstream - * @throws BitstreamFilterException if filter error - * @return whether bitstream is in bundle - * - */ - @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 bundles = bitstream.getBundles(); - for (Bundle b : bundles) - { - if (b.getName().equals(bundleName)) - { - return true; - } - } - } - catch(SQLException e) - { - throw new BitstreamFilterException(e); - } - return false; - } - } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterByFilename.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterByFilename.java index 4613540252..14247128e1 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterByFilename.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterByFilename.java @@ -7,47 +7,43 @@ */ package org.dspace.app.itemupdate; -import java.util.regex.*; +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() - { + + public BitstreamFilterByFilename() { //empty } /** - * Tests bitstream by matching the regular expression in the + * 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) - { + public boolean accept(Bitstream bitstream) throws BitstreamFilterException { + if (filenameRegex == null) { filenameRegex = props.getProperty("filename"); - if (filenameRegex == null) - { + if (filenameRegex == null) { throw new BitstreamFilterException("BitstreamFilter property 'filename' not found."); } pattern = Pattern.compile(filenameRegex); } - + Matcher m = pattern.matcher(bitstream.getName()); return m.matches(); - } - + } + } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterException.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterException.java index 5126f7d5f3..36e2756650 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterException.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/BitstreamFilterException.java @@ -8,30 +8,27 @@ package org.dspace.app.itemupdate; /** - * Exception class for BitstreamFilters - * + * 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); - } - +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); + } + } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/ContentsEntry.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/ContentsEntry.java index 61c7ca3b77..e192b92b89 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/ContentsEntry.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/ContentsEntry.java @@ -8,148 +8,124 @@ package org.dspace.app.itemupdate; import java.text.ParseException; -import java.util.regex.*; +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: - * } - * + * 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: + * } */ -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; +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(); + } - 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(); - } - } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java index 2d44e3dc47..cb5dcfb75d 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java @@ -14,99 +14,81 @@ import java.text.ParseException; import java.util.List; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +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 + * 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 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 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 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()); - } - } - } - } - } + 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 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 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()); + } + } + } + } + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsByFilterAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsByFilterAction.java index 8a0caaa24a..8871039f2d 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsByFilterAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsByFilterAction.java @@ -14,115 +14,104 @@ import java.util.ArrayList; import java.util.List; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +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 - * + * 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 deleted = new ArrayList(); - - Item item = itarch.getItem(); - List bundles = item.getBundles(); - - for (Bundle b : bundles) - { - List bitstreams = b.getBitstreams(); - String bundleName = b.getName(); + protected BitstreamFilter filter; - 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()); - } + /** + * 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 deleted = new ArrayList(); + + Item item = itarch.getItem(); + List bundles = item.getBundles(); + + for (Bundle b : bundles) { + List 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()); + } + } + } + } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteMetadataAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteMetadataAction.java index a9a478efa4..010b9d8eef 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteMetadataAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteMetadataAction.java @@ -12,60 +12,54 @@ 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.content.Item; import org.dspace.core.Context; /** - * Action to delete metadata - * - * + * 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 + /** + * 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 ardcv = itemService.getMetadataByMetadataString(item, f); + boolean suppressUndo) throws AuthorizeException, ParseException, SQLException { + Item item = itarch.getItem(); + for (String f : targetFields) { + DtoMetadata dummy = DtoMetadata.create(f, Item.ANY, ""); + List ardcv = itemService.getMetadataByMetadataString(item, f); - ItemUpdate.pr("Metadata to be deleted: "); - for (MetadataValue dcv : ardcv) - { - ItemUpdate.pr(" " + MetadataUtilities.getDCValueString(dcv)); - } + ItemUpdate.pr("Metadata to be deleted: "); + for (MetadataValue dcv : ardcv) { + ItemUpdate.pr(" " + MetadataUtilities.getDCValueString(dcv)); + } - if (!isTest) - { - if (!suppressUndo) - { - for (MetadataValue dcv : ardcv) - { + 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())); - } - } - + 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); - } - } - } + } + } + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/DerivativeTextBitstreamFilter.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/DerivativeTextBitstreamFilter.java index 24bc8f6b6f..3897501b73 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/DerivativeTextBitstreamFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/DerivativeTextBitstreamFilter.java @@ -10,15 +10,13 @@ package org.dspace.app.itemupdate; import java.util.Properties; /** - * Bitstream filter to delete from TEXT bundle - * + * Bitstream filter to delete from TEXT bundle */ public class DerivativeTextBitstreamFilter extends BitstreamFilterByBundleName { - - public DerivativeTextBitstreamFilter() - { - props = new Properties(); - props.setProperty("bundle", "TEXT"); - } + + public DerivativeTextBitstreamFilter() { + props = new Properties(); + props.setProperty("bundle", "TEXT"); + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/DtoMetadata.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/DtoMetadata.java index 2cdc72f1b1..6e4a4a88d6 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/DtoMetadata.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/DtoMetadata.java @@ -8,152 +8,131 @@ 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 .[.]} - * - * Does not support wildcard for qualifier - * + * 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 + * .[.]} + * + * 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); +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 to create metadata object - * - * - * @param compoundForm of the form .[.] - * @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); + /** + * 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); } - /** - * Determine if this metadata field matches the specified type: - * schema.element or schema.element.qualifier - * - * - * @param compoundForm of the form .[.|.*] - * @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); + /** + * Factory method to create metadata object + * + * @param compoundForm of the form .[.] + * @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 .[.|.*] + * @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; - } - + } + + public String getValue() { + return value; + } + } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/ItemArchive.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/ItemArchive.java index a66c923be7..8b07335904 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/ItemArchive.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/ItemArchive.java @@ -10,12 +10,11 @@ package org.dspace.app.itemupdate; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; -import java.io.FileWriter; -import java.io.FilenameFilter; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.InputStream; +import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.sql.SQLException; @@ -23,14 +22,13 @@ 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 javax.xml.transform.TransformerConfigurationException; import org.apache.log4j.Logger; import org.dspace.app.util.LocalSchemaFilenameFilter; @@ -40,20 +38,18 @@ 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 - * + * Encapsulates the Item in the context of the DSpace Archive Format */ public class ItemArchive { - private static final Logger log = Logger.getLogger(ItemArchive.class); + private static final Logger log = Logger.getLogger(ItemArchive.class); - public static final String DUBLIN_CORE_XML = "dublin_core.xml"; + public static final String DUBLIN_CORE_XML = "dublin_core.xml"; protected static DocumentBuilder builder = null; protected Transformer transformer = null; @@ -70,312 +66,278 @@ public class ItemArchive { protected HandleService handleService; protected ItemService itemService; -//constructors - protected ItemArchive() - { + //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(); + } + + /** + * 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 - { + 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 + + //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++) - { + for (int i = 0; i < file.length; i++) { is = new FileInputStream(file[i]); itarch.dtomList.addAll(MetadataUtilities.loadDublinCore(getDocumentBuilder(), is)); } - } - finally - { - if (is != null) - { + } 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()); + ItemUpdate.pr("Loaded metadata with " + itarch.dtomList.size() + " fields"); - return itarch; - } - - protected static DocumentBuilder getDocumentBuilder() - throws ParserConfigurationException - { - if (builder == null) - { - builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - } - return builder; - } + 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; - } + 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 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 + * 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 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; + 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, - * - * + * 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 .. * @throws SQLException if database error - * @throws Exception if 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()); + throws SQLException, AuthorizeException, Exception { + DtoMetadata dtom = getMetadataField(itemField); - this.addUndoMetadataField(dtom); //seed the undo list with the identifier field - - Iterator itr = itemService.findByMetadataField(context, dtom.schema, dtom.element, dtom.qualifier, dtom.value); - int count = 0; - while (itr.hasNext()) - { - item = itr.next(); - count++; - } + 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 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; + } - 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; - } + 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 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 + * @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()) - { + 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 - { + 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) - { + if (undoAddContents.size() > 0) { PrintWriter pw = null; - try - { + try { File f = new File(dir, ItemUpdate.DELETE_CONTENTS_FILE); pw = new PrintWriter(new BufferedWriter(new FileWriter(f))); - for (UUID i : undoAddContents) - { + for (UUID i : undoAddContents) { pw.println(i); } - } - finally - { + } finally { pw.close(); } } - } - finally - { - if (out != null) - { + } finally { + if (out != null) { out.close(); } } - } - + } + } //end class diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/ItemUpdate.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/ItemUpdate.java index 94890dcc1a..8c91a565da 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/ItemUpdate.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/ItemUpdate.java @@ -7,48 +7,63 @@ */ package org.dspace.app.itemupdate; -import org.apache.commons.cli.*; +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; - -import java.io.*; -import java.util.*; +import org.dspace.handle.factory.HandleServiceFactory; +import org.dspace.handle.service.HandleService; /** - * - * 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 + * 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 { @@ -64,32 +79,29 @@ public class ItemUpdate { protected static final EPersonService epersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); + protected static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - static - { + static { filterAliases.put("ORIGINAL", "org.dspace.app.itemupdate.OriginalBitstreamFilter"); - filterAliases.put("ORIGINAL_AND_DERIVATIVES", "org.dspace.app.itemupdate.OriginalWithDerivativesBitstreamFilter"); + 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() - { + static FilenameFilter directoryFilter = new FilenameFilter() { @Override - public boolean accept(File dir, String n) - { + 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() - { + static FilenameFilter fileFilter = new FilenameFilter() { @Override - public boolean accept(File dir, String n) - { + public boolean accept(File dir, String n) { File f = new File(dir.getAbsolutePath() + File.separatorChar + n); return (f.isFile()); } @@ -99,60 +111,59 @@ public class ItemUpdate { protected ActionManager actionMgr = new ActionManager(); protected List undoActionList = new ArrayList(); protected String eperson; - + /** - * * @param argv the command line arguments given */ - public static void main(String[] argv) - { + 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 + //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("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"); + 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("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 - { + try { CommandLine line = parser.parse(options, argv); - if (line.hasOption('h')) - { + if (line.hasOption('h')) { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("ItemUpdate", options); pr(""); @@ -166,91 +177,79 @@ public class ItemUpdate { System.exit(0); } - if (line.hasOption('v')) - { + if (line.hasOption('v')) { verbose = true; } - - if (line.hasOption('P')) - { + + 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 - { + 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 - { + if (line.hasOption('t')) { //test isTest = true; pr("**Test Run** - not actually updating items."); } - if (line.hasOption('i')) - { + if (line.hasOption('i')) { itemField = line.getOptionValue('i'); } - if (line.hasOption('d')) - { + if (line.hasOption('d')) { String[] targetFields = line.getOptionValues('d'); - DeleteMetadataAction delMetadataAction = (DeleteMetadataAction) iu.actionMgr.getUpdateAction(DeleteMetadataAction.class); + DeleteMetadataAction delMetadataAction = (DeleteMetadataAction) iu.actionMgr + .getUpdateAction(DeleteMetadataAction.class); delMetadataAction.addTargetFields(targetFields); //undo is an add - for (String field : targetFields) - { + for (String field : targetFields) { iu.undoActionList.add(" -a " + field + " "); } pr("Delete metadata for fields: "); - for (String s : targetFields) - { + for (String s : targetFields) { pr(" " + s); } } - if (line.hasOption('a')) - { + if (line.hasOption('a')) { String[] targetFields = line.getOptionValues('a'); - AddMetadataAction addMetadataAction = (AddMetadataAction) iu.actionMgr.getUpdateAction(AddMetadataAction.class); + 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) - { + for (String field : targetFields) { iu.undoActionList.add(" -d " + field + " "); } - for (String field : targetFields) - { + for (String field : targetFields) { iu.undoActionList.add(" -a " + field + " "); } pr("Add metadata for fields: "); - for (String s : targetFields) - { + for (String s : targetFields) { pr(" " + s); } } - if (line.hasOption('D')) // undo not supported - { + if (line.hasOption('D')) { // undo not supported pr("Delete bitstreams "); String[] filterNames = line.getOptionValues('D'); - if ((filterNames != null) && (filterNames.length > 1)) - { + if ((filterNames != null) && (filterNames.length > 1)) { pr("Error: Only one filter can be a used at a time."); System.exit(1); } @@ -258,84 +257,71 @@ public class ItemUpdate { 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); + if (filterName == null) { // indicates using delete_contents files + DeleteBitstreamsAction delAction = (DeleteBitstreamsAction) iu.actionMgr + .getUpdateAction(DeleteBitstreamsAction.class); delAction.setAlterProvenance(alterProvenance); - } - else - { + } else { // check if param is on ALIAS list String filterClassname = filterAliases.get(filterName); - if (filterClassname == null) - { + if (filterClassname == null) { filterClassname = filterName; } BitstreamFilter filter = null; - try - { + 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) - { + 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 - { + if (filterPropertiesName != null) { //not always required + try { // TODO try multiple relative locations, e.g. source dir - if (!filterPropertiesName.startsWith("/")) - { + 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); + } 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); + (DeleteBitstreamsByFilterAction) iu.actionMgr + .getUpdateAction(DeleteBitstreamsByFilterAction.class); delAction.setAlterProvenance(alterProvenance); delAction.setBitstreamFilter(filter); //undo not supported } } - if (line.hasOption('A')) - { + if (line.hasOption('A')) { pr("Add bitstreams "); - AddBitstreamsAction addAction = (AddBitstreamsAction) iu.actionMgr.getUpdateAction(AddBitstreamsAction.class); + 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()) - { + if (!iu.actionMgr.hasActions()) { pr("Error - an action must be specified"); System.exit(1); - } - else - { + } else { pr("Actions to be performed: "); - for (UpdateAction ua : iu.actionMgr) - { + for (UpdateAction ua : iu.actionMgr) { pr(" " + ua.getClass().getName()); } } @@ -346,36 +332,25 @@ public class ItemUpdate { 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/"; - } + HANDLE_PREFIX = handleService.getCanonicalPrefix(); iu.processArchive(context, sourcedir, itemField, metadataIndexName, alterProvenance, isTest); context.complete(); // complete all transactions - } - catch (Exception e) - { - if (context != null && context.isValid()) - { + } catch (Exception e) { + if (context != null && context.isValid()) { context.abort(); } e.printStackTrace(); pr(e.toString()); status = 1; - } - finally { + } finally { context.restoreAuthSystemState(); } - if (isTest) - { + if (isTest) { pr("***End of Test Run***"); - } - else - { + } else { pr("End."); } @@ -385,168 +360,145 @@ public class ItemUpdate { /** * process an archive * - * @param context DSpace Context - * @param sourceDirPath source path - * @param itemField item field + * @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 + * @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 - { + 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()) - { + 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()) - { + if (fSuppressUndo.exists()) { suppressUndo = true; } File undoDir = null; //sibling directory of source archive - - if (!suppressUndo && !isTest) - { + + if (!suppressUndo && !isTest) { undoDir = initUndoArchive(sourceDir); } - + int itemCount = 0; int successItemCount = 0; - for (String dirname : dircontents) - { + for (String dirname : dircontents) { itemCount++; pr(""); pr("processing item " + dirname); - try - { + try { ItemArchive itarch = ItemArchive.create(context, new File(sourceDir, dirname), itemField); - for (UpdateAction action : actionMgr) - { + for (UpdateAction action : actionMgr) { pr("action: " + action.getClass().getName()); action.execute(context, itarch, isTest, suppressUndo); - if (!isTest && !suppressUndo) - { + if (!isTest && !suppressUndo) { itarch.writeUndo(undoDir); } } - if (!isTest) - { + 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()); + context.uncacheEntity(item); + } + ItemUpdate.pr("Item " + dirname + " completed"); + successItemCount++; + } catch (Exception e) { + pr("Exception processing item " + dirname + ": " + e.toString()); e.printStackTrace(); } - } - - if (!suppressUndo && !isTest) - { + } + + 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) - { + if (itemField != null) { sb.append(" -i ").append(itemField); } - if (!alterProvenance) - { + if (!alterProvenance) { sb.append(" -P "); } - if (isTest) - { + if (isTest) { sb.append(" -t "); } - for (String actionOption : undoActionList) - { + for (String actionOption : undoActionList) { sb.append(actionOption); } PrintWriter pw = null; - try - { - File cmdFile = new File (undoDir.getParent(), undoDir.getName() + "_command.sh"); + try { + File cmdFile = new File(undoDir.getParent(), undoDir.getName() + "_command.sh"); pw = new PrintWriter(new BufferedWriter(new FileWriter(cmdFile))); pw.println(sb.toString()); - } - finally - { + } 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 - * + * 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 + * @throws IOException if IO error */ protected File initUndoArchive(File sourceDir) - throws FileNotFoundException, IOException - { + 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"); + 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 + while (undoDir.exists()) { + undoDir = new File(parentDir, "undo_" + sourceDirName + "_" + ++seqNo); //increment } // create root directory - if (!undoDir.mkdir()) - { + 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 - { + try { fSuppressUndo.createNewFile(); - } - catch(IOException e) - { + } catch (IOException e) { pr("ERROR creating Suppress Undo File " + e.toString()); throw e; } @@ -557,40 +509,36 @@ public class ItemUpdate { /** * 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) - { + 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."); } + throw new Exception("EPerson not specified."); + } EPerson myEPerson = null; - if (eperson.indexOf('@') != -1) - { + if (eperson.indexOf('@') != -1) { // @ sign, must be an email myEPerson = epersonService.findByEmail(context, eperson); - } - else - { + } else { myEPerson = epersonService.find(context, UUID.fromString(eperson)); } - if (myEPerson == null) - { + 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 @@ -598,22 +546,20 @@ public class ItemUpdate { * * @param s String */ - static void pr(String s) - { + static void pr(String s) { System.out.println(s); } - + /** - * print if verbose flag is set + * print if verbose flag is set + * * @param s String */ - static void prv(String s) - { - if (verbose) - { + static void prv(String s) { + if (verbose) { System.out.println(s); } } - + } //end of class diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/MetadataUtilities.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/MetadataUtilities.java index c570de9e60..82ed5f75a0 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/MetadataUtilities.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/MetadataUtilities.java @@ -11,14 +11,13 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; -import java.io.InputStream; 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; @@ -31,10 +30,14 @@ import javax.xml.transform.stream.StreamResult; import org.apache.commons.lang.StringUtils; import org.apache.xpath.XPathAPI; - -import org.dspace.content.*; +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; @@ -43,492 +46,420 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import org.dspace.authorize.AuthorizeException; -import org.dspace.core.ConfigurationManager; - /** - * 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 - * + * 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(); - /** - * - * 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 - * @throws SQLException if database error - * @return true if metadata field is found with matching value and was deleted + /** + * Default constructor */ - public static boolean deleteMetadataByValue(Context context, Item item, DtoMetadata dtom, boolean isLanguageStrict) throws SQLException { - List 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 vals = new ArrayList(); - 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) - { + 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 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 vals = new ArrayList(); + 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 - { + } 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; + } + return found; } /** - * Append text to value metadata field to item - * - * @param context DSpace Context - * @param item DSpace Item - * @param dtom metadata field + * 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 + * @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 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 vals = new ArrayList(); - 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()); - } - } + String textToAppend) + throws IllegalArgumentException, SQLException { + List ar = null; - if (isLanguageStrict) - { + // 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 vals = new ArrayList(); + 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 - { + } 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 + * 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 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 + * @throws SAXException if XML error + * @throws TransformerException if transformer error + * @throws AuthorizeException if authorization error */ public static List loadDublinCore(DocumentBuilder docBuilder, InputStream is) - throws SQLException, IOException, ParserConfigurationException, - SAXException, TransformerException, AuthorizeException - { - Document document = docBuilder.parse(is); - - List dtomList = new ArrayList(); - - // 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(); - } + throws SQLException, IOException, ParserConfigurationException, + SAXException, TransformerException, AuthorizeException { + Document document = docBuilder.parse(is); - // 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(); - } + List dtomList = new ArrayList(); - 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; - } + // 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 - * + * Write dublin_core.xml + * * @param docBuilder DocumentBuilder - * @param dtomList List of metadata fields + * @param dtomList List of metadata fields * @return xml document - * @throws ParserConfigurationException if parser config error + * @throws ParserConfigurationException if parser config error * @throws TransformerConfigurationException if transformer config error - * @throws TransformerException if transformer error + * @throws TransformerException if transformer error */ - public static Document writeDublinCore(DocumentBuilder docBuilder, List dtomList) - throws ParserConfigurationException, TransformerConfigurationException, TransformerException - { + public static Document writeDublinCore(DocumentBuilder docBuilder, List 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); + + 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; - } - + + return doc; + } + /** - * write xml document to output stream - * @param doc XML Document + * write xml document to output stream + * + * @param doc XML Document * @param transformer XML Transformer - * @param out OutputStream - * @throws IOException if IO Error + * @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); - } - - - + 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 n Node * @param name name * @return attribute value */ - private static String getAttributeValue(Node n, String name) - { + private static String getAttributeValue(Node n, String name) { NamedNodeMap nm = n.getAttributes(); - for (int i = 0; i < nm.getLength(); i++) - { + for (int i = 0; i < nm.getLength(); i++) { Node node = nm.item(i); - if (name.equals(node.getNodeName())) - { + 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) - { + private static String getStringValue(Node node) { String value = node.getNodeValue(); - if (node.hasChildNodes()) - { + if (node.hasChildNodes()) { Node first = node.getFirstChild(); - if (first.getNodeType() == Node.TEXT_NODE) - { + 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 + * @throws IOException if IO error + * @throws ParseException if parse error */ public static List readContentsFile(File f) - throws FileNotFoundException, IOException, ParseException - { - List 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; - } - ItemUpdate.pr("Contents entry: " + line); - list.add(ContentsEntry.parse(line)); - } - } - finally - { - try - { - in.close(); - } - catch(IOException e) - { - //skip - } - } - - return list; + throws FileNotFoundException, IOException, ParseException { + List 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; + } + 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 + * @throws IOException if IO Error */ public static List readDeleteContentsFile(File f) - throws FileNotFoundException, IOException - { - List 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; - } - + throws FileNotFoundException, IOException { + List 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; + } + } finally { + try { + in.close(); + } catch (IOException e) { + //skip + } + } + + return list; } /** - * Get display of Metadatum - * + * Get display of Metadatum + * * @param dcv MetadataValue * @return string displaying elements of the Metadatum */ - public static String getDCValueString(MetadataValue dcv) - { + 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 "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 .[.|.*]} - * 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; - } - -} + /** + * 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 .[.|.*]} + * 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; + } + +} diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/OriginalBitstreamFilter.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/OriginalBitstreamFilter.java index c865bfb511..991859d927 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/OriginalBitstreamFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/OriginalBitstreamFilter.java @@ -13,45 +13,37 @@ 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 +/** + * 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 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 bundles = bitstream.getBundles(); - for (Bundle bundle : bundles) - { - if (bundle.getName().equals("ORIGINAL")) - { - return true; - } - } - } - catch(SQLException e) - { - throw new BitstreamFilterException(e); - } - return false; - } + throws BitstreamFilterException { + try { + List bundles = bitstream.getBundles(); + for (Bundle bundle : bundles) { + if (bundle.getName().equals("ORIGINAL")) { + return true; + } + } + } catch (SQLException e) { + throw new BitstreamFilterException(e); + } + return false; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/OriginalWithDerivativesBitstreamFilter.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/OriginalWithDerivativesBitstreamFilter.java index 068a5a5e72..ec315ae15f 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/OriginalWithDerivativesBitstreamFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/OriginalWithDerivativesBitstreamFilter.java @@ -13,50 +13,41 @@ 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 +/** + * 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 - * @throws BitstreamFilterException if error - * @return true if bitstream is in specified bundles - */ - @Override +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 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; - } + throws BitstreamFilterException { + try { + List 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; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/ThumbnailBitstreamFilter.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/ThumbnailBitstreamFilter.java index fe5c1a6d05..2a8f9ac200 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/ThumbnailBitstreamFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/ThumbnailBitstreamFilter.java @@ -10,15 +10,13 @@ package org.dspace.app.itemupdate; import java.util.Properties; /** - * Bitstream filter targetting the THUMBNAIL bundle - * + * Bitstream filter targetting the THUMBNAIL bundle */ public class ThumbnailBitstreamFilter extends BitstreamFilterByBundleName { - - public ThumbnailBitstreamFilter() - { - props = new Properties(); - props.setProperty("bundle", "THUMBNAIL"); - } + + public ThumbnailBitstreamFilter() { + props = new Properties(); + props.setProperty("bundle", "THUMBNAIL"); + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateAction.java index 4fccfba1b7..e084ae6f24 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateAction.java @@ -12,24 +12,22 @@ import org.dspace.content.service.ItemService; import org.dspace.core.Context; /** - * Interface for actions to update an item - * + * Interface for actions to update an item */ -public interface UpdateAction -{ +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; - + /** + * 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; + } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateBitstreamsAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateBitstreamsAction.java index 7acd7d06bd..cd86e529a5 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateBitstreamsAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateBitstreamsAction.java @@ -12,36 +12,32 @@ import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; /** - * Base class for Bitstream actions - * - * + * Base class for Bitstream actions */ public abstract class UpdateBitstreamsAction implements UpdateAction { - protected boolean alterProvenance = true; + 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; - } + /** + * 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; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateMetadataAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateMetadataAction.java index 284a9cefb2..4c93de1af0 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateMetadataAction.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/UpdateMetadataAction.java @@ -11,60 +11,57 @@ 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 ..} ) - * on which to apply the action when the method execute is called. - * - * Implemented as a Set to avoid problems with duplicates - * + * This abstract subclass for metadata actions + * maintains a collection for the target metadata fields + * expressed as a string in the compound notation ( {@code ..} ) + * 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 targetFields = new HashSet(); - + protected Set targetFields = new HashSet(); + /** - * Get target fields - * + * Get target fields + * * @return set of fields to update */ - public Set getTargetFields() { - return targetFields; - } + public Set getTargetFields() { + return targetFields; + } - /** - * Set target fields - * - * @param targetFields Set of target fields to update - */ - public void addTargetFields(Set targetFields) { - for (String tf : targetFields) - { - this.targetFields.add(tf); - } - - } + /** + * Set target fields + * + * @param targetFields Set of target fields to update + */ + public void addTargetFields(Set 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); - } + /** + * 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); + } } diff --git a/dspace-api/src/main/java/org/dspace/app/launcher/CommandRunner.java b/dspace-api/src/main/java/org/dspace/app/launcher/CommandRunner.java index 33b21e5c61..ce33b6655b 100644 --- a/dspace-api/src/main/java/org/dspace/app/launcher/CommandRunner.java +++ b/dspace-api/src/main/java/org/dspace/app/launcher/CommandRunner.java @@ -15,29 +15,29 @@ 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 -{ +public class CommandRunner { + + /** + * Default constructor + */ + private CommandRunner() { } + /** - * * @param args the command line arguments given - * @throws IOException if IO error + * @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) - { + throws FileNotFoundException, IOException { + if (args.length > 0) { runManyCommands(args[0]); - } - else - { + } else { runManyCommands("-"); } // There is no sensible way to use the status returned by runManyCommands(). @@ -54,19 +54,15 @@ public class CommandRunner * * @param script the file of command lines to be executed. * @return status code - * @throws IOException if IO error + * @throws IOException if IO error * @throws FileNotFoundException if file doesn't exist */ static int runManyCommands(String script) - throws FileNotFoundException, IOException - { + throws FileNotFoundException, IOException { Reader input; - if ("-".equals(script)) - { + if ("-".equals(script)) { input = new InputStreamReader(System.in); - } - else - { + } else { input = new FileReader(script); } @@ -89,22 +85,16 @@ public class CommandRunner int status = 0; List tokens = new ArrayList(); Document commandConfigs = ScriptLauncher.getConfig(); - while (StreamTokenizer.TT_EOF != tokenizer.nextToken()) - { - if (StreamTokenizer.TT_EOL == tokenizer.ttype) - { - if (tokens.size() > 0) - { + 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) - { + if (status > 0) { break; } tokens.clear(); } - } - else - { + } else { tokens.add(tokenizer.sval); } } diff --git a/dspace-api/src/main/java/org/dspace/app/launcher/ScriptLauncher.java b/dspace-api/src/main/java/org/dspace/app/launcher/ScriptLauncher.java index eeec55d1c5..435c28bcb9 100644 --- a/dspace-api/src/main/java/org/dspace/app/launcher/ScriptLauncher.java +++ b/dspace-api/src/main/java/org/dspace/app/launcher/ScriptLauncher.java @@ -12,6 +12,7 @@ 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; @@ -25,38 +26,37 @@ import org.jdom.input.SAXBuilder; * @author Stuart Lewis * @author Mark Diggory */ -public class ScriptLauncher -{ - /** The service manager kernel */ +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 IOException if IO error * @throws FileNotFoundException if file doesn't exist */ public static void main(String[] args) - throws FileNotFoundException, IOException - { + throws FileNotFoundException, IOException { // Initialise the service manager kernel - try - { + try { kernelImpl = DSpaceKernelInit.getKernel(null); - if (!kernelImpl.isRunning()) - { + if (!kernelImpl.isRunning()) { kernelImpl.start(); } - } catch (Exception e) - { + } catch (Exception e) { // Failed to start so destroy it and log and throw an exception - try - { + try { kernelImpl.destroy(); - } - catch (Exception e1) - { + } catch (Exception e1) { // Nothing to do } String message = "Failure during kernel init: " + e.getMessage(); @@ -69,8 +69,7 @@ public class ScriptLauncher Document commandConfigs = getConfig(); // Check that there is at least one argument (if not display command options) - if (args.length < 1) - { + if (args.length < 1) { System.err.println("You must provide at least one command argument"); display(commandConfigs); System.exit(1); @@ -81,8 +80,7 @@ public class ScriptLauncher status = runOneCommand(commandConfigs, args); // Destroy the service kernel if it is still alive - if (kernelImpl != null) - { + if (kernelImpl != null) { kernelImpl.destroy(); kernelImpl = null; } @@ -90,29 +88,29 @@ public class ScriptLauncher System.exit(status); } + protected static int runOneCommand(Document commandConfigs, String[] args) { + return runOneCommand(commandConfigs, args, kernelImpl); + } + /** * Recognize and execute a single command. * - * @param doc Document + * @param commandConfigs Document * @param args the command line arguments given */ - static int runOneCommand(Document commandConfigs, String[] args) - { + public static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) { String request = args[0]; Element root = commandConfigs.getRootElement(); List commands = root.getChildren("command"); Element command = null; - for (Element candidate : commands) - { - if (request.equalsIgnoreCase(candidate.getChild("name").getValue())) - { + for (Element candidate : commands) { + if (request.equalsIgnoreCase(candidate.getChild("name").getValue())) { command = candidate; break; } } - if (null == command) - { + if (null == command) { // The command wasn't found System.err.println("Command not found: " + args[0]); display(commandConfigs); @@ -121,33 +119,26 @@ public class ScriptLauncher // Run each step List steps = command.getChildren("step"); - for (Element step : steps) - { + 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) - { + if ("dsrun".equals(request)) { + if (args.length < 2) { System.err.println("Error in launcher.xml: Missing class name"); return 1; } className = args[1]; - } - else { + } else { className = step.getChild("class").getValue(); } - try - { + try { target = Class.forName(className, true, Thread.currentThread().getContextClassLoader()); - } - catch (ClassNotFoundException e) - { + } catch (ClassNotFoundException e) { System.err.println("Error in launcher.xml: Invalid class name: " + className); return 1; } @@ -158,26 +149,20 @@ public class ScriptLauncher Class[] argTypes = {useargs.getClass()}; boolean passargs = true; if ((step.getAttribute("passuserargs") != null) && - ("false".equalsIgnoreCase(step.getAttribute("passuserargs").getValue()))) - { + ("false".equalsIgnoreCase(step.getAttribute("passuserargs").getValue()))) { passargs = false; } - if ((args.length == 1) || (("dsrun".equals(request)) && (args.length == 2)) || (!passargs)) - { + if ((args.length == 1) || (("dsrun".equals(request)) && (args.length == 2)) || (!passargs)) { useargs = new String[0]; - } - else - { + } 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)) - { + if ("dsrun".equals(request)) { x = 2; } String[] argsnew = new String[useargs.length - x]; - for (int i = x; i < useargs.length; i++) - { + for (int i = x; i < useargs.length; i++) { argsnew[i - x] = useargs[i]; } useargs = argsnew; @@ -185,16 +170,13 @@ public class ScriptLauncher // Add any extra properties List bits = step.getChildren("argument"); - if (step.getChild("argument") != null) - { + if (step.getChild("argument") != null) { String[] argsnew = new String[useargs.length + bits.size()]; int i = 0; - for (Element arg : bits) - { + for (Element arg : bits) { argsnew[i++] = arg.getValue(); } - for (; i < bits.size() + useargs.length; i++) - { + for (; i < bits.size() + useargs.length; i++) { argsnew[i] = useargs[i - bits.size()]; } useargs = argsnew; @@ -202,11 +184,10 @@ public class ScriptLauncher // Establish the request service startup RequestService requestService = kernelImpl.getServiceManager().getServiceByName( - RequestService.class.getName(), RequestService.class); - if (requestService == null) - { + RequestService.class.getName(), RequestService.class); + if (requestService == null) { throw new IllegalStateException( - "Could not get the DSpace RequestService to start the request transaction"); + "Could not get the DSpace RequestService to start the request transaction"); } // Establish a request related to the current session @@ -214,26 +195,23 @@ public class ScriptLauncher requestService.startRequest(); // Run the main() method - try - { + 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("");**/ + 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) - { + } catch (Exception e) { // Failure occurred in the request so we destroy it requestService.endRequest(e); @@ -254,20 +232,20 @@ public class ScriptLauncher * * @return The XML configuration file Document */ - protected static Document getConfig() - { + 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"; + System.getProperty("file.separator") + "config" + + System.getProperty("file.separator") + "launcher.xml"; SAXBuilder saxBuilder = new SAXBuilder(); Document doc = null; - try - { + try { doc = saxBuilder.build(config); - } - catch (Exception e) - { + } catch (Exception e) { System.err.println("Unable to load the launcher configuration file: [dspace]/config/launcher.xml"); System.err.println(e.getMessage()); e.printStackTrace(); @@ -278,10 +256,10 @@ public class ScriptLauncher /** * Display the commands that the current launcher config file knows about + * * @param commandConfigs configs as Document */ - private static void display(Document commandConfigs) - { + private static void display(Document commandConfigs) { // List all command elements List commands = commandConfigs.getRootElement().getChildren("command"); @@ -289,17 +267,15 @@ public class ScriptLauncher // We cannot just use commands.sort() because it tries to remove and // reinsert Elements within other Elements, and that doesn't work. TreeMap sortedCommands = new TreeMap<>(); - for (Element command : commands) - { + 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()) - { + for (Element command : sortedCommands.values()) { System.out.println(" - " + command.getChild("name").getValue() + - ": " + command.getChild("description").getValue()); + ": " + command.getChild("description").getValue()); } } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/Brand.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/Brand.java index d5658eb8d7..2d963dd3da 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/Brand.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/Brand.java @@ -7,12 +7,12 @@ */ package org.dspace.app.mediafilter; -import java.awt.image.BufferedImage; 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. @@ -20,143 +20,117 @@ import java.awt.Rectangle; * 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; +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; - } + /** + * 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. null 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; + /** + * 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. null 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); + 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 (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]); - } - } + if (allBrandText != null && allBrandText.length > 0) { + for (int i = 0; i < allBrandText.length; ++i) { + drawImage(brandImage, allBrandText[i]); + } + } - return brandImage; - } + 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(); + /** + * 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(); - int bx, by, tx, ty, bWidth, bHeight; + Graphics2D g2 = brandImage.createGraphics(); + g2.setFont(font); + FontMetrics fm = g2.getFontMetrics(); - 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; - bWidth = fm.stringWidth(brandText.getText()) + xOffset * 2 + 1; - bHeight = fm.getHeight(); + 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; + } - bx = 0; - by = 0; + Rectangle box = new Rectangle(bx, by, bWidth, bHeight); + int tx = bx + xOffset; + int ty = by + fm.getAscent(); - 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); - tx = bx + xOffset; - ty = by + fm.getAscent(); - - g2.setColor(Color.black); - g2.fill(box); - g2.setColor(Color.white); - g2.drawString(brandText.getText(), tx, ty); - } + g2.setColor(Color.black); + g2.fill(box); + g2.setColor(Color.white); + g2.drawString(brandText.getText(), tx, ty); + } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/BrandText.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/BrandText.java index 5085a7a19c..ae77f6048b 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/BrandText.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/BrandText.java @@ -13,73 +13,75 @@ package org.dspace.app.mediafilter; * 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"; +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; + 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. Identifier.BL - * @param the text associated with the location - */ - public BrandText(String location, String text) - { - this.location = location; - this.text = 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. Identifier.BL + * @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. Identifier.BL - */ - public String getLocation() - { - return location; - } + /** + * get the location the text of the Identifier object is associated with + * + * @return String one the class location constants e.g. Identifier.BL + */ + 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; - } + /** + * 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 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; - } + /** + * 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; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/BrandedPreviewJPEGFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/BrandedPreviewJPEGFilter.java index fc0b8c9e26..dadd8f2a92 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/BrandedPreviewJPEGFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/BrandedPreviewJPEGFilter.java @@ -7,16 +7,13 @@ */ package org.dspace.app.mediafilter; -import java.awt.image.*; +import java.awt.image.BufferedImage; import java.io.InputStream; - import javax.imageio.ImageIO; import org.dspace.content.Item; import org.dspace.core.ConfigurationManager; -import org.dspace.app.mediafilter.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 @@ -24,21 +21,17 @@ import org.dspace.app.mediafilter.JPEGFilter; * * @author Jason Sherman jsherman@usao.edu */ -public class BrandedPreviewJPEGFilter extends MediaFilter -{ +public class BrandedPreviewJPEGFilter extends MediaFilter { @Override - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".preview.jpg"; } /** * @return String bundle name - * */ @Override - public String getBundleName() - { + public String getBundleName() { return "BRANDED_PREVIEW"; } @@ -46,8 +39,7 @@ public class BrandedPreviewJPEGFilter extends MediaFilter * @return String bitstreamformat */ @Override - public String getFormatString() - { + public String getFormatString() { return "JPEG"; } @@ -55,42 +47,40 @@ public class BrandedPreviewJPEGFilter extends MediaFilter * @return String description */ @Override - public String getDescription() - { + public String getDescription() { return "Generated Branded Preview"; } - + /** * @param currentItem item - * @param source - * source input stream - * @param verbose verbose mode - * + * @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 - { + throws Exception { // read in bitstream's image BufferedImage buf = ImageIO.read(source); // get config params float xmax = (float) ConfigurationManager - .getIntProperty("webui.preview.maxwidth"); + .getIntProperty("webui.preview.maxwidth"); float ymax = (float) ConfigurationManager - .getIntProperty("webui.preview.maxheight"); + .getIntProperty("webui.preview.maxheight"); boolean blurring = (boolean) ConfigurationManager - .getBooleanProperty("webui.preview.blurring"); + .getBooleanProperty("webui.preview.blurring"); boolean hqscaling = (boolean) ConfigurationManager - .getBooleanProperty("webui.preview.hqscaling"); + .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); + return jpegFilter + .getThumbDim(currentItem, buf, verbose, xmax, ymax, blurring, hqscaling, brandHeight, brandFontPoint, + brandFont); } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/ExcelFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/ExcelFilter.java index 05b9049aa1..28db4cea8a 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/ExcelFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/ExcelFilter.java @@ -11,12 +11,11 @@ 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.apache.log4j.Logger; import org.dspace.content.Item; /* @@ -35,79 +34,62 @@ import org.dspace.content.Item; * filter.org.dspace.app.mediafilter.ExcelFilter.inputFormats = Microsoft Excel, Microsoft Excel XML * */ -public class ExcelFilter extends MediaFilter -{ +public class ExcelFilter extends MediaFilter { private static Logger log = Logger.getLogger(ExcelFilter.class); - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".txt"; } /** * @return String bundle name - * */ - public String getBundleName() - { + public String getBundleName() { return "TEXT"; } /** * @return String bitstream format - * - * */ - public String getFormatString() - { + public String getFormatString() { return "Text"; } /** * @return String description */ - public String getDescription() - { + public String getDescription() { return "Extracted text"; } /** - * @param item item - * @param source source input stream + * @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 - { + throws Exception { String extractedText = null; - try - { + try { POITextExtractor theExtractor = ExtractorFactory.createExtractor(source); - if (theExtractor instanceof ExcelExtractor) - { + if (theExtractor instanceof ExcelExtractor) { // for xls file extractedText = (theExtractor).getText(); - } - else if (theExtractor instanceof XSSFExcelExtractor) - { + } else if (theExtractor instanceof XSSFExcelExtractor) { // for xlsx file extractedText = (theExtractor).getText(); } - } - catch (Exception e) - { + } catch (Exception e) { log.error("Error filtering bitstream: " + e.getMessage(), e); throw e; } - if (extractedText != null) - { + if (extractedText != null) { // generate an input stream with the extracted text return IOUtils.toInputStream(extractedText, StandardCharsets.UTF_8); } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/FormatFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/FormatFilter.java index 852a0c1070..eb44d2e343 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/FormatFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/FormatFilter.java @@ -14,76 +14,70 @@ import org.dspace.content.Item; import org.dspace.core.Context; /** - * Public interface for any class which transforms or converts content/bitstreams + * 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 -{ +public interface FormatFilter { /** * Get a filename for a newly created filtered bitstream - * - * @param sourceName - * name of source bitstream + * + * @param sourceName name of source bitstream * @return filename generated by the filter - for example, document.pdf - * becomes document.pdf.txt + * becomes document.pdf.txt */ public String getFilteredName(String sourceName); /** * @return name of the bundle this filter will stick its generated - * Bitstreams + * 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. + * 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 + * 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 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; + throws Exception; /** - * Perform any pre-processing of the source bitstream *before* the actual + * Perform any pre-processing of the source bitstream *before* the actual * filtering takes place in MediaFilterManager.processBitstream(). *

* 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 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 + * @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; - + throws Exception; + /** * Perform any post-processing of the generated bitstream *after* this * filter has already been run. @@ -91,18 +85,14 @@ public interface FormatFilter * 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. + * + * @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; + throws Exception; } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/HTMLFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/HTMLFilter.java index 0a1c016a2c..1b982cb277 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/HTMLFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/HTMLFilter.java @@ -7,36 +7,31 @@ */ package org.dspace.app.mediafilter; -import org.dspace.content.Item; - 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 -{ +public class HTMLFilter extends MediaFilter { @Override - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".txt"; } /** * @return String bundle name - * */ @Override - public String getBundleName() - { + public String getBundleName() { return "TEXT"; } @@ -44,8 +39,7 @@ public class HTMLFilter extends MediaFilter * @return String bitstreamformat */ @Override - public String getFormatString() - { + public String getFormatString() { return "Text"; } @@ -53,23 +47,20 @@ public class HTMLFilter extends MediaFilter * @return String description */ @Override - public String getDescription() - { + public String getDescription() { return "Extracted text"; } /** * @param currentItem item - * @param source source input stream - * @param verbose verbose mode - * + * @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 - { + 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(); diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickImageThumbnailFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickImageThumbnailFilter.java index 8959058acb..b5143d68da 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickImageThumbnailFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickImageThumbnailFilter.java @@ -7,53 +7,46 @@ */ package org.dspace.app.mediafilter; -import org.dspace.content.Item; - 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 -{ +public class ImageMagickImageThumbnailFilter extends ImageMagickThumbnailFilter { /** * @param currentItem item - * @param source source input stream - * @param verbose verbose mode - * + * @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(); - } - } - } + 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(); + } + } + } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickPdfThumbnailFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickPdfThumbnailFilter.java index ff00e29c09..467303c3ca 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickPdfThumbnailFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickPdfThumbnailFilter.java @@ -7,43 +7,37 @@ */ package org.dspace.app.mediafilter; -import org.dspace.content.Item; - 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(); - } - } + @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(); + } + } } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickThumbnailFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickThumbnailFilter.java index 2f5fe2c13b..27413544b9 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickThumbnailFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickThumbnailFilter.java @@ -14,78 +14,70 @@ import java.io.InputStream; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import javax.imageio.ImageIO; - 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.Info; import org.im4java.core.IM4JavaException; import org.im4java.core.IMOperation; +import org.im4java.core.Info; import org.im4java.process.ProcessStarter; -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. */ -public abstract class ImageMagickThumbnailFilter extends MediaFilter -{ - protected static int width = 180; +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); + 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() { - } - - + 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) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".jpg"; } /** * @return String bundle name - * */ @Override - public String getBundleName() - { + public String getBundleName() { return "THUMBNAIL"; } @@ -93,8 +85,7 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter * @return String bitstreamformat */ @Override - public String getFormatString() - { + public String getFormatString() { return "JPEG"; } @@ -102,103 +93,110 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter * @return String bitstreamDescription */ @Override - public String getDescription() - { + 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.addImage(f.getAbsolutePath()); - op.thumbnail(width, height); - op.addImage(f2.getAbsolutePath()); - if (verbose) { - System.out.println("IM Thumbnail Param: "+op); + 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); } - cmd.run(op); - return f2; + fos.close(); + return f; } - - 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(); - Info imageInfo = new Info(f.getAbsolutePath(),true); - String s = "[" + page + "]"; - op.addImage(f.getAbsolutePath()+s); - if (flatten) - { - op.flatten(); - } - String imageClass = imageInfo.getImageClass(); - // PDFs using the CMYK color system can be handled specially if profiles are defined - if (imageClass.contains("CMYK") && cmyk_profile != null && srgb_profile != null) { - op.profile(cmyk_profile); - op.profile(srgb_profile); - } - op.addImage(f2.getAbsolutePath()); + + 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 Image Param: "+op); + System.out.println("IM Thumbnail Param: " + op); } - cmd.run(op); - return f2; + 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() + s, 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()) { + 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 + 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 } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/JPEGFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/JPEGFilter.java index b4e409c261..67a266ea26 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/JPEGFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/JPEGFilter.java @@ -7,16 +7,18 @@ */ package org.dspace.app.mediafilter; -import java.awt.Graphics2D; import java.awt.Color; -import java.awt.image.*; +import java.awt.Font; +import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Transparency; -import java.awt.Font; +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; @@ -29,21 +31,17 @@ import org.dspace.core.ConfigurationManager; * * @author Jason Sherman jsherman@usao.edu */ -public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats -{ +public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats { @Override - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".jpg"; } /** * @return String bundle name - * */ @Override - public String getBundleName() - { + public String getBundleName() { return "THUMBNAIL"; } @@ -51,8 +49,7 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats * @return String bitstreamformat */ @Override - public String getFormatString() - { + public String getFormatString() { return "JPEG"; } @@ -60,23 +57,20 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats * @return String description */ @Override - public String getDescription() - { + public String getDescription() { return "Generated Thumbnail"; } /** * @param currentItem item - * @param source source input stream - * @param verbose verbose mode - * + * @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 - { + throws Exception { // read in bitstream's image BufferedImage buf = ImageIO.read(source); @@ -84,45 +78,42 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats } public InputStream getThumb(Item currentItem, BufferedImage buf, boolean verbose) - throws Exception - { + throws Exception { // get config params float xmax = (float) ConfigurationManager - .getIntProperty("thumbnail.maxwidth"); + .getIntProperty("thumbnail.maxwidth"); float ymax = (float) ConfigurationManager - .getIntProperty("thumbnail.maxheight"); + .getIntProperty("thumbnail.maxheight"); boolean blurring = (boolean) ConfigurationManager - .getBooleanProperty("thumbnail.blurring"); + .getBooleanProperty("thumbnail.blurring"); boolean hqscaling = (boolean) ConfigurationManager - .getBooleanProperty("thumbnail.hqscaling"); + .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 - { + 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) - { + if (verbose) { System.out.println("original size: " + xsize + "," + ysize); } // scale by x first if needed - if (xsize > xmax) - { + 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) - { + if (verbose) { System.out.println("x scale factor: " + scale_factor); } @@ -133,15 +124,13 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats // if verbose flag is set, print out extracted text // to STDOUT - if (verbose) - { + if (verbose) { System.out.println("size after fitting to maximum width: " + xsize + "," + ysize); } } // scale by y if needed - if (ysize > ymax) - { + if (ysize > ymax) { float scale_factor = ymax / ysize; // now reduce x size @@ -151,31 +140,28 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats } // if verbose flag is set, print details to STDOUT - if (verbose) - { + if (verbose) { System.out.println("size after fitting to maximum height: " + xsize + ", " - + ysize); + + 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); + 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); + 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); + 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 @@ -188,7 +174,7 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats ConfigurationManager.getProperty("webui.preview.brand.abbrev"), currentItem == null ? "" : "hdl:" + currentItem.getHandle()); - g2d.drawImage(brandImage, (int)0, (int)ysize, (int) xsize, (int) 20, null); + g2d.drawImage(brandImage, (int) 0, (int) ysize, (int) xsize, (int) 20, null); } // now create an input stream for the thumbnail buffer and return it @@ -204,37 +190,32 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats @Override - public String[] getInputMIMETypes() - { + public String[] getInputMIMETypes() { return ImageIO.getReaderMIMETypes(); } @Override - public String[] getInputDescriptions() - { + public String[] getInputDescriptions() { return null; } @Override - public String[] getInputExtensions() - { + 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) ? + public BufferedImage getNormalizedInstance(BufferedImage buf) { + int type = (buf.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB_PRE; - int w, h; - w = buf.getWidth(); - 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; + 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; } /** @@ -244,55 +225,54 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats * @param buf buffered image * @return updated BufferedImage */ - public BufferedImage getBlurredInstance(BufferedImage buf) - { - buf = getNormalizedInstance(buf); + 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, - }; + // 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; + // 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 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) + * 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) - { + boolean higherQuality) { int type = (buf.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; - BufferedImage scalebuf = (BufferedImage)buf; - int w, h; + 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() diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilter.java index f8ecf67e21..da949624cf 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilter.java @@ -13,38 +13,34 @@ 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 + * 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 +public abstract class MediaFilter implements FormatFilter { + /** + * Perform any pre-processing of the source bitstream *before* the actual * filtering takes place in MediaFilterManager.processBitstream(). *

* 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 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 + * @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 - { + throws Exception { return true; //default to no pre-processing } - + /** * Perform any post-processing of the generated bitstream *after* this * filter has already been run. @@ -52,21 +48,16 @@ public abstract class MediaFilter implements FormatFilter * 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. + * + * @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 - { + throws Exception { //default to no post-processing necessary } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterCLITool.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterCLITool.java index 1300435cc9..fb9a120aa3 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterCLITool.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterCLITool.java @@ -7,7 +7,22 @@ */ package org.dspace.app.mediafilter; -import org.apache.commons.cli.*; +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; @@ -19,9 +34,6 @@ import org.dspace.core.Context; import org.dspace.core.SelfNamedPlugin; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.handle.factory.HandleServiceFactory; - -import java.util.*; -import org.apache.commons.lang.ArrayUtils; import org.dspace.services.factory.DSpaceServicesFactory; /** @@ -44,8 +56,12 @@ public class MediaFilterCLITool { //suffix (in dspace.cfg) for input formats supported by each filter private static final String INPUT_FORMATS_SUFFIX = "inputFormats"; - public static void main(String[] argv) throws Exception - { + /** + * Default constructor + */ + private MediaFilterCLITool() { } + + public static void main(String[] argv) throws Exception { // set headless for non-gui workstations System.setProperty("java.awt.headless", "true"); @@ -57,25 +73,25 @@ public class MediaFilterCLITool { Options options = new Options(); options.addOption("v", "verbose", false, - "print all extracted text and other details to STDOUT"); + "print all extracted text and other details to STDOUT"); options.addOption("q", "quiet", false, - "do not print anything except in the event of errors."); + "do not print anything except in the event of errors."); options.addOption("f", "force", false, - "force all bitstreams to be processed"); + "force all bitstreams to be processed"); options.addOption("i", "identifier", true, - "ONLY process bitstreams belonging to identifier"); + "ONLY process bitstreams belonging to identifier"); options.addOption("m", "maximum", true, - "process no more than maximum items"); + "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\")"); + "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); @@ -84,9 +100,9 @@ public class MediaFilterCLITool { 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)"); + "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); @@ -99,73 +115,61 @@ public class MediaFilterCLITool { Map> filterFormats = new HashMap<>(); CommandLine line = null; - try - { + try { line = parser.parse(options, argv); - } - catch(MissingArgumentException e) - { + } 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')) - { + if (line.hasOption('h')) { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("MediaFilterManager\n", options); System.exit(0); } - if (line.hasOption('v')) - { + if (line.hasOption('v')) { isVerbose = true; } isQuiet = line.hasOption('q'); - if (line.hasOption('f')) - { + if (line.hasOption('f')) { isForce = true; } - if (line.hasOption('i')) - { + if (line.hasOption('i')) { identifier = line.getOptionValue('i'); } - if (line.hasOption('m')) - { + if (line.hasOption('m')) { max2Process = Integer.parseInt(line.getOptionValue('m')); - if (max2Process <= 1) - { + if (max2Process <= 1) { System.out.println("Invalid maximum value '" + - line.getOptionValue('m') + "' - ignoring"); + line.getOptionValue('m') + "' - ignoring"); max2Process = Integer.MAX_VALUE; } } String filterNames[] = null; - if(line.hasOption('p')) - { + 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 + 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"); + "(e.g. MediaFilterManager -p \"Word Text Extractor\",\"PDF Text Extractor\")\n"); HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("MediaFilterManager\n", options); System.exit(1); } - } - else - { + } else { //retrieve list of all enabled media filter plugins! - filterNames = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty(MEDIA_FILTER_PLUGINS_KEY); + filterNames = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty(MEDIA_FILTER_PLUGINS_KEY); } MediaFilterService mediaFilterService = MediaFilterServiceFactory.getInstance().getMediaFilterService(); @@ -178,17 +182,16 @@ public class MediaFilterCLITool { List filterList = new ArrayList(); //set up each filter - for(int i=0; i< filterNames.length; i++) - { + 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] + "'"); + 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 - { + } else { filterList.add(filter); String filterClassName = filter.getClass().getName(); @@ -200,8 +203,7 @@ public class MediaFilterCLITool { //each "named" plugin that it defines. //So, we have to look for every key that fits the //following format: filter...inputFormats - if( SelfNamedPlugin.class.isAssignableFrom(filter.getClass()) ) - { + if (SelfNamedPlugin.class.isAssignableFrom(filter.getClass())) { //Get the plugin instance name for this class pluginName = ((SelfNamedPlugin) filter).getPluginInstanceName(); } @@ -212,45 +214,42 @@ public class MediaFilterCLITool { // filter...inputFormats //For other MediaFilters, format of key is: // filter..inputFormats - String[] formats = - DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty( + String[] formats = + DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty( FILTER_PREFIX + "." + filterClassName + - (pluginName!=null ? "." + pluginName : "") + - "." + INPUT_FORMATS_SUFFIX); + (pluginName != null ? "." + pluginName : "") + + "." + INPUT_FORMATS_SUFFIX); //add to internal map of filters to supported formats - if (ArrayUtils.isNotEmpty(formats)) - { + if (ArrayUtils.isNotEmpty(formats)) { //For SelfNamedPlugins, map key is: // //For other MediaFilters, map key is just: // filterFormats.put(filterClassName + - (pluginName!=null ? MediaFilterService.FILTER_PLUGIN_SEPARATOR + pluginName : ""), - Arrays.asList(formats)); + (pluginName != null ? MediaFilterService.FILTER_PLUGIN_SEPARATOR + + pluginName : ""), + Arrays.asList(formats)); } - }//end if filter!=null - }//end for + } //end if filter!=null + } //end for //If verbose, print out loaded mediafilter info - if(isVerbose) - { + if (isVerbose) { System.out.println("The following MediaFilters are enabled: "); Iterator i = filterFormats.keySet().iterator(); - while(i.hasNext()) - { + while (i.hasNext()) { String filterName = i.next(); System.out.println("Full Filter Name: " + filterName); String pluginName = null; - if(filterName.contains(MediaFilterService.FILTER_PLUGIN_SEPARATOR)) - { + if (filterName.contains(MediaFilterService.FILTER_PLUGIN_SEPARATOR)) { String[] fields = filterName.split(MediaFilterService.FILTER_PLUGIN_SEPARATOR); - filterName=fields[0]; - pluginName=fields[1]; + filterName = fields[0]; + pluginName = fields[1]; } System.out.println(filterName + - (pluginName!=null? " (Plugin: " + pluginName + ")": "")); + (pluginName != null ? " (Plugin: " + pluginName + ")" : "")); } } @@ -261,16 +260,14 @@ public class MediaFilterCLITool { //Retrieve list of identifiers to skip (if any) String skipIds[] = null; - if(line.hasOption('s')) - { + 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 + 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"); + "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); @@ -282,29 +279,24 @@ public class MediaFilterCLITool { Context c = null; - try - { + try { c = new Context(); // have to be super-user to do the filtering c.turnOffAuthorisationSystem(); // now apply the filters - if (identifier == null) - { + if (identifier == null) { mediaFilterService.applyFiltersAllItems(c); - } - else // restrict application scope to identifier - { + } else { + // restrict application scope to identifier DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(c, identifier); - if (dso == null) - { + if (dso == null) { throw new IllegalArgumentException("Cannot resolve " - + identifier + " to a DSpace object"); + + identifier + " to a DSpace object"); } - switch (dso.getType()) - { + switch (dso.getType()) { case Constants.COMMUNITY: mediaFilterService.applyFiltersCommunity(c, (Community) dso); break; @@ -314,20 +306,17 @@ public class MediaFilterCLITool { case Constants.ITEM: mediaFilterService.applyFiltersItem(c, (Item) dso); break; + default: + break; } } c.complete(); c = null; - } - catch (Exception e) - { + } catch (Exception e) { status = 1; - } - finally - { - if (c != null) - { + } finally { + if (c != null) { c.abort(); } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterServiceImpl.java index 403b232ff4..eb5eaaa255 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterServiceImpl.java @@ -7,11 +7,28 @@ */ 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.*; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; import org.dspace.content.Collection; -import org.dspace.content.service.*; +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; @@ -21,20 +38,16 @@ import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import java.io.InputStream; -import java.util.*; - /** * 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 + * 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 -{ +public class MediaFilterServiceImpl implements MediaFilterService, InitializingBean { @Autowired(required = true) protected AuthorizeService authorizeService; @Autowired(required = true) @@ -55,13 +68,13 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB 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 filterClasses = null; - + protected Map> filterFormats = new HashMap<>(); protected List skipList = null; //list of identifiers to skip during processing @@ -72,27 +85,25 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB protected boolean isQuiet = false; protected boolean isForce = false; // default to not forced - protected MediaFilterServiceImpl() - { + protected MediaFilterServiceImpl() { } @Override public void afterPropertiesSet() throws Exception { - String[] publicPermissionFilters = configurationService.getArrayProperty("filter.org.dspace.app.mediafilter.publicPermission"); + String[] publicPermissionFilters = configurationService + .getArrayProperty("filter.org.dspace.app.mediafilter.publicPermission"); - if(publicPermissionFilters != null) { - for(String filter : publicPermissionFilters) { + if (publicPermissionFilters != null) { + for (String filter : publicPermissionFilters) { publicFiltersClasses.add(filter.trim()); } } } @Override - public void applyFiltersAllItems(Context context) throws Exception - { - if(skipList!=null) - { + 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 topLevelCommunities = communityService.findAllTop(context); @@ -100,13 +111,10 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB for (Community topLevelCommunity : topLevelCommunities) { applyFiltersCommunity(context, topLevelCommunity); } - } - else - { + } else { //otherwise, just find every item and process Iterator itemIterator = itemService.findAll(context); - while (itemIterator.hasNext() && processed < max2Process) - { + while (itemIterator.hasNext() && processed < max2Process) { applyFiltersItem(context, itemIterator.next()); } } @@ -114,16 +122,14 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB @Override public void applyFiltersCommunity(Context context, Community community) - throws Exception - { //only apply filters if community not in skip-list - if(!inSkipList(community.getHandle())) - { - List subcommunities = community.getSubcommunities(); + throws Exception { //only apply filters if community not in skip-list + if (!inSkipList(community.getHandle())) { + List subcommunities = community.getSubcommunities(); for (Community subcommunity : subcommunities) { applyFiltersCommunity(context, subcommunity); } - - List collections = community.getCollections(); + + List collections = community.getCollections(); for (Collection collection : collections) { applyFiltersCollection(context, collection); } @@ -132,43 +138,36 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB @Override public void applyFiltersCollection(Context context, Collection collection) - throws Exception - { + throws Exception { //only apply filters if collection not in skip-list - if(!inSkipList(collection.getHandle())) - { + if (!inSkipList(collection.getHandle())) { Iterator itemIterator = itemService.findAllByCollection(context, collection); - while (itemIterator.hasNext() && processed < max2Process) - { + while (itemIterator.hasNext() && processed < max2Process) { applyFiltersItem(context, itemIterator.next()); } } } - + @Override - public void applyFiltersItem(Context c, Item item) throws Exception - { + 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; - } + 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 - { + public boolean filterItem(Context context, Item myItem) throws Exception { // get 'original' bundles List myBundles = itemService.getBundles(myItem, "ORIGINAL"); boolean done = false; @@ -185,12 +184,11 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB @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 + 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; @@ -209,7 +207,7 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB //For other MediaFilters, map key is just: // List fmts = filterFormats.get(filterClass.getClass().getName() + - (pluginName != null ? FILTER_PLUGIN_SEPARATOR + pluginName : "")); + (pluginName != null ? FILTER_PLUGIN_SEPARATOR + pluginName : "")); if (fmts.contains(myBitstream.getFormat(context).getShortDescription())) { try { @@ -222,7 +220,7 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB } catch (Exception e) { String handle = myItem.getHandle(); List bundles = myBitstream.getBundles(); - long size = myBitstream.getSize(); + long size = myBitstream.getSizeBytes(); String checksum = myBitstream.getChecksum() + " (" + myBitstream.getChecksumAlgorithm() + ")"; int assetstore = myBitstream.getStoreNumber(); @@ -290,7 +288,7 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB } } catch (Exception e) { System.out.println("ERROR filtering, skipping bitstream #" - + myBitstream.getID() + " " + e); + + myBitstream.getID() + " " + e); e.printStackTrace(); } } @@ -298,37 +296,33 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB } return filtered; } - + @Override public boolean processBitstream(Context context, Item item, Bitstream source, FormatFilter formatFilter) - throws Exception - { + throws Exception { //do pre-processing of this bitstream, and if it fails, skip this bitstream! - if(!formatFilter.preProcessBitstream(context, item, source, isVerbose)) - { + if (!formatFilter.preProcessBitstream(context, item, source, isVerbose)) { return false; } - - boolean overWrite = isForce; - + + 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 - + // check if destination bitstream exists + Bundle existingBundle = null; + Bitstream existingBitstream = null; List bundles = itemService.getBundles(item, formatFilter.getBundleName()); - // check if destination bitstream exists - if (bundles.size() > 0) - { + if (bundles.size() > 0) { // only finds the last match (FIXME?) for (Bundle bundle : bundles) { List bitstreams = bundle.getBitstreams(); for (Bitstream bitstream : bitstreams) { - if (bitstream.getName().equals(newName)) { - targetBundle = bundle; + if (bitstream.getName().trim().equals(newName.trim())) { + existingBundle = bundle; existingBitstream = bitstream; } } @@ -336,116 +330,108 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB } // if exists and overwrite = false, exit - if (!overWrite && (existingBitstream != null)) - { - if (!isQuiet) - { + if (!overWrite && (existingBitstream != null)) { + if (!isQuiet) { System.out.println("SKIPPED: bitstream " + source.getID() - + " (item: " + item.getHandle() + ") because '" + newName + "' already exists"); + + " (item: " + item.getHandle() + ") because '" + newName + "' already exists"); } return false; } - - if(isVerbose) { + + if (isVerbose) { System.out.println("PROCESSING: bitstream " + source.getID() - + " (item: " + item.getHandle() + ")"); + + " (item: " + item.getHandle() + ")"); } - InputStream destStream; - try { - System.out.println("File: " + newName); - destStream = formatFilter.getDestinationStream(item, bitstreamService.retrieve(context, source), isVerbose); + System.out.println("File: " + newName); + + // start filtering of the bitstream, using try with resource to close all InputStreams properly + try ( + // get the source stream + InputStream srcStream = bitstreamService.retrieve(context, source); + // filter the source stream to produce the destination stream + // this is the hard work, check for OutOfMemoryErrors at the end of the try clause. + InputStream destStream = formatFilter.getDestinationStream(item, srcStream, isVerbose); + ) { if (destStream == null) { if (!isQuiet) { System.out.println("SKIPPED: bitstream " + source.getID() + " (item: " + item.getHandle() + ") because filtering was unsuccessful"); } - return false; } + + Bundle targetBundle; // bundle we're modifying + if (bundles.size() < 1) { + // create new bundle if needed + targetBundle = bundleService.create(context, item, formatFilter.getBundleName()); + } else { + // take the first match as we already looked out for the correct bundle name + targetBundle = bundles.get(0); + } + + // create bitstream to store the filter result + Bitstream b = bitstreamService.create(context, targetBundle, destStream); + // set the name, source and description 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()); + // Set the format of the bitstream + 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); + } + + //do post-processing of the generated bitstream + formatFilter.postProcessBitstream(context, item, b); + } 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 (existingBitstream != null) { + bundleService.removeBitstream(context, existingBundle, existingBitstream); } - if (!isQuiet) - { + if (!isQuiet) { System.out.println("FILTERED: bitstream " + source.getID() - + " (item: " + item.getHandle() + ") and created '" + newName + "'"); + + " (item: " + item.getHandle() + ") and created '" + newName + "'"); } - //do post-processing of the generated bitstream - formatFilter.postProcessBitstream(context, item, b); - return true; } - + @Override - public Item getCurrentItem() - { + public Item getCurrentItem() { return currentItem; } - + @Override - public boolean inSkipList(String identifier) - { - if(skipList!=null && skipList.contains(identifier)) - { - if (!isQuiet) - { + 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 - { + } else { return false; } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/PDFBoxThumbnail.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/PDFBoxThumbnail.java index f482914a58..b20f279f7a 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/PDFBoxThumbnail.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/PDFBoxThumbnail.java @@ -7,18 +7,14 @@ */ package org.dspace.app.mediafilter; -import java.awt.image.*; +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; -import org.dspace.app.mediafilter.JPEGFilter; - /** * Create JPEG thumbnails from PDF cover page using PDFBox. * Based on JPEGFilter: @@ -29,21 +25,17 @@ import org.dspace.app.mediafilter.JPEGFilter; * @author Ivan Masár helix84@centrum.sk * @author Jason Sherman jsherman@usao.edu */ -public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFormats -{ +public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFormats { @Override - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".jpg"; } /** * @return String bundle name - * */ @Override - public String getBundleName() - { + public String getBundleName() { return "THUMBNAIL"; } @@ -51,8 +43,7 @@ public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFor * @return String bitstreamformat */ @Override - public String getFormatString() - { + public String getFormatString() { return "JPEG"; } @@ -60,23 +51,20 @@ public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFor * @return String description */ @Override - public String getDescription() - { + public String getDescription() { return "Generated Thumbnail"; } /** * @param currentItem item - * @param source source input stream - * @param verbose verbose mode - * + * @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 - { + throws Exception { PDDocument doc = PDDocument.load(source); PDFRenderer renderer = new PDFRenderer(doc); BufferedImage buf = renderer.renderImage(0); @@ -88,20 +76,17 @@ public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFor } @Override - public String[] getInputMIMETypes() - { + public String[] getInputMIMETypes() { return ImageIO.getReaderMIMETypes(); } @Override - public String[] getInputDescriptions() - { + public String[] getInputDescriptions() { return null; } @Override - public String[] getInputExtensions() - { + public String[] getInputExtensions() { // Temporarily disabled as JDK 1.6 only // return ImageIO.getReaderFileSuffixes(); return null; diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/PDFFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/PDFFilter.java index b68d488813..6f398dabde 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/PDFFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/PDFFilter.java @@ -28,24 +28,20 @@ import org.dspace.core.ConfigurationManager; * instantiate filter - bitstream format doesn't exist * */ -public class PDFFilter extends MediaFilter -{ +public class PDFFilter extends MediaFilter { private static Logger log = Logger.getLogger(PDFFilter.class); @Override - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".txt"; } /** * @return String bundle name - * */ @Override - public String getBundleName() - { + public String getBundleName() { return "TEXT"; } @@ -53,8 +49,7 @@ public class PDFFilter extends MediaFilter * @return String bitstreamformat */ @Override - public String getFormatString() - { + public String getFormatString() { return "Text"; } @@ -62,25 +57,21 @@ public class PDFFilter extends MediaFilter * @return String description */ @Override - public String getDescription() - { + public String getDescription() { return "Extracted text"; } /** * @param currentItem item - * @param source source input stream - * @param verbose verbose mode - * + * @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 - { + throws Exception { + try { boolean useTemporaryFile = ConfigurationManager.getBooleanProperty("pdffilter.largepdfs", false); // get input stream from bitstream @@ -92,62 +83,43 @@ public class PDFFilter extends MediaFilter File tempTextFile = null; ByteArrayOutputStream byteStream = null; - if (useTemporaryFile) - { + if (useTemporaryFile) { tempTextFile = File.createTempFile("dspacepdfextract" + source.hashCode(), ".txt"); tempTextFile.deleteOnExit(); writer = new OutputStreamWriter(new FileOutputStream(tempTextFile)); - } - else - { + } else { byteStream = new ByteArrayOutputStream(); writer = new OutputStreamWriter(byteStream); } - - try - { + + try { pdfDoc = PDDocument.load(source); pts.writeText(pdfDoc, writer); - } - finally - { - try - { - if (pdfDoc != null) - { + } finally { + try { + if (pdfDoc != null) { pdfDoc.close(); } - } - catch(Exception e) - { - log.error("Error closing PDF file: " + e.getMessage(), e); + } catch (Exception e) { + log.error("Error closing PDF file: " + e.getMessage(), e); } - try - { + try { writer.close(); - } - catch(Exception e) - { - log.error("Error closing temporary extract file: " + e.getMessage(), e); + } catch (Exception e) { + log.error("Error closing temporary extract file: " + e.getMessage(), e); } } - if (useTemporaryFile) - { + if (useTemporaryFile) { return new FileInputStream(tempTextFile); - } - else - { + } else { byte[] bytes = byteStream.toByteArray(); return new ByteArrayInputStream(bytes); } - } - catch (OutOfMemoryError oome) - { + } catch (OutOfMemoryError oome) { log.error("Error parsing PDF document " + oome.getMessage(), oome); - if (!ConfigurationManager.getBooleanProperty("pdffilter.skiponmemoryexception", false)) - { + if (!ConfigurationManager.getBooleanProperty("pdffilter.skiponmemoryexception", false)) { throw oome; } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/PoiWordFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/PoiWordFilter.java index 1d83fb9e51..158f52f1f9 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/PoiWordFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/PoiWordFilter.java @@ -8,8 +8,8 @@ package org.dspace.app.mediafilter; import java.io.ByteArrayInputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import org.apache.poi.POITextExtractor; import org.apache.poi.extractor.ExtractorFactory; @@ -23,55 +23,45 @@ import org.slf4j.LoggerFactory; * Extract flat text from Microsoft Word documents (.doc, .docx). */ public class PoiWordFilter - extends MediaFilter -{ + extends MediaFilter { private static final Logger LOG = LoggerFactory.getLogger(PoiWordFilter.class); @Override - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".txt"; } @Override - public String getBundleName() - { + public String getBundleName() { return "TEXT"; } @Override - public String getFormatString() - { + public String getFormatString() { return "Text"; } @Override - public String getDescription() - { + public String getDescription() { return "Extracted text"; } @Override public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose) - throws Exception - { + throws Exception { String text; - try - { + 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) - { + } 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) - { + if (verbose) { System.out.println(text); } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/PowerPointFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/PowerPointFilter.java index dc21e9ee00..e0345ed3e8 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/PowerPointFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/PowerPointFilter.java @@ -10,47 +10,41 @@ package org.dspace.app.mediafilter; import java.io.ByteArrayInputStream; import java.io.InputStream; -import org.apache.poi.extractor.ExtractorFactory; -import org.apache.poi.xslf.extractor.XSLFPowerPointExtractor; -import org.apache.poi.hslf.extractor.PowerPointExtractor; -import org.apache.poi.POITextExtractor; - 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 -{ +public class PowerPointFilter extends MediaFilter { private static Logger log = Logger.getLogger(PowerPointFilter.class); @Override - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".txt"; } /** * @return String bundle name - * */ @Override - public String getBundleName() - { + public String getBundleName() { return "TEXT"; } /** * @return String bitstream format - * - * TODO: Check that this is correct + * + * TODO: Check that this is correct */ @Override - public String getFormatString() - { + public String getFormatString() { return "Text"; } @@ -58,59 +52,48 @@ public class PowerPointFilter extends MediaFilter * @return String description */ @Override - public String getDescription() - { + public String getDescription() { return "Extracted text"; } /** * @param currentItem item - * @param source source input stream - * @param verbose verbose mode - * + * @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 - { + throws Exception { - try - { + try { String extractedText = null; new ExtractorFactory(); POITextExtractor pptExtractor = ExtractorFactory - .createExtractor(source); + .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) - { + 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); - } - - // Legacy PowerPoint files - else if (pptExtractor instanceof PowerPointExtractor) - { + .getText(true, true); + } else if (pptExtractor instanceof PowerPointExtractor) { // Legacy PowerPoint files extractedText = ((PowerPointExtractor) pptExtractor).getText() - + " " + ((PowerPointExtractor) pptExtractor).getNotes(); + + " " + ((PowerPointExtractor) pptExtractor).getNotes(); } - if (extractedText != null) - { + if (extractedText != null) { // if verbose flag is set, print out extracted text // to STDOUT - if (verbose) - { + if (verbose) { System.out.println(extractedText); } @@ -120,9 +103,7 @@ public class PowerPointFilter extends MediaFilter return bais; } - } - catch (Exception e) - { + } catch (Exception e) { log.error("Error filtering bitstream: " + e.getMessage(), e); throw e; } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/SelfRegisterInputFormats.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/SelfRegisterInputFormats.java index 43f852da71..7e7a8a7499 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/SelfRegisterInputFormats.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/SelfRegisterInputFormats.java @@ -11,8 +11,7 @@ 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 interface SelfRegisterInputFormats { public String[] getInputMIMETypes(); public String[] getInputDescriptions(); diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/WordFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/WordFilter.java index 8a1452941e..5051c01fd4 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/WordFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/WordFilter.java @@ -8,39 +8,34 @@ package org.dspace.app.mediafilter; import java.io.ByteArrayInputStream; -import java.io.InputStream; 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 -{ +public class WordFilter extends MediaFilter { private static Logger log = Logger.getLogger(WordFilter.class); @Override - public String getFilteredName(String oldFilename) - { + public String getFilteredName(String oldFilename) { return oldFilename + ".txt"; } /** * @return String bundle name - * */ @Override - public String getBundleName() - { + public String getBundleName() { return "TEXT"; } @@ -48,8 +43,7 @@ public class WordFilter extends MediaFilter * @return String bitstreamformat */ @Override - public String getFormatString() - { + public String getFormatString() { return "Text"; } @@ -57,35 +51,30 @@ public class WordFilter extends MediaFilter * @return String description */ @Override - public String getDescription() - { + public String getDescription() { return "Extracted text"; } /** * @param currentItem item - * @param source source input stream - * @param verbose verbose mode - * + * @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 - { + throws Exception { // get input stream from bitstream // pass to filter, get string back - try - { + 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) - { + if (verbose) { System.out.println(extractedText); } @@ -94,12 +83,10 @@ public class WordFilter extends MediaFilter ByteArrayInputStream bais = new ByteArrayInputStream(textBytes); return bais; // will this work? or will the byte array be out of scope? - } - catch (IOException ioe) - { + } catch (IOException ioe) { System.out.println("Invalid Word Format"); log.error("Error detected - Word File format not recognized: " - + ioe.getMessage(), ioe); + + ioe.getMessage(), ioe); throw ioe; } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/factory/MediaFilterServiceFactory.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/factory/MediaFilterServiceFactory.java index f9e6c89772..92615f8064 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/factory/MediaFilterServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/factory/MediaFilterServiceFactory.java @@ -11,7 +11,8 @@ 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 + * Abstract factory to get services for the mediafilter package, use MediaFilterServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -19,7 +20,8 @@ public abstract class MediaFilterServiceFactory { public abstract MediaFilterService getMediaFilterService(); - public static MediaFilterServiceFactory getInstance(){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("mediaFilterServiceFactory", MediaFilterServiceFactory.class); + public static MediaFilterServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("mediaFilterServiceFactory", MediaFilterServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/factory/MediaFilterServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/factory/MediaFilterServiceFactoryImpl.java index f629f187d0..df6142b516 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/factory/MediaFilterServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/factory/MediaFilterServiceFactoryImpl.java @@ -11,7 +11,8 @@ 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 + * Factory implementation to get services for the mediafilter package, use MediaFilterServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/service/MediaFilterService.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/service/MediaFilterService.java index d88a22bce7..83198a5083 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/service/MediaFilterService.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/service/MediaFilterService.java @@ -7,6 +7,9 @@ */ 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; @@ -14,9 +17,6 @@ import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.core.Context; -import java.util.List; -import java.util.Map; - /** * 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 @@ -36,10 +36,10 @@ public interface MediaFilterService { public void applyFiltersAllItems(Context context) throws Exception; public void applyFiltersCommunity(Context context, Community community) - throws Exception; + throws Exception; public void applyFiltersCollection(Context context, Collection collection) - throws Exception; + throws Exception; public void applyFiltersItem(Context c, Item item) throws Exception; @@ -49,9 +49,9 @@ public interface MediaFilterService { * filters if possible. * * @param context context - * @param myItem item + * @param myItem item * @return true if any bitstreams processed, - * false if none + * false if none * @throws Exception if error */ public boolean filterItem(Context context, Item myItem) throws Exception; @@ -63,11 +63,11 @@ public interface MediaFilterService { * instantiated. Exceptions from filtering will be logged to STDOUT and * swallowed. * - * @param c context - * @param myItem item + * @param c context + * @param myItem item * @param myBitstream bitstream * @return true if bitstream processed, - * false if no applicable filter or already processed + * false if no applicable filter or already processed * @throws Exception if error */ public boolean filterBitstream(Context c, Item myItem, Bitstream myBitstream) throws Exception; @@ -79,20 +79,16 @@ public interface MediaFilterService { * 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 - * @throws Exception if error occurs + * @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 + * exists and overWrite is not set + * @throws Exception if error occurs */ public boolean processBitstream(Context context, Item item, Bitstream source, FormatFilter formatFilter) - throws Exception; + throws Exception; /** * Return the item that is currently being processed/filtered @@ -109,11 +105,9 @@ public interface MediaFilterService { /** * Check whether or not to skip processing the given identifier. * - * @param identifier - * identifier (handle) of a community, collection or item - * + * @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. + * during processing. Otherwise, return false. */ public boolean inSkipList(String identifier); diff --git a/dspace-api/src/main/java/org/dspace/app/packager/Packager.java b/dspace-api/src/main/java/org/dspace/app/packager/Packager.java index 0ac366bef3..5010e707ab 100644 --- a/dspace-api/src/main/java/org/dspace/app/packager/Packager.java +++ b/dspace-api/src/main/java/org/dspace/app/packager/Packager.java @@ -7,7 +7,19 @@ */ package org.dspace.app.packager; -import org.apache.commons.cli.*; +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; @@ -24,10 +36,6 @@ import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.workflow.WorkflowException; -import java.io.*; -import java.sql.SQLException; -import java.util.List; - /** * Command-line interface to the Packager plugin. *

@@ -43,7 +51,8 @@ import java.util.List; * (Add the -h option to get the command to show its own help) * *

- *  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)
+ *  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}
@@ -63,7 +72,8 @@ import java.util.List;
  *
  *  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)
+ *       -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} ..]]
@@ -73,14 +83,19 @@ import java.util.List;
  *                  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
+ *                  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
+ *   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:
@@ -105,49 +120,60 @@ import java.util.List;
  * @author Tim Donohue
  * @version $Revision$
  */
-public class Packager
-{
+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)
-    {
+    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
-    {
+    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)");
+                          "Handle(s) of parent Community or Collection into which to ingest object (repeatable)");
         options.addOption("e", "eperson", true,
-                "email address of eperson doing importing");
+                          "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).");
+            .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)");
+            .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.");
+                          "Disseminate package (output); default is to submit.");
         options.addOption("s", "submit", false,
-                "Submission package (Input); this is the default. ");
+                          "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.");
+        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);
@@ -162,15 +188,13 @@ public class Packager
         //initialize a new packager -- we'll add all our current params as settings
         Packager myPackager = new Packager();
 
-        if (line.hasOption('h'))
-        {
+        if (line.hasOption('h')) {
             HelpFormatter myhelp = new HelpFormatter();
             myhelp.printHelp("Packager  [options]  package-file|-\n",
-                    options);
+                             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'))
-            {
+            if (line.hasOption('t')) {
                 System.out.println("\n--------------------------------------------------------------");
                 System.out.println("Additional options for the " + line.getOptionValue('t') + " packager:");
                 System.out.println("--------------------------------------------------------------");
@@ -179,44 +203,36 @@ public class Packager
                 PackageIngester sip = (PackageIngester) pluginService
                     .getNamedPlugin(PackageIngester.class, line.getOptionValue('t'));
 
-                if (sip != null)
-                {
+                if (sip != null) {
                     System.out.println("\n\n" + line.getOptionValue('t') + " Submission (SIP) plugin options:\n");
                     System.out.println(sip.getParameterHelp());
-                }
-                else
-                {
+                } 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)
-                {
+                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 {
+                    System.out
+                        .println("\nNo valid Dissemination plugin found for " + line.getOptionValue('t') + " type.");
                 }
 
-            }
-            else  //otherwise, display list of valid packager types
-            {
+            } 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)
-                {
+                    .getAllPluginNames(PackageIngester.class);
+                for (int i = 0; i < pn.length; ++i) {
                     System.out.println("  " + pn[i]);
                 }
                 System.out
-                        .println("\nAvailable Dissemination Package (DIP) types:");
+                    .println("\nAvailable Dissemination Package (DIP) types:");
                 pn = pluginService.getAllPluginNames(PackageDisseminator.class);
-                for (int i = 0; i < pn.length; ++i)
-                {
+                for (int i = 0; i < pn.length; ++i) {
                     System.out.println("  " + pn[i]);
                 }
             }
@@ -224,85 +240,66 @@ public class Packager
         }
 
         //look for flag to disable all user interaction
-        if(line.hasOption('u'))
-        {
+        if (line.hasOption('u')) {
             myPackager.userInteractionEnabled = false;
         }
-        if (line.hasOption('w'))
-        {
+        if (line.hasOption('w')) {
             pkgParams.setWorkflowEnabled(false);
         }
-        if (line.hasOption('r'))
-        {
+        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())
-        {
+        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())
-        {
+        if (line.hasOption('f') && pkgParams.restoreModeEnabled()) {
             pkgParams.setReplaceModeEnabled(true);
         }
-        if (line.hasOption('e'))
-        {
+        if (line.hasOption('e')) {
             eperson = line.getOptionValue('e');
         }
-        if (line.hasOption('p'))
-        {
+        if (line.hasOption('p')) {
             parents = line.getOptionValues('p');
         }
-        if (line.hasOption('t'))
-        {
+        if (line.hasOption('t')) {
             myPackager.packageType = line.getOptionValue('t');
         }
-        if (line.hasOption('i'))
-        {
+        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
+        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)
-        {
+        if (files.length > 0) {
             sourceFile = files[0];
         }
-        if (line.hasOption('d'))
-        {
+        if (line.hasOption('d')) {
             myPackager.submit = false;
         }
-        if (line.hasOption('o'))
-        {
+        if (line.hasOption('o')) {
             String popt[] = line.getOptionValues('o');
-            for (int i = 0; i < popt.length; ++i)
-            {
+            for (int i = 0; i < popt.length; ++i) {
                 String pair[] = popt[i].split("\\=", 2);
-                if (pair.length == 2)
-                {
+                if (pair.length == 2) {
                     pkgParams.addProperty(pair[0].trim(), pair[1].trim());
-                }
-                else if (pair.length == 1)
-                {
+                } else if (pair.length == 1) {
                     pkgParams.addProperty(pair[0].trim(), "");
-                }
-                else
-                {
+                } else {
                     System.err
-                            .println("Warning: Illegal package option format: \""
-                                    + popt[i] + "\"");
+                        .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)
-        {
+        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);
@@ -313,68 +310,60 @@ public class Packager
         Context context = new Context();
         EPerson myEPerson = null;
         myEPerson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, eperson);
-        if (myEPerson == null)
-        {
+        if (myEPerson == null) {
             usageError("Error, eperson cannot be found: " + eperson);
         }
         context.setCurrentUser(myEPerson);
 
 
         //If we are in REPLACE mode
-        if(pkgParams.replaceModeEnabled())
-        {
+        if (pkgParams.replaceModeEnabled()) {
             context.setMode(Context.Mode.BATCH_EDIT);
             PackageIngester sip = (PackageIngester) pluginService
-                    .getNamedPlugin(PackageIngester.class, myPackager.packageType);
-            if (sip == null)
-            {
+                .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)
-                {
+            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 + "\"");
+                                                           + "Cannot resolve handle \"" + identifier + "\"");
                 }
             }
 
             String choiceString = null;
-            if(myPackager.userInteractionEnabled)
-            {
+            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.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
-            {
+            } else {
                 //user interaction disabled -- default answer to 'yes', otherwise script won't continue
                 choiceString = "y";
             }
 
-            if (choiceString.equalsIgnoreCase("y"))
-            {
+            if (choiceString.equalsIgnoreCase("y")) {
                 System.out.println("Beginning replacement process...");
 
-                try
-                {
+                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)
-                {
+                } catch (Exception e) {
                     // abort all operations
                     e.printStackTrace();
                     context.abort();
@@ -383,78 +372,67 @@ public class Packager
                 }
             }
 
-        }
-        //else if normal SUBMIT mode (or basic RESTORE mode -- which is a special type of submission)
-        else if (myPackager.submit || pkgParams.restoreModeEnabled())
-        {
+        } 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)
-            {
+                .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)
-            {
+            if (parents != null) {
                 System.out.println("Destination parents:");
 
                 parentObjs = new DSpaceObject[parents.length];
-                for (int i = 0; i < parents.length; i++)
-                {
+                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)
-                    {
+                                                                                                          parents[i]);
+                    if (parentObjs[i] == null) {
                         throw new IllegalArgumentException(
-                                "Bad parent list -- "
-                                        + "Cannot resolve parent handle \""
-                                        + parents[i] + "\"");
+                            "Bad parent list -- "
+                                + "Cannot resolve parent handle \""
+                                + parents[i] + "\"");
                     }
                     System.out.println((i == 0 ? "Owner: " : "Parent: ")
-                            + parentObjs[i].getHandle());
+                                           + parentObjs[i].getHandle());
                 }
             }
 
-            try
-            {
+            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)
-            {
+            } catch (Exception e) {
                 // abort all operations
                 e.printStackTrace();
                 context.abort();
                 System.out.println(e);
                 System.exit(1);
             }
-        }// else, if DISSEMINATE mode
-        else
-        {
+        } 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)
-            {
+            if (dip == null) {
                 usageError("Error, Unknown package type: " + myPackager.packageType);
             }
 
-            DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, identifier);
-            if (dso == null)
-            {
+            DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService()
+                                                   .resolveToObject(context, identifier);
+            if (dso == null) {
                 throw new IllegalArgumentException("Bad identifier/handle -- "
-                        + "Cannot resolve handle \"" + identifier + "\"");
+                                                       + "Cannot resolve handle \"" + identifier + "\"");
             }
 
             //disseminate the requested object
@@ -470,26 +448,26 @@ public class Packager
      * 

* 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 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 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 + * @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 - { + 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()) - { + if (!pkgFile.exists()) { System.out.println("\nERROR: Package located at " + sourceFile + " does not exist!"); System.exit(1); } @@ -498,108 +476,92 @@ public class Packager //find first parent (if specified) -- this will be the "owner" of the object DSpaceObject parent = null; - if(parentObjs!=null && parentObjs.length>0) - { + 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 - { + try { //If we are doing a recursive ingest, call ingestAll() - if(pkgParams.recursiveModeEnabled()) - { + 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."); + 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 hdlResults = sip.ingestAll(context, parent, pkgFile, pkgParams, null); - if (hdlResults != 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) - { + 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 - { + } 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")) - { + if (choiceString.equalsIgnoreCase("y")) { System.out.println("\n\n"); - for (String result : hdlResults) - { - DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, result); + for (String result : hdlResults) { + DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService() + .resolveToObject(context, result); - if(dso!=null) - { + if (dso != null) { if (pkgParams.restoreModeEnabled()) { System.out.println("RESTORED DSpace " + Constants.typeText[dso.getType()] + - " [ hdl=" + dso.getHandle() + ", dbID=" + dso.getID() + " ] "); + " [ hdl=" + dso.getHandle() + ", dbID=" + dso + .getID() + " ] "); } else { System.out.println("CREATED new DSpace " + Constants.typeText[dso.getType()] + - " [ hdl=" + dso.getHandle() + ", dbID=" + dso.getID() + " ] "); + " [ hdl=" + dso.getHandle() + ", dbID=" + dso + .getID() + " ] "); } } } } } - } - else - { + } else { //otherwise, just one package to ingest - try - { + try { DSpaceObject dso = sip.ingest(context, parent, pkgFile, pkgParams, null); - if (dso != null) - { - if (pkgParams.restoreModeEnabled()) - { + if (dso != null) { + if (pkgParams.restoreModeEnabled()) { System.out.println("RESTORED DSpace " + Constants.typeText[dso.getType()] + - " [ hdl=" + dso.getHandle() + ", dbID=" + dso.getID() + " ] "); - } - else - { + " [ hdl=" + dso.getHandle() + ", dbID=" + dso.getID() + " ] "); + } else { System.out.println("CREATED new DSpace " + Constants.typeText[dso.getType()] + - " [ hdl=" + dso.getHandle() + ", dbID=" + dso.getID() + " ] "); + " [ hdl=" + dso.getHandle() + ", dbID=" + dso.getID() + " ] "); } } - } - catch (IllegalStateException ie) - { + } 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) - { + 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) - { + } catch (WorkflowException e) { throw new PackageException(e); } } @@ -609,128 +571,116 @@ public class Packager * 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 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 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 + * @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 - { + 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); + " [ hdl=" + dso.getHandle() + " ] to " + outputFile); //If we are doing a recursive dissemination of this object & all its child objects, call disseminateAll() - if(pkgParams.recursiveModeEnabled()) - { + 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."); + 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 fileResults = dip.disseminateAll(context, dso, pkgParams, pkgFile); - if(fileResults!=null) - { + 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) - { + 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 - { + } 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")) - { + if (choiceString.equalsIgnoreCase("y")) { System.out.println("\n\n"); - for(File result : fileResults) - { + for (File result : fileResults) { System.out.println("CREATED package file: " + result.getCanonicalPath()); } } } - } - else - { + } else { //otherwise, just disseminate a single object to a single package file dip.disseminate(context, dso, pkgParams, pkgFile); - if(pkgFile!=null && pkgFile.exists()) - { + 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 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 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 + * @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 - { + 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()) - { + 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) - { + if (objToReplace != null) { System.out.println("Will replace existing DSpace " + Constants.typeText[objToReplace.getType()] + - " [ hdl=" + objToReplace.getHandle() + " ]"); + " [ 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 - { + 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) + if (pkgParams.recursiveModeEnabled()) { + //ingest first object using package & recursively replace anything else that package references + // (child objects, etc) List hdlResults = sip.replaceAll(context, objToReplace, pkgFile, pkgParams); if (hdlResults != null) { @@ -739,52 +689,42 @@ public class Packager String choiceString = null; //Ask if user wants full list printed to command line, as this may be rather long. - if (this.userInteractionEnabled) - { + 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 - { + } 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")) - { + if (choiceString.equalsIgnoreCase("y")) { System.out.println("\n\n"); - for (String result : hdlResults) - { - DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, result); + for (String result : hdlResults) { + DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService() + .resolveToObject(context, result); - if (dso != null) - { + if (dso != null) { System.out.println("REPLACED DSpace " + Constants.typeText[dso.getType()] + - " [ hdl=" + dso.getHandle() + " ] "); + " [ hdl=" + dso.getHandle() + " ] "); } } } } - } - else - { + } else { //otherwise, just one object to replace DSpaceObject dso = sip.replace(context, objToReplace, pkgFile, pkgParams); - if (dso != null) - { + if (dso != null) { System.out.println("REPLACED DSpace " + Constants.typeText[dso.getType()] + - " [ hdl=" + dso.getHandle() + " ] "); + " [ hdl=" + dso.getHandle() + " ] "); } } - } - catch (WorkflowException e) - { + } catch (WorkflowException e) { throw new PackageException(e); } } diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItem.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItem.java index 0a549db077..d96cbbb5a4 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItem.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItem.java @@ -7,26 +7,37 @@ */ package org.dspace.app.requestitem; +import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + import org.dspace.content.Bitstream; import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; -import javax.persistence.*; -import java.util.Date; - /** * Object representing an Item Request */ @Entity -@Table(name="requestitem") +@Table(name = "requestitem") public class RequestItem implements ReloadableEntity { @Id - @Column(name="requestitem_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="requestitem_seq") - @SequenceGenerator(name="requestitem_seq", sequenceName="requestitem_seq", allocationSize = 1) + @Column(name = "requestitem_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "requestitem_seq") + @SequenceGenerator(name = "requestitem_seq", sequenceName = "requestitem_seq", allocationSize = 1) private int requestitem_id; @ManyToOne(fetch = FetchType.LAZY) @@ -43,9 +54,9 @@ public class RequestItem implements ReloadableEntity { @Column(name = "request_name", length = 64) private String reqName; -// @Column(name = "request_message") + // @Column(name = "request_message") // @Lob - @Column(name="request_message", columnDefinition = "text") + @Column(name = "request_message", columnDefinition = "text") private String reqMessage; @Column(name = "token", unique = true, length = 48) @@ -71,10 +82,10 @@ public class RequestItem implements ReloadableEntity { /** * Protected constructor, create object using: - * {@link org.dspace.app.requestitem.service.RequestItemService#createRequest(Context, Bitstream, Item, boolean, String, String, String)} + * {@link org.dspace.app.requestitem.service.RequestItemService#createRequest(Context, Bitstream, Item, + * boolean, String, String, String)} */ - protected RequestItem() - { + protected RequestItem() { } public Integer getID() { diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthor.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthor.java index 6d795b8a4d..49e26fe00b 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthor.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthor.java @@ -12,19 +12,18 @@ import org.dspace.eperson.EPerson; /** * Simple DTO to transfer data about the corresponding author for the Request * Copy feature - * + * * @author Andrea Bollini - * */ public class RequestItemAuthor { - private String fullName; - private String email; + private String fullName; + private String email; - public RequestItemAuthor(String fullName, String email) { - super(); - this.fullName = fullName; - this.email = email; - } + public RequestItemAuthor(String fullName, String email) { + super(); + this.fullName = fullName; + this.email = email; + } public RequestItemAuthor(EPerson ePerson) { super(); @@ -32,11 +31,11 @@ public class RequestItemAuthor { this.email = ePerson.getEmail(); } - public String getEmail() { - return email; - } + public String getEmail() { + return email; + } - public String getFullName() { - return fullName; - } + public String getFullName() { + return fullName; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthorExtractor.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthorExtractor.java index d94c7320de..bba0913193 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthorExtractor.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemAuthorExtractor.java @@ -15,11 +15,10 @@ import org.dspace.core.Context; /** * Interface to abstract the strategy for select the author to contact for * request copy - * + * * @author Andrea Bollini - * */ public interface RequestItemAuthorExtractor { - public RequestItemAuthor getRequestItemAuthor(Context context, Item item) - throws SQLException; + public RequestItemAuthor getRequestItemAuthor(Context context, Item item) + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemHelpdeskStrategy.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemHelpdeskStrategy.java index ddd6d50ba5..d9922a9179 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemHelpdeskStrategy.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemHelpdeskStrategy.java @@ -7,6 +7,8 @@ */ package org.dspace.app.requestitem; +import java.sql.SQLException; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.Item; @@ -17,16 +19,15 @@ import org.dspace.eperson.EPerson; import org.dspace.eperson.service.EPersonService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; - /** * RequestItem strategy to allow DSpace support team's helpdesk to receive requestItem request * With this enabled, then the Item author/submitter doesn't receive the request, but the helpdesk instead does. * - * Failover to the RequestItemSubmitterStrategy, which means the submitter would get the request if there is no specified helpdesk email. + * Failover to the RequestItemSubmitterStrategy, which means the submitter would get the request if there is no + * specified helpdesk email. * - * @author Sam Ottenhoff - * @author Peter Dietz + * @author Sam Ottenhoff + * @author Peter Dietz */ public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy { @@ -35,11 +36,13 @@ public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy { @Autowired(required = true) protected EPersonService ePersonService; - public RequestItemHelpdeskStrategy() {} + public RequestItemHelpdeskStrategy() { + } @Override public RequestItemAuthor getRequestItemAuthor(Context context, Item item) throws SQLException { - boolean helpdeskOverridesSubmitter = ConfigurationManager.getBooleanProperty("request.item.helpdesk.override", false); + boolean helpdeskOverridesSubmitter = ConfigurationManager + .getBooleanProperty("request.item.helpdesk.override", false); String helpDeskEmail = ConfigurationManager.getProperty("mail.helpdesk"); if (helpdeskOverridesSubmitter && StringUtils.isNotBlank(helpDeskEmail)) { @@ -54,19 +57,20 @@ public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy { * Return a RequestItemAuthor object for the specified helpdesk email address. * It makes an attempt to find if there is a matching eperson for the helpdesk address, to use the name, * Otherwise it falls back to a helpdeskname key in the Messages.props. - * @param context context + * + * @param context context * @param helpDeskEmail email * @return RequestItemAuthor * @throws SQLException if database error */ - public RequestItemAuthor getHelpDeskPerson(Context context, String helpDeskEmail) throws SQLException{ + public RequestItemAuthor getHelpDeskPerson(Context context, String helpDeskEmail) throws SQLException { EPerson helpdeskEPerson = null; context.turnOffAuthorisationSystem(); helpdeskEPerson = ePersonService.findByEmail(context, helpDeskEmail); context.restoreAuthSystemState(); - if(helpdeskEPerson != null) { + if (helpdeskEPerson != null) { return new RequestItemAuthor(helpdeskEPerson); } else { String helpdeskName = I18nUtil.getMessage( diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemMetadataStrategy.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemMetadataStrategy.java index 464ad0e768..652f81f8c7 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemMetadataStrategy.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemMetadataStrategy.java @@ -11,8 +11,8 @@ import java.sql.SQLException; import java.util.List; import org.apache.commons.lang.StringUtils; -import org.dspace.content.MetadataValue; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.core.I18nUtil; @@ -21,9 +21,8 @@ import org.springframework.beans.factory.annotation.Autowired; /** * Try to look to an item metadata for the corresponding author name and email. * Failover to the RequestItemSubmitterStrategy - * + * * @author Andrea Bollini - * */ public class RequestItemMetadataStrategy extends RequestItemSubmitterStrategy { @@ -33,49 +32,44 @@ public class RequestItemMetadataStrategy extends RequestItemSubmitterStrategy { @Autowired(required = true) protected ItemService itemService; - public RequestItemMetadataStrategy() { - } + public RequestItemMetadataStrategy() { + } - @Override - public RequestItemAuthor getRequestItemAuthor(Context context, Item item) - throws SQLException { - if (emailMetadata != null) - { - List vals = itemService.getMetadataByMetadataString(item, emailMetadata); - if (vals.size() > 0) - { - String email = vals.iterator().next().getValue(); - String fullname = null; - if (fullNameMetadata != null) - { + @Override + public RequestItemAuthor getRequestItemAuthor(Context context, Item item) + throws SQLException { + if (emailMetadata != null) { + List vals = itemService.getMetadataByMetadataString(item, emailMetadata); + if (vals.size() > 0) { + String email = vals.iterator().next().getValue(); + String fullname = null; + if (fullNameMetadata != null) { List nameVals = itemService.getMetadataByMetadataString(item, fullNameMetadata); - if (nameVals.size() > 0) - { - fullname = nameVals.iterator().next().getValue(); - } - } - - if (StringUtils.isBlank(fullname)) - { - fullname = I18nUtil - .getMessage( - "org.dspace.app.requestitem.RequestItemMetadataStrategy.unnamed", - context); - } - RequestItemAuthor author = new RequestItemAuthor( - fullname, email); - return author; - } - } - return super.getRequestItemAuthor(context, item); - } + if (nameVals.size() > 0) { + fullname = nameVals.iterator().next().getValue(); + } + } - public void setEmailMetadata(String emailMetadata) { - this.emailMetadata = emailMetadata; - } + if (StringUtils.isBlank(fullname)) { + fullname = I18nUtil + .getMessage( + "org.dspace.app.requestitem.RequestItemMetadataStrategy.unnamed", + context); + } + RequestItemAuthor author = new RequestItemAuthor( + fullname, email); + return author; + } + } + return super.getRequestItemAuthor(context, item); + } - public void setFullNameMetadata(String fullNameMetadata) { - this.fullNameMetadata = fullNameMetadata; - } + public void setEmailMetadata(String emailMetadata) { + this.emailMetadata = emailMetadata; + } + + public void setFullNameMetadata(String fullNameMetadata) { + this.fullNameMetadata = fullNameMetadata; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemServiceImpl.java index 979a28730c..baf64e8657 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemServiceImpl.java @@ -7,6 +7,9 @@ */ package org.dspace.app.requestitem; +import java.sql.SQLException; +import java.util.Date; + import org.apache.log4j.Logger; import org.dspace.app.requestitem.dao.RequestItemDAO; import org.dspace.app.requestitem.service.RequestItemService; @@ -16,9 +19,6 @@ import org.dspace.core.Context; import org.dspace.core.Utils; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Date; - /** * Service implementation for the RequestItem object. * This class is responsible for all business logic calls for the RequestItem object and is autowired by spring. @@ -33,13 +33,13 @@ public class RequestItemServiceImpl implements RequestItemService { @Autowired(required = true) protected RequestItemDAO requestItemDAO; - protected RequestItemServiceImpl() - { + protected RequestItemServiceImpl() { } @Override - public String createRequest(Context context, Bitstream bitstream, Item item, boolean allFiles, String reqEmail, String reqName, String reqMessage) throws SQLException { + public String createRequest(Context context, Bitstream bitstream, Item item, boolean allFiles, String reqEmail, + String reqName, String reqMessage) throws SQLException { RequestItem requestItem = requestItemDAO.create(context, new RequestItem()); requestItem.setToken(Utils.generateHexKey()); @@ -53,10 +53,9 @@ public class RequestItemServiceImpl implements RequestItemService { requestItemDAO.save(context, requestItem); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Created requestitem_token " + requestItem.getID() - + " with token " + requestItem.getToken() + "\""); + + " with token " + requestItem.getToken() + "\""); } return requestItem.getToken(); } diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemSubmitterStrategy.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemSubmitterStrategy.java index b7fde10f1d..8ed6238a8c 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemSubmitterStrategy.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemSubmitterStrategy.java @@ -15,22 +15,21 @@ import org.dspace.eperson.EPerson; /** * Basic strategy that looks to the original submitter. - * - * @author Andrea Bollini * + * @author Andrea Bollini */ public class RequestItemSubmitterStrategy implements RequestItemAuthorExtractor { - public RequestItemSubmitterStrategy() { - } + public RequestItemSubmitterStrategy() { + } - @Override - public RequestItemAuthor getRequestItemAuthor(Context context, Item item) - throws SQLException { - EPerson submitter = item.getSubmitter(); - RequestItemAuthor author = new RequestItemAuthor( - submitter.getFullName(), submitter.getEmail()); - return author; - } + @Override + public RequestItemAuthor getRequestItemAuthor(Context context, Item item) + throws SQLException { + EPerson submitter = item.getSubmitter(); + RequestItemAuthor author = new RequestItemAuthor( + submitter.getFullName(), submitter.getEmail()); + return author; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/dao/RequestItemDAO.java b/dspace-api/src/main/java/org/dspace/app/requestitem/dao/RequestItemDAO.java index 386ded0bab..74caa16d0e 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/dao/RequestItemDAO.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/dao/RequestItemDAO.java @@ -7,15 +7,16 @@ */ package org.dspace.app.requestitem.dao; +import java.sql.SQLException; + import org.dspace.app.requestitem.RequestItem; import org.dspace.core.Context; import org.dspace.core.GenericDAO; -import java.sql.SQLException; - /** * Database Access Object interface class for the RequestItem object. - * The implementation of this class is responsible for all database calls for the RequestItem object and is autowired by spring + * The implementation of this class is responsible for all database calls for the RequestItem object and is autowired + * by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java index 76a1083a9d..351f40ae13 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java @@ -7,14 +7,16 @@ */ package org.dspace.app.requestitem.dao.impl; -import org.dspace.app.requestitem.RequestItem; -import org.dspace.app.requestitem.dao.RequestItemDAO; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.app.requestitem.RequestItem; +import org.dspace.app.requestitem.RequestItem_; +import org.dspace.app.requestitem.dao.RequestItemDAO; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; /** * Hibernate implementation of the Database Access Object interface class for the RequestItem object. @@ -23,18 +25,19 @@ import java.sql.SQLException; * * @author kevinvandevelde at atmire.com */ -public class RequestItemDAOImpl extends AbstractHibernateDAO implements RequestItemDAO -{ - protected RequestItemDAOImpl() - { +public class RequestItemDAOImpl extends AbstractHibernateDAO implements RequestItemDAO { + protected RequestItemDAOImpl() { super(); } @Override public RequestItem findByToken(Context context, String token) throws SQLException { - Criteria criteria = createCriteria(context, RequestItem.class); - criteria.add(Restrictions.eq("token", token)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RequestItem.class); + Root requestItemRoot = criteriaQuery.from(RequestItem.class); + criteriaQuery.select(requestItemRoot); + criteriaQuery.where(criteriaBuilder.equal(requestItemRoot.get(RequestItem_.token), token)); + return uniqueResult(context, criteriaQuery, false, RequestItem.class, -1, -1); } diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/factory/RequestItemServiceFactory.java b/dspace-api/src/main/java/org/dspace/app/requestitem/factory/RequestItemServiceFactory.java index 3108de992e..e3c18239fd 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/factory/RequestItemServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/factory/RequestItemServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.app.requestitem.service.RequestItemService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the requestitem package, use RequestItemServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the requestitem package, use RequestItemServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class RequestItemServiceFactory { public abstract RequestItemService getRequestItemService(); - public static RequestItemServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("requestItemServiceFactory", RequestItemServiceFactory.class); + public static RequestItemServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("requestItemServiceFactory", RequestItemServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/factory/RequestItemServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/app/requestitem/factory/RequestItemServiceFactoryImpl.java index b402d05b97..b908a4c956 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/factory/RequestItemServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/factory/RequestItemServiceFactoryImpl.java @@ -8,11 +8,11 @@ package org.dspace.app.requestitem.factory; import org.dspace.app.requestitem.service.RequestItemService; -import org.dspace.handle.service.HandleService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the requestitem package, use RequestItemServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the requestitem package, use RequestItemServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/service/RequestItemService.java b/dspace-api/src/main/java/org/dspace/app/requestitem/service/RequestItemService.java index 92876c5dba..43e1a0201a 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/service/RequestItemService.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/service/RequestItemService.java @@ -16,7 +16,8 @@ import org.dspace.core.Context; /** * Service interface class for the RequestItem object. - * The implementation of this class is responsible for all business logic calls for the RequestItem object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the RequestItem object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -24,38 +25,31 @@ public interface RequestItemService { /** * Generate a request item representing the request and put it into the DB - * @param context - * The relevant DSpace Context. - * @param bitstream - * The requested bitstream - * @param item - * The requested item - * @param reqMessage - * Request message text - * @param allFiles - * true indicates that all bitstreams of this item are requested - * @param reqEmail email - * Requester email - * @param reqName - * Requester name + * + * @param context The relevant DSpace Context. + * @param bitstream The requested bitstream + * @param item The requested item + * @param reqMessage Request message text + * @param allFiles true indicates that all bitstreams of this item are requested + * @param reqEmail email + * Requester email + * @param reqName Requester name * @return the token of the request item * @throws SQLException if database error */ - public String createRequest(Context context, Bitstream bitstream, Item item, boolean allFiles, String reqEmail, String reqName, String reqMessage) - throws SQLException; + public String createRequest(Context context, Bitstream bitstream, Item item, boolean allFiles, String reqEmail, + String reqName, String reqMessage) + throws SQLException; public RequestItem findByToken(Context context, String token); /** * Save updates to the record. Only accept_request, and decision_date are set-able. * - * @param context - * The relevant DSpace Context. - * @param requestItem - * requested item + * @param context The relevant DSpace Context. + * @param requestItem requested item */ public void update(Context context, RequestItem requestItem); - } diff --git a/dspace-api/src/main/java/org/dspace/app/sfx/SFXFileReaderServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/sfx/SFXFileReaderServiceImpl.java index 2bef54187a..8d58347bc5 100644 --- a/dspace-api/src/main/java/org/dspace/app/sfx/SFXFileReaderServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/sfx/SFXFileReaderServiceImpl.java @@ -11,23 +11,20 @@ import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.util.List; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.sfx.service.SFXFileReaderService; -import org.dspace.content.MetadataValue; -import org.dspace.content.service.ItemService; -import org.springframework.beans.factory.annotation.Autowired; -import org.w3c.dom.Document; - import org.dspace.content.DCPersonName; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.service.ItemService; import org.dspace.core.Constants; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.ParserConfigurationException; - +import org.springframework.beans.factory.annotation.Autowired; +import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -78,8 +75,7 @@ public class SFXFileReaderServiceImpl implements SFXFileReaderService { } @Override - public Document parseFile(String fileName) - { + public Document parseFile(String fileName) { log.info("Parsing XML file... " + fileName); DocumentBuilder docBuilder; Document doc = null; @@ -178,7 +174,8 @@ public class SFXFileReaderServiceImpl implements SFXFileReaderService { } } if (finish == 4) { - List dcvalue = itemService.getMetadata(item, schema, element, qualifier, Item.ANY); + List dcvalue = itemService + .getMetadata(item, schema, element, qualifier, Item.ANY); if (dcvalue.size() > 0) { // Issued Date if (element.equals("date") && qualifier.equals("issued")) { @@ -190,7 +187,8 @@ public class SFXFileReaderServiceImpl implements SFXFileReaderService { if (myquery.equals("")) { myquery = querystring + URLEncoder.encode(fullDate, Constants.DEFAULT_ENCODING); } else { - myquery = myquery + "&" + querystring + URLEncoder.encode(fullDate, Constants.DEFAULT_ENCODING); + myquery = myquery + "&" + querystring + URLEncoder + .encode(fullDate, Constants.DEFAULT_ENCODING); } } else { // Contributor Author @@ -209,13 +207,16 @@ public class SFXFileReaderServiceImpl implements SFXFileReaderService { if (myquery.equals("")) { myquery = querystring + URLEncoder.encode(dpnName, Constants.DEFAULT_ENCODING); } else { - myquery = myquery + "&" + querystring + URLEncoder.encode(dpnName, Constants.DEFAULT_ENCODING); + myquery = myquery + "&" + querystring + URLEncoder + .encode(dpnName, Constants.DEFAULT_ENCODING); } } else { if (myquery.equals("")) { - myquery = querystring + URLEncoder.encode(dcvalue.get(0).getValue(), Constants.DEFAULT_ENCODING); + myquery = querystring + URLEncoder + .encode(dcvalue.get(0).getValue(), Constants.DEFAULT_ENCODING); } else { - myquery = myquery + "&" + querystring + URLEncoder.encode(dcvalue.get(0).getValue(), Constants.DEFAULT_ENCODING); + myquery = myquery + "&" + querystring + URLEncoder + .encode(dcvalue.get(0).getValue(), Constants.DEFAULT_ENCODING); } } } diff --git a/dspace-api/src/main/java/org/dspace/app/sfx/factory/SfxServiceFactory.java b/dspace-api/src/main/java/org/dspace/app/sfx/factory/SfxServiceFactory.java index c7a49a5a64..365d2e4abb 100644 --- a/dspace-api/src/main/java/org/dspace/app/sfx/factory/SfxServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/app/sfx/factory/SfxServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.app.sfx.service.SFXFileReaderService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the sfx package, use SfxServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the sfx package, use SfxServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -19,7 +20,8 @@ public abstract class SfxServiceFactory { public abstract SFXFileReaderService getSfxFileReaderService(); - public static SfxServiceFactory getInstance(){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("sfxServiceFactory", SfxServiceFactory.class); + public static SfxServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("sfxServiceFactory", SfxServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/app/sfx/factory/SfxServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/app/sfx/factory/SfxServiceFactoryImpl.java index aa8520a010..4576cd05da 100644 --- a/dspace-api/src/main/java/org/dspace/app/sfx/factory/SfxServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/sfx/factory/SfxServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.app.sfx.service.SFXFileReaderService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the sfx package, use SfxServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the sfx package, use SfxServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/app/sfx/service/SFXFileReaderService.java b/dspace-api/src/main/java/org/dspace/app/sfx/service/SFXFileReaderService.java index 820abe4a97..4be2750f88 100644 --- a/dspace-api/src/main/java/org/dspace/app/sfx/service/SFXFileReaderService.java +++ b/dspace-api/src/main/java/org/dspace/app/sfx/service/SFXFileReaderService.java @@ -7,12 +7,12 @@ */ package org.dspace.app.sfx.service; +import java.io.IOException; + import org.dspace.content.Item; import org.w3c.dom.Document; import org.w3c.dom.Node; -import java.io.IOException; - /** * XML configuration file reader for DSpace metadata fields (DC) mapping * to OpenURL parameters. @@ -33,14 +33,15 @@ public interface SFXFileReaderService { * Loads the SFX configuration file * * @param fileName The name of the SFX configuration file - * @param item The item to process, from which metadata values will be taken - * + * @param item The item to process, from which metadata values will be taken * @return the SFX string * @throws IOException if IO error */ public String loadSFXFile(String fileName, Item item) throws IOException; - /** Parses XML file and returns XML document. + /** + * Parses XML file and returns XML document. + * * @param fileName XML file to parse * @return XML document or null if error occurred. The error is caught and logged. */ @@ -67,6 +68,7 @@ public interface SFXFileReaderService { /** * Is Empty text Node * + * * @param nd node * @return true or false */ @@ -74,7 +76,8 @@ public interface SFXFileReaderService { /** * Returns the value of the node's attribute named {@code } - * @param e node + * + * @param e node * @param name name * @return value */ @@ -83,8 +86,9 @@ public interface SFXFileReaderService { /** * Returns the value found in the Text node (if any) in the * node list that's passed in. + * * @param node node * @return value */ public String getValue(Node node); -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAJournal.java b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAJournal.java index 67f358b042..d405887da5 100644 --- a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAJournal.java +++ b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAJournal.java @@ -9,12 +9,10 @@ package org.dspace.app.sherpa; /** * POJO representation for a SHERPA journal - * + * * @author Andrea Bollini - * */ -public class SHERPAJournal -{ +public class SHERPAJournal { private String title; private String issn; @@ -24,8 +22,7 @@ public class SHERPAJournal private String romeopub; public SHERPAJournal(String title, String issn, String zetopub, - String romeopub) - { + String romeopub) { super(); this.title = title; this.issn = issn; @@ -33,23 +30,19 @@ public class SHERPAJournal this.romeopub = romeopub; } - public String getTitle() - { + public String getTitle() { return title; } - public String getIssn() - { + public String getIssn() { return issn; } - public String getZetopub() - { + public String getZetopub() { return zetopub; } - public String getRomeopub() - { + public String getRomeopub() { return romeopub; } diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAPublisher.java b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAPublisher.java index a1b4fd6add..3af4572faa 100644 --- a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAPublisher.java +++ b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAPublisher.java @@ -11,12 +11,10 @@ import java.util.List; /** * POJO representation for a SHERPA Publisher record - * + * * @author Andrea Bollini - * */ -public class SHERPAPublisher -{ +public class SHERPAPublisher { private String name; private String alias; @@ -34,7 +32,7 @@ public class SHERPAPublisher private String pubarchiving; private List pubrestriction; - + private List condition; private String paidaccessurl; @@ -52,14 +50,13 @@ public class SHERPAPublisher private String dateupdated; public SHERPAPublisher(String name, String alias, String homeurl, - String prearchiving, List prerestriction, - String postarchiving, List postrestriction, - String pubarchiving, List pubrestriction, - List condition, String paidaccessurl, - String paidaccessname, String paidaccessnotes, - List copyright, String romeocolour, String datedded, - String dateupdated) - { + String prearchiving, List prerestriction, + String postarchiving, List postrestriction, + String pubarchiving, List pubrestriction, + List condition, String paidaccessurl, + String paidaccessname, String paidaccessnotes, + List copyright, String romeocolour, String datedded, + String dateupdated) { this.name = name; this.alias = alias; @@ -95,88 +92,71 @@ public class SHERPAPublisher this.dateupdated = dateupdated; } - public String getName() - { + public String getName() { return name; } - public String getAlias() - { + public String getAlias() { return alias; } - public String getHomeurl() - { + public String getHomeurl() { return homeurl; } - public String getPrearchiving() - { + public String getPrearchiving() { return prearchiving; } - public List getPrerestriction() - { + public List getPrerestriction() { return prerestriction; } - public String getPostarchiving() - { + public String getPostarchiving() { return postarchiving; } - public List getPostrestriction() - { + public List getPostrestriction() { return postrestriction; } - public String getPubarchiving() - { + public String getPubarchiving() { return pubarchiving; } - - public List getPubrestriction() - { + + public List getPubrestriction() { return pubrestriction; } - - public List getCondition() - { + + public List getCondition() { return condition; } - public String getPaidaccessurl() - { + public String getPaidaccessurl() { return paidaccessurl; } - public String getPaidaccessname() - { + public String getPaidaccessname() { return paidaccessname; } - public String getPaidaccessnotes() - { + public String getPaidaccessnotes() { return paidaccessnotes; } - public List getCopyright() - { + public List getCopyright() { return copyright; } - public String getRomeocolour() - { + public String getRomeocolour() { return romeocolour; } - public String getDatedded() - { + public String getDatedded() { return dateadded; } - public String getDateupdated() - { + public String getDateupdated() { return dateupdated; } diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAResponse.java b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAResponse.java index 87148ed8ea..2384225562 100644 --- a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAResponse.java +++ b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAResponse.java @@ -10,7 +10,6 @@ package org.dspace.app.sherpa; import java.io.InputStream; import java.util.LinkedList; import java.util.List; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -21,12 +20,10 @@ import org.w3c.dom.Element; /** * JAVA representation for a SHERPA API Response - * + * * @author Andrea Bollini - * */ -public class SHERPAResponse -{ +public class SHERPAResponse { private boolean error; private String message; @@ -41,12 +38,10 @@ public class SHERPAResponse private List publishers; - public SHERPAResponse(InputStream xmlData) - { - try - { + public SHERPAResponse(InputStream xmlData) { + try { DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -56,16 +51,15 @@ public class SHERPAResponse Element xmlRoot = inDoc.getDocumentElement(); Element headersElement = XMLUtils.getSingleElement(xmlRoot, - "header"); + "header"); Element journalsElement = XMLUtils.getSingleElement(xmlRoot, - "journals"); + "journals"); Element publishersElement = XMLUtils.getSingleElement(xmlRoot, - "publishers"); + "publishers"); message = XMLUtils.getElementValue(headersElement, "message"); - if (StringUtils.isNotBlank(message)) - { + if (StringUtils.isNotBlank(message)) { error = true; return; } @@ -75,147 +69,133 @@ public class SHERPAResponse disclaimer = XMLUtils.getElementValue(headersElement, "disclaimer"); List journalsList = XMLUtils.getElementList( - journalsElement, "journal"); + journalsElement, "journal"); List publishersList = XMLUtils.getElementList( - publishersElement, "publisher"); + publishersElement, "publisher"); - if (journalsList != null) - { + if (journalsList != null) { journals = new LinkedList(); - for (Element journalElement : journalsList) - { + for (Element journalElement : journalsList) { journals.add(new SHERPAJournal( - XMLUtils.getElementValue(journalElement, "jtitle"), - XMLUtils.getElementValue(journalElement, "issn"), - XMLUtils.getElementValue(journalElement, "zetopub"), - XMLUtils.getElementValue(journalElement, "romeopub"))); + XMLUtils.getElementValue(journalElement, "jtitle"), + XMLUtils.getElementValue(journalElement, "issn"), + XMLUtils.getElementValue(journalElement, "zetopub"), + XMLUtils.getElementValue(journalElement, "romeopub"))); } } - if (publishersList != null) - { + if (publishersList != null) { publishers = new LinkedList(); - for (Element publisherElement : publishersList) - { + for (Element publisherElement : publishersList) { Element preprintsElement = XMLUtils.getSingleElement( - publisherElement, "preprints"); + publisherElement, "preprints"); Element preprintsRestrictionElement = XMLUtils - .getSingleElement(publisherElement, - "prerestrictions"); + .getSingleElement(publisherElement, + "prerestrictions"); Element postprintsElement = XMLUtils.getSingleElement( - publisherElement, "postprints"); + publisherElement, "postprints"); Element postprintsRestrictionElement = XMLUtils - .getSingleElement(publisherElement, - "postrestrictions"); + .getSingleElement(publisherElement, + "postrestrictions"); Element pdfversionElement = XMLUtils.getSingleElement( - publisherElement, "pdfversion"); + publisherElement, "pdfversion"); Element pdfversionRestrictionElement = XMLUtils - .getSingleElement(publisherElement, - "pdfrestrictions"); - + .getSingleElement(publisherElement, + "pdfrestrictions"); + Element conditionsElement = XMLUtils.getSingleElement( - publisherElement, "conditions"); + publisherElement, "conditions"); Element paidaccessElement = XMLUtils.getSingleElement( - publisherElement, "paidaccess"); + publisherElement, "paidaccess"); Element copyrightlinksElement = XMLUtils.getSingleElement( - publisherElement, "copyrightlinks"); + publisherElement, "copyrightlinks"); publishers - .add(new SHERPAPublisher(XMLUtils.getElementValue( - publisherElement, "name"), - XMLUtils.getElementValue(publisherElement, - "alias"), XMLUtils.getElementValue( - publisherElement, "homeurl"), - - XMLUtils.getElementValue(preprintsElement, - "prearchiving"), - XMLUtils.getElementValueList( - preprintsRestrictionElement, - "prerestriction"), - - XMLUtils.getElementValue(postprintsElement, - "postarchiving"), - XMLUtils.getElementValueList( - postprintsRestrictionElement, - "postrestriction"), - - XMLUtils.getElementValue(pdfversionElement, - "pdfarchiving"), - XMLUtils.getElementValueList( - pdfversionRestrictionElement, - "pdfrestriction"), - - XMLUtils - .getElementValueList( - conditionsElement, - "condition"), XMLUtils - .getElementValue(paidaccessElement, - "paidaccessurl"), XMLUtils - .getElementValue(paidaccessElement, - "paidaccessname"), XMLUtils - .getElementValue(paidaccessElement, - "paidaccessnotes"), - XMLUtils.getElementValueArrayList( - copyrightlinksElement, - "copyrightlink", - "copyrightlinktext", - "copyrightlinkurl"), XMLUtils - .getElementValue(publisherElement, - "romeocolour"), XMLUtils - .getElementValue(publisherElement, - "dateadded"), XMLUtils - .getElementValue(publisherElement, - "dateupdated"))); + .add(new SHERPAPublisher(XMLUtils.getElementValue( + publisherElement, "name"), + XMLUtils.getElementValue(publisherElement, + "alias"), XMLUtils.getElementValue( + publisherElement, "homeurl"), + + XMLUtils.getElementValue(preprintsElement, + "prearchiving"), + XMLUtils.getElementValueList( + preprintsRestrictionElement, + "prerestriction"), + + XMLUtils.getElementValue(postprintsElement, + "postarchiving"), + XMLUtils.getElementValueList( + postprintsRestrictionElement, + "postrestriction"), + + XMLUtils.getElementValue(pdfversionElement, + "pdfarchiving"), + XMLUtils.getElementValueList( + pdfversionRestrictionElement, + "pdfrestriction"), + + XMLUtils + .getElementValueList( + conditionsElement, + "condition"), XMLUtils + .getElementValue(paidaccessElement, + "paidaccessurl"), XMLUtils + .getElementValue(paidaccessElement, + "paidaccessname"), XMLUtils + .getElementValue(paidaccessElement, + "paidaccessnotes"), + XMLUtils.getElementValueArrayList( + copyrightlinksElement, + "copyrightlink", + "copyrightlinktext", + "copyrightlinkurl"), XMLUtils + .getElementValue(publisherElement, + "romeocolour"), XMLUtils + .getElementValue(publisherElement, + "dateadded"), XMLUtils + .getElementValue(publisherElement, + "dateupdated"))); } } - } - catch (Exception e) - { + } catch (Exception e) { error = true; } } - public SHERPAResponse(String message) - { + public SHERPAResponse(String message) { this.message = message; this.error = true; } - public boolean isError() - { + public boolean isError() { return error; } - public String getMessage() - { + public String getMessage() { return message; } - public String getLicense() - { + public String getLicense() { return license; } - public String getLicenseURL() - { + public String getLicenseURL() { return licenseURL; } - public String getDisclaimer() - { + public String getDisclaimer() { return disclaimer; } - public List getJournals() - { + public List getJournals() { return journals; } - public List getPublishers() - { + public List getPublishers() { return publishers; } } diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAService.java b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAService.java index 4b3a0aeea8..d1680a687d 100644 --- a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAService.java +++ b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAService.java @@ -19,29 +19,30 @@ import org.apache.http.impl.client.HttpClientBuilder; import org.apache.log4j.Logger; import org.dspace.core.ConfigurationManager; -public class SHERPAService -{ +public class SHERPAService { private CloseableHttpClient client = null; private int maxNumberOfTries; private long sleepBetweenTimeouts; private int timeout = 5000; - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(SHERPAService.class); public SHERPAService() { HttpClientBuilder builder = HttpClientBuilder.create(); - // httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as not to hammer the SHERPA service too much. + // httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as + // not to hammer the SHERPA service too much. client = builder - .disableAutomaticRetries() - .setMaxConnTotal(5) - .build(); + .disableAutomaticRetries() + .setMaxConnTotal(5) + .build(); } - public SHERPAResponse searchByJournalISSN(String query) - { + public SHERPAResponse searchByJournalISSN(String query) { String endpoint = ConfigurationManager.getProperty("sherpa.romeo.url"); String apiKey = ConfigurationManager.getProperty("sherpa.romeo.apikey"); @@ -49,16 +50,16 @@ public class SHERPAService SHERPAResponse sherpaResponse = null; int numberOfTries = 0; - while(numberOfTries getISSNs(Context context, Item item); } diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/submit/MetadataAuthorityISSNExtractor.java b/dspace-api/src/main/java/org/dspace/app/sherpa/submit/MetadataAuthorityISSNExtractor.java index f068c36175..a08b4d9502 100644 --- a/dspace-api/src/main/java/org/dspace/app/sherpa/submit/MetadataAuthorityISSNExtractor.java +++ b/dspace-api/src/main/java/org/dspace/app/sherpa/submit/MetadataAuthorityISSNExtractor.java @@ -10,35 +10,30 @@ package org.dspace.app.sherpa.submit; import java.util.ArrayList; import java.util.List; -import org.dspace.content.MetadataValue; 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; -public class MetadataAuthorityISSNExtractor implements ISSNItemExtractor -{ +public class MetadataAuthorityISSNExtractor implements ISSNItemExtractor { @Autowired(required = true) public ItemService itemService; private List metadataList; - public void setMetadataList(List metadataList) - { + public void setMetadataList(List metadataList) { this.metadataList = metadataList; } @Override - public List getISSNs(Context context, Item item) - { + public List getISSNs(Context context, Item item) { List values = new ArrayList(); - for (String metadata : metadataList) - { + for (String metadata : metadataList) { List dcvalues = itemService.getMetadataByMetadataString(item, metadata); - for (MetadataValue dcvalue : dcvalues) - { + for (MetadataValue dcvalue : dcvalues) { String authority = dcvalue.getAuthority(); - if(authority !=null){ + if (authority != null) { values.add(authority); } } diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/submit/MetadataValueISSNExtractor.java b/dspace-api/src/main/java/org/dspace/app/sherpa/submit/MetadataValueISSNExtractor.java index 786f399418..6ed0e4fc9b 100644 --- a/dspace-api/src/main/java/org/dspace/app/sherpa/submit/MetadataValueISSNExtractor.java +++ b/dspace-api/src/main/java/org/dspace/app/sherpa/submit/MetadataValueISSNExtractor.java @@ -10,33 +10,28 @@ package org.dspace.app.sherpa.submit; import java.util.ArrayList; import java.util.List; -import org.dspace.content.MetadataValue; 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; -public class MetadataValueISSNExtractor implements ISSNItemExtractor -{ +public class MetadataValueISSNExtractor implements ISSNItemExtractor { @Autowired(required = true) public ItemService itemService; private List metadataList; - public void setMetadataList(List metadataList) - { + public void setMetadataList(List metadataList) { this.metadataList = metadataList; } @Override - public List getISSNs(Context context, Item item) - { + public List getISSNs(Context context, Item item) { List values = new ArrayList(); - for (String metadata : metadataList) - { + for (String metadata : metadataList) { List dcvalues = itemService.getMetadataByMetadataString(item, metadata); - for (MetadataValue dcvalue : dcvalues) - { + for (MetadataValue dcvalue : dcvalues) { values.add(dcvalue.getValue()); } } diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/submit/SHERPASubmitConfigurationService.java b/dspace-api/src/main/java/org/dspace/app/sherpa/submit/SHERPASubmitConfigurationService.java index 071c4d03d1..69447fd8c6 100644 --- a/dspace-api/src/main/java/org/dspace/app/sherpa/submit/SHERPASubmitConfigurationService.java +++ b/dspace-api/src/main/java/org/dspace/app/sherpa/submit/SHERPASubmitConfigurationService.java @@ -9,17 +9,14 @@ package org.dspace.app.sherpa.submit; import java.util.List; -public class SHERPASubmitConfigurationService -{ +public class SHERPASubmitConfigurationService { private List issnItemExtractors; - public void setIssnItemExtractors(List issnItemExtractors) - { + public void setIssnItemExtractors(List issnItemExtractors) { this.issnItemExtractors = issnItemExtractors; } - - public List getIssnItemExtractors() - { + + public List getIssnItemExtractors() { return issnItemExtractors; } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/submit/SHERPASubmitService.java b/dspace-api/src/main/java/org/dspace/app/sherpa/submit/SHERPASubmitService.java index d87d809477..732c606ae8 100644 --- a/dspace-api/src/main/java/org/dspace/app/sherpa/submit/SHERPASubmitService.java +++ b/dspace-api/src/main/java/org/dspace/app/sherpa/submit/SHERPASubmitService.java @@ -19,59 +19,48 @@ import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.core.LogManager; -public class SHERPASubmitService -{ +public class SHERPASubmitService { private SHERPAService sherpaService; private SHERPASubmitConfigurationService configuration; - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(SHERPASubmitService.class); - public void setConfiguration(SHERPASubmitConfigurationService configuration) - { + public void setConfiguration(SHERPASubmitConfigurationService configuration) { this.configuration = configuration; } - public void setSherpaService(SHERPAService sherpaService) - { + public void setSherpaService(SHERPAService sherpaService) { this.sherpaService = sherpaService; } - public SHERPAResponse searchRelatedJournals(Context context, Item item) - { + public SHERPAResponse searchRelatedJournals(Context context, Item item) { Set issns = getISSNs(context, item); - if (issns == null || issns.size() == 0) - { + if (issns == null || issns.size() == 0) { return null; - } - else - { + } else { return sherpaService.searchByJournalISSN(StringUtils.join(issns, ",")); } } - public SHERPAResponse searchRelatedJournalsByISSN(String issn) - { + public SHERPAResponse searchRelatedJournalsByISSN(String issn) { return sherpaService.searchByJournalISSN(issn); } - public Set getISSNs(Context context, Item item) - { + public Set getISSNs(Context context, Item item) { Set issns = new LinkedHashSet(); - if (configuration.getIssnItemExtractors() == null) - { + if (configuration.getIssnItemExtractors() == null) { log.warn(LogManager.getHeader(context, "searchRelatedJournals", - "no issnItemExtractors defined")); + "no issnItemExtractors defined")); return null; } - for (ISSNItemExtractor extractor : configuration.getIssnItemExtractors()) - { + for (ISSNItemExtractor extractor : configuration.getIssnItemExtractors()) { List eIssns = extractor.getISSNs(context, item); - if (eIssns != null) - { - for (String eIssn : eIssns) - { + if (eIssns != null) { + for (String eIssn : eIssns) { issns.add(eIssn.trim()); } } @@ -79,15 +68,11 @@ public class SHERPASubmitService return issns; } - public boolean hasISSNs(Context context, Item item) - { + public boolean hasISSNs(Context context, Item item) { Set issns = getISSNs(context, item); - if (issns == null || issns.size() == 0) - { + if (issns == null || issns.size() == 0) { return false; - } - else - { + } else { return true; } } diff --git a/dspace-api/src/main/java/org/dspace/app/sitemap/AbstractGenerator.java b/dspace-api/src/main/java/org/dspace/app/sitemap/AbstractGenerator.java index 8891943d08..3089af285a 100644 --- a/dspace-api/src/main/java/org/dspace/app/sitemap/AbstractGenerator.java +++ b/dspace-api/src/main/java/org/dspace/app/sitemap/AbstractGenerator.java @@ -36,35 +36,44 @@ import java.util.zip.GZIPOutputStream; * * @author Robert Tansley */ -public abstract class AbstractGenerator -{ - /** Number of files written so far */ +public abstract class AbstractGenerator { + /** + * Number of files written so far + */ protected int fileCount; - /** Number of bytes written to current file */ + /** + * Number of bytes written to current file + */ protected int bytesWritten; - /** Number of URLs written to current file */ + /** + * Number of URLs written to current file + */ protected int urlsWritten; - /** Directory files are written to */ + /** + * Directory files are written to + */ protected File outputDir; - /** Current output */ + /** + * Current output + */ protected PrintStream currentOutput; - /** Size in bytes of trailing boilerplate */ + /** + * Size in bytes of trailing boilerplate + */ private int trailingByteCount; /** * Initialize this generator to write to the given directory. This must be * called by any subclass constructor. * - * @param outputDirIn - * directory to write sitemap files to + * @param outputDirIn directory to write sitemap files to */ - public AbstractGenerator(File outputDirIn) - { + public AbstractGenerator(File outputDirIn) { fileCount = 0; outputDir = outputDirIn; trailingByteCount = getTrailingBoilerPlate().length(); @@ -75,17 +84,15 @@ public abstract class AbstractGenerator * Start writing a new sitemap file. * * @throws IOException if IO error - * if an error occurs creating the file + * if an error occurs creating the file */ - protected void startNewFile() throws IOException - { + protected void startNewFile() throws IOException { String lbp = getLeadingBoilerPlate(); OutputStream fo = new FileOutputStream(new File(outputDir, - getFilename(fileCount))); + getFilename(fileCount))); - if (useCompression()) - { + if (useCompression()) { fo = new GZIPOutputStream(fo); } @@ -98,26 +105,21 @@ public abstract class AbstractGenerator /** * Add the given URL to the sitemap. * - * @param url - * Full URL to add - * @param lastMod - * Date URL was last modified, or {@code null} + * @param url Full URL to add + * @param lastMod Date URL was last modified, or {@code null} * @throws IOException if IO error - * if an error occurs writing + * if an error occurs writing */ - public void addURL(String url, Date lastMod) throws IOException - { + public void addURL(String url, Date lastMod) throws IOException { // Kick things off if this is the first call - if (currentOutput == null) - { + if (currentOutput == null) { startNewFile(); } String newURLText = getURLText(url, lastMod); if (bytesWritten + newURLText.length() + trailingByteCount > getMaxSize() - || urlsWritten + 1 > getMaxURLs()) - { + || urlsWritten + 1 > getMaxURLs()) { closeCurrentFile(); startNewFile(); } @@ -131,10 +133,9 @@ public abstract class AbstractGenerator * Finish with the current sitemap file. * * @throws IOException if IO error - * if an error occurs writing + * if an error occurs writing */ - protected void closeCurrentFile() throws IOException - { + protected void closeCurrentFile() throws IOException { currentOutput.print(getTrailingBoilerPlate()); currentOutput.close(); fileCount++; @@ -146,22 +147,18 @@ public abstract class AbstractGenerator * been completed, and invalidates the generator. * * @return number of sitemap files written. - * * @throws IOException if IO error - * if an error occurs writing + * if an error occurs writing */ - public int finish() throws IOException - { - if (null != currentOutput) - { + public int finish() throws IOException { + if (null != currentOutput) { closeCurrentFile(); } OutputStream fo = new FileOutputStream(new File(outputDir, - getIndexFilename())); + getIndexFilename())); - if (useCompression()) - { + if (useCompression()) { fo = new GZIPOutputStream(fo); } @@ -175,11 +172,9 @@ public abstract class AbstractGenerator /** * Return marked-up text to be included in a sitemap about a given URL. * - * @param url - * URL to add information about - * @param lastMod - * date URL was last modified, or {@code null} if unknown or not - * applicable + * @param url URL to add information about + * @param lastMod date URL was last modified, or {@code null} if unknown or not + * applicable * @return the mark-up to include */ public abstract String getURLText(String url, Date lastMod); @@ -219,15 +214,14 @@ public abstract class AbstractGenerator * GZIP-compressed. * * @return {@code true} if GZIP compression should be used, {@code false} - * otherwise. + * otherwise. */ public abstract boolean useCompression(); /** * Return the filename a sitemap at the given index should be stored at. * - * @param number - * index of the sitemap file (zero is first). + * @param number index of the sitemap file (zero is first). * @return the filename to write the sitemap to. */ public abstract String getFilename(int number); @@ -242,13 +236,11 @@ public abstract class AbstractGenerator /** * Write the index file. * - * @param output - * stream to write the index to - * @param sitemapCount - * number of sitemaps that were generated + * @param output stream to write the index to + * @param sitemapCount number of sitemaps that were generated * @throws IOException if IO error - * if an IO error occurs + * if an IO error occurs */ public abstract void writeIndex(PrintStream output, int sitemapCount) - throws IOException; + throws IOException; } diff --git a/dspace-api/src/main/java/org/dspace/app/sitemap/GenerateSitemaps.java b/dspace-api/src/main/java/org/dspace/app/sitemap/GenerateSitemaps.java index 5cdfac88d6..9c0640e072 100644 --- a/dspace-api/src/main/java/org/dspace/app/sitemap/GenerateSitemaps.java +++ b/dspace-api/src/main/java/org/dspace/app/sitemap/GenerateSitemaps.java @@ -7,7 +7,26 @@ */ package org.dspace.app.sitemap; -import org.apache.commons.cli.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.sql.SQLException; +import java.util.Date; +import java.util.Iterator; +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.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -23,34 +42,31 @@ import org.dspace.core.LogManager; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLEncoder; -import java.sql.SQLException; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - /** * Command-line utility for generating HTML and Sitemaps.org protocol Sitemaps. - * + * * @author Robert Tansley * @author Stuart Lewis */ -public class GenerateSitemaps -{ - /** Logger */ +public class GenerateSitemaps { + /** + * Logger + */ private static Logger log = Logger.getLogger(GenerateSitemaps.class); private static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final CollectionService collectionService = + ContentServiceFactory.getInstance().getCollectionService(); private static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - private static final ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + private static final ConfigurationService configurationService = + DSpaceServicesFactory.getInstance().getConfigurationService(); - public static void main(String[] args) throws Exception - { + /** + * Default constructor + */ + private GenerateSitemaps() { } + + public static void main(String[] args) throws Exception { final String usage = GenerateSitemaps.class.getCanonicalName(); CommandLineParser parser = new PosixParser(); @@ -60,35 +76,30 @@ public class GenerateSitemaps options.addOption("h", "help", false, "help"); options.addOption("s", "no_sitemaps", false, - "do not generate sitemaps.org protocol sitemap"); + "do not generate sitemaps.org protocol sitemap"); options.addOption("b", "no_htmlmap", false, - "do not generate a basic HTML sitemap"); + "do not generate a basic HTML sitemap"); options.addOption("a", "ping_all", false, - "ping configured search engines"); + "ping configured search engines"); options - .addOption("p", "ping", true, - "ping specified search engine URL"); + .addOption("p", "ping", true, + "ping specified search engine URL"); CommandLine line = null; - try - { + try { line = parser.parse(options, args); - } - catch (ParseException pe) - { + } catch (ParseException pe) { hf.printHelp(usage, options); System.exit(1); } - if (line.hasOption('h')) - { + if (line.hasOption('h')) { hf.printHelp(usage, options); System.exit(0); } - if (line.getArgs().length != 0) - { + if (line.getArgs().length != 0) { hf.printHelp(usage, options); System.exit(1); } @@ -98,37 +109,30 @@ public class GenerateSitemaps * usage */ if (line.getArgs().length != 0 || line.hasOption('b') - && line.hasOption('s') && !line.hasOption('g') - && !line.hasOption('m') && !line.hasOption('y') - && !line.hasOption('p')) - { + && line.hasOption('s') && !line.hasOption('g') + && !line.hasOption('m') && !line.hasOption('y') + && !line.hasOption('p')) { System.err - .println("Nothing to do (no sitemap to generate, no search engines to ping)"); + .println("Nothing to do (no sitemap to generate, no search engines to ping)"); hf.printHelp(usage, options); System.exit(1); } // Note the negation (CLI options indicate NOT to generate a sitemap) - if (!line.hasOption('b') || !line.hasOption('s')) - { + if (!line.hasOption('b') || !line.hasOption('s')) { generateSitemaps(!line.hasOption('b'), !line.hasOption('s')); } - if (line.hasOption('a')) - { + if (line.hasOption('a')) { pingConfiguredSearchEngines(); } - if (line.hasOption('p')) - { - try - { + if (line.hasOption('p')) { + try { pingSearchEngine(line.getOptionValue('p')); - } - catch (MalformedURLException me) - { + } catch (MalformedURLException me) { System.err - .println("Bad search engine URL (include all except sitemap URL)"); + .println("Bad search engine URL (include all except sitemap URL)"); System.exit(1); } } @@ -138,45 +142,39 @@ public class GenerateSitemaps /** * Generate sitemap.org protocol and/or basic HTML sitemaps. - * - * @param makeHTMLMap - * if {@code true}, generate an HTML sitemap. - * @param makeSitemapOrg - * if {@code true}, generate an sitemap.org sitemap. + * + * @param makeHTMLMap if {@code true}, generate an HTML sitemap. + * @param makeSitemapOrg if {@code true}, generate an sitemap.org sitemap. * @throws SQLException if database error - * if a database error occurs. - * @throws IOException if IO error - * if IO error occurs. + * if a database error occurs. + * @throws IOException if IO error + * if IO error occurs. */ public static void generateSitemaps(boolean makeHTMLMap, - boolean makeSitemapOrg) throws SQLException, IOException - { + boolean makeSitemapOrg) throws SQLException, IOException { String sitemapStem = configurationService.getProperty("dspace.url") - + "/sitemap"; + + "/sitemap"; String htmlMapStem = configurationService.getProperty("dspace.url") - + "/htmlmap"; + + "/htmlmap"; String handleURLStem = configurationService.getProperty("dspace.url") - + "/handle/"; + + "/handle/"; File outputDir = new File(configurationService.getProperty("sitemap.dir")); - if (!outputDir.exists() && !outputDir.mkdir()) - { + if (!outputDir.exists() && !outputDir.mkdir()) { log.error("Unable to create output directory"); } - + AbstractGenerator html = null; AbstractGenerator sitemapsOrg = null; - if (makeHTMLMap) - { + if (makeHTMLMap) { html = new HTMLSitemapGenerator(outputDir, htmlMapStem + "?map=", - null); + null); } - if (makeSitemapOrg) - { + if (makeSitemapOrg) { sitemapsOrg = new SitemapsOrgGenerator(outputDir, sitemapStem - + "?map=", null); + + "?map=", null); } Context c = new Context(Context.Mode.READ_ONLY); @@ -214,18 +212,15 @@ public class GenerateSitemaps Iterator allItems = itemService.findAll(c); int itemCount = 0; - while (allItems.hasNext()) - { + while (allItems.hasNext()) { Item i = allItems.next(); String url = handleURLStem + i.getHandle(); Date lastMod = i.getLastModified(); - if (makeHTMLMap) - { + if (makeHTMLMap) { html.addURL(url, lastMod); } - if (makeSitemapOrg) - { + if (makeSitemapOrg) { sitemapsOrg.addURL(url, lastMod); } @@ -234,22 +229,20 @@ public class GenerateSitemaps itemCount++; } - if (makeHTMLMap) - { + if (makeHTMLMap) { int files = html.finish(); log.info(LogManager.getHeader(c, "write_sitemap", - "type=html,num_files=" + files + ",communities=" - + comms.size() + ",collections=" + colls.size() - + ",items=" + itemCount)); + "type=html,num_files=" + files + ",communities=" + + comms.size() + ",collections=" + colls.size() + + ",items=" + itemCount)); } - if (makeSitemapOrg) - { + if (makeSitemapOrg) { int files = sitemapsOrg.finish(); log.info(LogManager.getHeader(c, "write_sitemap", - "type=html,num_files=" + files + ",communities=" - + comms.size() + ",collections=" + colls.size() - + ",items=" + itemCount)); + "type=html,num_files=" + files + ",communities=" + + comms.size() + ",collections=" + colls.size() + + ",items=" + itemCount)); } c.abort(); @@ -257,94 +250,75 @@ public class GenerateSitemaps /** * Ping all search engines configured in {@code dspace.cfg}. - * - * @throws UnsupportedEncodingException - * theoretically should never happen + * + * @throws UnsupportedEncodingException theoretically should never happen */ public static void pingConfiguredSearchEngines() - throws UnsupportedEncodingException - { + throws UnsupportedEncodingException { String[] engineURLs = configurationService - .getArrayProperty("sitemap.engineurls"); - - if (ArrayUtils.isEmpty(engineURLs)) - { + .getArrayProperty("sitemap.engineurls"); + + if (ArrayUtils.isEmpty(engineURLs)) { log.warn("No search engine URLs configured to ping"); return; } - for (int i = 0; i < engineURLs.length; i++) - { - try - { + for (int i = 0; i < engineURLs.length; i++) { + try { pingSearchEngine(engineURLs[i]); - } - catch (MalformedURLException me) - { + } catch (MalformedURLException me) { log.warn("Bad search engine URL in configuration: " - + engineURLs[i]); + + engineURLs[i]); } } } /** * Ping the given search engine. - * - * @param engineURL - * Search engine URL minus protocol etc, e.g. - * {@code www.google.com} - * @throws MalformedURLException - * if the passed in URL is malformed - * @throws UnsupportedEncodingException - * theoretically should never happen + * + * @param engineURL Search engine URL minus protocol etc, e.g. + * {@code www.google.com} + * @throws MalformedURLException if the passed in URL is malformed + * @throws UnsupportedEncodingException theoretically should never happen */ public static void pingSearchEngine(String engineURL) - throws MalformedURLException, UnsupportedEncodingException - { + throws MalformedURLException, UnsupportedEncodingException { // Set up HTTP proxy if ((StringUtils.isNotBlank(configurationService.getProperty("http.proxy.host"))) - && (StringUtils.isNotBlank(configurationService.getProperty("http.proxy.port")))) - { + && (StringUtils.isNotBlank(configurationService.getProperty("http.proxy.port")))) { System.setProperty("proxySet", "true"); System.setProperty("proxyHost", configurationService - .getProperty("http.proxy.host")); + .getProperty("http.proxy.host")); System.getProperty("proxyPort", configurationService - .getProperty("http.proxy.port")); + .getProperty("http.proxy.port")); } String sitemapURL = configurationService.getProperty("dspace.url") - + "/sitemap"; + + "/sitemap"; URL url = new URL(engineURL + URLEncoder.encode(sitemapURL, "UTF-8")); - try - { + try { HttpURLConnection connection = (HttpURLConnection) url - .openConnection(); + .openConnection(); BufferedReader in = new BufferedReader(new InputStreamReader( - connection.getInputStream())); + connection.getInputStream())); String inputLine; StringBuffer resp = new StringBuffer(); - while ((inputLine = in.readLine()) != null) - { + while ((inputLine = in.readLine()) != null) { resp.append(inputLine).append("\n"); } in.close(); - if (connection.getResponseCode() == 200) - { + if (connection.getResponseCode() == 200) { log.info("Pinged " + url.toString() + " successfully"); - } - else - { + } else { log.warn("Error response pinging " + url.toString() + ":\n" - + resp); + + resp); } - } - catch (IOException e) - { + } catch (IOException e) { log.warn("Error pinging " + url.toString(), e); } } diff --git a/dspace-api/src/main/java/org/dspace/app/sitemap/HTMLSitemapGenerator.java b/dspace-api/src/main/java/org/dspace/app/sitemap/HTMLSitemapGenerator.java index 3cdb20b41e..94ea0a596b 100644 --- a/dspace-api/src/main/java/org/dspace/app/sitemap/HTMLSitemapGenerator.java +++ b/dspace-api/src/main/java/org/dspace/app/sitemap/HTMLSitemapGenerator.java @@ -16,34 +16,33 @@ import java.util.Date; * Class for generating HTML "sitemaps" which contain links to various pages in * a DSpace site. This should improve search engine coverage of the DSpace site * and limit the server load caused by crawlers. - * + * * @author Robert Tansley * @author Stuart Lewis */ -public class HTMLSitemapGenerator extends AbstractGenerator -{ - /** Stem of URLs sitemaps will eventually appear at */ +public class HTMLSitemapGenerator extends AbstractGenerator { + /** + * Stem of URLs sitemaps will eventually appear at + */ protected String indexURLStem; - /** Tail of URLs sitemaps will eventually appear at */ + /** + * Tail of URLs sitemaps will eventually appear at + */ protected String indexURLTail; /** * Construct an HTML sitemap generator, writing files to the given * directory, and with the sitemaps eventually exposed at starting with the * given URL stem and tail. - * - * @param outputDirIn - * Directory to write sitemap files to - * @param urlStem - * start of URL that sitemap files will appear at, e.g. - * {@code http://dspace.myu.edu/sitemap?sitemap=} - * @param urlTail - * end of URL that sitemap files will appear at, e.g. - * {@code .html} or {@code null} + * + * @param outputDirIn Directory to write sitemap files to + * @param urlStem start of URL that sitemap files will appear at, e.g. + * {@code http://dspace.myu.edu/sitemap?sitemap=} + * @param urlTail end of URL that sitemap files will appear at, e.g. + * {@code .html} or {@code null} */ - public HTMLSitemapGenerator(File outputDirIn, String urlStem, String urlTail) - { + public HTMLSitemapGenerator(File outputDirIn, String urlStem, String urlTail) { super(outputDirIn); indexURLStem = urlStem; @@ -51,70 +50,60 @@ public class HTMLSitemapGenerator extends AbstractGenerator } @Override - public String getFilename(int number) - { + public String getFilename(int number) { return "sitemap" + number + ".html"; } @Override - public String getLeadingBoilerPlate() - { + public String getLeadingBoilerPlate() { return "\n" - + "URL List

    "; + + "URL List
      "; } @Override - public int getMaxSize() - { + public int getMaxSize() { // 50k return 51200; } @Override - public int getMaxURLs() - { + public int getMaxURLs() { return 1000; } @Override - public String getTrailingBoilerPlate() - { + public String getTrailingBoilerPlate() { return "
    \n"; } @Override - public String getURLText(String url, Date lastMod) - { + public String getURLText(String url, Date lastMod) { StringBuffer urlText = new StringBuffer(); urlText.append("
  • ").append(url) - .append("
  • \n"); + .append("\n"); return urlText.toString(); } @Override - public boolean useCompression() - { + public boolean useCompression() { return false; } @Override - public String getIndexFilename() - { + public String getIndexFilename() { return "sitemap_index.html"; } @Override public void writeIndex(PrintStream output, int sitemapCount) - throws IOException - { + throws IOException { output.println(getLeadingBoilerPlate()); - for (int i = 0; i < sitemapCount; i++) - { + for (int i = 0; i < sitemapCount; i++) { output.print("
  • sitemap " + i); + + "\">sitemap " + i); output.print("
  • \n"); } diff --git a/dspace-api/src/main/java/org/dspace/app/sitemap/SitemapsOrgGenerator.java b/dspace-api/src/main/java/org/dspace/app/sitemap/SitemapsOrgGenerator.java index 293f6425e2..9a0d5a6ba4 100644 --- a/dspace-api/src/main/java/org/dspace/app/sitemap/SitemapsOrgGenerator.java +++ b/dspace-api/src/main/java/org/dspace/app/sitemap/SitemapsOrgGenerator.java @@ -18,38 +18,39 @@ import java.util.Date; * Class for generating Sitemaps to improve * search engine coverage of the DSpace site and limit the server load caused by * crawlers. - * + * * @author Robert Tansley * @author Stuart Lewis */ -public class SitemapsOrgGenerator extends AbstractGenerator -{ - /** Stem of URLs sitemaps will eventually appear at */ +public class SitemapsOrgGenerator extends AbstractGenerator { + /** + * Stem of URLs sitemaps will eventually appear at + */ protected String indexURLStem; - /** Tail of URLs sitemaps will eventually appear at */ + /** + * Tail of URLs sitemaps will eventually appear at + */ protected String indexURLTail; - /** The correct date format */ + /** + * The correct date format + */ protected DateFormat w3dtfFormat = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss'Z'"); + "yyyy-MM-dd'T'HH:mm:ss'Z'"); /** * Construct a sitemaps.org protocol sitemap generator, writing files to the * given directory, and with the sitemaps eventually exposed at starting * with the given URL stem and tail. - * - * @param outputDirIn - * Directory to write sitemap files to - * @param urlStem - * start of URL that sitemap files will appear at, e.g. - * {@code http://dspace.myu.edu/sitemap?sitemap=} - * @param urlTail - * end of URL that sitemap files will appear at, e.g. - * {@code .html} or {@code null} + * + * @param outputDirIn Directory to write sitemap files to + * @param urlStem start of URL that sitemap files will appear at, e.g. + * {@code http://dspace.myu.edu/sitemap?sitemap=} + * @param urlTail end of URL that sitemap files will appear at, e.g. + * {@code .html} or {@code null} */ - public SitemapsOrgGenerator(File outputDirIn, String urlStem, String urlTail) - { + public SitemapsOrgGenerator(File outputDirIn, String urlStem, String urlTail) { super(outputDirIn); indexURLStem = urlStem; @@ -57,47 +58,40 @@ public class SitemapsOrgGenerator extends AbstractGenerator } @Override - public String getFilename(int number) - { + public String getFilename(int number) { return "sitemap" + number + ".xml.gz"; } @Override - public String getLeadingBoilerPlate() - { + public String getLeadingBoilerPlate() { return "\n" - + ""; + + ""; } @Override - public int getMaxSize() - { + public int getMaxSize() { // 10 Mb return 10485760; } @Override - public int getMaxURLs() - { + public int getMaxURLs() { return 50000; } @Override - public String getTrailingBoilerPlate() - { + public String getTrailingBoilerPlate() { return ""; } @Override - public String getURLText(String url, Date lastMod) - { + public String getURLText(String url, Date lastMod) { StringBuffer urlText = new StringBuffer(); urlText.append("").append(url).append(""); - if (lastMod != null) - { + if (lastMod != null) { urlText.append("").append(w3dtfFormat.format(lastMod)) - .append(""); + .append(""); } urlText.append("\n"); @@ -105,31 +99,27 @@ public class SitemapsOrgGenerator extends AbstractGenerator } @Override - public boolean useCompression() - { + public boolean useCompression() { return true; } @Override - public String getIndexFilename() - { + public String getIndexFilename() { return "sitemap_index.xml.gz"; } @Override public void writeIndex(PrintStream output, int sitemapCount) - throws IOException - { + throws IOException { String now = w3dtfFormat.format(new Date()); output.println("\n"); output - .println(""); + .println(""); - for (int i = 0; i < sitemapCount; i++) - { + for (int i = 0; i < sitemapCount; i++) { output.print("" + indexURLStem + i + indexURLTail - + ""); + + ""); output.print("" + now + "\n"); } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/CreateStatReport.java b/dspace-api/src/main/java/org/dspace/app/statistics/CreateStatReport.java index 2bf85155bf..29e9065a15 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/CreateStatReport.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/CreateStatReport.java @@ -18,52 +18,69 @@ 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.dspace.core.Context; import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; /** * This class allows the running of the DSpace statistic tools - * - * Usage: {@code java CreateStatReport -r } - * Available: {@code - * } - * - * @author Chris Yates * + * Usage: {@code java CreateStatReport -r } + * Available: {@code + * } + * + * @author Chris Yates */ public class CreateStatReport { - /**Current date and time*/ - private static Calendar calendar = null; - - /**Reporting start date and time*/ - private static Calendar reportStartDate = null; - - /**Path of log directory*/ - private static String outputLogDirectory = null; - - /**Path of reporting directory*/ - private static String outputReportDirectory = null; - - /**File suffix for log files*/ - private static String outputSuffix = ".dat"; - - /**User context*/ - private static Context context; + /** + * Current date and time + */ + private static Calendar calendar = null; - /** the config file from which to configure the analyser */ + /** + * Reporting start date and time + */ + private static Calendar reportStartDate = null; + + /** + * Path of log directory + */ + private static String outputLogDirectory = null; + + /** + * Path of reporting directory + */ + private static String outputReportDirectory = null; + + /** + * File suffix for log files + */ + private static String outputSuffix = ".dat"; + + /** + * User context + */ + private static Context context; + + /** + * the config file from which to configure the analyser + */ private static String configFile = ConfigurationManager.getProperty("dspace.dir") + - File.separator + "config" + File.separator + - "dstat.cfg"; + File.separator + "config" + File.separator + + "dstat.cfg"; + + /** + * Default constructor + */ + private CreateStatReport() { } /* - * Main method to be run from the command line executes individual statistic methods - * - * Usage: java CreateStatReport -r - */ - public static void main(String[] argv) throws Exception { + * Main method to be run from the command line executes individual statistic methods + * + * Usage: java CreateStatReport -r + */ + public static void main(String[] argv) throws Exception { // Open the statistics config file FileInputStream fis = new java.io.FileInputStream(new File(configFile)); @@ -71,126 +88,82 @@ public class CreateStatReport { config.load(fis); int startMonth = 0; int startYear = 2005; - try - { + try { startYear = Integer.parseInt(config.getProperty("start.year", "1").trim()); - } catch (NumberFormatException nfe) - { + } catch (NumberFormatException nfe) { System.err.println("start.year is incorrectly set in dstat.cfg. Must be a number (e.g. 2005)."); System.exit(0); } - try - { + try { startMonth = Integer.parseInt(config.getProperty("start.month", "2005").trim()); - } catch (NumberFormatException nfe) - { + } catch (NumberFormatException nfe) { System.err.println("start.month is incorrectly set in dstat.cfg. Must be a number between 1 and 12."); System.exit(0); } reportStartDate = new GregorianCalendar(startYear, startMonth - 1, 1); calendar = new GregorianCalendar(); - + // create context as super user context = new Context(); context.turnOffAuthorisationSystem(); - + //get paths to directories outputLogDirectory = ConfigurationManager.getProperty("log.report.dir") + File.separator; outputReportDirectory = ConfigurationManager.getProperty("report.dir") + File.separator; - - //read in command line variable to determine which statistic to run - CommandLineParser parser = new PosixParser(); - Options options = new Options(); - options.addOption("r", "report", true, "report"); - CommandLine line = parser.parse(options, argv); - - String statAction = null; - - if(line.hasOption('r')) - { - statAction = line.getOptionValue('r'); - } - - if (statAction == null) { - usage(); - System.exit(0); - } - //call appropriate statistics method - if(statAction.equals("stat-monthly")) { - statMonthly(); - } - - if(statAction.equals("stat-general")) { - statGeneral(); - } - - if(statAction.equals("stat-initial")) { - statInitial(); - } - - if(statAction.equals("stat-report-general")) { - statReportGeneral(); - } - - if(statAction.equals("stat-report-initial")) { - statReportInitial(); - } - - if(statAction.equals("stat-report-monthly")) { - statReportMonthly(); - } - } - - /** - * This method generates a report from the first of the current month to the end of the current month. - * - * @throws Exception if error - */ - private static void statMonthly() throws Exception { - + //read in command line variable to determine which statistic to run + CommandLineParser parser = new PosixParser(); + Options options = new Options(); + options.addOption("r", "report", true, "report"); + CommandLine line = parser.parse(options, argv); + + String statAction = null; + + if (line.hasOption('r')) { + statAction = line.getOptionValue('r'); + } + + if (statAction == null) { + usage(); + System.exit(0); + } + + //call appropriate statistics method + if (statAction.equals("stat-monthly")) { + statMonthly(); + } + + if (statAction.equals("stat-general")) { + statGeneral(); + } + + if (statAction.equals("stat-initial")) { + statInitial(); + } + + if (statAction.equals("stat-report-general")) { + statReportGeneral(); + } + + if (statAction.equals("stat-report-initial")) { + statReportInitial(); + } + + if (statAction.equals("stat-report-monthly")) { + statReportMonthly(); + } + } + + /** + * This method generates a report from the first of the current month to the end of the current month. + * + * @throws Exception if error + */ + private static void statMonthly() throws Exception { + //Output Prefix String outputPrefix = "dspace-log-monthly-"; - - // set up our command line variables - String myLogDir = null; - String myFileTemplate = null; - String myConfigFile = null; - StringBuffer myOutFile = null; - Date myStartDate = null; - Date myEndDate = null; - boolean myLookUp = false; - - Calendar start = new GregorianCalendar( calendar.get(Calendar.YEAR), - calendar.get(Calendar.MONTH), - calendar.getActualMinimum(Calendar.DAY_OF_MONTH)); - myStartDate = start.getTime(); - - Calendar end = new GregorianCalendar( calendar.get(Calendar.YEAR), - calendar.get(Calendar.MONTH), - calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); - myEndDate = end.getTime(); - - myOutFile = new StringBuffer(outputLogDirectory); - myOutFile.append(outputPrefix); - myOutFile.append(calendar.get(Calendar.YEAR)); - myOutFile.append("-"); - myOutFile.append(calendar.get(Calendar.MONTH)+1); - myOutFile.append(outputSuffix); - - LogAnalyser.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate, myEndDate, myLookUp); - } - - /** - * This method generates a full report based on the full log period - * - * @throws Exception if error - */ - private static void statGeneral() throws Exception { - - //Output Prefix - String outputPrefix = "dspace-log-general-"; - + // set up our command line variables String myLogDir = null; String myFileTemplate = null; @@ -198,31 +171,74 @@ public class CreateStatReport { StringBuffer myOutFile = null; Date myStartDate = null; Date myEndDate = null; - boolean myLookUp = false; - + boolean myLookUp = false; + + Calendar start = new GregorianCalendar(calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.getActualMinimum(Calendar.DAY_OF_MONTH)); + myStartDate = start.getTime(); + + Calendar end = new GregorianCalendar(calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); + myEndDate = end.getTime(); + myOutFile = new StringBuffer(outputLogDirectory); myOutFile.append(outputPrefix); myOutFile.append(calendar.get(Calendar.YEAR)); myOutFile.append("-"); - myOutFile.append(calendar.get(Calendar.MONTH)+1); + myOutFile.append(calendar.get(Calendar.MONTH) + 1); + myOutFile.append(outputSuffix); + + LogAnalyser + .processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate, myEndDate, + myLookUp); + } + + /** + * This method generates a full report based on the full log period + * + * @throws Exception if error + */ + private static void statGeneral() throws Exception { + + //Output Prefix + String outputPrefix = "dspace-log-general-"; + + // set up our command line variables + String myLogDir = null; + String myFileTemplate = null; + String myConfigFile = null; + StringBuffer myOutFile = null; + Date myStartDate = null; + Date myEndDate = null; + boolean myLookUp = false; + + myOutFile = new StringBuffer(outputLogDirectory); + myOutFile.append(outputPrefix); + myOutFile.append(calendar.get(Calendar.YEAR)); + myOutFile.append("-"); + myOutFile.append(calendar.get(Calendar.MONTH) + 1); myOutFile.append("-"); myOutFile.append(calendar.get(Calendar.DAY_OF_MONTH)); - myOutFile.append(outputSuffix); - - LogAnalyser.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate, myEndDate, myLookUp); - } - - /** - * This script starts from the year and month specified below and loops each month until the current month - * generating a monthly aggregation files for the DStat system. - * - * @throws Exception if error - */ - private static void statInitial() throws Exception { - - //Output Prefix + myOutFile.append(outputSuffix); + + LogAnalyser + .processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate, myEndDate, + myLookUp); + } + + /** + * This script starts from the year and month specified below and loops each month until the current month + * generating a monthly aggregation files for the DStat system. + * + * @throws Exception if error + */ + private static void statInitial() throws Exception { + + //Output Prefix String outputPrefix = "dspace-log-monthly-"; - + // set up our command line variables String myLogDir = null; String myFileTemplate = null; @@ -230,163 +246,165 @@ public class CreateStatReport { StringBuffer myOutFile = null; Date myStartDate = null; Date myEndDate = null; - boolean myLookUp = false; - - Calendar reportEndDate = new GregorianCalendar( calendar.get(Calendar.YEAR), - calendar.get(Calendar.MONTH), - calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); + boolean myLookUp = false; - Calendar currentMonth = (Calendar)reportStartDate.clone(); - while(currentMonth.before(reportEndDate)) { - - Calendar start = new GregorianCalendar( currentMonth.get(Calendar.YEAR), - currentMonth.get(Calendar.MONTH), - currentMonth.getActualMinimum(Calendar.DAY_OF_MONTH)); - myStartDate = start.getTime(); + Calendar reportEndDate = new GregorianCalendar(calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); - Calendar end = new GregorianCalendar( currentMonth.get(Calendar.YEAR), - currentMonth.get(Calendar.MONTH), - currentMonth.getActualMaximum(Calendar.DAY_OF_MONTH)); - myEndDate = end.getTime(); - - myOutFile = new StringBuffer(outputLogDirectory); - myOutFile.append(outputPrefix); - myOutFile.append(currentMonth.get(Calendar.YEAR)); - myOutFile.append("-"); - myOutFile.append(currentMonth.get(Calendar.MONTH)+1); - myOutFile.append(outputSuffix); - - LogAnalyser.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate, myEndDate, myLookUp); - - currentMonth.add(Calendar.MONTH, 1); - } - } - - /** - * This method generates a full report based on the full log period - * - * @throws Exception if error - */ - private static void statReportGeneral() throws Exception { - - //Prefix - String inputPrefix = "dspace-log-general-"; - String outputPrefix = "report-general-"; - - String myFormat = "html"; + Calendar currentMonth = (Calendar) reportStartDate.clone(); + while (currentMonth.before(reportEndDate)) { + + Calendar start = new GregorianCalendar(currentMonth.get(Calendar.YEAR), + currentMonth.get(Calendar.MONTH), + currentMonth.getActualMinimum(Calendar.DAY_OF_MONTH)); + myStartDate = start.getTime(); + + Calendar end = new GregorianCalendar(currentMonth.get(Calendar.YEAR), + currentMonth.get(Calendar.MONTH), + currentMonth.getActualMaximum(Calendar.DAY_OF_MONTH)); + myEndDate = end.getTime(); + + myOutFile = new StringBuffer(outputLogDirectory); + myOutFile.append(outputPrefix); + myOutFile.append(currentMonth.get(Calendar.YEAR)); + myOutFile.append("-"); + myOutFile.append(currentMonth.get(Calendar.MONTH) + 1); + myOutFile.append(outputSuffix); + + LogAnalyser.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate, + myEndDate, myLookUp); + + currentMonth.add(Calendar.MONTH, 1); + } + } + + /** + * This method generates a full report based on the full log period + * + * @throws Exception if error + */ + private static void statReportGeneral() throws Exception { + + //Prefix + String inputPrefix = "dspace-log-general-"; + String outputPrefix = "report-general-"; + + String myFormat = "html"; StringBuffer myInput = null; StringBuffer myOutput = null; String myMap = null; - + myInput = new StringBuffer(outputLogDirectory); myInput.append(inputPrefix); myInput.append(calendar.get(Calendar.YEAR)); myInput.append("-"); - myInput.append(calendar.get(Calendar.MONTH)+1); + myInput.append(calendar.get(Calendar.MONTH) + 1); myInput.append("-"); myInput.append(calendar.get(Calendar.DAY_OF_MONTH)); - myInput.append(outputSuffix); - + myInput.append(outputSuffix); + myOutput = new StringBuffer(outputReportDirectory); myOutput.append(outputPrefix); myOutput.append(calendar.get(Calendar.YEAR)); myOutput.append("-"); - myOutput.append(calendar.get(Calendar.MONTH)+1); + myOutput.append(calendar.get(Calendar.MONTH) + 1); myOutput.append("-"); myOutput.append(calendar.get(Calendar.DAY_OF_MONTH)); myOutput.append("."); myOutput.append(myFormat); - - ReportGenerator.processReport(context, myFormat, myInput.toString(), myOutput.toString(), myMap); - } - - /** - * This script starts from the year and month specified below and loops each month until the current month - * generating monthly reports from the DStat aggregation files - * - * @throws Exception if error - */ - private static void statReportInitial() throws Exception { - - //Prefix - String inputPrefix = "dspace-log-monthly-"; - String outputPrefix = "report-"; - - String myFormat = "html"; - StringBuffer myInput = null; - StringBuffer myOutput = null; - String myMap = null; - - Calendar reportEndDate = new GregorianCalendar( calendar.get(Calendar.YEAR), - calendar.get(Calendar.MONTH), - calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); - - Calendar currentMonth = (Calendar)reportStartDate.clone(); - while(currentMonth.before(reportEndDate)) { - - myInput = new StringBuffer(outputLogDirectory); - myInput.append(inputPrefix); - myInput.append(currentMonth.get(Calendar.YEAR)); - myInput.append("-"); - myInput.append(currentMonth.get(Calendar.MONTH)+1); - myInput.append(outputSuffix); - - myOutput = new StringBuffer(outputReportDirectory); - myOutput.append(outputPrefix); - myOutput.append(currentMonth.get(Calendar.YEAR)); - myOutput.append("-"); - myOutput.append(currentMonth.get(Calendar.MONTH)+1); - myOutput.append("."); - myOutput.append(myFormat); - - ReportGenerator.processReport(context, myFormat, myInput.toString(), myOutput.toString(), myMap); - - currentMonth.add(Calendar.MONTH, 1); - } - } - - /** - * This method generates a report from the aggregation files which have been run for the most recent month - * - * @throws Exception if error - */ - private static void statReportMonthly() throws Exception - { - //Prefix - String inputPrefix = "dspace-log-monthly-"; - String outputPrefix = "report-"; - - String myFormat = "html"; + ReportGenerator.processReport(context, myFormat, myInput.toString(), myOutput.toString(), myMap); + } + + /** + * This script starts from the year and month specified below and loops each month until the current month + * generating monthly reports from the DStat aggregation files + * + * @throws Exception if error + */ + private static void statReportInitial() throws Exception { + + //Prefix + String inputPrefix = "dspace-log-monthly-"; + String outputPrefix = "report-"; + + String myFormat = "html"; StringBuffer myInput = null; StringBuffer myOutput = null; String myMap = null; - + + Calendar reportEndDate = new GregorianCalendar(calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); + + Calendar currentMonth = (Calendar) reportStartDate.clone(); + + while (currentMonth.before(reportEndDate)) { + + myInput = new StringBuffer(outputLogDirectory); + myInput.append(inputPrefix); + myInput.append(currentMonth.get(Calendar.YEAR)); + myInput.append("-"); + myInput.append(currentMonth.get(Calendar.MONTH) + 1); + myInput.append(outputSuffix); + + myOutput = new StringBuffer(outputReportDirectory); + myOutput.append(outputPrefix); + myOutput.append(currentMonth.get(Calendar.YEAR)); + myOutput.append("-"); + myOutput.append(currentMonth.get(Calendar.MONTH) + 1); + myOutput.append("."); + myOutput.append(myFormat); + + ReportGenerator.processReport(context, myFormat, myInput.toString(), myOutput.toString(), myMap); + + currentMonth.add(Calendar.MONTH, 1); + } + } + + /** + * This method generates a report from the aggregation files which have been run for the most recent month + * + * @throws Exception if error + */ + private static void statReportMonthly() throws Exception { + //Prefix + String inputPrefix = "dspace-log-monthly-"; + String outputPrefix = "report-"; + + String myFormat = "html"; + StringBuffer myInput = null; + StringBuffer myOutput = null; + String myMap = null; + myInput = new StringBuffer(outputLogDirectory); myInput.append(inputPrefix); myInput.append(calendar.get(Calendar.YEAR)); myInput.append("-"); - myInput.append(calendar.get(Calendar.MONTH)+1); - myInput.append(outputSuffix); - + myInput.append(calendar.get(Calendar.MONTH) + 1); + myInput.append(outputSuffix); + myOutput = new StringBuffer(outputReportDirectory); myOutput.append(outputPrefix); myOutput.append(calendar.get(Calendar.YEAR)); myOutput.append("-"); - myOutput.append(calendar.get(Calendar.MONTH)+1); + myOutput.append(calendar.get(Calendar.MONTH) + 1); myOutput.append("."); myOutput.append(myFormat); - + ReportGenerator.processReport(context, myFormat, myInput.toString(), myOutput.toString(), myMap); - } - - /* - * Output the usage information - */ - private static void usage() throws Exception { - - System.out.println("Usage: java CreateStatReport -r "); - System.out.println("Available: "); - return; - } + } + + /* + * Output the usage information + */ + private static void usage() throws Exception { + + System.out.println("Usage: java CreateStatReport -r "); + System.out.println( + "Available: " + + ""); + return; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/HTMLReport.java b/dspace-api/src/main/java/org/dspace/app/statistics/HTMLReport.java index 29d5abc792..a555ae55e7 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/HTMLReport.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/HTMLReport.java @@ -7,85 +7,94 @@ */ package org.dspace.app.statistics; -import org.dspace.core.ConfigurationManager; - +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; import java.text.DateFormat; - import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.io.*; + +import org.dspace.core.ConfigurationManager; /** * This class provides HTML reports for the ReportGenerator class * - * @author Richard Jones + * @author Richard Jones */ -public class HTMLReport implements Report -{ +public class HTMLReport implements Report { // FIXME: all of these methods should do some content escaping before // outputting anything - - /** a list of the statistic blocks being managed by this class */ + + /** + * a list of the statistic blocks being managed by this class + */ private List blocks = new ArrayList(); - - /** the title for the page */ + + /** + * the title for the page + */ private String pageTitle = null; - - /** the main title for the page */ + + /** + * the main title for the page + */ private String mainTitle = null; - - /** start date for report */ + + /** + * start date for report + */ private Date start = null; - - /** end date for report */ + + /** + * end date for report + */ private Date end = null; - /** the output file to which to write aggregation data */ - private String output = ConfigurationManager.getProperty("dspace.dir") + - File.separator + "log" + File.separator + "report"; - + /** + * the output file to which to write aggregation data + */ + private String output = ConfigurationManager.getProperty("dspace.dir") + + File.separator + "log" + File.separator + "report"; + /** * constructor for HTML reporting */ - public HTMLReport() - { + public HTMLReport() { // empty constructor } - public void setOutput(String newOutput) - { - if (newOutput != null) - { + public void setOutput(String newOutput) { + if (newOutput != null) { output = newOutput; } } - + /** * return a string containing the report as generated by this class * - * @return the HTML report + * @return the HTML report */ @Override - public String render() - { + public String render() { StringBuffer frag = new StringBuffer(); - + // get the page headings frag.append(header(pageTitle)); frag.append(mainTitle()); frag.append(dateRange()); - + // output the report blocks // FIXME: perhaps the order of report blocks should be configurable Iterator statSets = blocks.iterator(); - while (statSets.hasNext()) - { + while (statSets.hasNext()) { frag.append(navigation()); - + Statistics stats = statSets.next(); frag.append(sectionHeader(stats.getSectionHeader())); frag.append(topLink()); @@ -93,51 +102,46 @@ public class HTMLReport implements Report frag.append(floorInfo(stats.getFloor())); frag.append(statBlock(stats)); } - + // output the footer and return frag.append(footer()); // NB: HTMLReport now takes responsibility to write the output file, // so that the Report/ReportGenerator can have more general usage // finally write the string into the output file - try - { - FileOutputStream fos = new FileOutputStream(output); + try { + FileOutputStream fos = new FileOutputStream(output); OutputStreamWriter osr = new OutputStreamWriter(fos, "UTF-8"); PrintWriter out = new PrintWriter(osr); out.write(frag.toString()); out.close(); - } - catch (IOException e) - { + } catch (IOException e) { System.out.println("Unable to write to output file " + output); System.exit(0); } - + return frag.toString(); } - - + + /** * provide a link back to the top of the page * - * @return a string containing the link text HTML formatted + * @return a string containing the link text HTML formatted */ - public String topLink() - { + public String topLink() { return ""; } - - + + /** * build the internal navigation for the report * - * @return an HTML string providing internal page navigation + * @return an HTML string providing internal page navigation */ - public String navigation() - { + public String navigation() { StringBuffer frag = new StringBuffer(); - + frag.append("
    "); frag.append("General Overview"); frag.append(" | "); @@ -157,146 +161,135 @@ public class HTMLReport implements Report frag.append(" | "); frag.append("Processing Information"); frag.append("
    "); - + return frag.toString(); } - + /** * add a statistics block to the report to the class register * - * @param stat the statistics object to be added to the report + * @param stat the statistics object to be added to the report */ @Override - public void addBlock(Statistics stat) - { + public void addBlock(Statistics stat) { blocks.add(stat); return; } - - + + /** * set the starting date for the report * - * @param start the start date for the report + * @param start the start date for the report */ @Override - public void setStartDate(Date start) - { + public void setStartDate(Date start) { this.start = (start == null ? null : new Date(start.getTime())); } - - + + /** * set the end date for the report * - * @param end the end date for the report + * @param end the end date for the report */ @Override - public void setEndDate(Date end) - { + public void setEndDate(Date end) { this.end = (end == null ? null : new Date(end.getTime())); } - - + + /** * output the date range in the relevant format. This requires that the * date ranges have been set using setStartDate() and setEndDate() * - * @return a string containing date range information + * @return a string containing date range information */ @Override - public String dateRange() - { + public String dateRange() { StringBuffer frag = new StringBuffer(); DateFormat df = DateFormat.getDateInstance(); - + frag.append("
    "); - if (start != null) - { + if (start != null) { frag.append(df.format(start)); - } - else - { + } else { frag.append("from start of records "); } - + frag.append(" to "); - - if (end != null) - { + + if (end != null) { frag.append(df.format(end)); - } - else - { + } else { frag.append(" end of records"); } - + frag.append("
    \n\n"); - + return frag.toString(); } - - + + /** * output the title in the relevant format. This requires that the title * has been set with setMainTitle() * - * @return a string containing the title of the report + * @return a string containing the title of the report */ @Override - public String mainTitle() - { + public String mainTitle() { return "\n\n"; } - - + + /** * set the main title for the report * - * @param name the name of the service - * @param serverName the name of the server + * @param name the name of the service + * @param serverName the name of the server */ @Override - public void setMainTitle(String name, String serverName) - { + public void setMainTitle(String name, String serverName) { mainTitle = "Statistics for " + name + " on " + serverName; - if (pageTitle == null) - { + if (pageTitle == null) { pageTitle = mainTitle; } return; } - - + + /** * output any top headers that this page needs * - * @return a string containing the header for the report + * @return a string containing the header for the report */ @Override - public String header() - { + public String header() { return header(""); } - + /** * output any top headers that this page needs, and include a title * argument (Title support currently not implemented) * - * @param title the title of the item being headered + * @param title the title of the item being headered */ @Override - public String header(String title) - { - // FIXME: this need to be figured out to integrate nicely into the + public String header(String title) { + // FIXME: this need to be figured out to integrate nicely into the // whole JSTL thing, but for the moment it's just going to deliver // some styles StringBuffer frag = new StringBuffer(); - + frag.append("\n"); - + return frag.toString(); } - - + + /** * output the section header in HTML format * - * @param title the title of the section - * - * @return a string containing the section title HTML formatted + * @param title the title of the section + * @return a string containing the section title HTML formatted */ @Override - public String sectionHeader(String title) - { + public String sectionHeader(String title) { // prepare the title to be an style link // FIXME: this should be made more generic and used in a number of locations String aName = title.toLowerCase(); @@ -330,153 +321,126 @@ public class HTMLReport implements Report return "\n\n"; } - - + + /** * output the report block based on the passed mapping, where the mapping * should be "name of report element" to "value", where both sides of the * mapping should be Strings. This class also assumes that the reference * is a linkable URL to the resource * - * @param content the statistic object array to be displayed - * - * @return a string containing the statistics block HTML formatted + * @param content the statistic object array to be displayed + * @return a string containing the statistics block HTML formatted */ @Override - public String statBlock(Statistics content) - { + public String statBlock(Statistics content) { StringBuffer frag = new StringBuffer(); Stat[] stats = content.getStats(); - + // start the table frag.append("\n"); - + // prepare the table headers - if (content.getStatName() != null || content.getResultName() != null) - { + if (content.getStatName() != null || content.getResultName() != null) { frag.append("\t\n"); frag.append("\t\t\n"); frag.append("\t\t\n"); frag.append("\t\n"); } - + // output the statistics in the table - for (int i = 0; i < stats.length; i++) - { + for (int i = 0; i < stats.length; i++) { String style = null; - - if ((i & 1) == 1) - { + + if ((i & 1) == 1) { style = "reportOddRow"; - } - else - { + } else { style = "reportEvenRow"; } - + frag.append("\t\n\t\t\n\t\t\n\t\n"); } - + frag.append("
    \n"); - if (content.getStatName() != null) - { + if (content.getStatName() != null) { frag.append("\t\t\t" + content.getStatName() + "\n"); - } - else - { + } else { frag.append("\t\t\t \n"); } frag.append("\t\t\n"); - if (content.getResultName() != null) - { + if (content.getResultName() != null) { frag.append("\t\t\t" + content.getResultName() + "\n"); - } - else - { + } else { frag.append("\t\t\t \n"); } frag.append("\t\t
    \n"); frag.append("\t\t\t"); - if (stats[i].getReference() != null) - { + if (stats[i].getReference() != null) { frag.append(""); } frag.append(this.clean(stats[i].getKey())); - if (stats[i].getReference() != null) - { + if (stats[i].getReference() != null) { frag.append(""); } frag.append("\n"); frag.append("\t\t\n"); frag.append("\t\t\t").append(ReportTools.numberFormat(stats[i].getValue())); - if (stats[i].getUnits() != null) - { + if (stats[i].getUnits() != null) { frag.append(" ").append(stats[i].getUnits()); } frag.append("\n"); frag.append("\t\t
    \n"); - + return frag.toString(); } - - + + /** * output the floor information in HTML format * - * @param floor the floor number for the section being displayed - * - * @return a string containing floor information HTML formatted + * @param floor the floor number for the section being displayed + * @return a string containing floor information HTML formatted */ @Override - public String floorInfo(int floor) - { - if (floor > 0) - { + public String floorInfo(int floor) { + if (floor > 0) { StringBuffer frag = new StringBuffer(); frag.append("
    "); frag.append("(more than " + ReportTools.numberFormat(floor) + " times)"); frag.append("
    \n"); return frag.toString(); - } - else - { + } else { return ""; } } - + /** * output the explanation of the report block in HTML format * - * @param explanation some text explaining the coming report block - * - * @return a string containing an explanaton HTML formatted + * @param explanation some text explaining the coming report block + * @return a string containing an explanaton HTML formatted */ @Override - public String blockExplanation(String explanation) - { - if (explanation != null) - { + public String blockExplanation(String explanation) { + if (explanation != null) { StringBuffer frag = new StringBuffer(); frag.append("
    "); frag.append(explanation); frag.append("
    \n\n"); return frag.toString(); - } - else - { + } else { return ""; } } - + /** * output the final footers for this file * - * @return a string containing the report footer + * @return a string containing the report footer */ @Override - public String footer() - { + public String footer() { return ""; } @@ -486,12 +450,11 @@ public class HTMLReport implements Report * @param s The String to clean * @return The cleaned String */ - private String clean(String s) - { + private String clean(String s) { // Clean up the statistics keys s = s.replace("<", "<"); s = s.replaceAll(">", ">"); return s; } - + } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/LogAnalyser.java b/dspace-api/src/main/java/org/dspace/app/statistics/LogAnalyser.java index ec60e87901..f46d6cb569 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/LogAnalyser.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/LogAnalyser.java @@ -7,6 +7,28 @@ */ package org.dspace.app.statistics; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.sql.SQLException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.apache.commons.lang3.StringUtils; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; @@ -15,22 +37,6 @@ import org.dspace.discovery.DiscoverQuery; import org.dspace.discovery.SearchServiceException; import org.dspace.discovery.SearchUtils; -import java.sql.SQLException; - -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; - /** * This class performs all the actual analysis of a given set of DSpace log * files. Most input can be configured; use the -help flag for a full list @@ -40,192 +46,288 @@ import java.io.IOException; * can then be used for display purposes using the related ReportGenerator * class. * - * @author Richard Jones + * @author Richard Jones */ -public class LogAnalyser -{ - +public class LogAnalyser { + // set up our class globals // FIXME: there are so many of these perhaps they should exist in a static // object of their own - + ///////////////// // aggregators ///////////////// - - /** aggregator for all actions performed in the system */ + + /** + * aggregator for all actions performed in the system + */ private static Map actionAggregator; - - /** aggregator for all searches performed */ + + /** + * aggregator for all searches performed + */ private static Map searchAggregator; - - /** aggregator for user logins */ + + /** + * aggregator for user logins + */ private static Map userAggregator; - - /** aggregator for item views */ + + /** + * aggregator for item views + */ private static Map itemAggregator; - - /** aggregator for current archive state statistics */ + + /** + * aggregator for current archive state statistics + */ private static Map archiveStats; - - /** warning counter */ + + /** + * warning counter + */ private static int warnCount = 0; - /** exception counter */ + /** + * exception counter + */ private static int excCount = 0; - - /** log line counter */ + + /** + * log line counter + */ private static int lineCount = 0; - + ////////////////// // config data ////////////////// - - /** list of actions to be included in the general summary */ + + /** + * list of actions to be included in the general summary + */ private static List generalSummary; - - /** list of words not to be aggregated */ + + /** + * list of words not to be aggregated + */ private static List excludeWords; - - /** list of search types to be ignored, such as "author:" */ + + /** + * list of search types to be ignored, such as "author:" + */ private static List excludeTypes; - - /** list of characters to be excluded */ + + /** + * list of characters to be excluded + */ private static List excludeChars; - - /** list of item types to be reported on in the current state */ + + /** + * list of item types to be reported on in the current state + */ private static List itemTypes; - - /** bottom limit to output for search word analysis */ + + /** + * bottom limit to output for search word analysis + */ private static int searchFloor; - - /** bottom limit to output for item view analysis */ + + /** + * bottom limit to output for item view analysis + */ private static int itemFloor; - - /** number of items from most popular to be looked up in the database */ + + /** + * number of items from most popular to be looked up in the database + */ private static int itemLookup; - - /** mode to use for user email display */ + + /** + * mode to use for user email display + */ private static String userEmail; - - /** URL of the service being analysed */ + + /** + * URL of the service being analysed + */ private static String url; - - /** Name of the service being analysed */ + + /** + * Name of the service being analysed + */ private static String name; - - /** Name of the service being analysed */ + + /** + * Name of the service being analysed + */ private static String hostName; - - /** the average number of views per item */ + + /** + * the average number of views per item + */ private static int views = 0; - + /////////////////////// // regular expressions /////////////////////// - - /** Exclude characters regular expression pattern */ - private static Pattern excludeCharRX = null; - - /** handle indicator string regular expression pattern */ - private static Pattern handleRX = null; - - /** item id indicator string regular expression pattern */ - private static Pattern itemRX = null; - - /** query string indicator regular expression pattern */ - private static Pattern queryRX = null; - - /** collection indicator regular expression pattern */ - private static Pattern collectionRX = null; - - /** community indicator regular expression pattern */ - private static Pattern communityRX = null; - - /** results indicator regular expression pattern */ - private static Pattern resultsRX = null; - - /** single character regular expression pattern */ - private static Pattern singleRX = null; - - /** a pattern to match a valid version 1.3 log file line */ - private static Pattern valid13 = null; - /** basic log line */ - private static Pattern validBase = null; + /** + * Exclude characters regular expression pattern + */ + private static Pattern excludeCharRX = null; - /** a pattern to match a valid version 1.4 log file line */ - private static Pattern valid14 = null; - - /** pattern to match valid log file names */ - private static Pattern logRegex = null; - - /** pattern to match commented out lines from the config file */ - private static final Pattern comment = Pattern.compile("^#"); - - /** pattern to match genuine lines from the config file */ - private static final Pattern real = Pattern.compile("^(.+)=(.+)"); - - /** pattern to match all search types */ - private static Pattern typeRX = null; - - /** pattern to match all search types */ - private static Pattern wordRX = null; - - ////////////////////////// - // Miscellaneous variables - ////////////////////////// - - /** process timing clock */ - private static Calendar startTime = null; - - ///////////////////////// - // command line options - //////////////////////// - - /** the log directory to be analysed */ - private static String logDir = ConfigurationManager.getProperty("log.report.dir"); + /** + * handle indicator string regular expression pattern + */ + private static Pattern handleRX = null; - /** the regex to describe the file name format */ - private static String fileTemplate = "dspace\\.log.*"; - - /** the config file from which to configure the analyser */ - private static String configFile = ConfigurationManager.getProperty("dspace.dir") + - File.separator + "config" + File.separator + - "dstat.cfg"; - - /** the output file to which to write aggregation data */ - private static String outFile = ConfigurationManager.getProperty("log.report.dir") + File.separator + "dstat.dat"; - - /** the starting date of the report */ - private static Date startDate = null; - - /** the end date of the report */ - private static Date endDate = null; - - /** the starting date of the report as obtained from the log files */ - private static Date logStartDate = null; - - /** the end date of the report as obtained from the log files */ - private static Date logEndDate = null; + /** + * item id indicator string regular expression pattern + */ + private static Pattern itemRX = null; + + /** + * query string indicator regular expression pattern + */ + private static Pattern queryRX = null; + + /** + * collection indicator regular expression pattern + */ + private static Pattern collectionRX = null; + + /** + * community indicator regular expression pattern + */ + private static Pattern communityRX = null; + + /** + * results indicator regular expression pattern + */ + private static Pattern resultsRX = null; + + /** + * single character regular expression pattern + */ + private static Pattern singleRX = null; + + /** + * a pattern to match a valid version 1.3 log file line + */ + private static Pattern valid13 = null; + + /** + * basic log line + */ + private static Pattern validBase = null; + + /** + * a pattern to match a valid version 1.4 log file line + */ + private static Pattern valid14 = null; + + /** + * pattern to match valid log file names + */ + private static Pattern logRegex = null; + + /** + * pattern to match commented out lines from the config file + */ + private static final Pattern comment = Pattern.compile("^#"); + + /** + * pattern to match genuine lines from the config file + */ + private static final Pattern real = Pattern.compile("^(.+)=(.+)"); + + /** + * pattern to match all search types + */ + private static Pattern typeRX = null; + + /** + * pattern to match all search types + */ + private static Pattern wordRX = null; + + ////////////////////////// + // Miscellaneous variables + ////////////////////////// + + /** + * process timing clock + */ + private static Calendar startTime = null; + + ///////////////////////// + // command line options + //////////////////////// + + /** + * the log directory to be analysed + */ + private static String logDir = ConfigurationManager.getProperty("log.report.dir"); + + /** + * the regex to describe the file name format + */ + private static String fileTemplate = "dspace\\.log.*"; + + /** + * the config file from which to configure the analyser + */ + private static String configFile = ConfigurationManager.getProperty("dspace.dir") + + File.separator + "config" + File.separator + + "dstat.cfg"; + + /** + * the output file to which to write aggregation data + */ + private static String outFile = ConfigurationManager.getProperty("log.report.dir") + File.separator + "dstat.dat"; + + /** + * the starting date of the report + */ + private static Date startDate = null; + + /** + * the end date of the report + */ + private static Date endDate = null; + + /** + * the starting date of the report as obtained from the log files + */ + private static Date logStartDate = null; + + /** + * the end date of the report as obtained from the log files + */ + private static Date logEndDate = null; + + /** + * Default constructor + */ + private LogAnalyser() { } /** * main method to be run from command line. See usage information for * details as to how to use the command line flags (-help) + * * @param argv the command line arguments given - * @throws Exception if error + * @throws Exception if error * @throws SQLException if database error */ - public static void main(String [] argv) - throws Exception, SQLException - { + public static void main(String[] argv) + throws Exception, SQLException { // first, start the processing clock startTime = new GregorianCalendar(); - + // create context as super user Context context = new Context(); context.turnOffAuthorisationSystem(); - + // set up our command line variables String myLogDir = null; String myFileTemplate = null; @@ -234,232 +336,200 @@ public class LogAnalyser Date myStartDate = null; Date myEndDate = null; boolean myLookUp = false; - + // read in our command line options - for (int i = 0; i < argv.length; i++) - { - if (argv[i].equals("-log")) - { - myLogDir = argv[i+1]; + for (int i = 0; i < argv.length; i++) { + if (argv[i].equals("-log")) { + myLogDir = argv[i + 1]; } - - if (argv[i].equals("-file")) - { - myFileTemplate = argv[i+1]; + + if (argv[i].equals("-file")) { + myFileTemplate = argv[i + 1]; } - - if (argv[i].equals("-cfg")) - { - myConfigFile = argv[i+1]; + + if (argv[i].equals("-cfg")) { + myConfigFile = argv[i + 1]; } - - if (argv[i].equals("-out")) - { - myOutFile = argv[i+1]; + + if (argv[i].equals("-out")) { + myOutFile = argv[i + 1]; } - - if (argv[i].equals("-help")) - { + + if (argv[i].equals("-help")) { LogAnalyser.usage(); System.exit(0); } - - if (argv[i].equals("-start")) - { - myStartDate = parseDate(argv[i+1]); + + if (argv[i].equals("-start")) { + myStartDate = parseDate(argv[i + 1]); } - - if (argv[i].equals("-end")) - { - myEndDate = parseDate(argv[i+1]); + + if (argv[i].equals("-end")) { + myEndDate = parseDate(argv[i + 1]); } - - if (argv[i].equals("-lookup")) - { + + if (argv[i].equals("-lookup")) { myLookUp = true; } } - + // now call the method which actually processes the logs processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile, myStartDate, myEndDate, myLookUp); } - + /** * using the pre-configuration information passed here, analyse the logs * and produce the aggregation file * - * @param context the DSpace context object this occurs under - * @param myLogDir the passed log directory. Uses default if null - * @param myFileTemplate the passed file name regex. Uses default if null - * @param myConfigFile the DStat config file. Uses default if null - * @param myOutFile the file to which to output aggregation data. Uses default if null - * @param myStartDate the desired start of the analysis. Starts from the beginning otherwise - * @param myEndDate the desired end of the analysis. Goes to the end otherwise - * @param myLookUp force a lookup of the database + * @param context the DSpace context object this occurs under + * @param myLogDir the passed log directory. Uses default if null + * @param myFileTemplate the passed file name regex. Uses default if null + * @param myConfigFile the DStat config file. Uses default if null + * @param myOutFile the file to which to output aggregation data. Uses default if null + * @param myStartDate the desired start of the analysis. Starts from the beginning otherwise + * @param myEndDate the desired end of the analysis. Goes to the end otherwise + * @param myLookUp force a lookup of the database * @return aggregate output - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws SearchServiceException if search error */ - public static String processLogs(Context context, String myLogDir, - String myFileTemplate, String myConfigFile, - String myOutFile, Date myStartDate, - Date myEndDate, boolean myLookUp) - throws IOException, SQLException, SearchServiceException { - // FIXME: perhaps we should have all parameters and aggregators put + public static String processLogs(Context context, String myLogDir, + String myFileTemplate, String myConfigFile, + String myOutFile, Date myStartDate, + Date myEndDate, boolean myLookUp) + throws IOException, SQLException, SearchServiceException { + // FIXME: perhaps we should have all parameters and aggregators put // together in a single aggregating object - + // if the timer has not yet been started, then start it startTime = new GregorianCalendar(); - + //instantiate aggregators actionAggregator = new HashMap(); searchAggregator = new HashMap(); userAggregator = new HashMap(); itemAggregator = new HashMap(); archiveStats = new HashMap(); - + //instantiate lists generalSummary = new ArrayList(); excludeWords = new ArrayList(); excludeTypes = new ArrayList(); excludeChars = new ArrayList(); itemTypes = new ArrayList(); - + // set the parameters for this analysis setParameters(myLogDir, myFileTemplate, myConfigFile, myOutFile, myStartDate, myEndDate, myLookUp); - + // pre prepare our standard file readers and buffered readers FileReader fr = null; BufferedReader br = null; - + // read in the config information, throwing an error if we fail to open // the given config file readConfig(configFile); - + // assemble the regular expressions for later use (requires the file // template to build the regex to match it setRegex(fileTemplate); - + // get the log files File[] logFiles = getLogFiles(logDir); - + // standard loop counter int i = 0; - + // for every log file do analysis // FIXME: it is easy to implement not processing log files after the // dates exceed the end boundary, but is there an easy way to do it // for the start of the file? Note that we can assume that the contents // of the log file are sequential, but can we assume the files are // provided in a data sequence? - for (i = 0; i < logFiles.length; i++) - { + for (i = 0; i < logFiles.length; i++) { // check to see if this file is a log file agains the global regex Matcher matchRegex = logRegex.matcher(logFiles[i].getName()); - if (matchRegex.matches()) - { + if (matchRegex.matches()) { // if it is a log file, open it up and lets have a look at the // contents. - try - { - fr = new FileReader(logFiles[i].toString()); + try { + fr = new FileReader(logFiles[i].toString()); br = new BufferedReader(fr); - } - catch (IOException e) - { + } catch (IOException e) { System.out.println("Failed to read log file " + logFiles[i].toString()); System.exit(0); - } + } // for each line in the file do the analysis // FIXME: perhaps each section needs to be dolled out to an // analysing class to allow pluggability of other methods of // analysis, and ease of code reading too - Pending further thought String line = null; - while ((line = br.readLine()) != null) - { + while ((line = br.readLine()) != null) { // get the log line object LogLine logLine = getLogLine(line); // if there are line segments get on with the analysis - if (logLine != null) - { - // first find out if we are constraining by date and + if (logLine != null) { + // first find out if we are constraining by date and // if so apply the restrictions - if ((startDate != null) && (!logLine.afterDate(startDate))) - { + if ((startDate != null) && (!logLine.afterDate(startDate))) { continue; } - - if ((endDate !=null) && (!logLine.beforeDate(endDate))) - { + + if ((endDate != null) && (!logLine.beforeDate(endDate))) { break; } - + // count the number of lines parsed lineCount++; - + // if we are not constrained by date, register the date // as the start/end date if it is the earliest/latest so far // FIXME: this should probably have a method of its own - if (startDate == null) - { - if (logStartDate != null) - { - if (logLine.beforeDate(logStartDate)) - { + if (startDate == null) { + if (logStartDate != null) { + if (logLine.beforeDate(logStartDate)) { logStartDate = logLine.getDate(); } - } - else - { + } else { logStartDate = logLine.getDate(); } } - - if (endDate == null) - { - if (logEndDate != null) - { - if (logLine.afterDate(logEndDate)) - { + + if (endDate == null) { + if (logEndDate != null) { + if (logLine.afterDate(logEndDate)) { logEndDate = logLine.getDate(); } - } - else - { + } else { logEndDate = logLine.getDate(); } } // count the warnings - if (logLine.isLevel("WARN")) - { + if (logLine.isLevel("WARN")) { // FIXME: really, this ought to be some kind of level // aggregator warnCount++; } // count the exceptions - if (logLine.isLevel("ERROR")) - { + if (logLine.isLevel("ERROR")) { excCount++; } - if ( null == logLine.getAction() ) { + if (null == logLine.getAction()) { continue; } // is the action a search? - if (logLine.isAction("search")) - { + if (logLine.isAction("search")) { // get back all the valid search words from the query String[] words = analyseQuery(logLine.getParams()); - + // for each search word add to the aggregator or // increment the aggregator's counter - for (int j = 0; j < words.length; j++) - { + for (int j = 0; j < words.length; j++) { // FIXME: perhaps aggregators ought to be objects // themselves searchAggregator.put(words[j], increment(searchAggregator, words[j])); @@ -467,20 +537,18 @@ public class LogAnalyser } // is the action a login, and are we counting user logins? - if (logLine.isAction("login") && !userEmail.equals("off")) - { + if (logLine.isAction("login") && !userEmail.equals("off")) { userAggregator.put(logLine.getUser(), increment(userAggregator, logLine.getUser())); } // is the action an item view? - if (logLine.isAction("view_item")) - { + if (logLine.isAction("view_item")) { String handle = logLine.getParams(); // strip the handle string Matcher matchHandle = handleRX.matcher(handle); handle = matchHandle.replaceAll(""); - + // strip the item id string Matcher matchItem = itemRX.matcher(handle); handle = matchItem.replaceAll("").trim(); @@ -501,164 +569,145 @@ public class LogAnalyser } } - + // do we want to do a database lookup? Do so only if the start and // end dates are null or lookUp is true // FIXME: this is a kind of separate section. Would it be worth building // the summary string separately and then inserting it into the real // summary later? Especially if we make the archive analysis more complex archiveStats.put("All Items", getNumItems(context)); - for (i = 0; i < itemTypes.size(); i++) - { + for (i = 0; i < itemTypes.size(); i++) { archiveStats.put(itemTypes.get(i), getNumItems(context, itemTypes.get(i))); } - + // now do the host name and url lookup hostName = ConfigurationManager.getProperty("dspace.hostname").trim(); name = ConfigurationManager.getProperty("dspace.name").trim(); url = ConfigurationManager.getProperty("dspace.url").trim(); - if ((url != null) && (!url.endsWith("/"))) - { - url = url + "/"; + if ((url != null) && (!url.endsWith("/"))) { + url = url + "/"; } - + // do the average views analysis - if ((archiveStats.get("All Items")).intValue() != 0) - { + if ((archiveStats.get("All Items")).intValue() != 0) { // FIXME: this is dependent on their being a query on the db, which // there might not always be if it becomes configurable Double avg = Math.ceil( - (actionAggregator.get("view_item")).doubleValue() / - (archiveStats.get("All Items")).doubleValue()); + (actionAggregator.get("view_item")).doubleValue() / + (archiveStats.get("All Items")).doubleValue()); views = avg.intValue(); } - + // finally, write the output return createOutput(); } - - + + /** * set the passed parameters up as global class variables. This has to * be done in a separate method because the API permits for running from * the command line with args or calling the processLogs method statically * from elsewhere * - * @param myLogDir the log file directory to be analysed - * @param myFileTemplate regex for log file names - * @param myConfigFile config file to use for dstat - * @param myOutFile file to write the aggregation into - * @param myStartDate requested log reporting start date - * @param myEndDate requested log reporting end date - * @param myLookUp requested look up force flag + * @param myLogDir the log file directory to be analysed + * @param myFileTemplate regex for log file names + * @param myConfigFile config file to use for dstat + * @param myOutFile file to write the aggregation into + * @param myStartDate requested log reporting start date + * @param myEndDate requested log reporting end date + * @param myLookUp requested look up force flag */ - public static void setParameters(String myLogDir, String myFileTemplate, - String myConfigFile, String myOutFile, - Date myStartDate, Date myEndDate, - boolean myLookUp) - { - if (myLogDir != null) - { + public static void setParameters(String myLogDir, String myFileTemplate, + String myConfigFile, String myOutFile, + Date myStartDate, Date myEndDate, + boolean myLookUp) { + if (myLogDir != null) { logDir = myLogDir; } - if (myFileTemplate != null) - { + if (myFileTemplate != null) { fileTemplate = myFileTemplate; } - - if (myConfigFile != null) - { + + if (myConfigFile != null) { configFile = myConfigFile; } - - if (myStartDate != null) - { + + if (myStartDate != null) { startDate = new Date(myStartDate.getTime()); } - - if (myEndDate != null) - { + + if (myEndDate != null) { endDate = new Date(myEndDate.getTime()); } - - if (myOutFile != null) - { + + if (myOutFile != null) { outFile = myOutFile; } - + return; } - - + + /** * generate the analyser's output to the specified out file + * * @return output */ - public static String createOutput() - { + public static String createOutput() { // start a string buffer to hold the final output StringBuffer summary = new StringBuffer(); - + // define an iterator that will be used to go over the hashmap keys Iterator keys = null; - + // output the number of lines parsed summary.append("log_lines=" + Integer.toString(lineCount) + "\n"); - + // output the number of warnings encountered summary.append("warnings=" + Integer.toString(warnCount) + "\n"); summary.append("exceptions=" + Integer.toString(excCount) + "\n"); - + // set the general summary config up in the aggregator file - for (int i = 0; i < generalSummary.size(); i++) - { + for (int i = 0; i < generalSummary.size(); i++) { summary.append("general_summary=" + generalSummary.get(i) + "\n"); } - + // output the host name summary.append("server_name=" + hostName + "\n"); - - // output the service name + + // output the service name summary.append("service_name=" + name + "\n"); - + // output the date information if necessary SimpleDateFormat sdf = new SimpleDateFormat("dd'/'MM'/'yyyy"); - - if (startDate != null) - { + + if (startDate != null) { summary.append("start_date=" + sdf.format(startDate) + "\n"); - } - else if (logStartDate != null) - { + } else if (logStartDate != null) { summary.append("start_date=" + sdf.format(logStartDate) + "\n"); } - - if (endDate != null) - { + + if (endDate != null) { summary.append("end_date=" + sdf.format(endDate) + "\n"); - } - else if (logEndDate != null) - { + } else if (logEndDate != null) { summary.append("end_date=" + sdf.format(logEndDate) + "\n"); } - + // write out the archive stats keys = archiveStats.keySet().iterator(); - while (keys.hasNext()) - { + while (keys.hasNext()) { String key = keys.next(); summary.append("archive." + key + "=" + archiveStats.get(key) + "\n"); } - + // write out the action aggregation results keys = actionAggregator.keySet().iterator(); - while (keys.hasNext()) - { + while (keys.hasNext()) { String key = keys.next(); summary.append("action." + key + "=" + actionAggregator.get(key) + "\n"); } - + // depending on the config settings for reporting on emails output the // login information summary.append("user_email=" + userEmail + "\n"); @@ -668,186 +717,168 @@ public class LogAnalyser // for each email address either write out the address and the count // or alias it with an "Address X" label, to keep the data confidential // FIXME: the users reporting should also have a floor value - while (keys.hasNext()) - { + while (keys.hasNext()) { String key = keys.next(); summary.append("user."); - if (userEmail.equals("on")) - { + if (userEmail.equals("on")) { summary.append(key + "=" + userAggregator.get(key) + "\n"); - } - else if (userEmail.equals("alias")) - { + } else if (userEmail.equals("alias")) { summary.append("Address " + Integer.toString(address++) + "=" + userAggregator.get(key) + "\n"); } } - + // FIXME: all values which have floors set should provide an "other" // record which counts how many other things which didn't make it into // the listing there are - + // output the search word information summary.append("search_floor=" + searchFloor + "\n"); keys = searchAggregator.keySet().iterator(); - while (keys.hasNext()) - { + while (keys.hasNext()) { String key = keys.next(); - if ((searchAggregator.get(key)).intValue() >= searchFloor) - { + if ((searchAggregator.get(key)).intValue() >= searchFloor) { summary.append("search." + key + "=" + searchAggregator.get(key) + "\n"); } } - + // FIXME: we should do a lot more with the search aggregator // Possible feature list: // - constrain by collection/community perhaps? // - we should consider building our own aggregator class which can // be full of rich data. Perhaps this and the Stats class should // be the same thing. - + // item viewing information summary.append("item_floor=" + itemFloor + "\n"); summary.append("host_url=" + url + "\n"); summary.append("item_lookup=" + itemLookup + "\n"); - + // write out the item access information keys = itemAggregator.keySet().iterator(); - while (keys.hasNext()) - { + while (keys.hasNext()) { String key = keys.next(); - if ((itemAggregator.get(key)).intValue() >= itemFloor) - { + if ((itemAggregator.get(key)).intValue() >= itemFloor) { summary.append("item." + key + "=" + itemAggregator.get(key) + "\n"); } } - + // output the average views per item - if (views > 0) - { + if (views > 0) { summary.append("avg_item_views=" + views + "\n"); } - + // insert the analysis processing time information Calendar endTime = new GregorianCalendar(); long timeInMillis = (endTime.getTimeInMillis() - startTime.getTimeInMillis()); summary.append("analysis_process_time=" + Long.toString(timeInMillis / 1000) + "\n"); - + // finally write the string into the output file - try - { + try { BufferedWriter out = new BufferedWriter(new FileWriter(outFile)); out.write(summary.toString()); out.flush(); out.close(); - } - catch (IOException e) - { + } catch (IOException e) { System.out.println("Unable to write to output file " + outFile); System.exit(0); } - + return summary.toString(); } - - + + /** * get an array of file objects representing the passed log directory - * - * @param logDir the log directory in which to pick up files * - * @return an array of file objects representing the given logDir + * @param logDir the log directory in which to pick up files + * @return an array of file objects representing the given logDir */ - public static File[] getLogFiles(String logDir) - { + public static File[] getLogFiles(String logDir) { // open the log files directory, read in the files, check that they // match the passed regular expression then analyse the content File logs = new File(logDir); - + // if log dir is not a directory throw and error and exit - if (!logs.isDirectory()) - { + if (!logs.isDirectory()) { System.out.println("Passed log directory is not a directory"); System.exit(0); } - + // get the files in the directory return logs.listFiles(); } - - + + /** * set up the regular expressions to be used by this analyser. Mostly this * exists to provide a degree of segregation and readability to the code * and to ensure that you only need to set up the regular expressions to * be used once * - * @param fileTemplate the regex to be used to identify dspace log files + * @param fileTemplate the regex to be used to identify dspace log files */ - public static void setRegex(String fileTemplate) - { + public static void setRegex(String fileTemplate) { // build the exclude characters regular expression StringBuffer charRegEx = new StringBuffer(); charRegEx.append("["); - for (int i = 0; i < excludeChars.size(); i++) - { + for (int i = 0; i < excludeChars.size(); i++) { charRegEx.append("\\").append(excludeChars.get(i)); } charRegEx.append("]"); excludeCharRX = Pattern.compile(charRegEx.toString()); - + // regular expression to find handle indicators in strings handleRX = Pattern.compile("handle="); - + // regular expression to find item_id indicators in strings itemRX = Pattern.compile(",item_id=.*$"); - + // regular expression to find query indicators in strings queryRX = Pattern.compile("query="); - + // regular expression to find collections in strings collectionRX = Pattern.compile("collection_id=[0-9]*,"); - + // regular expression to find communities in strings communityRX = Pattern.compile("community_id=[0-9]*,"); - + // regular expression to find search result sets resultsRX = Pattern.compile(",results=(.*)"); - + // regular expressions to find single characters anywhere in the string singleRX = Pattern.compile("( . |^. | .$)"); - + // set up the standard log file line regular expression - String logLineBase = "^(\\d\\d\\d\\d-\\d\\d\\-\\d\\d) \\d\\d:\\d\\d:\\d\\d,\\d\\d\\d (\\w+)\\s+\\S+ @ (.*)"; //date time LEVEL class @ whatever - String logLine13 = "^(\\d\\d\\d\\d-\\d\\d\\-\\d\\d) \\d\\d:\\d\\d:\\d\\d,\\d\\d\\d (\\w+)\\s+\\S+ @ ([^:]+):[^:]+:([^:]+):(.*)"; - String logLine14 = "^(\\d\\d\\d\\d-\\d\\d\\-\\d\\d) \\d\\d:\\d\\d:\\d\\d,\\d\\d\\d (\\w+)\\s+\\S+ @ ([^:]+):[^:]+:[^:]+:([^:]+):(.*)"; + String logLineBase = "^(\\d\\d\\d\\d-\\d\\d\\-\\d\\d) \\d\\d:\\d\\d:\\d\\d,\\d\\d\\d (\\w+)\\s+\\S+ @ (.*)"; + //date time LEVEL class @ whatever + String logLine13 = "^(\\d\\d\\d\\d-\\d\\d\\-\\d\\d) \\d\\d:\\d\\d:\\d\\d,\\d\\d\\d (\\w+)\\s+\\S+ @ ([^:]+)" + + ":[^:]+:([^:]+):(.*)"; + String logLine14 = "^(\\d\\d\\d\\d-\\d\\d\\-\\d\\d) \\d\\d:\\d\\d:\\d\\d,\\d\\d\\d (\\w+)\\s+\\S+ @ ([^:]+)" + + ":[^:]+:[^:]+:([^:]+):(.*)"; valid13 = Pattern.compile(logLine13); valid14 = Pattern.compile(logLine14); validBase = Pattern.compile(logLineBase); - + // set up the pattern for validating log file names logRegex = Pattern.compile(fileTemplate); - + // set up the pattern for matching any of the query types StringBuffer typeRXString = new StringBuffer(); typeRXString.append("("); - for (int i = 0; i < excludeTypes.size(); i++) - { - if (i > 0) - { + for (int i = 0; i < excludeTypes.size(); i++) { + if (i > 0) { typeRXString.append("|"); } typeRXString.append(excludeTypes.get(i)); } typeRXString.append(")"); typeRX = Pattern.compile(typeRXString.toString()); - + // set up the pattern for matching any of the words to exclude StringBuffer wordRXString = new StringBuffer(); wordRXString.append("("); - for (int i = 0; i < excludeWords.size(); i++) - { - if (i > 0) - { + for (int i = 0; i < excludeWords.size(); i++) { + if (i > 0) { wordRXString.append("|"); } wordRXString.append(" " + excludeWords.get(i) + " "); @@ -858,36 +889,35 @@ public class LogAnalyser } wordRXString.append(")"); wordRX = Pattern.compile(wordRXString.toString()); - + return; } /** * get the current config file name + * * @return The name of the config file */ - public static String getConfigFile() - { + public static String getConfigFile() { return configFile; } /** * Read in the current config file and populate the class globals. + * * @throws IOException if IO error */ - public static void readConfig() throws IOException - { + public static void readConfig() throws IOException { readConfig(configFile); } /** * Read in the given config file and populate the class globals. * - * @param configFile the config file to read in + * @param configFile the config file to read in * @throws IOException if IO error */ - public static void readConfig(String configFile) throws IOException - { + public static void readConfig(String configFile) throws IOException { //instantiate aggregators actionAggregator = new HashMap(); searchAggregator = new HashMap(); @@ -905,78 +935,64 @@ public class LogAnalyser // prepare our standard file readers and buffered readers FileReader fr = null; BufferedReader br = null; - + String record = null; - try - { - fr = new FileReader(configFile); + try { + fr = new FileReader(configFile); br = new BufferedReader(fr); - } - catch (IOException e) - { + } catch (IOException e) { System.out.println("Failed to read config file: " + configFile); System.exit(0); - } - + } + // read in the config file and set up our instance variables - while ((record = br.readLine()) != null) - { + while ((record = br.readLine()) != null) { // check to see what kind of line we have Matcher matchComment = comment.matcher(record); Matcher matchReal = real.matcher(record); // if the line is not a comment and is real, read it in - if (!matchComment.matches() && matchReal.matches()) - { + if (!matchComment.matches() && matchReal.matches()) { // lift the values out of the matcher's result groups String key = matchReal.group(1).trim(); String value = matchReal.group(2).trim(); - - // read the config values into our instance variables (see + + // read the config values into our instance variables (see // documentation for more info on config params) - if (key.equals("general.summary")) - { + if (key.equals("general.summary")) { actionAggregator.put(value, Integer.valueOf(0)); generalSummary.add(value); } - - if (key.equals("exclude.word")) - { + + if (key.equals("exclude.word")) { excludeWords.add(value); } - if (key.equals("exclude.type")) - { + if (key.equals("exclude.type")) { excludeTypes.add(value); } - if (key.equals("exclude.character")) - { + if (key.equals("exclude.character")) { excludeChars.add(value); } - if (key.equals("item.type")) - { + if (key.equals("item.type")) { itemTypes.add(value); } - if (key.equals("item.floor")) - { + if (key.equals("item.floor")) { itemFloor = Integer.parseInt(value); } - if (key.equals("search.floor")) - { + if (key.equals("search.floor")) { searchFloor = Integer.parseInt(value); } - if (key.equals("item.lookup")) - { + if (key.equals("item.lookup")) { itemLookup = Integer.parseInt(value); } - if (key.equals("user.email")) - { + if (key.equals("user.email")) { userEmail = value; } } @@ -985,127 +1001,112 @@ public class LogAnalyser // close the inputs br.close(); fr.close(); - + return; } - + /** * increment the value of the given map at the given key by one. - * - * @param map the map whose value we want to increase - * @param key the key of the map whose value to increase * - * @return an integer object containing the new value + * @param map the map whose value we want to increase + * @param key the key of the map whose value to increase + * @return an integer object containing the new value */ - public static Integer increment(Map map, String key) - { + public static Integer increment(Map map, String key) { Integer newValue = null; - if (map.containsKey(key)) - { + if (map.containsKey(key)) { // FIXME: this seems like a ridiculous way to add Integers newValue = Integer.valueOf((map.get(key)).intValue() + 1); - } - else - { + } else { newValue = Integer.valueOf(1); } return newValue; } - + /** * Take the standard date string requested at the command line and convert * it into a Date object. Throws and error and exits if the date does * not parse * - * @param date the string representation of the date - * - * @return a date object containing the date, with the time set to - * 00:00:00 + * @param date the string representation of the date + * @return a date object containing the date, with the time set to + * 00:00:00 */ - public static Date parseDate(String date) - { + public static Date parseDate(String date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy'-'MM'-'dd"); Date parsedDate = null; - - try - { - parsedDate = sdf.parse(date); - } - catch (ParseException e) - { + + try { + parsedDate = sdf.parse(date); + } catch (ParseException e) { System.out.println("The date is not in the correct format"); System.exit(0); } return parsedDate; } - - + + /** * Take the date object and convert it into a string of the form YYYY-MM-DD * - * @param date the date to be converted - * - * @return A string of the form YYYY-MM-DD + * @param date the date to be converted + * @return A string of the form YYYY-MM-DD */ - public static String unParseDate(Date date) - { + public static String unParseDate(Date date) { // Use SimpleDateFormat SimpleDateFormat sdf = new SimpleDateFormat("yyyy'-'MM'-'dd'T'hh:mm:ss'Z'"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); return sdf.format(date); } - - + + /** * Take a search query string and pull out all of the meaningful information * from it, giving the results in the form of a String array, a single word * to each element - * - * @param query the search query to be analysed * - * @return the string array containing meaningful search terms + * @param query the search query to be analysed + * @return the string array containing meaningful search terms */ - public static String[] analyseQuery(String query) - { + public static String[] analyseQuery(String query) { // register our standard loop counter int i = 0; - + // make the query string totally lower case, to ensure we don't miss out // on matches due to capitalisation query = query.toLowerCase(); - + // now perform successive find and replace operations using pre-defined // global regular expressions Matcher matchQuery = queryRX.matcher(query); query = matchQuery.replaceAll(" "); - + Matcher matchCollection = collectionRX.matcher(query); query = matchCollection.replaceAll(" "); - + Matcher matchCommunity = communityRX.matcher(query); query = matchCommunity.replaceAll(" "); - + Matcher matchResults = resultsRX.matcher(query); query = matchResults.replaceAll(" "); Matcher matchTypes = typeRX.matcher(query); query = matchTypes.replaceAll(" "); - + Matcher matchChars = excludeCharRX.matcher(query); query = matchChars.replaceAll(" "); - + Matcher matchWords = wordRX.matcher(query); query = matchWords.replaceAll(" "); - + Matcher single = singleRX.matcher(query); query = single.replaceAll(" "); - + // split the remaining string by whitespace, trim and stuff into an // array to be returned StringTokenizer st = new StringTokenizer(query); String[] words = new String[st.countTokens()]; - for (i = 0; i < words.length; i++) - { + for (i = 0; i < words.length; i++) { words[i] = st.nextToken().trim(); } @@ -1113,101 +1114,86 @@ public class LogAnalyser // why? and how do we fix it? return words; } - - + + /** * split the given line into it's relevant segments if applicable (i.e. the * line matches the required regular expression. * - * @param line the line to be segmented - * @return a Log Line object for the given line + * @param line the line to be segmented + * @return a Log Line object for the given line */ - public static LogLine getLogLine(String line) - { + public static LogLine getLogLine(String line) { // FIXME: consider moving this code into the LogLine class. To do this // we need to much more carefully define the structure and behaviour // of the LogLine class Matcher match; - - if (line.indexOf(":ip_addr") > 0) - { + + if (line.indexOf(":ip_addr") > 0) { match = valid14.matcher(line); - } - else - { + } else { match = valid13.matcher(line); } - - if (match.matches()) - { + + if (match.matches()) { // set up a new log line object LogLine logLine = new LogLine(parseDate(match.group(1).trim()), LogManager.unescapeLogField(match.group(2)).trim(), LogManager.unescapeLogField(match.group(3)).trim(), LogManager.unescapeLogField(match.group(4)).trim(), LogManager.unescapeLogField(match.group(5)).trim()); - + return logLine; - } - else - { + } else { match = validBase.matcher(line); - if ( match.matches() ) { + if (match.matches()) { LogLine logLine = new LogLine(parseDate(match.group(1).trim()), - LogManager.unescapeLogField(match.group(2)).trim(), - null, - null, - null + LogManager.unescapeLogField(match.group(2)).trim(), + null, + null, + null ); return logLine; } return null; } } - - + + /** - * get the number of items in the archive which were accessioned between + * get the number of items in the archive which were accessioned between * the provided start and end dates, with the given value for the DC field * 'type' (unqualified) * - * @param context the DSpace context for the action - * @param type value for DC field 'type' (unqualified) - * - * @return an integer containing the relevant count - * @throws SQLException if database error + * @param context the DSpace context for the action + * @param type value for DC field 'type' (unqualified) + * @return an integer containing the relevant count + * @throws SQLException if database error * @throws SearchServiceException if search error */ public static Integer getNumItems(Context context, String type) - throws SQLException, SearchServiceException { + throws SQLException, SearchServiceException { // FIXME: this method is clearly not optimised - + // FIXME: we don't yet collect total statistics, such as number of items // withdrawn, number in process of submission etc. We should probably do // that DiscoverQuery discoverQuery = new DiscoverQuery(); - if (StringUtils.isNotBlank(type)) - { - discoverQuery.addFilterQueries("dc.type=" + type +"*"); + if (StringUtils.isNotBlank(type)) { + discoverQuery.addFilterQueries("dc.type=" + type + "*"); } StringBuilder accessionedQuery = new StringBuilder(); accessionedQuery.append("dc.date.accessioned_dt:["); - if (startDate != null) - { + if (startDate != null) { accessionedQuery.append(unParseDate(startDate)); - } - else - { + } else { accessionedQuery.append("*"); } accessionedQuery.append(" TO "); - if (endDate != null) - { + if (endDate != null) { accessionedQuery.append(unParseDate(endDate)); - } - else - { + } else { accessionedQuery.append("*"); } accessionedQuery.append("]"); @@ -1215,72 +1201,70 @@ public class LogAnalyser discoverQuery.addFilterQueries("withdrawn: false"); discoverQuery.addFilterQueries("archived: true"); - return (int)SearchUtils.getSearchService().search(context, discoverQuery).getTotalSearchResults(); + return (int) SearchUtils.getSearchService().search(context, discoverQuery).getTotalSearchResults(); } - - + + /** * get the total number of items in the archive at time of execution, * ignoring all other constraints * - * @param context the DSpace context the action is being performed in - * - * @return an Integer containing the number of items in the - * archive - * @throws SQLException if database error + * @param context the DSpace context the action is being performed in + * @return an Integer containing the number of items in the + * archive + * @throws SQLException if database error * @throws SearchServiceException if search error */ public static Integer getNumItems(Context context) - throws SQLException, SearchServiceException { + throws SQLException, SearchServiceException { return getNumItems(context, null); } - - + + /** * print out the usage information for this class to the standard out */ - public static void usage() - { + public static void usage() { String usage = "Usage Information:\n" + "LogAnalyser [options [parameters]]\n" + "-log [log directory]\n" + - "\tOptional\n" + - "\tSpecify a directory containing log files\n" + - "\tDefault uses [dspace.dir]/log from dspace.cfg\n" + + "\tOptional\n" + + "\tSpecify a directory containing log files\n" + + "\tDefault uses [dspace.dir]/log from dspace.cfg\n" + "-file [file name regex]\n" + - "\tOptional\n" + - "\tSpecify a regular expression as the file name template.\n" + - "\tCurrently this needs to be correctly escaped for Java string handling (FIXME)\n" + - "\tDefault uses dspace.log*\n" + + "\tOptional\n" + + "\tSpecify a regular expression as the file name template.\n" + + "\tCurrently this needs to be correctly escaped for Java string handling (FIXME)\n" + + "\tDefault uses dspace.log*\n" + "-cfg [config file path]\n" + - "\tOptional\n" + - "\tSpecify a config file to be used\n" + - "\tDefault uses dstat.cfg in dspace config directory\n" + + "\tOptional\n" + + "\tSpecify a config file to be used\n" + + "\tDefault uses dstat.cfg in dspace config directory\n" + "-out [output file path]\n" + - "\tOptional\n" + - "\tSpecify an output file to write results into\n" + - "\tDefault uses dstat.dat in dspace log directory\n" + + "\tOptional\n" + + "\tSpecify an output file to write results into\n" + + "\tDefault uses dstat.dat in dspace log directory\n" + "-start [YYYY-MM-DD]\n" + - "\tOptional\n" + - "\tSpecify the start date of the analysis\n" + - "\tIf a start date is specified then no attempt to gather \n" + - "\tcurrent database statistics will be made unless -lookup is\n" + - "\talso passed\n" + - "\tDefault is to start from the earliest date records exist for\n" + + "\tOptional\n" + + "\tSpecify the start date of the analysis\n" + + "\tIf a start date is specified then no attempt to gather \n" + + "\tcurrent database statistics will be made unless -lookup is\n" + + "\talso passed\n" + + "\tDefault is to start from the earliest date records exist for\n" + "-end [YYYY-MM-DD]\n" + - "\tOptional\n" + - "\tSpecify the end date of the analysis\n" + - "\tIf an end date is specified then no attempt to gather \n" + - "\tcurrent database statistics will be made unless -lookup is\n" + - "\talso passed\n" + - "\tDefault is to work up to the last date records exist for\n" + + "\tOptional\n" + + "\tSpecify the end date of the analysis\n" + + "\tIf an end date is specified then no attempt to gather \n" + + "\tcurrent database statistics will be made unless -lookup is\n" + + "\talso passed\n" + + "\tDefault is to work up to the last date records exist for\n" + "-lookup\n" + - "\tOptional\n" + - "\tForce a lookup of the current database statistics\n" + - "\tOnly needs to be used if date constraints are also in place\n" + + "\tOptional\n" + + "\tForce a lookup of the current database statistics\n" + + "\tOnly needs to be used if date constraints are also in place\n" + "-help\n" + - "\tdisplay this usage information\n"; - + "\tdisplay this usage information\n"; + System.out.println(usage); } } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/LogLine.java b/dspace-api/src/main/java/org/dspace/app/statistics/LogLine.java index f8d4d5cced..31dd87db55 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/LogLine.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/LogLine.java @@ -15,161 +15,152 @@ import java.util.Date; * * The components that it represents are: Date, Level, User, Action, and additional * Params - * - * @author Richard Jones + * + * @author Richard Jones */ -public class LogLine -{ - /** the date of the log file line */ +public class LogLine { + /** + * the date of the log file line + */ private Date date = null; - - /** the level of the log line type */ + + /** + * the level of the log line type + */ private String level = null; - - /** the user performing the logged action */ + + /** + * the user performing the logged action + */ private String user = null; - - /** the action being performed */ + + /** + * the action being performed + */ private String action = null; - - /** the parameters associated with the line */ + + /** + * the parameters associated with the line + */ private String params = null; - + /** * constructor to create new statistic */ - LogLine(Date date, String level, String user, String action, String params) - { + LogLine(Date date, String level, String user, String action, String params) { this.date = date; this.level = level; - this.user = user; + this.user = user; this.action = action; this.params = params; } - - /** + + /** * get the date of the log line * - * @return the date of this log line + * @return the date of this log line */ - public Date getDate() - { + public Date getDate() { return this.date == null ? null : new Date(this.date.getTime()); } - - + + /** * get the level of this log line * - * @return the level of the log line + * @return the level of the log line */ - public String getLevel() - { + public String getLevel() { return this.level; } - - + + /** * get the user performing the logged action * - * @return the user performing the logged action + * @return the user performing the logged action */ - public String getUser() - { + public String getUser() { return this.user; } - - + + /** * get the action being performed * - * @return the logged action + * @return the logged action */ - public String getAction() - { + public String getAction() { return this.action; } - - + + /** * get the parameters associated with the action * - * @return the parameters associated with the action + * @return the parameters associated with the action */ - public String getParams() - { + public String getParams() { return this.params; } - - + + /** * find out if this log file line is before the given date * - * @param date the date to be compared to - * - * @return true if the line is before the given date, false if not + * @param date the date to be compared to + * @return true if the line is before the given date, false if not */ - public boolean beforeDate(Date date) - { - if (date != null) - { + public boolean beforeDate(Date date) { + if (date != null) { return (date.compareTo(this.date) >= 0); } return false; } - - + + /** * find out if this log file line is after the given date * - * @param date the date to be compared to - * - * @return true if the line is after the given date, false if not + * @param date the date to be compared to + * @return true if the line is after the given date, false if not */ - public boolean afterDate(Date date) - { - if (date != null) - { + public boolean afterDate(Date date) { + if (date != null) { return (date.compareTo(this.date) <= 0); } return false; } - - + + /** * find out if the log line is of the given level. Levels are either * INFO, WARN or ERROR * - * @param level the level we want to test for - * - * @return true if the line is of the specified level, false if not + * @param level the level we want to test for + * @return true if the line is of the specified level, false if not */ - public boolean isLevel(String level) - { - if (this.getLevel().equals(level)) - { + public boolean isLevel(String level) { + if (this.getLevel().equals(level)) { return true; } return false; } - - + + /** - * find out if the log line is of the given action. Actions are not + * find out if the log line is of the given action. Actions are not * directly constrained by the vocabulary, and any system module may define * any action name for its behaviour * - * @param action the action we want to test for - * - * @return true if the line is of the specified action, false if not + * @param action the action we want to test for + * @return true if the line is of the specified action, false if not */ - public boolean isAction(String action) - { - if (this.getAction().equals(action)) - { + public boolean isAction(String action) { + if (this.getAction().equals(action)) { return true; } return false; } - + } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/Report.java b/dspace-api/src/main/java/org/dspace/app/statistics/Report.java index 20550e680a..398d63b131 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/Report.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/Report.java @@ -7,8 +7,6 @@ */ package org.dspace.app.statistics; -import org.dspace.app.statistics.Statistics; - import java.util.Date; /** @@ -20,120 +18,114 @@ import java.util.Date; * any logic contained within it. It's also been made public, so that you can create a Report * type without monkeying about in the statistics package. * - * @author Richard Jones + * @author Richard Jones */ -public interface Report -{ +public interface Report { /** * output any top headers that this page needs * - * @return a string containing the header for the report + * @return a string containing the header for the report */ public abstract String header(); - + /** * output any top headers that this page needs * - * @param title the title of the report, useful for email subjects or - * HTML headers - * - * @return a string containing the header for the report + * @param title the title of the report, useful for email subjects or + * HTML headers + * @return a string containing the header for the report */ public abstract String header(String title); - + /** * output the title in the relevant format. This requires that the title * has been set with setMainTitle() * - * @return a string containing the title of the report + * @return a string containing the title of the report */ public abstract String mainTitle(); - + /** * output the date range in the relevant format. This requires that the * date ranges have been set using setStartDate() and setEndDate() * - * @return a string containing date range information + * @return a string containing date range information */ public abstract String dateRange(); - + /** * output the section header in the relevant format * - * @param title the title of the current section header - * - * @return a string containing the formatted section header + * @param title the title of the current section header + * @return a string containing the formatted section header */ public abstract String sectionHeader(String title); - + /** * output the report block based on the passed statistics object array * - * @param content a statistics object to form the basis of the displayed - * stat block - * - * @return a string containing the formatted statistics block + * @param content a statistics object to form the basis of the displayed + * stat block + * @return a string containing the formatted statistics block */ public abstract String statBlock(Statistics content); - + /** * output the floor information in the relevant format * - * @param floor the floor value for the statistics block - * - * @return a string containing the formatted floor information + * @param floor the floor value for the statistics block + * @return a string containing the formatted floor information */ public abstract String floorInfo(int floor); - + /** * output the explanation of the stat block in the relevant format * - * @param explanation the explanatory or clarification text for the stats - * - * @return a string containing the formatted explanation + * @param explanation the explanatory or clarification text for the stats + * @return a string containing the formatted explanation */ public abstract String blockExplanation(String explanation); - + /** * output the final footers for this file * - * @return a string containing the report footer + * @return a string containing the report footer */ public abstract String footer(); - + /** * set the main title for the report * - * @param name the name of the service - * @param serverName the name of the server + * @param name the name of the service + * @param serverName the name of the server */ - public abstract void setMainTitle (String name, String serverName); - + public abstract void setMainTitle(String name, String serverName); + /** * add a statistics block to the report to the class register * - * @param stat the statistics object to be added to the report + * @param stat the statistics object to be added to the report */ public abstract void addBlock(Statistics stat); - + /** * render the report * - * @return a string containing the full content of the report + * @return a string containing the full content of the report */ public abstract String render(); - + /** * set the starting date for the report * - * @param start the start date for the report + * @param start the start date for the report */ public abstract void setStartDate(Date start); - + /** * set the end date for the report * - * @param end the end date for the report + * @param end the end date for the report */ public abstract void setEndDate(Date end); } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/ReportGenerator.java b/dspace-api/src/main/java/org/dspace/app/statistics/ReportGenerator.java index b8a8143af0..8c38cc842d 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/ReportGenerator.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/ReportGenerator.java @@ -27,9 +27,9 @@ import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.dspace.content.Item; import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataValue; -import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; @@ -45,155 +45,199 @@ import org.dspace.handle.service.HandleService; * * Use the -help flag for more information * - * @author Richard Jones + * @author Richard Jones */ -public class ReportGenerator -{ +public class ReportGenerator { // set up our class globals - + ///////////////// // aggregators ///////////////// - - /** aggregator for all actions performed in the system */ + + /** + * aggregator for all actions performed in the system + */ private static Map actionAggregator; - - /** aggregator for all searches performed */ + + /** + * aggregator for all searches performed + */ private static Map searchAggregator; - - /** aggregator for user logins */ + + /** + * aggregator for user logins + */ private static Map userAggregator; - - /** aggregator for item views */ + + /** + * aggregator for item views + */ private static Map itemAggregator; - - /** aggregator for current archive state statistics */ + + /** + * aggregator for current archive state statistics + */ private static Map archiveStats; - - + + ////////////////// // statistics config data ////////////////// - - /** bottom limit to output for search word analysis */ + + /** + * bottom limit to output for search word analysis + */ private static int searchFloor; - - /** bottom limit to output for item view analysis */ + + /** + * bottom limit to output for item view analysis + */ private static int itemFloor; - - /** number of items from most popular to be looked up in the database */ + + /** + * number of items from most popular to be looked up in the database + */ private static int itemLookup; - - /** mode to use for user email display */ + + /** + * mode to use for user email display + */ private static String userEmail; - - /** URL of the service being analysed */ + + /** + * URL of the service being analysed + */ private static String url; - - /** Name of the service being analysed */ + + /** + * Name of the service being analysed + */ private static String name; - /** average number of views per item */ + /** + * average number of views per item + */ private static int avgItemViews; - - /** name of the server being analysed */ + + /** + * name of the server being analysed + */ private static String serverName; - - /** start date of this report */ + + /** + * start date of this report + */ private static Date startDate = null; - - /** end date of this report */ + + /** + * end date of this report + */ private static Date endDate = null; - - /** the time taken to build the aggregation file from the log */ + + /** + * the time taken to build the aggregation file from the log + */ private static int processTime; - - /** the number of log lines analysed */ + + /** + * the number of log lines analysed + */ private static int logLines; - - /** the number of warnings encountered */ + + /** + * the number of warnings encountered + */ private static int warnings; - - /** the list of results to be displayed in the general summary */ + + /** + * the list of results to be displayed in the general summary + */ private static List generalSummary; - + ////////////////// // regular expressions ////////////////// - - /** pattern that matches an unqualified aggregator property */ + + /** + * pattern that matches an unqualified aggregator property + */ private static Pattern real = Pattern.compile("^(.+)=(.+)"); - + ////////////////////////// // Miscellaneous variables ////////////////////////// - - /** process timing clock */ + + /** + * process timing clock + */ private static Calendar startTime = null; - - /** a map from log file action to human readable action */ + + /** + * a map from log file action to human readable action + */ private static Map actionMap = null; - + ///////////////// // report generator config data //////////////// - - /** the input file to build the report from */ + + /** + * the input file to build the report from + */ private static String input = null; - - /** the log file action to human readable action map */ + + /** + * the log file action to human readable action map + */ private static String map = ConfigurationManager.getProperty("dspace.dir") + File.separator + "config" + File.separator + "dstat.map"; private static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); private static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - + /** + * Default constructor + */ + private ReportGenerator() { } + /** * main method to be run from command line. See usage information for * details as to how to use the command line flags + * * @param argv the command line arguments given - * @throws Exception on generic exception - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws Exception on generic exception + * @throws SQLException An exception that provides information on a database access error or other errors. */ - public static void main(String [] argv) - throws Exception, SQLException - { + public static void main(String[] argv) + throws Exception, SQLException { // create context as super user Context context = new Context(); context.turnOffAuthorisationSystem(); - + String myFormat = null; String myInput = null; String myOutput = null; String myMap = null; - + // read in our command line options - for (int i = 0; i < argv.length; i++) - { - if (argv[i].equals("-format")) - { - myFormat = argv[i+1].toLowerCase(); + for (int i = 0; i < argv.length; i++) { + if (argv[i].equals("-format")) { + myFormat = argv[i + 1].toLowerCase(); } - - if (argv[i].equals("-in")) - { - myInput = argv[i+1]; + + if (argv[i].equals("-in")) { + myInput = argv[i + 1]; } - - if (argv[i].equals("-out")) - { - myOutput = argv[i+1]; + + if (argv[i].equals("-out")) { + myOutput = argv[i + 1]; } - - if (argv[i].equals("-map")) - { - myMap = argv[i+1]; + + if (argv[i].equals("-map")) { + myMap = argv[i + 1]; } - - if (argv[i].equals("-help")) - { + + if (argv[i].equals("-help")) { usage(); System.exit(0); } @@ -201,44 +245,40 @@ public class ReportGenerator processReport(context, myFormat, myInput, myOutput, myMap); } - + /** - * using the pre-configuration information passed here, read in the + * using the pre-configuration information passed here, read in the * aggregation data and output a file containing the report in the * requested format * * this method is retained for backwards compatibility, but delegates the actual * wprk to a new method * - * @param context the DSpace context in which this action is performed - * @param myFormat the desired output format (currently on HTML supported) - * @param myInput the aggregation file to be turned into a report - * @param myOutput the file into which to write the report - * @param myMap the map - * @throws Exception if error + * @param context the DSpace context in which this action is performed + * @param myFormat the desired output format (currently on HTML supported) + * @param myInput the aggregation file to be turned into a report + * @param myOutput the file into which to write the report + * @param myMap the map + * @throws Exception if error * @throws SQLException if database error */ - public static void processReport(Context context, String myFormat, + public static void processReport(Context context, String myFormat, String myInput, String myOutput, String myMap) - throws Exception, SQLException - { - if (myMap != null) - { + throws Exception, SQLException { + if (myMap != null) { map = myMap; } // create the relevant report type // FIXME: at the moment we only support HTML report generation Report report = null; - if (myFormat.equals("html")) - { + if (myFormat.equals("html")) { report = new HTMLReport(); - ((HTMLReport)report).setOutput(myOutput); + ((HTMLReport) report).setOutput(myOutput); } - if (report == null) - { + if (report == null) { throw new IllegalStateException("Must specify a valid report format"); } @@ -249,18 +289,18 @@ public class ReportGenerator * using the pre-configuration information passed here, read in the * aggregation data and output a file containing the report in the * requested format + * * @param context context - * @param report report + * @param report report * @param myInput input - * @throws Exception if error + * @throws Exception if error * @throws SQLException if database error */ public static void processReport(Context context, Report report, String myInput) - throws Exception, SQLException - { + throws Exception, SQLException { startTime = new GregorianCalendar(); - + /** instantiate aggregators */ actionAggregator = new HashMap(); searchAggregator = new HashMap(); @@ -268,133 +308,121 @@ public class ReportGenerator itemAggregator = new HashMap(); archiveStats = new HashMap(); actionMap = new HashMap(); - + /** instantite lists */ generalSummary = new ArrayList(); - + // set the parameters for this analysis setParameters(myInput); - + // read the input file readInput(input); - + // load the log file action to human readable action map readMap(map); - + report.setStartDate(startDate); report.setEndDate(endDate); report.setMainTitle(name, serverName); - + // define our standard variables for re-use // FIXME: we probably don't need these once we've finished re-factoring Iterator keys = null; int i = 0; String explanation = null; int value; - + // FIXME: All of these sections should probably be buried in their own // custom methods - + Statistics overview = new Statistics(); - + overview.setSectionHeader("General Overview"); - + Iterator summaryEntries = generalSummary.iterator(); - while (summaryEntries.hasNext()) - { + while (summaryEntries.hasNext()) { String entry = summaryEntries.next(); - if (actionAggregator.containsKey(entry)) - { + if (actionAggregator.containsKey(entry)) { int count = Integer.parseInt(actionAggregator.get(entry)); overview.add(new Stat(translate(entry), count)); } } - + report.addBlock(overview); - + // prepare the archive statistics package - if (archiveStats.size() > 0) - { + if (archiveStats.size() > 0) { Statistics archiveInfo = prepareStats(archiveStats, true, false); archiveInfo.setSectionHeader("Archive Information"); archiveInfo.setStatName("Content Type"); archiveInfo.setResultName("Number of items"); - + report.addBlock(archiveInfo); } - - - + + // process the items in preparation to be displayed. This includes sorting // by view number, building the links, and getting further info where // necessary Statistics viewedItems = new Statistics("Item/Handle", "Number of views", itemFloor); viewedItems.setSectionHeader("Items Viewed"); - + Stat[] items = new Stat[itemAggregator.size()]; - + keys = itemAggregator.keySet().iterator(); i = 0; - while (keys.hasNext()) - { + while (keys.hasNext()) { String key = keys.next(); String link = url + "handle/" + key; value = Integer.parseInt(itemAggregator.get(key)); items[i] = new Stat(key, value, link); i++; } - + Arrays.sort(items); - + String info = null; - for (i = 0; i < items.length; i++) - { + for (i = 0; i < items.length; i++) { // Allow negative value to say that all items should be looked up - if (itemLookup < 0 || i < itemLookup) - { + if (itemLookup < 0 || i < itemLookup) { info = getItemInfo(context, items[i].getKey()); } - + // if we get something back from the db then set it as the key, // else just use the link - if (info != null) - { - items[i].setKey(info + " (" + items[i].getKey() + ")"); - } - else - { + if (info != null) { + items[i].setKey(info + " (" + items[i].getKey() + ")"); + } else { items[i].setKey(items[i].getReference()); } - + // reset the info register info = null; } - + viewedItems.add(items); - + report.addBlock(viewedItems); - + // prepare a report of the full action statistics Statistics fullInfo = prepareStats(actionAggregator, true, true); fullInfo.setSectionHeader("All Actions Performed"); fullInfo.setStatName("Action"); fullInfo.setResultName("Number of times"); - + report.addBlock(fullInfo); - + // prepare the user login statistics package - if (!userEmail.equals("off")) - { + if (!userEmail.equals("off")) { Statistics userLogins = prepareStats(userAggregator, true, false); userLogins.setSectionHeader("User Logins"); userLogins.setStatName("User"); userLogins.setResultName("Number of logins"); - if (userEmail.equals("alias")) - { + if (userEmail.equals("alias")) { explanation = "(distinct addresses)"; userLogins.setExplanation(explanation); } - + report.addBlock(userLogins); } @@ -404,48 +432,47 @@ public class ReportGenerator searchWords.setStatName("Word"); searchWords.setResultName("Number of searches"); searchWords.setFloor(searchFloor); - + report.addBlock(searchWords); - + // FIXME: because this isn't an aggregator it can't be passed to // prepareStats; should we overload this method for use with this kind // of data? // prepare the average item views statistics - if (avgItemViews > 0) - { + if (avgItemViews > 0) { Statistics avg = new Statistics(); avg.setSectionHeader("Averaging Information"); Stat[] average = new Stat[1]; - + average[0] = new Stat("Average views per item", avgItemViews); avg.add(average); report.addBlock(avg); } - - + + // prepare the log line level statistics // FIXME: at the moment we only know about warnings, but future versions // should aggregate all log line levels and display here Statistics levels = new Statistics("Level", "Number of lines"); levels.setSectionHeader("Log Level Information"); - + Stat[] level = new Stat[1]; level[0] = new Stat("Warnings", warnings); - + levels.add(level); - + report.addBlock(levels); - + // get the display processing time information Calendar endTime = new GregorianCalendar(); long timeInMillis = (endTime.getTimeInMillis() - startTime.getTimeInMillis()); int outputProcessTime = (int) (timeInMillis / 1000); - + // prepare the processing information statistics Statistics process = new Statistics("Operation", ""); process.setSectionHeader("Processing Information"); - + Stat[] proc = new Stat[3]; proc[0] = new Stat("Log Processing Time", processTime); proc[0].setUnits("seconds"); @@ -453,333 +480,251 @@ public class ReportGenerator proc[1].setUnits("seconds"); proc[2] = new Stat("Log File Lines Analysed", logLines); proc[2].setUnits("lines"); - + process.add(proc); - + report.addBlock(process); report.render(); - + return; } - - + + /** * a standard stats block preparation method for use when an aggregator * has to be put out in its entirity. This method will not be able to * deal with complex cases, although it will perform sorting by value and * translations as per the map file if requested * - * @param aggregator the aggregator that should be converted - * @param sort should the resulting stats be sorted by value - * @param translate translate the stat name using the map file - * - * @return a Statistics object containing all the relevant information + * @param aggregator the aggregator that should be converted + * @param sort should the resulting stats be sorted by value + * @param translate translate the stat name using the map file + * @return a Statistics object containing all the relevant information */ - public static Statistics prepareStats(Map aggregator, boolean sort, boolean translate) - { + public static Statistics prepareStats(Map aggregator, boolean sort, boolean translate) { Stat[] stats = new Stat[aggregator.size()]; - if (aggregator.size() > 0) - { + if (aggregator.size() > 0) { int i = 0; - for (Map.Entry aggregatorEntry : aggregator.entrySet()) - { + for (Map.Entry aggregatorEntry : aggregator.entrySet()) { String key = aggregatorEntry.getKey(); int value = Integer.parseInt(aggregatorEntry.getValue()); - if (translate) - { + if (translate) { stats[i] = new Stat(translate(key), value); - } - else - { + } else { stats[i] = new Stat(key, value); } i++; } - - if (sort) - { + + if (sort) { Arrays.sort(stats); } } - + // add the results to the statistics object Statistics statistics = new Statistics(); statistics.add(stats); - + return statistics; } - - + + /** * look the given text up in the action map table and return a translated * value if one exists. If no translation exists the original text is * returned * - * @param text the text to be translated - * - * @return a string containing either the translated text or the original - * text + * @param text the text to be translated + * @return a string containing either the translated text or the original + * text */ - public static String translate(String text) - { - if (actionMap.containsKey(text)) - { + public static String translate(String text) { + if (actionMap.containsKey(text)) { return actionMap.get(text); - } - else - { + } else { return text; } } - - + + /** * read in the action map file which converts log file line actions into * actions which are more understandable to humans * - * @param map the map file + * @param map the map file * @throws IOException if IO error */ public static void readMap(String map) - throws IOException - { + throws IOException { FileReader fr = null; BufferedReader br = null; - try - { + try { // read in the map file, printing a warning if none is found String record = null; - try - { + try { fr = new FileReader(map); br = new BufferedReader(fr); - } - catch (IOException e) - { + } catch (IOException e) { System.err.println("Failed to read map file: log file actions will be displayed without translation"); return; } // loop through the map file and read in the values - while ((record = br.readLine()) != null) - { + while ((record = br.readLine()) != null) { Matcher matchReal = real.matcher(record); // if the line is real then read it in - if (matchReal.matches()) - { + if (matchReal.matches()) { actionMap.put(matchReal.group(1).trim(), matchReal.group(2).trim()); } } - } - finally - { - if (br != null) - { - try - { + } finally { + if (br != null) { + try { br.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } - if (fr != null) - { - try - { + if (fr != null) { + try { fr.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } } - - + + /** * set the passed parameters up as global class variables. This has to * be done in a separate method because the API permits for running from * the command line with args or calling the processReport method statically * from elsewhere * - * @param myInput regex for log file names + * @param myInput regex for log file names */ - public static void setParameters(String myInput) - { - if (myInput != null) - { + public static void setParameters(String myInput) { + if (myInput != null) { input = myInput; } - + return; } - - + + /** * read the input file and populate all the class globals with the contents * The values that come from this file form the basis of the analysis report * - * @param input the aggregator file - * @throws IOException if IO error + * @param input the aggregator file + * @throws IOException if IO error * @throws ParseException if parse error */ public static void readInput(String input) - throws IOException, ParseException - { + throws IOException, ParseException { FileReader fr = null; BufferedReader br = null; - + // read in the analysis information, throwing an error if we fail to open // the given file String record = null; - try - { + try { fr = new FileReader(input); br = new BufferedReader(fr); - } - catch (IOException e) - { + } catch (IOException e) { System.out.println("Failed to read input file: " + input); return; - } - + } + // first initialise a date format object to do our date processing // if necessary SimpleDateFormat sdf = new SimpleDateFormat("dd'/'MM'/'yyyy"); // FIXME: although this works, it is not very elegant // loop through the aggregator file and read in the values - while ((record = br.readLine()) != null) - { + while ((record = br.readLine()) != null) { // match real lines Matcher matchReal = real.matcher(record); - + // pre-prepare our input strings String section = null; String key = null; String value = null; - + // temporary string to hold the left hand side of the equation String left = null; - + // match the line or skip this record - if (matchReal.matches()) - { + if (matchReal.matches()) { // lift the values out of the matcher's result groups left = matchReal.group(1).trim(); value = matchReal.group(2).trim(); - + // now analyse the left hand side, splitting by ".", taking the // first token as the section and the remainder of the string // as they key if it exists StringTokenizer tokens = new StringTokenizer(left, "."); int numTokens = tokens.countTokens(); - if (tokens.hasMoreTokens()) - { + if (tokens.hasMoreTokens()) { section = tokens.nextToken(); - if (numTokens > 1) - { + if (numTokens > 1) { key = left.substring(section.length() + 1); - } - else - { + } else { key = ""; } } - } - else - { + } else { continue; } - + // if the line is real, then we carry on // read the analysis contents in - if ("archive".equals(section)) - { + if ("archive".equals(section)) { archiveStats.put(key, value); - } - else if ("action".equals(section)) - { + } else if ("action".equals(section)) { actionAggregator.put(key, value); - } - else if ("user".equals(section)) - { + } else if ("user".equals(section)) { userAggregator.put(key, value); - } - else if ("search".equals(section)) - { + } else if ("search".equals(section)) { searchAggregator.put(key, value); - } - else if ("item".equals(section)) - { + } else if ("item".equals(section)) { itemAggregator.put(key, value); - } - else if ("user_email".equals(section)) - { + } else if ("user_email".equals(section)) { userEmail = value; - } - else if ("item_floor".equals(section)) - { + } else if ("item_floor".equals(section)) { itemFloor = Integer.parseInt(value); - } - else if ("search_floor".equals(section)) - { + } else if ("search_floor".equals(section)) { searchFloor = Integer.parseInt(value); - } - else if ("host_url".equals(section)) - { + } else if ("host_url".equals(section)) { url = value; - } - else if ("item_lookup".equals(section)) - { + } else if ("item_lookup".equals(section)) { itemLookup = Integer.parseInt(value); - } - else if ("avg_item_views".equals(section)) - { - try - { + } else if ("avg_item_views".equals(section)) { + try { avgItemViews = Integer.parseInt(value); - } - catch (NumberFormatException e) - { + } catch (NumberFormatException e) { avgItemViews = 0; } - } - else if ("server_name".equals(section)) - { + } else if ("server_name".equals(section)) { serverName = value; - } - else if ("service_name".equals(section)) - { + } else if ("service_name".equals(section)) { name = value; - } - else if ("start_date".equals(section)) - { + } else if ("start_date".equals(section)) { startDate = sdf.parse(value); - } - else if ("end_date".equals(section)) - { + } else if ("end_date".equals(section)) { endDate = sdf.parse(value); - } - else if ("analysis_process_time".equals(section)) - { + } else if ("analysis_process_time".equals(section)) { processTime = Integer.parseInt(value); - } - else if ("general_summary".equals(section)) - { + } else if ("general_summary".equals(section)) { generalSummary.add(value); - } - else if ("log_lines".equals(section)) - { + } else if ("log_lines".equals(section)) { logLines = Integer.parseInt(value); - } - else if ("warnings".equals(section)) - { + } else if ("warnings".equals(section)) { warnings = Integer.parseInt(value); } } @@ -788,91 +733,82 @@ public class ReportGenerator br.close(); fr.close(); } - + /** * get the information for the item with the given handle * - * @param context the DSpace context we are operating under - * @param handle the handle of the item being looked up, in the form - * 1234/567 and so forth - * - * @return a string containing a reference (almost citation) to the - * article + * @param context the DSpace context we are operating under + * @param handle the handle of the item being looked up, in the form + * 1234/567 and so forth + * @return a string containing a reference (almost citation) to the + * article * @throws SQLException if database error */ public static String getItemInfo(Context context, String handle) - throws SQLException - { + throws SQLException { Item item = null; - + // ensure that the handle exists - try - { + try { item = (Item) handleService.resolveToObject(context, handle); - } - catch (Exception e) - { + } catch (Exception e) { return null; } - + // if no handle that matches is found then also return null - if (item == null) - { + if (item == null) { return null; } - + // build the referece // FIXME: here we have blurred the line between content and presentation // and it should probably be un-blurred List title = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); - List author = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "contributor", "author", Item.ANY); - + List author = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "contributor", "author", Item.ANY); + StringBuffer authors = new StringBuffer(); - if (author.size() > 0) - { + if (author.size() > 0) { authors.append("(" + author.get(0).getValue()); } - if (author.size() > 1) - { + if (author.size() > 1) { authors.append(" et al"); } - if (author.size() > 0) - { - authors.append(")"); + if (author.size() > 0) { + authors.append(")"); } - + String content = title.get(0).getValue() + " " + authors.toString(); - + return content; } - - + + /** * output the usage information to the terminal */ - public static void usage() - { + public static void usage() { String usage = "Usage Information:\n" + - "ReportGenerator [options [parameters]]\n" + - "-format [output format]\n" + - "\tRequired\n" + - "\tSpecify the format that you would like the output in\n" + - "\tOptions:\n" + - "\t\thtml\n" + - "-in [aggregation file]\n" + - "\tRequired\n" + - "\tSpecify the aggregation data file to display\n" + - "-out [output file]\n" + - "\tOptional\n" + - "\tSpecify the file to output the report to\n" + - "\tDefault uses [dspace log directory]/report\n" + - "-map [map file]\n" + - "\tOptional\n" + - "\tSpecify the map file to translate log file actions into human readable actions\n" + - "\tDefault uses [dspace config directory]/dstat.map\n" + - "-help\n" + - "\tdisplay this usage information\n"; - + "ReportGenerator [options [parameters]]\n" + + "-format [output format]\n" + + "\tRequired\n" + + "\tSpecify the format that you would like the output in\n" + + "\tOptions:\n" + + "\t\thtml\n" + + "-in [aggregation file]\n" + + "\tRequired\n" + + "\tSpecify the aggregation data file to display\n" + + "-out [output file]\n" + + "\tOptional\n" + + "\tSpecify the file to output the report to\n" + + "\tDefault uses [dspace log directory]/report\n" + + "-map [map file]\n" + + "\tOptional\n" + + "\tSpecify the map file to translate log file actions into human readable actions\n" + + "\tDefault uses [dspace config directory]/dstat.map\n" + + "-help\n" + + "\tdisplay this usage information\n"; + System.out.println(usage); } } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/ReportTools.java b/dspace-api/src/main/java/org/dspace/app/statistics/ReportTools.java index 81e8606236..8637b59f85 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/ReportTools.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/ReportTools.java @@ -10,27 +10,30 @@ package org.dspace.app.statistics; import java.text.NumberFormat; /** - * This class provides a number of tools that may be useful to the methods + * This class provides a number of tools that may be useful to the methods * which generate the different types of report * - * @author Richard Jones + * @author Richard Jones */ -public class ReportTools -{ +public class ReportTools { + + /** + * Default constructor + */ + private ReportTools() { } + /** * method to take the given integer and produce a string to be used in * the display of the report. Basically provides an interface for a * standard NumberFormat class, but without the hassle of instantiating * and localising it. * - * @param number the integer to be formatted - * - * @return a string containing the formatted number + * @param number the integer to be formatted + * @return a string containing the formatted number */ - public static String numberFormat(int number) - { + public static String numberFormat(int number) { NumberFormat nf = NumberFormat.getIntegerInstance(); return nf.format((double) number); } - + } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/Stat.java b/dspace-api/src/main/java/org/dspace/app/statistics/Stat.java index 34d6c0dbb1..717c8d666c 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/Stat.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/Stat.java @@ -8,160 +8,151 @@ package org.dspace.app.statistics; /** - * This is a primitive class to represent a single statistic, which will + * This is a primitive class to represent a single statistic, which will * generally be a key value pair but with the capabilities for being sorted * * Note: this class has a natural ordering that is inconsistent with equals * - * @author Richard Jones + * @author Richard Jones */ -public class Stat implements Comparable -{ +public class Stat implements Comparable { // FIXME: this class is functional but a bit messy, and should be neatened // up and completed - - /** the key, which is effectively the text of the statistic */ + + /** + * the key, which is effectively the text of the statistic + */ private String key = null; - - /** the value assigned to the key, generally a count of the key */ + + /** + * the value assigned to the key, generally a count of the key + */ private int value = 0; - - /** a reference to an external resource which relates to this statistic */ + + /** + * a reference to an external resource which relates to this statistic + */ private String reference = null; - - /** the units that this statistic is in */ + + /** + * the units that this statistic is in + */ private String units = null; - + /** * constructor to create new statistic * - * @param key the key for the statistic - * @param value the value for the statistic + * @param key the key for the statistic + * @param value the value for the statistic */ - Stat(String key, int value) - { + Stat(String key, int value) { this.key = key; this.value = value; } - + /** * constructor to create new statistic * - * @param key the key for the statistic - * @param value the value for the statistic - * @param reference the value for the external reference + * @param key the key for the statistic + * @param value the value for the statistic + * @param reference the value for the external reference */ - Stat(String key, int value, String reference) - { + Stat(String key, int value, String reference) { this.key = key; this.value = value; this.reference = reference; } - + /** * set the units of this statistic * - * @param unit the units that this statistic is measured in + * @param unit the units that this statistic is measured in */ - public void setUnits(String unit) - { + public void setUnits(String unit) { this.units = unit; } - + /** * get the unts that this statistic is measured in * - * @return the units this statistic is measured in + * @return the units this statistic is measured in */ - public String getUnits() - { + public String getUnits() { return this.units; } - - /** + + /** * get the value of the statistic * - * @return the value of this statistic + * @return the value of this statistic */ - public int getValue() - { + public int getValue() { return this.value; } - - + + /** * get the key (text describing) the statistic * - * @return the key for this statistic + * @return the key for this statistic */ - public String getKey() - { + public String getKey() { return this.key; } - - + + /** * get the reference to related statistic information * - * @return the reference for this statistic + * @return the reference for this statistic */ - public String getReference() - { + public String getReference() { return this.reference; } - - + + /** * set the reference information * - * @param key the key for this statistic + * @param key the key for this statistic */ - public void setKey(String key) - { + public void setKey(String key) { this.key = key; } - - + + /** * set the reference information * - * @param reference the reference for this statistic + * @param reference the reference for this statistic */ - public void setReference(String reference) - { + public void setReference(String reference) { this.reference = reference; } - - - /** + + + /** * compare the current object to the given object returning -1 if o is less * than the current object, 0 if they are the same, and +1 if o is greater * than the current object. * - * @param o the object to compare to the current one - * - * @return +1, 0, -1 if o is less than, equal to, or greater than the - * current object value. + * @param o the object to compare to the current one + * @return +1, 0, -1 if o is less than, equal to, or greater than the + * current object value. */ @Override - public int compareTo(Object o) - { + public int compareTo(Object o) { int objectValue = ((Stat) o).getValue(); - - if (objectValue < this.getValue()) - { + + if (objectValue < this.getValue()) { return -1; - } - else if (objectValue == this.getValue()) - { + } else if (objectValue == this.getValue()) { return 0; - } - else if (objectValue > this.getValue()) - { + } else if (objectValue > this.getValue()) { return 1; } - + return 0; - } - + } + } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/Statistics.java b/dspace-api/src/main/java/org/dspace/app/statistics/Statistics.java index 81bdd11213..447f047548 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/Statistics.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/Statistics.java @@ -13,207 +13,201 @@ import java.util.List; /** * This class provides a wrapper for a related set of statistics. It contains * headers for the Stat key and value pairs for the convenience of displaying - * them to users as, for example, HTML table headers. It also holds the + * them to users as, for example, HTML table headers. It also holds the * list of statistics, and can have them added to itself individually or in * arrays * - * @author Richard Jones + * @author Richard Jones */ -public class Statistics -{ +public class Statistics { // FIXME: this class could probably do with some tidying - - /** the header for the statistics type. Useful for outputting to user */ + + /** + * the header for the statistics type. Useful for outputting to user + */ private String statName = null; - - /** the header for the results. Useful for outputting to user */ + + /** + * the header for the results. Useful for outputting to user + */ private String resultName = null; - - /** a list to hold all of the stat elements that this object contains */ + + /** + * a list to hold all of the stat elements that this object contains + */ private List stats = new ArrayList(); - - /** the floor value for this set of statistics */ + + /** + * the floor value for this set of statistics + */ private int floor = 0; - - /** an explanation of this statistics set */ + + /** + * an explanation of this statistics set + */ private String explanation = null; - - /** the main section header for this set of statistics */ + + /** + * the main section header for this set of statistics + */ private String sectionHeader = null; - + /** * constructor to create new set of statistics */ - Statistics() - { + Statistics() { // empty constructor } - + /** * constructor to create new statistic with relevant headers * - * @param statName name of the statistic - * @param resultName name of the result + * @param statName name of the statistic + * @param resultName name of the result */ - Statistics(String statName, String resultName) - { + Statistics(String statName, String resultName) { this.statName = statName; this.resultName = resultName; } - + /** * constructor to create new statistic with relevant headers * - * @param statName name of the statistic - * @param resultName name of the result + * @param statName name of the statistic + * @param resultName name of the result */ - Statistics(String statName, String resultName, int floor) - { + Statistics(String statName, String resultName, int floor) { this.statName = statName; this.resultName = resultName; this.floor = floor; } - + /** * add an individual statistic to this object * - * @param stat a statistic for this object + * @param stat a statistic for this object */ - public void add(Stat stat) - { + public void add(Stat stat) { this.stats.add(stat); return; } - + /** * set the name of the statistic column * - * @param name the name of the statistic column + * @param name the name of the statistic column */ - public void setStatName(String name) - { + public void setStatName(String name) { this.statName = name; } - + /** * set the name of the results column * - * @param name the name of the results column + * @param name the name of the results column */ - public void setResultName(String name) - { + public void setResultName(String name) { this.resultName = name; } - - + + /** * set the explanatory or clarification information for this block of stats * - * @param explanation the explanation for this stat block + * @param explanation the explanation for this stat block */ - public void setExplanation(String explanation) - { + public void setExplanation(String explanation) { this.explanation = explanation; } - - + + /** * get the explanation or clarification information for this block of stats * - * @return the explanation for this stat block + * @return the explanation for this stat block */ - public String getExplanation() - { + public String getExplanation() { return this.explanation; } - - + + /** * set the floor value used in this stat block * - * @param floor the floor value for this stat block + * @param floor the floor value for this stat block */ - public void setFloor(int floor) - { + public void setFloor(int floor) { this.floor = floor; } - - + + /** * get the floor value used in this stat block * - * @return the floor value for this stat block + * @return the floor value for this stat block */ - public int getFloor() - { + public int getFloor() { return this.floor; } - - + + /** * set the header for this particular stats block * - * @param header for this stats block + * @param header for this stats block */ - public void setSectionHeader(String header) - { + public void setSectionHeader(String header) { this.sectionHeader = header; } - - + + /** * get the header for this particular stats block * - * @return the header for this stats block + * @return the header for this stats block */ - public String getSectionHeader() - { + public String getSectionHeader() { return this.sectionHeader; } - + /** * add an array of statistics to this object * - * @param stats an array of statistics + * @param stats an array of statistics */ - public void add(Stat[] stats) - { - for (int i = 0; i < stats.length; i++) - { + public void add(Stat[] stats) { + for (int i = 0; i < stats.length; i++) { this.stats.add(stats[i]); } return; } - + /** * get an array of statistics back from this object * - * @return the statistics array + * @return the statistics array */ - public Stat[] getStats() - { + public Stat[] getStats() { Stat[] myStats = new Stat[stats.size()]; myStats = (Stat[]) stats.toArray(myStats); return myStats; } - + /** * get the name of the statistic * - * @return the name of the statistic + * @return the name of the statistic */ - public String getStatName() - { + public String getStatName() { return statName; } - + /** * get the name of the result set * - * @return the name of the result set + * @return the name of the result set */ - public String getResultName() - { + public String getResultName() { return resultName; } } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/StatisticsLoader.java b/dspace-api/src/main/java/org/dspace/app/statistics/StatisticsLoader.java index cc125897bb..02957bde4f 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/StatisticsLoader.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/StatisticsLoader.java @@ -7,23 +7,27 @@ */ package org.dspace.app.statistics; -import org.apache.commons.lang.time.DateUtils; -import org.dspace.core.ConfigurationManager; - -import java.text.DateFormat; -import java.util.*; -import java.util.regex.Pattern; -import java.util.regex.Matcher; import java.io.File; import java.io.FilenameFilter; -import java.text.SimpleDateFormat; +import java.text.DateFormat; import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.time.DateUtils; +import org.dspace.core.ConfigurationManager; /** * Helper class for loading the analysis / report files from the reports directory */ -public class StatisticsLoader -{ +public class StatisticsLoader { private static Map monthlyAnalysis = null; private static Map monthlyReports = null; @@ -31,30 +35,29 @@ public class StatisticsLoader private static StatsFile generalReport = null; private static Date lastLoaded = null; - private static int fileCount = 0; + private static int fileCount = 0; private static Pattern analysisMonthlyPattern; private static Pattern analysisGeneralPattern; private static Pattern reportMonthlyPattern; private static Pattern reportGeneralPattern; - private static ThreadLocal monthlySDF; - private static ThreadLocal generalSDF; + private static ThreadLocal monthlySDF; + private static ThreadLocal generalSDF; // one time initialisation of the regex patterns and formatters we will use - static - { + static { analysisMonthlyPattern = Pattern.compile("dspace-log-monthly-([0-9][0-9][0-9][0-9]-[0-9]+)\\.dat"); analysisGeneralPattern = Pattern.compile("dspace-log-general-([0-9]+-[0-9]+-[0-9]+)\\.dat"); - reportMonthlyPattern = Pattern.compile("report-([0-9][0-9][0-9][0-9]-[0-9]+)\\.html"); - reportGeneralPattern = Pattern.compile("report-general-([0-9]+-[0-9]+-[0-9]+)\\.html"); + reportMonthlyPattern = Pattern.compile("report-([0-9][0-9][0-9][0-9]-[0-9]+)\\.html"); + reportGeneralPattern = Pattern.compile("report-general-([0-9]+-[0-9]+-[0-9]+)\\.html"); - monthlySDF = new ThreadLocal(){ + monthlySDF = new ThreadLocal() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy'-'M"); } - }; + }; generalSDF = new ThreadLocal() { @Override @@ -64,42 +67,44 @@ public class StatisticsLoader }; } + /** + * Default constructor + */ + private StatisticsLoader() { } + /** * Get an array of the dates of the report files. + * * @return array of dates */ - public static Date[] getMonthlyReportDates() - { + public static Date[] getMonthlyReportDates() { return sortDatesDescending(getDatesFromMap(monthlyReports)); } /** * Get an array of the dates of the analysis files. + * * @return array of dates */ - public static Date[] getMonthlyAnalysisDates() - { + public static Date[] getMonthlyAnalysisDates() { return sortDatesDescending(getDatesFromMap(monthlyAnalysis)); } /** * Convert the formatted dates that are the keys of the map into a date array. - * @param monthlyMap map + * + * @param monthlyMap map * @return array of dates */ - protected static Date[] getDatesFromMap(Map monthlyMap) - { + protected static Date[] getDatesFromMap(Map monthlyMap) { Set keys = monthlyMap.keySet(); Date[] dates = new Date[keys.size()]; int i = 0; - for (String date : keys) - { - try - { + for (String date : keys) { + try { dates[i] = monthlySDF.get().parse(date); - } - catch (ParseException pe) - { + } catch (ParseException pe) { + // ignore } i++; @@ -110,33 +115,23 @@ public class StatisticsLoader /** * Sort the date array in descending (reverse chronological) order. + * * @param dates array of dates * @return sorted dates. */ - protected static Date[] sortDatesDescending(Date[] dates) - { + protected static Date[] sortDatesDescending(Date[] dates) { Arrays.sort(dates, new Comparator() { @Override - public int compare(Date d1, Date d2) - { - if (d1 == null && d2 == null) - { + public int compare(Date d1, Date d2) { + if (d1 == null && d2 == null) { return 0; - } - else if (d1 == null) - { + } else if (d1 == null) { return -1; - } - else if (d2 == null) - { + } else if (d2 == null) { return 1; - } - else if (d1.before(d2)) - { + } else if (d1.before(d2)) { return 1; - } - else if (d2.before(d1)) - { + } else if (d2.before(d1)) { return -1; } @@ -148,11 +143,11 @@ public class StatisticsLoader /** * Get the analysis file for a given date. + * * @param date date * @return File */ - public static File getAnalysisFor(String date) - { + public static File getAnalysisFor(String date) { StatisticsLoader.syncFileList(); StatsFile sf = (monthlyAnalysis == null ? null : monthlyAnalysis.get(date)); return sf == null ? null : sf.file; @@ -160,11 +155,11 @@ public class StatisticsLoader /** * Get the report file for a given date. + * * @param date date * @return File */ - public static File getReportFor(String date) - { + public static File getReportFor(String date) { StatisticsLoader.syncFileList(); StatsFile sf = (monthlyReports == null ? null : monthlyReports.get(date)); return sf == null ? null : sf.file; @@ -172,20 +167,20 @@ public class StatisticsLoader /** * Get the current general analysis file. + * * @return File */ - public static File getGeneralAnalysis() - { + public static File getGeneralAnalysis() { StatisticsLoader.syncFileList(); return generalAnalysis == null ? null : generalAnalysis.file; } /** * Get the current general report file. + * * @return File */ - public static File getGeneralReport() - { + public static File getGeneralReport() { StatisticsLoader.syncFileList(); return generalReport == null ? null : generalReport.file; } @@ -199,99 +194,80 @@ public class StatisticsLoader * 2) We haven't cached anything yet * 3) The cache was last generate over an hour ago */ - private static void syncFileList() - { + private static void syncFileList() { // Get an array of all the analysis and report files present File[] fileList = StatisticsLoader.getAnalysisAndReportFileList(); - if (fileList != null && fileList.length != fileCount) - { + if (fileList != null && fileList.length != fileCount) { StatisticsLoader.loadFileList(fileList); - } - else if (lastLoaded == null) - { + } else if (lastLoaded == null) { StatisticsLoader.loadFileList(fileList); - } - else if (DateUtils.addHours(lastLoaded, 1).before(new Date())) - { + } else if (DateUtils.addHours(lastLoaded, 1).before(new Date())) { StatisticsLoader.loadFileList(fileList); } } /** * Generate the cached file list from the array of files + * * @param fileList array of files */ - private static synchronized void loadFileList(File[] fileList) - { + private static synchronized void loadFileList(File[] fileList) { // If we haven't been passed an array of files, get one now - if (fileList == null || fileList.length == 0) - { + if (fileList == null || fileList.length == 0) { fileList = StatisticsLoader.getAnalysisAndReportFileList(); } // Create new maps for the monthly analysis / reports Map newMonthlyAnalysis = new HashMap(); - Map newMonthlyReports = new HashMap(); + Map newMonthlyReports = new HashMap(); StatsFile newGeneralAnalysis = null; StatsFile newGeneralReport = null; - if (fileList != null) - { - for (File thisFile : fileList) - { + if (fileList != null) { + for (File thisFile : fileList) { StatsFile statsFile = null; // If we haven't identified this file yet - if (statsFile == null) - { + if (statsFile == null) { // See if it is a monthly analysis file statsFile = makeStatsFile(thisFile, analysisMonthlyPattern, monthlySDF.get()); - if (statsFile != null) - { + if (statsFile != null) { // If it is, add it to the map newMonthlyAnalysis.put(statsFile.dateStr, statsFile); } } // If we haven't identified this file yet - if (statsFile == null) - { + if (statsFile == null) { // See if it is a monthly report file statsFile = makeStatsFile(thisFile, reportMonthlyPattern, monthlySDF.get()); - if (statsFile != null) - { + if (statsFile != null) { // If it is, add it to the map newMonthlyReports.put(statsFile.dateStr, statsFile); } } // If we haven't identified this file yet - if (statsFile == null) - { + if (statsFile == null) { // See if it is a general analysis file statsFile = makeStatsFile(thisFile, analysisGeneralPattern, generalSDF.get()); - if (statsFile != null) - { + if (statsFile != null) { // If it is, ensure that we are pointing to the most recent file - if (newGeneralAnalysis == null || statsFile.date.after(newGeneralAnalysis.date)) - { + if (newGeneralAnalysis == null || statsFile.date.after(newGeneralAnalysis.date)) { newGeneralAnalysis = statsFile; } } } // If we haven't identified this file yet - if (statsFile == null) - { + if (statsFile == null) { // See if it is a general report file statsFile = makeStatsFile(thisFile, reportGeneralPattern, generalSDF.get()); - if (statsFile != null) - { + if (statsFile != null) { // If it is, ensure that we are pointing to the most recent file - if (newGeneralReport == null || statsFile.date.after(newGeneralReport.date)) - { + if (newGeneralReport == null || statsFile.date.after(newGeneralReport.date)) { newGeneralReport = statsFile; } } @@ -301,9 +277,9 @@ public class StatisticsLoader // Store the newly discovered values in the member cache monthlyAnalysis = newMonthlyAnalysis; - monthlyReports = newMonthlyReports; + monthlyReports = newMonthlyReports; generalAnalysis = newGeneralAnalysis; - generalReport = newGeneralReport; + generalReport = newGeneralReport; lastLoaded = new Date(); } @@ -312,45 +288,40 @@ public class StatisticsLoader * formatters are used to identify the file as a particular type, * and extract the relevant information. If the file is not identified * by the formatter provided, then we return null. - * @param thisFile file + * + * @param thisFile file * @param thisPattern patter - * @param sdf date format + * @param sdf date format * @return StatsFile */ - private static StatsFile makeStatsFile(File thisFile, Pattern thisPattern, DateFormat sdf) - { + private static StatsFile makeStatsFile(File thisFile, Pattern thisPattern, DateFormat sdf) { Matcher matcher = thisPattern.matcher(thisFile.getName()); - if (matcher.matches()) - { + if (matcher.matches()) { StatsFile sf = new StatsFile(); sf.file = thisFile; sf.path = thisFile.getPath(); sf.dateStr = matcher.group(1).trim(); - try - { + try { sf.date = sdf.parse(sf.dateStr); - } - catch (ParseException e) - { - + } catch (ParseException e) { + // ignore } return sf; } - + return null; } /** * Get an array of all the analysis and report files. + * * @return array of files */ - private static File[] getAnalysisAndReportFileList() - { + private static File[] getAnalysisAndReportFileList() { File reportDir = new File(ConfigurationManager.getProperty("log.report.dir")); - if (reportDir != null) - { + if (reportDir != null) { return reportDir.listFiles(new AnalysisAndReportFilter()); } @@ -360,8 +331,7 @@ public class StatisticsLoader /** * Simple class for holding information about an analysis/report file. */ - private static class StatsFile - { + private static class StatsFile { File file; String path; Date date; @@ -372,28 +342,22 @@ public class StatisticsLoader * Filter used to restrict files in the reports directory to just * analysis or report types. */ - private static class AnalysisAndReportFilter implements FilenameFilter - { + private static class AnalysisAndReportFilter implements FilenameFilter { @Override - public boolean accept(File dir, String name) - { - if (analysisMonthlyPattern.matcher(name).matches()) - { + public boolean accept(File dir, String name) { + if (analysisMonthlyPattern.matcher(name).matches()) { return true; } - if (analysisGeneralPattern.matcher(name).matches()) - { + if (analysisGeneralPattern.matcher(name).matches()) { return true; } - if (reportMonthlyPattern.matcher(name).matches()) - { + if (reportMonthlyPattern.matcher(name).matches()) { return true; } - - if (reportGeneralPattern.matcher(name).matches()) - { + + if (reportGeneralPattern.matcher(name).matches()) { return true; } diff --git a/dspace-api/src/main/java/org/dspace/app/util/AbstractDSpaceWebapp.java b/dspace-api/src/main/java/org/dspace/app/util/AbstractDSpaceWebapp.java index 4f4d3d1124..12389ecfce 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/AbstractDSpaceWebapp.java +++ b/dspace-api/src/main/java/org/dspace/app/util/AbstractDSpaceWebapp.java @@ -27,8 +27,7 @@ import org.slf4j.LoggerFactory; * @author mwood */ abstract public class AbstractDSpaceWebapp - implements DSpaceWebappMXBean -{ + implements DSpaceWebappMXBean { private static final Logger log = LoggerFactory.getLogger(AbstractDSpaceWebapp.class); protected final WebAppService webAppService = UtilServiceFactory.getInstance().getWebAppService(); @@ -42,9 +41,10 @@ abstract public class AbstractDSpaceWebapp protected WebApp webApp; - /** Prevent null instantiation. */ - protected AbstractDSpaceWebapp() - { + /** + * Prevent null instantiation. + */ + protected AbstractDSpaceWebapp() { } /** @@ -52,22 +52,21 @@ abstract public class AbstractDSpaceWebapp * * @param kind what kind of application is this? (XMLUI, JSPUI, etc.) */ - public AbstractDSpaceWebapp(String kind) - { + public AbstractDSpaceWebapp(String kind) { this.kind = kind; started = new Date(); url = ConfigurationManager.getProperty("dspace.url"); - if (null == url) - { + if (null == url) { throw new IllegalStateException("dspace.url is undefined"); } } - /** Record that this application is running. */ - public void register() - { + /** + * Record that this application is running. + */ + public void register() { // Create the database entry Timestamp now = new Timestamp(started.getTime()); try { @@ -79,9 +78,10 @@ abstract public class AbstractDSpaceWebapp } } - /** Record that this application is not running. */ - public void deregister() - { + /** + * Record that this application is not running. + */ + public void deregister() { // Remove the database entry try { Context context = new Context(); @@ -93,20 +93,17 @@ abstract public class AbstractDSpaceWebapp } @Override - public String getKind() - { + public String getKind() { return kind; } @Override - public String getURL() - { + public String getURL() { return url; } @Override - public String getStarted() - { + public String getStarted() { return started.toString(); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/AuthorizeUtil.java b/dspace-api/src/main/java/org/dspace/app/util/AuthorizeUtil.java index c18dd0985f..bb7e8e43b8 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/AuthorizeUtil.java +++ b/dspace-api/src/main/java/org/dspace/app/util/AuthorizeUtil.java @@ -15,43 +15,50 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.ItemService; import org.dspace.core.Constants; import org.dspace.core.Context; /** * This class is an addition to the AuthorizeManager that perform authorization * check on not CRUD (ADD, WRITE, etc.) actions. - * + * * @author bollini - * */ -public class AuthorizeUtil -{ +public class AuthorizeUtil { - private static final AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); + private static final AuthorizeService authorizeService = + AuthorizeServiceFactory.getInstance().getAuthorizeService(); private static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final CollectionService collectionService = + ContentServiceFactory.getInstance().getCollectionService(); + + /** + * Default constructor + */ + private AuthorizeUtil() { } /** * Is allowed manage (create, remove, edit) bitstream's policies in the * current context? * - * @param context - * the DSpace Context Object - * @param bitstream - * the bitstream that the policy refer to + * @param context the DSpace Context Object + * @param bitstream the bitstream that the policy refer to * @throws AuthorizeException if authorization error - * if the current context (current user) is not allowed to - * manage the bitstream's policies - * @throws SQLException if database error - * if a db error occur + * if the current context (current user) is not allowed to + * manage the bitstream's policies + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageBitstreamPolicy(Context context, - Bitstream bitstream) throws AuthorizeException, SQLException - { + Bitstream bitstream) throws AuthorizeException, SQLException { Bundle bundle = bitstream.getBundles().get(0); authorizeManageBundlePolicy(context, bundle); } @@ -59,20 +66,17 @@ public class AuthorizeUtil /** * Is allowed manage (create, remove, edit) bundle's policies in the * current context? - * - * @param context - * the DSpace Context Object - * @param bundle - * the bundle that the policy refer to + * + * @param context the DSpace Context Object + * @param bundle the bundle that the policy refer to * @throws AuthorizeException if authorization error - * if the current context (current user) is not allowed to - * manage the bundle's policies - * @throws SQLException if database error - * if a db error occur + * if the current context (current user) is not allowed to + * manage the bundle's policies + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageBundlePolicy(Context context, - Bundle bundle) throws AuthorizeException, SQLException - { + Bundle bundle) throws AuthorizeException, SQLException { Item item = bundle.getItems().get(0); authorizeManageItemPolicy(context, item); } @@ -80,167 +84,127 @@ public class AuthorizeUtil /** * Is allowed manage (create, remove, edit) item's policies in the * current context? - * - * @param context - * the DSpace Context Object - * @param item - * the item that the policy refer to + * + * @param context the DSpace Context Object + * @param item the item that the policy refer to * @throws AuthorizeException if authorization error - * if the current context (current user) is not allowed to - * manage the item's policies - * @throws SQLException if database error - * if a db error occur + * if the current context (current user) is not allowed to + * manage the item's policies + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageItemPolicy(Context context, Item item) - throws AuthorizeException, SQLException - { - if (AuthorizeConfiguration.canItemAdminManagePolicies()) - { + throws AuthorizeException, SQLException { + if (AuthorizeConfiguration.canItemAdminManagePolicies()) { authorizeService.authorizeAction(context, item, Constants.ADMIN); - } - else if (AuthorizeConfiguration.canCollectionAdminManageItemPolicies()) - { + } else if (AuthorizeConfiguration.canCollectionAdminManageItemPolicies()) { authorizeService.authorizeAction(context, item - .getOwningCollection(), Constants.ADMIN); - } - else if (AuthorizeConfiguration.canCommunityAdminManageItemPolicies()) - { + .getOwningCollection(), Constants.ADMIN); + } else if (AuthorizeConfiguration.canCommunityAdminManageItemPolicies()) { authorizeService - .authorizeAction(context, item.getOwningCollection() - .getCommunities().get(0), Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + .authorizeAction(context, item.getOwningCollection() + .getCommunities().get(0), Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin are allowed to manage item policies"); + "Only system admin are allowed to manage item policies"); } } /** * Is allowed manage (create, remove, edit) collection's policies in the * current context? - * - * @param context - * the DSpace Context Object - * @param collection - * the collection that the policy refer to + * + * @param context the DSpace Context Object + * @param collection the collection that the policy refer to * @throws AuthorizeException if authorization error - * if the current context (current user) is not allowed to - * manage the collection's policies - * @throws SQLException if database error - * if a db error occur + * if the current context (current user) is not allowed to + * manage the collection's policies + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageCollectionPolicy(Context context, - Collection collection) throws AuthorizeException, SQLException - { - if (AuthorizeConfiguration.canCollectionAdminManagePolicies()) - { + Collection collection) throws AuthorizeException, SQLException { + if (AuthorizeConfiguration.canCollectionAdminManagePolicies()) { authorizeService.authorizeAction(context, collection, - Constants.ADMIN); - } - else if (AuthorizeConfiguration - .canCommunityAdminManageCollectionPolicies()) - { + Constants.ADMIN); + } else if (AuthorizeConfiguration + .canCommunityAdminManageCollectionPolicies()) { authorizeService.authorizeAction(context, collection - .getCommunities().get(0), Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + .getCommunities().get(0), Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin are allowed to manage collection policies"); + "Only system admin are allowed to manage collection policies"); } } /** * Is allowed manage (create, remove, edit) community's policies in the * current context? - * - * @param context - * the DSpace Context Object - * @param community - * the community that the policy refer to + * + * @param context the DSpace Context Object + * @param community the community that the policy refer to * @throws AuthorizeException if authorization error - * if the current context (current user) is not allowed to - * manage the community's policies - * @throws SQLException if database error - * if a db error occur + * if the current context (current user) is not allowed to + * manage the community's policies + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageCommunityPolicy(Context context, - Community community) throws AuthorizeException, SQLException - { - if (AuthorizeConfiguration.canCommunityAdminManagePolicies()) - { + Community community) throws AuthorizeException, SQLException { + if (AuthorizeConfiguration.canCommunityAdminManagePolicies()) { authorizeService.authorizeAction(context, community, - Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin are allowed to manage community policies"); + "Only system admin are allowed to manage community policies"); } } /** * Throw an AuthorizeException if the current user is not a System Admin - * - * @param context - * the DSpace Context Object + * + * @param context the DSpace Context Object * @throws AuthorizeException if authorization error - * if the current user is not a System Admin - * @throws SQLException if database error - * if a db error occur + * if the current user is not a System Admin + * @throws SQLException if database error + * if a db error occur */ public static void requireAdminRole(Context context) - throws AuthorizeException, SQLException - { - if (!authorizeService.isAdmin(context)) - { + throws AuthorizeException, SQLException { + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin are allowed to perform this action"); + "Only system admin are allowed to perform this action"); } } /** * Is the current user allowed to manage (add, remove, replace) the item's * CC License - * - * @param context - * the DSpace Context Object - * @param item - * the item that the CC License refer to + * + * @param context the DSpace Context Object + * @param item the item that the CC License refer to * @throws AuthorizeException if authorization error - * if the current user is not allowed to - * manage the item's CC License - * @throws SQLException if database error - * if a db error occur + * if the current user is not allowed to + * manage the item's CC License + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageCCLicense(Context context, Item item) - throws AuthorizeException, SQLException - { - try - { + throws AuthorizeException, SQLException { + try { authorizeService.authorizeAction(context, item, Constants.ADD); authorizeService.authorizeAction(context, item, Constants.REMOVE); - } - catch (AuthorizeException authex) - { - if (AuthorizeConfiguration.canItemAdminManageCCLicense()) - { + } catch (AuthorizeException authex) { + if (AuthorizeConfiguration.canItemAdminManageCCLicense()) { authorizeService - .authorizeAction(context, item, Constants.ADMIN); - } - else if (AuthorizeConfiguration.canCollectionAdminManageCCLicense()) - { + .authorizeAction(context, item, Constants.ADMIN); + } else if (AuthorizeConfiguration.canCollectionAdminManageCCLicense()) { authorizeService.authorizeAction(context, itemService - .getParentObject(context, item), Constants.ADMIN); - } - else if (AuthorizeConfiguration.canCommunityAdminManageCCLicense()) - { + .getParentObject(context, item), Constants.ADMIN); + } else if (AuthorizeConfiguration.canCommunityAdminManageCCLicense()) { authorizeService.authorizeAction(context, itemService - .getParentObject(context, item), Constants.ADMIN); - } - else - { + .getParentObject(context, item), Constants.ADMIN); + } else { requireAdminRole(context); } } @@ -249,379 +213,302 @@ public class AuthorizeUtil /** * Is the current user allowed to manage (create, remove, edit) the * collection's template item? - * - * @param context - * the DSpace Context Object - * @param collection - * the collection + * + * @param context the DSpace Context Object + * @param collection the collection * @throws AuthorizeException if authorization error - * if the current user is not allowed to manage the collection's - * template item - * @throws SQLException if database error - * if a db error occur + * if the current user is not allowed to manage the collection's + * template item + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageTemplateItem(Context context, - Collection collection) throws AuthorizeException, SQLException - { + Collection collection) throws AuthorizeException, SQLException { boolean isAuthorized = collectionService.canEditBoolean(context, collection, false); if (!isAuthorized - && AuthorizeConfiguration - .canCollectionAdminManageTemplateItem()) - { + && AuthorizeConfiguration + .canCollectionAdminManageTemplateItem()) { authorizeService.authorizeAction(context, collection, - Constants.ADMIN); - } - else if (!isAuthorized - && AuthorizeConfiguration - .canCommunityAdminManageCollectionTemplateItem()) - { + Constants.ADMIN); + } else if (!isAuthorized + && AuthorizeConfiguration + .canCommunityAdminManageCollectionTemplateItem()) { List communities = collection.getCommunities(); Community parent = communities != null && communities.size() > 0 ? communities.get(0) - : null; + : null; authorizeService.authorizeAction(context, parent, Constants.ADMIN); - } - else if (!isAuthorized && !authorizeService.isAdmin(context)) - { + } else if (!isAuthorized && !authorizeService.isAdmin(context)) { throw new AuthorizeException( - "You are not authorized to create a template item for the collection"); + "You are not authorized to create a template item for the collection"); } } /** * Can the current user manage (create, remove, edit) the submitters group of * the collection? - * - * @param context - * the DSpace Context Object - * @param collection - * the collection + * + * @param context the DSpace Context Object + * @param collection the collection * @throws AuthorizeException if authorization error - * if the current user is not allowed to manage the collection's - * submitters group - * @throws SQLException if database error - * if a db error occur + * if the current user is not allowed to manage the collection's + * submitters group + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageSubmittersGroup(Context context, - Collection collection) throws AuthorizeException, SQLException - { - if (AuthorizeConfiguration.canCollectionAdminManageSubmitters()) - { + Collection collection) throws AuthorizeException, SQLException { + if (AuthorizeConfiguration.canCollectionAdminManageSubmitters()) { authorizeService.authorizeAction(context, collection, - Constants.ADMIN); - } - else if (AuthorizeConfiguration - .canCommunityAdminManageCollectionSubmitters()) - { + Constants.ADMIN); + } else if (AuthorizeConfiguration + .canCommunityAdminManageCollectionSubmitters()) { authorizeService.authorizeAction(context, collection - .getCommunities().get(0), Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + .getCommunities().get(0), Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin are allowed to manage collection submitters"); + "Only system admin are allowed to manage collection submitters"); } } /** * Can the current user manage (create, remove, edit) the workflow groups of * the collection? - * - * @param context - * the DSpace Context Object - * @param collection - * the collection + * + * @param context the DSpace Context Object + * @param collection the collection * @throws AuthorizeException if authorization error - * if the current user is not allowed to manage the collection's - * workflow groups - * @throws SQLException if database error - * if a db error occur + * if the current user is not allowed to manage the collection's + * workflow groups + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManageWorkflowsGroup(Context context, - Collection collection) throws AuthorizeException, SQLException - { - if (AuthorizeConfiguration.canCollectionAdminManageWorkflows()) - { + Collection collection) throws AuthorizeException, SQLException { + if (AuthorizeConfiguration.canCollectionAdminManageWorkflows()) { authorizeService.authorizeAction(context, collection, - Constants.ADMIN); - } - else if (AuthorizeConfiguration - .canCommunityAdminManageCollectionWorkflows()) - { + Constants.ADMIN); + } else if (AuthorizeConfiguration + .canCommunityAdminManageCollectionWorkflows()) { authorizeService.authorizeAction(context, collection - .getCommunities().get(0), Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + .getCommunities().get(0), Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin are allowed to manage collection workflow"); + "Only system admin are allowed to manage collection workflow"); } } /** * Can the current user create/edit the admins group of the collection? * please note that the remove action need a separate check - * - * @see #authorizeRemoveAdminGroup(Context, Collection) - * - * @param context - * the DSpace Context Object - * @param collection - * the collection + * + * @param context the DSpace Context Object + * @param collection the collection * @throws AuthorizeException if authorization error - * if the current user is not allowed to create/edit the - * collection's admins group - * @throws SQLException if database error - * if a db error occur + * if the current user is not allowed to create/edit the + * collection's admins group + * @throws SQLException if database error + * if a db error occur + * @see #authorizeRemoveAdminGroup(Context, Collection) */ public static void authorizeManageAdminGroup(Context context, - Collection collection) throws AuthorizeException, SQLException - { - if (AuthorizeConfiguration.canCollectionAdminManageAdminGroup()) - { + Collection collection) throws AuthorizeException, SQLException { + if (AuthorizeConfiguration.canCollectionAdminManageAdminGroup()) { authorizeService.authorizeAction(context, collection, - Constants.ADMIN); - } - else if (AuthorizeConfiguration - .canCommunityAdminManageCollectionAdminGroup()) - { + Constants.ADMIN); + } else if (AuthorizeConfiguration + .canCommunityAdminManageCollectionAdminGroup()) { authorizeService.authorizeAction(context, collection - .getCommunities().get(0), Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + .getCommunities().get(0), Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin are allowed to manage collection admin"); + "Only system admin are allowed to manage collection admin"); } } /** * Can the current user remove the admins group of the collection? * please note that the create/edit actions need separate check - * - * @see #authorizeManageAdminGroup(Context, Collection) - * - * @param context - * the DSpace Context Object - * @param collection - * the collection + * + * @param context the DSpace Context Object + * @param collection the collection * @throws AuthorizeException if authorization error - * if the current user is not allowed to remove the - * collection's admins group - * @throws SQLException if database error - * if a db error occur + * if the current user is not allowed to remove the + * collection's admins group + * @throws SQLException if database error + * if a db error occur + * @see #authorizeManageAdminGroup(Context, Collection) */ public static void authorizeRemoveAdminGroup(Context context, - Collection collection) throws AuthorizeException, SQLException - { + Collection collection) throws AuthorizeException, SQLException { List parentCommunities = collection.getCommunities(); if (AuthorizeConfiguration - .canCommunityAdminManageCollectionAdminGroup() - && parentCommunities != null && parentCommunities.size() > 0) - { + .canCommunityAdminManageCollectionAdminGroup() + && parentCommunities != null && parentCommunities.size() > 0) { authorizeService.authorizeAction(context, collection - .getCommunities().get(0), Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + .getCommunities().get(0), Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin can remove the admin group of a collection"); + "Only system admin can remove the admin group of a collection"); } } /** * Can the current user create/edit the admins group of the community? * please note that the remove action need a separate check - * - * @see #authorizeRemoveAdminGroup(Context, Collection) - * - * @param context - * the DSpace Context Object - * @param community - * the community + * + * @param context the DSpace Context Object + * @param community the community * @throws AuthorizeException if authorization error - * if the current user is not allowed to create/edit the - * community's admins group - * @throws SQLException if database error - * if a db error occur + * if the current user is not allowed to create/edit the + * community's admins group + * @throws SQLException if database error + * if a db error occur + * @see #authorizeRemoveAdminGroup(Context, Collection) */ public static void authorizeManageAdminGroup(Context context, - Community community) throws AuthorizeException, SQLException - { - if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup()) - { + Community community) throws AuthorizeException, SQLException { + if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup()) { authorizeService.authorizeAction(context, community, - Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin are allowed to manage community admin"); + "Only system admin are allowed to manage community admin"); } } /** * Can the current user remove the admins group of the community? * please note that the create/edit actions need separate check - * - * @see #authorizeManageAdminGroup(Context, Community) - * - * @param context - * the DSpace Context Object - * @param community - * the community + * + * @param context the DSpace Context Object + * @param community the community * @throws AuthorizeException if authorization error - * if the current user is not allowed to remove the - * collection's admins group - * @throws SQLException if database error - * if a db error occur + * if the current user is not allowed to remove the + * collection's admins group + * @throws SQLException if database error + * if a db error occur + * @see #authorizeManageAdminGroup(Context, Community) */ public static void authorizeRemoveAdminGroup(Context context, - Community community) throws SQLException, AuthorizeException - { + Community community) throws SQLException, AuthorizeException { List parentCommunities = community.getParentCommunities(); Community parentCommunity = null; - if(0 < parentCommunities.size()) - { + if (0 < parentCommunities.size()) { parentCommunity = parentCommunities.get(0); } if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup() - && parentCommunity != null) - { + && parentCommunity != null) { authorizeService.authorizeAction(context, parentCommunity, - Constants.ADMIN); - } - else if (!authorizeService.isAdmin(context)) - { + Constants.ADMIN); + } else if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only system admin can remove the admin group of the community"); + "Only system admin can remove the admin group of the community"); } } /** * Can the current user remove or edit the supplied policy? - * - * @param c - * the DSpace Context Object - * @param rp - * a resource policy + * + * @param c the DSpace Context Object + * @param rp a resource policy * @throws AuthorizeException if authorization error - * if the current context (current user) is not allowed to - * remove/edit the policy - * @throws SQLException if database error - * if a db error occur + * if the current context (current user) is not allowed to + * remove/edit the policy + * @throws SQLException if database error + * if a db error occur */ public static void authorizeManagePolicy(Context c, ResourcePolicy rp) - throws SQLException, AuthorizeException - { - switch (rp.getdSpaceObject().getType()) - { - case Constants.BITSTREAM: - authorizeManageBitstreamPolicy(c, (Bitstream) rp.getdSpaceObject()); - break; - case Constants.BUNDLE: - authorizeManageBundlePolicy(c, (Bundle) rp.getdSpaceObject()); - break; + throws SQLException, AuthorizeException { + switch (rp.getdSpaceObject().getType()) { + case Constants.BITSTREAM: + authorizeManageBitstreamPolicy(c, (Bitstream) rp.getdSpaceObject()); + break; + case Constants.BUNDLE: + authorizeManageBundlePolicy(c, (Bundle) rp.getdSpaceObject()); + break; - case Constants.ITEM: - authorizeManageItemPolicy(c, (Item) rp.getdSpaceObject()); - break; - case Constants.COLLECTION: - authorizeManageCollectionPolicy(c, (Collection) rp.getdSpaceObject()); - break; - case Constants.COMMUNITY: - authorizeManageCommunityPolicy(c, (Community) rp.getdSpaceObject()); - break; + case Constants.ITEM: + authorizeManageItemPolicy(c, (Item) rp.getdSpaceObject()); + break; + case Constants.COLLECTION: + authorizeManageCollectionPolicy(c, (Collection) rp.getdSpaceObject()); + break; + case Constants.COMMUNITY: + authorizeManageCommunityPolicy(c, (Community) rp.getdSpaceObject()); + break; - default: - requireAdminRole(c); - break; + default: + requireAdminRole(c); + break; } } /** * Can the current user withdraw the item? - * - * @param context - * the DSpace Context Object - * @param item - * the item - * @throws SQLException if database error - * if a db error occur + * + * @param context the DSpace Context Object + * @param item the item + * @throws SQLException if database error + * if a db error occur * @throws AuthorizeException if authorization error - * if the current user is not allowed to perform the item - * withdraw + * if the current user is not allowed to perform the item + * withdraw */ public static void authorizeWithdrawItem(Context context, Item item) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { boolean authorized = false; - if (AuthorizeConfiguration.canCollectionAdminPerformItemWithdrawn()) - { + if (AuthorizeConfiguration.canCollectionAdminPerformItemWithdrawn()) { authorized = authorizeService.authorizeActionBoolean(context, item - .getOwningCollection(), Constants.ADMIN); - } - else if (AuthorizeConfiguration.canCommunityAdminPerformItemWithdrawn()) - { + .getOwningCollection(), Constants.ADMIN); + } else if (AuthorizeConfiguration.canCommunityAdminPerformItemWithdrawn()) { authorized = authorizeService - .authorizeActionBoolean(context, item.getOwningCollection() - .getCommunities().get(0), Constants.ADMIN); + .authorizeActionBoolean(context, item.getOwningCollection() + .getCommunities().get(0), Constants.ADMIN); } - if (!authorized) - { + if (!authorized) { authorized = authorizeService.authorizeActionBoolean(context, item - .getOwningCollection(), Constants.REMOVE, false); + .getOwningCollection(), Constants.REMOVE, false); } // authorized - if (!authorized) - { + if (!authorized) { throw new AuthorizeException( - "To withdraw item must be COLLECTION_ADMIN or have REMOVE authorization on owning Collection"); + "To withdraw item must be COLLECTION_ADMIN or have REMOVE authorization on owning Collection"); } } /** - * Can the current user reinstate the item? - * - * @param context - * the DSpace Context Object - * @param item - * the item - * @throws SQLException if database error - * if a db error occur - * @throws AuthorizeException if authorization error - * if the current user is not allowed to perform the item - * reinstatement - */ + * Can the current user reinstate the item? + * + * @param context the DSpace Context Object + * @param item the item + * @throws SQLException if database error + * if a db error occur + * @throws AuthorizeException if authorization error + * if the current user is not allowed to perform the item + * reinstatement + */ public static void authorizeReinstateItem(Context context, Item item) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { List colls = item.getCollections(); - for (Collection coll : colls) - { + for (Collection coll : colls) { if (!AuthorizeConfiguration - .canCollectionAdminPerformItemReinstatiate()) - { + .canCollectionAdminPerformItemReinstatiate()) { if (AuthorizeConfiguration - .canCommunityAdminPerformItemReinstatiate() - && authorizeService.authorizeActionBoolean(context, - coll.getCommunities().get(0), Constants.ADMIN)) - { + .canCommunityAdminPerformItemReinstatiate() + && authorizeService.authorizeActionBoolean(context, + coll.getCommunities().get(0), Constants.ADMIN)) { // authorized - } - else - { + } else { authorizeService.authorizeAction(context, coll, - Constants.ADD, false); + Constants.ADD, false); } - } - else - { + } else { authorizeService.authorizeAction(context, coll, - Constants.ADD); + Constants.ADD); } } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/CollectionDropDown.java b/dspace-api/src/main/java/org/dspace/app/util/CollectionDropDown.java index 8a32986ca8..025e061b50 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/CollectionDropDown.java +++ b/dspace-api/src/main/java/org/dspace/app/util/CollectionDropDown.java @@ -8,7 +8,9 @@ package org.dspace.app.util; import java.sql.SQLException; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; import org.dspace.content.Collection; import org.dspace.content.Community; @@ -23,61 +25,54 @@ import org.dspace.core.Context; public class CollectionDropDown { - private static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); + /** + * Default constructor + */ + private CollectionDropDown() { } + /** * Get full path starting from a top-level community via subcommunities down to a collection. * The full path will not be truncated. - * - * @param context - * The relevant DSpace Context. - * @param col - * Get full path for this collection + * + * @param context The relevant DSpace Context. + * @param col Get full path for this collection * @return Full path to the collection * @throws SQLException if database error */ - public static String collectionPath(Context context, Collection col) throws SQLException - { + public static String collectionPath(Context context, Collection col) throws SQLException { return CollectionDropDown.collectionPath(context, col, 0); } - + /** * Get full path starting from a top-level community via subcommunities down to a collection. * The full cat will be truncated to the specified number of characters and prepended with an ellipsis. - * - * @param context - * The relevant DSpace Context. - * @param col - * Get full path for this collection - * @param maxchars - * Truncate the full path to maxchar characters. 0 means do not truncate. + * + * @param context The relevant DSpace Context. + * @param col Get full path for this collection + * @param maxchars Truncate the full path to maxchar characters. 0 means do not truncate. * @return Full path to the collection (truncated) * @throws SQLException if database error */ - public static String collectionPath(Context context, Collection col, int maxchars) throws SQLException - { + public static String collectionPath(Context context, Collection col, int maxchars) throws SQLException { String separator = ConfigurationManager.getProperty("subcommunity.separator"); - if (separator == null) - { + if (separator == null) { separator = " > "; } - + List getCom = null; StringBuffer name = new StringBuffer(""); getCom = communityService.getAllParents(context, col); // all communities containing given collection - for (Community com : getCom) - { + for (Community com : getCom) { name.insert(0, com.getName() + separator); } name.append(col.getName()); - if (maxchars != 0) - { + if (maxchars != 0) { int len = name.length(); - if (len > maxchars) - { + if (len > maxchars) { name = new StringBuffer(name.substring(len - (maxchars - 1), len)); name.insert(0, "\u2026"); // prepend with an ellipsis (cut from left) } @@ -88,18 +83,17 @@ public class CollectionDropDown { /** * Annotates an array of collections with their respective full paths (@see #collectionPath() method in this class). - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. * @param collections An array of collections to annotate with their hierarchical paths. - * The array and all its entries must be non-null. + * The array and all its entries must be non-null. * @return A sorted array of collection path entries (essentially collection/path pairs). * @throws SQLException In case there are problems annotating a collection with its path. */ - public static CollectionPathEntry[] annotateWithPaths(Context context, List collections) throws SQLException - { + public static CollectionPathEntry[] annotateWithPaths(Context context, List collections) + throws SQLException { CollectionPathEntry[] result = new CollectionPathEntry[collections.size()]; - for (int i = 0; i < collections.size(); i++) - { + for (int i = 0; i < collections.size(); i++) { Collection collection = collections.get(i); CollectionPathEntry entry = new CollectionPathEntry(collection, collectionPath(context, collection)); result[i] = entry; @@ -113,36 +107,30 @@ public class CollectionDropDown { * two instances will be compared first on their full path and if those are equal, * the comparison will fall back to comparing collection IDs. */ - public static class CollectionPathEntry implements Comparable - { + public static class CollectionPathEntry implements Comparable { public Collection collection; public String path; - public CollectionPathEntry(Collection collection, String path) - { + public CollectionPathEntry(Collection collection, String path) { this.collection = collection; this.path = path; } @Override - public int compareTo(CollectionPathEntry other) - { - if (!this.path.equals(other.path)) - { + public int compareTo(CollectionPathEntry other) { + if (!this.path.equals(other.path)) { return this.path.compareTo(other.path); } return this.collection.getID().compareTo(other.collection.getID()); } @Override - public boolean equals(Object o) - { + public boolean equals(Object o) { return o != null && o instanceof CollectionPathEntry && this.compareTo((CollectionPathEntry) o) == 0; } @Override - public int hashCode() - { + public int hashCode() { return Objects.hash(path, collection.getID()); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/Configuration.java b/dspace-api/src/main/java/org/dspace/app/util/Configuration.java index 249c38b00e..e9b125c41c 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/Configuration.java +++ b/dspace-api/src/main/java/org/dspace/app/util/Configuration.java @@ -22,8 +22,13 @@ import org.dspace.services.factory.DSpaceServicesFactory; * * @author mwood */ -public class Configuration -{ +public class Configuration { + + /** + * Default constructor + */ + private Configuration() { } + /** * Command-line interface for running configuration tasks. Possible * arguments: @@ -38,74 +43,62 @@ public class Configuration * * @param argv the command line arguments given */ - public static void main(String[] argv) - { + public static void main(String[] argv) { // Build a description of the command line Options options = new Options(); options.addOption("p", "property", true, "name of the desired property"); options.addOption("m", "module", true, - "optional name of the module in which 'property' exists"); + "optional name of the module in which 'property' exists"); options.addOption("r", "raw", false, - "do not do property substitution on the value"); + "do not do property substitution on the value"); options.addOption("?", "Get help"); options.addOption("h", "help", false, "Get help"); // Analyze the command line CommandLineParser parser = new DefaultParser(); CommandLine cmd = null; - try - { + try { cmd = parser.parse(options, argv); - } catch (ParseException ex) - { + } catch (ParseException ex) { System.err.println(ex.getMessage()); System.exit(1); } // Give help if asked - if (cmd.hasOption('?') || cmd.hasOption('h')) - { + if (cmd.hasOption('?') || cmd.hasOption('h')) { new HelpFormatter().printHelp("dsprop [options]", - "Display the value of a DSpace configuration property", - options, - "If --module is omitted, then --property gives the entire" + - " name of the property. Otherwise the name is" + - " composed of module.property."); + "Display the value of a DSpace configuration property", + options, + "If --module is omitted, then --property gives the entire" + + " name of the property. Otherwise the name is" + + " composed of module.property."); System.exit(0); } // Check for missing required values - if (!cmd.hasOption('p')) - { + if (!cmd.hasOption('p')) { System.err.println("Error: -p is required"); System.exit(1); } // Figure out the property's full name StringBuilder propNameBuilder = new StringBuilder(1024); - if (cmd.hasOption('m')) - { + if (cmd.hasOption('m')) { propNameBuilder.append(cmd.getOptionValue('m')) - .append('.'); + .append('.'); } propNameBuilder.append(cmd.getOptionValue('p')); String propName = propNameBuilder.toString(); // Print the property's value, if it exists ConfigurationService cfg = DSpaceServicesFactory.getInstance().getConfigurationService(); - if (!cfg.hasProperty(propName)) - { + if (!cfg.hasProperty(propName)) { System.out.println(); - } - else - { + } else { String val; - if (cmd.hasOption('r')) - { + if (cmd.hasOption('r')) { val = cfg.getPropertyValue(propName).toString(); - } - else - { + } else { val = cfg.getProperty(propName); } System.out.println(val); diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInput.java b/dspace-api/src/main/java/org/dspace/app/util/DCInput.java index f094c67805..5564b66806 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DCInput.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DCInput.java @@ -10,124 +10,178 @@ package org.dspace.app.util; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import org.apache.commons.lang.StringUtils; import org.dspace.content.MetadataSchema; +import org.dspace.core.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Class representing a line in an input form. - * + * * @author Brian S. Hughes, based on work by Jenny Toves, OCLC */ -public class DCInput -{ - /** the DC element name */ +public class DCInput { + + private static final Logger log = LoggerFactory.getLogger(DCInput.class); + + /** + * the DC element name + */ private String dcElement = null; - /** the DC qualifier, if any */ + /** + * the DC qualifier, if any + */ private String dcQualifier = null; - /** the DC namespace schema */ + /** + * the DC namespace schema + */ private String dcSchema = null; - - /** the input language */ + + /** + * the input language + */ private boolean language = false; - - /** the language code use for the input */ + + /** + * the language code use for the input + */ private static final String LanguageName = "common_iso_languages"; - /** the language list and their value */ + /** + * the language list and their value + */ private List valueLanguageList = null; - /** a label describing input */ + /** + * a label describing input + */ private String label = null; - /** the input type */ + /** + * a style instruction to apply to the input. The exact way to use the style value is UI depending that receive the + * value from the REST API as is + */ + private String style = null; + + /** + * the input type + */ private String inputType = null; - /** is input required? */ + /** + * is input required? + */ private boolean required = false; - /** if required, text to display when missing */ + /** + * if required, text to display when missing + */ private String warning = null; - /** is input repeatable? */ + /** + * is input repeatable? + */ private boolean repeatable = false; - /** 'hint' text to display */ + /** + * 'hint' text to display + */ private String hint = null; - /** if input list-controlled, name of list */ + /** + * if input list-controlled, name of list + */ private String valueListName = null; - /** if input list-controlled, the list itself */ + /** + * if input list-controlled, the list itself + */ private List valueList = null; - /** if non-null, visibility scope restriction */ + /** + * if non-null, visibility scope restriction + */ private String visibility = null; - - /** if non-null, readonly out of the visibility scope */ + + /** + * if non-null, readonly out of the visibility scope + */ private String readOnly = null; - /** the name of the controlled vocabulary to use */ + /** + * the name of the controlled vocabulary to use + */ private String vocabulary = null; - /** is the entry closed to vocabulary terms? */ + /** + * is the entry closed to vocabulary terms? + */ private boolean closedVocabulary = false; - /** allowed document types */ + /** + * the regex to comply with, null if nothing + */ + private String regex = null; + + /** + * allowed document types + */ private List typeBind = null; - /** - * The scope of the input sets, this restricts hidden metadata fields from - * view during workflow processing. + /** + * The scope of the input sets, this restricts hidden metadata fields from + * view during workflow processing. */ public static final String WORKFLOW_SCOPE = "workflow"; - /** - * The scope of the input sets, this restricts hidden metadata fields from - * view by the end user during submission. + /** + * The scope of the input sets, this restricts hidden metadata fields from + * view by the end user during submission. */ public static final String SUBMISSION_SCOPE = "submit"; - + /** * Class constructor for creating a DCInput object based on the contents of * a HashMap - * - * @param fieldMap - * named field values. - * - * @param listMap - * value-pairs map, computed from the forms definition XML file + * + * @param fieldMap named field values. + * @param listMap value-pairs map, computed from the forms definition XML file */ - public DCInput(Map fieldMap, Map> listMap) - { + public DCInput(Map fieldMap, Map> listMap) { dcElement = fieldMap.get("dc-element"); dcQualifier = fieldMap.get("dc-qualifier"); // Default the schema to dublin core dcSchema = fieldMap.get("dc-schema"); - if (dcSchema == null) - { + if (dcSchema == null) { dcSchema = MetadataSchema.DC_SCHEMA; } //check if the input have a language tag language = Boolean.valueOf(fieldMap.get("language")); valueLanguageList = new ArrayList(); - if (language) - { - valueLanguageList = listMap.get(LanguageName); + if (language) { + String languageNameTmp = fieldMap.get("value-pairs-name"); + if (StringUtils.isBlank(languageNameTmp)) { + languageNameTmp = LanguageName; + } + valueLanguageList = listMap.get(languageNameTmp); } - + String repStr = fieldMap.get("repeatable"); repeatable = "true".equalsIgnoreCase(repStr) - || "yes".equalsIgnoreCase(repStr); + || "yes".equalsIgnoreCase(repStr); label = fieldMap.get("label"); inputType = fieldMap.get("input-type"); // these types are list-controlled if ("dropdown".equals(inputType) || "qualdrop_value".equals(inputType) - || "list".equals(inputType)) - { + || "list".equals(inputType)) { valueListName = fieldMap.get("value-pairs-name"); valueList = listMap.get(valueListName); } @@ -137,58 +191,50 @@ public class DCInput visibility = fieldMap.get("visibility"); readOnly = fieldMap.get("readonly"); vocabulary = fieldMap.get("vocabulary"); + regex = fieldMap.get("regex"); String closedVocabularyStr = fieldMap.get("closedVocabulary"); closedVocabulary = "true".equalsIgnoreCase(closedVocabularyStr) - || "yes".equalsIgnoreCase(closedVocabularyStr); - + || "yes".equalsIgnoreCase(closedVocabularyStr); + // parsing of the element (using the colon as split separator) typeBind = new ArrayList(); String typeBindDef = fieldMap.get("type-bind"); - if(typeBindDef != null && typeBindDef.trim().length() > 0) { - String[] types = typeBindDef.split(","); - for(String type : types) { - typeBind.add( type.trim() ); - } + if (typeBindDef != null && typeBindDef.trim().length() > 0) { + String[] types = typeBindDef.split(","); + for (String type : types) { + typeBind.add(type.trim()); + } } - + style = fieldMap.get("style"); } /** * Is this DCInput for display in the given scope? The scope should be * either "workflow" or "submit", as per the input forms definition. If the * internal visibility is set to "null" then this will always return true. - * - * @param scope - * String identifying the scope that this input's visibility - * should be tested for - * + * + * @param scope String identifying the scope that this input's visibility + * should be tested for * @return whether the input should be displayed or not */ - public boolean isVisible(String scope) - { + public boolean isVisible(String scope) { return (visibility == null || visibility.equals(scope)); } - + /** - * Is this DCInput for display in readonly mode in the given scope? + * Is this DCInput for display in readonly mode in the given scope? * If the scope differ from which in visibility field then we use the out attribute * of the visibility element. Possible values are: hidden (default) and readonly. * If the DCInput is visible in the scope then this methods must return false - * - * @param scope - * String identifying the scope that this input's readonly visibility - * should be tested for - * + * + * @param scope String identifying the scope that this input's readonly visibility + * should be tested for * @return whether the input should be displayed in a readonly way or fully hidden */ - public boolean isReadOnly(String scope) - { - if (isVisible(scope)) - { + public boolean isReadOnly(String scope) { + if (isVisible(scope)) { return false; - } - else - { + } else { return readOnly != null && readOnly.equalsIgnoreCase("readonly"); } } @@ -196,189 +242,174 @@ public class DCInput /** * Get the repeatable flag for this row - * + * * @return the repeatable flag */ - public boolean isRepeatable() - { + public boolean isRepeatable() { return repeatable; } /** * Alternate way of calling isRepeatable() - * + * * @return the repeatable flag */ - public boolean getRepeatable() - { + public boolean getRepeatable() { return isRepeatable(); } /** * Get the input type for this row - * + * * @return the input type */ - public String getInputType() - { + public String getInputType() { return inputType; } /** - * Get the DC element for this form row. - * + * Get the DC element for this form field. + * * @return the DC element */ - public String getElement() - { + public String getElement() { return dcElement; } /** - * Get the DC namespace prefix for this form row. - * + * Get the DC namespace prefix for this form field. + * * @return the DC namespace prefix */ - public String getSchema() - { + public String getSchema() { return dcSchema; } /** * Get the warning string for a missing required field, formatted for an * HTML table. - * + * * @return the string prompt if required field was ignored */ - public String getWarning() - { + public String getWarning() { return warning; } /** - * Is there a required string for this form row? - * + * Is there a required string for this form field? + * * @return true if a required string is set */ - public boolean isRequired() - { + public boolean isRequired() { return required; } /** - * Get the DC qualifier for this form row. - * + * Get the DC qualifier for this form field. + * * @return the DC qualifier */ - public String getQualifier() - { + public String getQualifier() { return dcQualifier; } - + /** - * Get the language for this form row. - * + * Get the language for this form field. + * * @return the language state */ - public boolean getLanguage() - { + public boolean getLanguage() { return language; } /** - * Get the hint for this form row, formatted for an HTML table - * + * Get the hint for this form field + * * @return the hints */ - public String getHints() - { + public String getHints() { return hint; } /** - * Get the label for this form row. - * + * Get the label for this form field. + * * @return the label */ - public String getLabel() - { + public String getLabel() { return label; } /** - * Get the name of the pairs type + * Get the style for this form field * + * @return the style + */ + public String getStyle() { + return style; + } + + /** + * Get the name of the pairs type + * * @return the pairs type name */ - public String getPairsType() - { + public String getPairsType() { return valueListName; } /** * Get the name of the pairs type - * + * * @return the pairs type name */ - public List getPairs() - { + public List getPairs() { return valueList; } /** - * Get the list of language tags - * + * Get the list of language tags + * * @return the list of language */ - public List getValueLanguageList() - { + public List getValueLanguageList() { return valueLanguageList; } - + /** * Get the name of the controlled vocabulary that is associated with this * field - * + * * @return the name of associated the vocabulary */ - public String getVocabulary() - { + public String getVocabulary() { return vocabulary; } /** * Set the name of the controlled vocabulary that is associated with this * field - * - * @param vocabulary - * the name of the vocabulary + * + * @param vocabulary the name of the vocabulary */ - public void setVocabulary(String vocabulary) - { + public void setVocabulary(String vocabulary) { this.vocabulary = vocabulary; } /** * Gets the display string that corresponds to the passed storage string in * a particular display-storage pair set. - * - * @param pairTypeName - * Name of display-storage pair set to search - * @param storedString - * the string that gets stored - * + * + * @param pairTypeName Name of display-storage pair set to search + * @param storedString the string that gets stored * @return the displayed string whose selection causes storageString to be - * stored, null if no match + * stored, null if no match */ - public String getDisplayString(String pairTypeName, String storedString) - { - if (valueList != null && storedString != null) - { - for (int i = 0; i < valueList.size(); i += 2) - { - if (storedString.equals(valueList.get(i + 1))) - { + public String getDisplayString(String pairTypeName, String storedString) { + if (valueList != null && storedString != null) { + for (int i = 0; i < valueList.size(); i += 2) { + if (storedString.equals(valueList.get(i + 1))) { return valueList.get(i); } } @@ -389,23 +420,16 @@ public class DCInput /** * Gets the stored string that corresponds to the passed display string in a * particular display-storage pair set. - * - * @param pairTypeName - * Name of display-storage pair set to search - * @param displayedString - * the string that gets displayed - * + * + * @param pairTypeName Name of display-storage pair set to search + * @param displayedString the string that gets displayed * @return the string that gets stored when displayString gets selected, - * null if no match + * null if no match */ - public String getStoredString(String pairTypeName, String displayedString) - { - if (valueList != null && displayedString != null) - { - for (int i = 0; i < valueList.size(); i += 2) - { - if (displayedString.equals(valueList.get(i))) - { + public String getStoredString(String pairTypeName, String displayedString) { + if (valueList != null && displayedString != null) { + for (int i = 0; i < valueList.size(); i += 2) { + if (displayedString.equals(valueList.get(i))) { return valueList.get(i + 1); } } @@ -413,33 +437,72 @@ public class DCInput return null; } - /** - * The closed attribute of the vocabulary tag for this field as set in - * input-forms.xml - * - * {@code - * - * ..... - * nsrc - * - * } - * @return the closedVocabulary flags: true if the entry should be restricted - * only to vocabulary terms, false otherwise - */ - public boolean isClosedVocabulary() { - return closedVocabulary; - } + /** + * The closed attribute of the vocabulary tag for this field as set in + * submission-forms.xml + * + * {@code + * + * ..... + * nsrc + * + * } + * + * @return the closedVocabulary flags: true if the entry should be restricted + * only to vocabulary terms, false otherwise + */ + public boolean isClosedVocabulary() { + return closedVocabulary; + } - /** - * Decides if this field is valid for the document type - * @param typeName Document type name - * @return true when there is no type restriction or typeName is allowed - */ - public boolean isAllowedFor(String typeName) { - if(typeBind.size() == 0) - return true; - - return typeBind.contains(typeName); - } - + /** + * Decides if this field is valid for the document type + * + * @param typeName Document type name + * @return true when there is no type restriction or typeName is allowed + */ + public boolean isAllowedFor(String typeName) { + if (typeBind.size() == 0) { + return true; + } + + return typeBind.contains(typeName); + } + + public String getScope() { + return visibility; + } + + public String getRegex() { + return regex; + } + + public String getFieldName() { + return Utils.standardize(this.getSchema(), this.getElement(), this.getQualifier(), "."); + } + + public boolean isQualdropValue() { + if ("qualdrop_value".equals(getInputType())) { + return true; + } + return false; + } + + public boolean validate(String value) { + if (StringUtils.isNotBlank(value)) { + try { + if (StringUtils.isNotBlank(regex)) { + Pattern pattern = Pattern.compile(regex); + if (!pattern.matcher(value).matches()) { + return false; + } + } + } catch (PatternSyntaxException ex) { + log.error("Regex validation failed!", ex.getMessage()); + } + + } + + return true; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInputSet.java b/dspace-api/src/main/java/org/dspace/app/util/DCInputSet.java index 0a888b7ad4..faa3fb7190 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DCInputSet.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DCInputSet.java @@ -7,7 +7,6 @@ */ package org.dspace.app.util; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -18,104 +17,85 @@ import java.util.Map; * @version $Revision$ */ -public class DCInputSet -{ - /** name of the input set */ - private String formName = null; - /** the inputs ordered by page and row position */ - private DCInput[][] inputPages = null; - - /** constructor - * @param formName form name - * @param pages pages - * @param listMap map - */ - public DCInputSet(String formName, List>> pages, Map> listMap) - { +public class DCInputSet { + /** + * name of the input set + */ + private String formName = null; + /** + * the inputs ordered by row position + */ + private DCInput[][] inputs = null; + + /** + * constructor + * + * @param formName form name + * @param mandatoryFlags + * @param rows the rows + * @param listMap map + */ + public DCInputSet(String formName, List>> rows, Map> listMap) { this.formName = formName; - inputPages = new DCInput[pages.size()][]; - for ( int i = 0; i < inputPages.length; i++ ) - { - List> page = pages.get(i); - inputPages[i] = new DCInput[page.size()]; - for ( int j = 0; j < inputPages[i].length; j++ ) - { - inputPages[i][j] = new DCInput(page.get(j), listMap); + this.inputs = new DCInput[rows.size()][]; + for (int i = 0; i < inputs.length; i++) { + List> fields = rows.get(i); + inputs[i] = new DCInput[fields.size()]; + for (int j = 0; j < inputs[i].length; j++) { + Map field = rows.get(i).get(j); + inputs[i][j] = new DCInput(field, listMap); } } } - + /** * Return the name of the form that defines this input set + * * @return formName the name of the form */ - public String getFormName() - { + public String getFormName() { return formName; } - + /** - * Return the number of pages in this input set + * Return the number of fields in this input set + * * @return number of pages */ - public int getNumberPages() - { - return inputPages.length; + public int getNumberFields() { + return inputs.length; } - - /** - * Get all the rows for a page from the form definition - * - * @param pageNum desired page within set - * @param addTitleAlternative flag to add the additional title row - * @param addPublishedBefore flag to add the additional published info - * - * @return an array containing the page's displayable rows - */ - - public DCInput[] getPageRows(int pageNum, boolean addTitleAlternative, - boolean addPublishedBefore) - { - List filteredInputs = new ArrayList(); - if ( pageNum < inputPages.length ) - { - for (int i = 0; i < inputPages[pageNum].length; i++ ) - { - DCInput input = inputPages[pageNum][i]; - if (doField(input, addTitleAlternative, addPublishedBefore)) - { - filteredInputs.add(input); - } - } - } - // Convert list into an array - DCInput[] inputArray = new DCInput[filteredInputs.size()]; - return filteredInputs.toArray(inputArray); + /** + * Get all the fields + * + * @return an array containing the fields + */ + + public DCInput[][] getFields() { + return inputs; } - + /** * Does this set of inputs include an alternate title field? * * @return true if the current set has an alternate title field */ - public boolean isDefinedMultTitles() - { - return isFieldPresent("title.alternative"); + public boolean isDefinedMultTitles() { + return isFieldPresent("dc.title.alternative"); } - + /** * Does this set of inputs include the previously published fields? * * @return true if the current set has all the prev. published fields */ - public boolean isDefinedPubBefore() - { - return ( isFieldPresent("date.issued") && - isFieldPresent("identifier.citation") && - isFieldPresent("publisher.null") ); + public boolean isDefinedPubBefore() { + return (isFieldPresent("dc.date.issued") && + isFieldPresent("dc.identifier.citation") && + isFieldPresent("dc.publisher")); } - + /** * Does the current input set define the named field? * Scan through every field in every page of the input set @@ -123,77 +103,63 @@ public class DCInputSet * @param fieldName selects the field. * @return true if the current set has the named field */ - public boolean isFieldPresent(String fieldName) - { - for (int i = 0; i < inputPages.length; i++) - { - DCInput[] pageInputs = inputPages[i]; - for (int row = 0; row < pageInputs.length; row++) - { - String fullName = pageInputs[row].getElement() + "." + - pageInputs[row].getQualifier(); - if (fullName.equals(fieldName)) - { + public boolean isFieldPresent(String fieldName) { + for (int i = 0; i < inputs.length; i++) { + for (int j = 0; j < inputs[i].length; j++) { + DCInput field = inputs[i][j]; + String fullName = field.getFieldName(); + if (fullName.equals(fieldName)) { return true; } } } return false; } - + /** * Does the current input set define the named field? * and is valid for the specified document type * Scan through every field in every page of the input set * - * @param fieldName field name + * @param fieldName field name * @param documentType doc type * @return true if the current set has the named field */ - public boolean isFieldPresent(String fieldName, String documentType) - { - if (documentType == null) { - documentType = ""; - } - for (int i = 0; i < inputPages.length; i++) - { - DCInput[] pageInputs = inputPages[i]; - for (int row = 0; row < pageInputs.length; row++) - { - String fullName = pageInputs[row].getElement() + "." + - pageInputs[row].getQualifier(); - if (fullName.equals(fieldName) ) - { - if (pageInputs[row].isAllowedFor(documentType)) { - return true; - } - } - } - } - return false; - } - + public boolean isFieldPresent(String fieldName, String documentType) { + if (documentType == null) { + documentType = ""; + } + for (int i = 0; i < inputs.length; i++) { + for (int j = 0; j < inputs[i].length; j++) { + DCInput field = inputs[i][j]; + String fullName = field.getFieldName(); + if (fullName.equals(fieldName)) { + if (field.isAllowedFor(documentType)) { + return true; + } + } + } + } + return false; + } + protected boolean doField(DCInput dcf, boolean addTitleAlternative, - boolean addPublishedBefore) - { - String rowName = dcf.getElement() + "." + dcf.getQualifier(); - if ( rowName.equals("title.alternative") && ! addTitleAlternative ) - { + boolean addPublishedBefore) { + String rowName = dcf.getFieldName(); + if (rowName.equals("dc.title.alternative") && !addTitleAlternative) { return false; } - if (rowName.equals("date.issued") && ! addPublishedBefore ) - { + if (rowName.equals("dc.date.issued") && !addPublishedBefore) { return false; } - if (rowName.equals("publisher.null") && ! addPublishedBefore ) - { + if (rowName.equals("dc.publisher.null") && !addPublishedBefore) { return false; } - if (rowName.equals("identifier.citation") && ! addPublishedBefore ) - { + if (rowName.equals("dc.identifier.citation") && !addPublishedBefore) { return false; } return true; } + } diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java index d2219e0ec0..b473e602b8 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java @@ -8,18 +8,31 @@ package org.dspace.app.util; import java.io.File; -import java.util.*; - -import org.dspace.services.factory.DSpaceServicesFactory; -import org.xml.sax.SAXException; -import org.w3c.dom.*; -import javax.xml.parsers.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.servlet.ServletException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import org.apache.commons.lang3.StringUtils; +import org.dspace.content.Collection; import org.dspace.content.MetadataSchema; +import org.dspace.core.Utils; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; /** * Submission form generator for DSpace. Reads and parses the installation - * form definitions file, input-forms.xml, from the configuration directory. + * form definitions file, submission-forms.xml, from the configuration directory. * A forms definition details the page and field layout of the metadata * collection pages used by the submission process. Each forms definition * starts with a unique name that gets associated with that form set. @@ -35,41 +48,39 @@ import org.dspace.content.MetadataSchema; * supply the value stored in the database if its sibling display value gets * selected from a choice list. * - * @author Brian S. Hughes + * @author Brian S. Hughes * @version $Revision$ */ -public class DCInputsReader -{ +public class DCInputsReader { /** * The ID of the default collection. Will never be the ID of a named * collection */ public static final String DEFAULT_COLLECTION = "default"; - /** Name of the form definition XML file */ - static final String FORM_DEF_FILE = "input-forms.xml"; - - /** Keyname for storing dropdown value-pair set name */ - static final String PAIR_TYPE_NAME = "value-pairs-name"; + /** + * Name of the form definition XML file + */ + static final String FORM_DEF_FILE = "submission-forms.xml"; /** - * Reference to the collections to forms map, computed from the forms - * definition file + * Keyname for storing dropdown value-pair set name */ - private Map whichForms = null; + static final String PAIR_TYPE_NAME = "value-pairs-name"; + /** * Reference to the forms definitions map, computed from the forms * definition file */ - private Map>>> formDefns = null; + private Map>>> formDefns = null; /** * Reference to the value-pairs map, computed from the forms definition file */ private Map> valuePairs = null; // Holds display/storage pairs - + /** * Mini-cache of last DCInputSet requested. If submissions are not typically * form-interleaved, there will be a modest win. @@ -87,8 +98,7 @@ public class DCInputsReader */ public DCInputsReader() - throws DCInputsReaderException - { + throws DCInputsReaderException { // Load from default file String defsFile = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") + File.separator + "config" + File.separator + FORM_DEF_FILE; @@ -98,50 +108,40 @@ public class DCInputsReader public DCInputsReader(String fileName) - throws DCInputsReaderException - { + throws DCInputsReaderException { buildInputs(fileName); } private void buildInputs(String fileName) - throws DCInputsReaderException - { - whichForms = new HashMap(); - formDefns = new HashMap>>>(); + throws DCInputsReaderException { + formDefns = new HashMap>>>(); valuePairs = new HashMap>(); String uri = "file:" + new File(fileName).getAbsolutePath(); - try - { + try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); - + DocumentBuilder db = factory.newDocumentBuilder(); Document doc = db.parse(uri); doNodes(doc); checkValues(); - } - catch (FactoryConfigurationError fe) - { - throw new DCInputsReaderException("Cannot create Submission form parser",fe); - } - catch (Exception e) - { - throw new DCInputsReaderException("Error creating submission forms: "+e); + } catch (FactoryConfigurationError fe) { + throw new DCInputsReaderException("Cannot create Submission form parser", fe); + } catch (Exception e) { + throw new DCInputsReaderException("Error creating submission forms: " + e); } } - - public Iterator getPairsNameIterator() - { + + public Iterator getPairsNameIterator() { return valuePairs.keySet().iterator(); } - public List getPairs(String name) - { + public List getPairs(String name) { return valuePairs.get(name); } @@ -149,273 +149,278 @@ public class DCInputsReader * Returns the set of DC inputs used for a particular collection, or the * default set if no inputs defined for the collection * - * @param collectionHandle - * collection's unique Handle + * @param collectionHandle collection's unique Handle * @return DC input set - * @throws DCInputsReaderException - * if no default set defined + * @throws DCInputsReaderException if no default set defined + * @throws ServletException */ - public DCInputSet getInputs(String collectionHandle) - throws DCInputsReaderException - { - String formName = whichForms.get(collectionHandle); - if (formName == null) - { - formName = whichForms.get(DEFAULT_COLLECTION); + public List getInputsByCollectionHandle(String collectionHandle) + throws DCInputsReaderException { + SubmissionConfig config; + try { + config = new SubmissionConfigReader().getSubmissionConfigByCollection(collectionHandle); + String formName = config.getSubmissionName(); + if (formName == null) { + throw new DCInputsReaderException("No form designated as default"); + } + List results = new ArrayList(); + for (int idx = 0; idx < config.getNumberOfSteps(); idx++) { + SubmissionStepConfig step = config.getStep(idx); + if (SubmissionStepConfig.INPUT_FORM_STEP_NAME.equals(step.getType())) { + results.add(getInputsByFormName(step.getId())); + } + } + return results; + } catch (SubmissionConfigReaderException e) { + throw new DCInputsReaderException("No form designated as default", e); } - if (formName == null) - { - throw new DCInputsReaderException("No form designated as default"); + } + + public List getInputsBySubmissionName(String name) + throws DCInputsReaderException { + SubmissionConfig config; + try { + config = new SubmissionConfigReader().getSubmissionConfigByName(name); + String formName = config.getSubmissionName(); + if (formName == null) { + throw new DCInputsReaderException("No form designated as default"); + } + List results = new ArrayList(); + for (int idx = 0; idx < config.getNumberOfSteps(); idx++) { + SubmissionStepConfig step = config.getStep(idx); + if (SubmissionStepConfig.INPUT_FORM_STEP_NAME.equals(step.getType())) { + results.add(getInputsByFormName(step.getId())); + } + } + return results; + } catch (SubmissionConfigReaderException e) { + throw new DCInputsReaderException("No form designated as default", e); } + } + + /** + * Returns the set of DC inputs used for a particular input form + * + * @param formName input form unique name + * @return DC input set + * @throws DCInputsReaderException if not found + */ + public DCInputSet getInputsByFormName(String formName) + throws DCInputsReaderException { // check mini-cache, and return if match - if ( lastInputSet != null && lastInputSet.getFormName().equals( formName ) ) - { + if (lastInputSet != null && lastInputSet.getFormName().equals(formName)) { return lastInputSet; } // cache miss - construct new DCInputSet List>> pages = formDefns.get(formName); - if ( pages == null ) - { - throw new DCInputsReaderException("Missing the " + formName + " form"); + if (pages == null) { + throw new DCInputsReaderException("Missing the " + formName + " form"); } - lastInputSet = new DCInputSet(formName, pages, valuePairs); + lastInputSet = new DCInputSet(formName, + pages, valuePairs); return lastInputSet; } - + /** - * Return the number of pages the inputs span for a desginated collection - * @param collectionHandle collection's unique Handle - * @return number of pages of input - * @throws DCInputsReaderException if no default set defined + * @return the number of defined input forms */ - public int getNumberInputPages(String collectionHandle) - throws DCInputsReaderException - { - return getInputs(collectionHandle).getNumberPages(); + public int countInputs() { + return formDefns.size(); } - + + + /** + * Returns all the Input forms with pagination + * + * @param limit max number of Input Forms to return + * @param offset number of Input form to skip in the return + * @return the list of input forms + * @throws DCInputsReaderException + */ + public List getAllInputs(Integer limit, Integer offset) throws DCInputsReaderException { + int idx = 0; + int count = 0; + List subConfigs = new LinkedList(); + for (String key : formDefns.keySet()) { + if (offset == null || idx >= offset) { + count++; + subConfigs.add(getInputsByFormName(key)); + } + idx++; + if (count >= limit) { + break; + } + } + return subConfigs; + } + + /** * Process the top level child nodes in the passed top-level node. These * should correspond to the collection-form maps, the form definitions, and * the display/storage word pairs. * - * @param n - * top-level DOM node + * @param n top-level DOM node */ private void doNodes(Node n) - throws SAXException, DCInputsReaderException - { - if (n == null) - { + throws SAXException, DCInputsReaderException { + if (n == null) { return; } Node e = getElement(n); NodeList nl = e.getChildNodes(); int len = nl.getLength(); - boolean foundMap = false; boolean foundDefs = false; - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node nd = nl.item(i); - if ((nd == null) || isEmptyTextNode(nd)) - { + if ((nd == null) || isEmptyTextNode(nd)) { continue; } String tagName = nd.getNodeName(); - if (tagName.equals("form-map")) - { - processMap(nd); - foundMap = true; - } - else if (tagName.equals("form-definitions")) - { + if (tagName.equals("form-definitions")) { processDefinition(nd); foundDefs = true; - } - else if (tagName.equals("form-value-pairs")) - { + } else if (tagName.equals("form-value-pairs")) { processValuePairs(nd); } // Ignore unknown nodes } - if (!foundMap) - { - throw new DCInputsReaderException("No collection to form map found"); - } - if (!foundDefs) - { + if (!foundDefs) { throw new DCInputsReaderException("No form definition found"); } } - /** - * Process the form-map section of the XML file. - * Each element looks like: - * - * Extract the collection handle and form name, put name in hashmap keyed - * by the collection handle. - */ - private void processMap(Node e) - throws SAXException - { - NodeList nl = e.getChildNodes(); - int len = nl.getLength(); - for (int i = 0; i < len; i++) - { - Node nd = nl.item(i); - if (nd.getNodeName().equals("name-map")) - { - String id = getAttribute(nd, "collection-handle"); - String value = getAttribute(nd, "form-name"); - String content = getValue(nd); - if (id == null) - { - throw new SAXException("name-map element is missing collection-handle attribute"); - } - if (value == null) - { - throw new SAXException("name-map element is missing form-name attribute"); - } - if (content != null && content.length() > 0) - { - throw new SAXException("name-map element has content, it should be empty."); - } - whichForms.put(id, value); - } // ignore any child node that isn't a "name-map" - } - } - /** * Process the form-definitions section of the XML file. Each element is - * formed thusly:
    ...pages...
    Each pages - * subsection is formed: ...fields... Each field + * formed thusly:
    ...row...
    Each rows + * subsection is formed: ...fields... Each field * is formed from: dc-element, dc-qualifier, label, hint, input-type name, * required text, and repeatable flag. */ private void processDefinition(Node e) - throws SAXException, DCInputsReaderException - { + throws SAXException, DCInputsReaderException { int numForms = 0; NodeList nl = e.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node nd = nl.item(i); // process each form definition - if (nd.getNodeName().equals("form")) - { + if (nd.getNodeName().equals("form")) { numForms++; String formName = getAttribute(nd, "name"); - if (formName == null) - { + if (formName == null) { throw new SAXException("form element has no name attribute"); } - List>> pages = new ArrayList>>(); // the form contains pages - formDefns.put(formName, pages); + List>> rows = new ArrayList>>(); // the form + // contains rows of fields + formDefns.put(formName, rows); NodeList pl = nd.getChildNodes(); int lenpg = pl.getLength(); - for (int j = 0; j < lenpg; j++) - { + for (int j = 0; j < lenpg; j++) { Node npg = pl.item(j); - // process each page definition - if (npg.getNodeName().equals("page")) - { - String pgNum = getAttribute(npg, "number"); - if (pgNum == null) - { - throw new SAXException("Form " + formName + " has no identified pages"); - } - List> page = new ArrayList>(); - pages.add(page); - NodeList flds = npg.getChildNodes(); - int lenflds = flds.getLength(); - for (int k = 0; k < lenflds; k++) - { - Node nfld = flds.item(k); - if ( nfld.getNodeName().equals("field") ) - { - // process each field definition - Map field = new HashMap(); - page.add(field); - processPageParts(formName, pgNum, nfld, field); - - // we omit the duplicate validation, allowing multiple fields definition for - // the same metadata and different visibility/type-bind - } - } - } // ignore any child that is not a 'page' + if (npg.getNodeName().equals("row")) { + List> fields = new ArrayList>(); // the fields in the + // row + // process each row definition + processRow(formName, j, npg, fields); + rows.add(fields); + } } - // sanity check number of pages - if (pages.size() < 1) - { - throw new DCInputsReaderException("Form " + formName + " has no pages"); + // sanity check number of fields + if (rows.size() < 1) { + throw new DCInputsReaderException("Form " + formName + " has no rows"); } } } - if (numForms == 0) - { + if (numForms == 0) { throw new DCInputsReaderException("No form definition found"); } } + /** + * Process parts of a row + */ + private void processRow(String formName, int rowIdx, Node n, List> fields) + throws SAXException, DCInputsReaderException { + + NodeList pl = n.getChildNodes(); + int lenpg = pl.getLength(); + for (int j = 0; j < lenpg; j++) { + Node npg = pl.item(j); + + if (npg.getNodeName().equals("field")) { + // process each field definition + Map field = new HashMap(); + processField(formName, npg, field); + fields.add(field); + String key = field.get(PAIR_TYPE_NAME); + if (StringUtils + .isNotBlank(key)) { + String schema = field.get("dc-schema"); + String element = field.get("dc-element"); + String qualifier = field + .get("dc-qualifier"); + String metadataField = schema + "." + + element; + if (StringUtils.isNotBlank(qualifier)) { + metadataField += "." + qualifier; + } + } + + // we omit the duplicate validation, allowing multiple + // fields definition for + // the same metadata and different visibility/type-bind + } + } + // sanity check number of fields + if (fields.size() < 1) { + throw new DCInputsReaderException("Form " + formName + "row " + rowIdx + " has no fields"); + } + } + + /** * Process parts of a field * At the end, make sure that input-types 'qualdrop_value' and * 'twobox' are marked repeatable. Complain if dc-element, label, * or input-type are missing. */ - private void processPageParts(String formName, String page, Node n, Map field) - throws SAXException - { + private void processField(String formName, Node n, Map field) + throws SAXException { NodeList nl = n.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node nd = nl.item(i); - if ( ! isEmptyTextNode(nd) ) - { + if (!isEmptyTextNode(nd)) { String tagName = nd.getNodeName(); - String value = getValue(nd); + String value = getValue(nd); field.put(tagName, value); - if (tagName.equals("input-type")) - { + if (tagName.equals("input-type")) { if (value.equals("dropdown") || value.equals("qualdrop_value") - || value.equals("list")) - { + || value.equals("list")) { String pairTypeName = getAttribute(nd, PAIR_TYPE_NAME); - if (pairTypeName == null) - { + if (pairTypeName == null) { throw new SAXException("Form " + formName + ", field " + - field.get("dc-element") + - "." + field.get("dc-qualifier") + - " has no name attribute"); - } - else - { + field.get("dc-element") + + "." + field.get("dc-qualifier") + + " has no name attribute"); + } else { field.put(PAIR_TYPE_NAME, pairTypeName); } } - } - else if (tagName.equals("vocabulary")) - { + } else if (tagName.equals("vocabulary")) { String closedVocabularyString = getAttribute(nd, "closed"); field.put("closedVocabulary", closedVocabularyString); - } - else if (tagName.equals("language")) - { - if (Boolean.valueOf(value)) - { + } else if (tagName.equals("language")) { + if (Boolean.valueOf(value)) { String pairTypeName = getAttribute(nd, PAIR_TYPE_NAME); - if (pairTypeName == null) - { + if (pairTypeName == null) { throw new SAXException("Form " + formName + ", field " + - field.get("dc-element") + - "." + field.get("dc-qualifier") + - " has no language attribute"); - } - else - { + field.get("dc-element") + + "." + field.get("dc-qualifier") + + " has no language attribute"); + } else { field.put(PAIR_TYPE_NAME, pairTypeName); } } @@ -423,32 +428,26 @@ public class DCInputsReader } } String missing = null; - if (field.get("dc-element") == null) - { + if (field.get("dc-element") == null) { missing = "dc-element"; } - if (field.get("label") == null) - { + if (field.get("label") == null) { missing = "label"; } - if (field.get("input-type") == null) - { + if (field.get("input-type") == null) { missing = "input-type"; } - if ( missing != null ) - { - String msg = "Required field " + missing + " missing on page " + page + " of form " + formName; + if (missing != null) { + String msg = "Required field " + missing + " missing on form " + formName; throw new SAXException(msg); } String type = field.get("input-type"); - if (type.equals("twobox") || type.equals("qualdrop_value")) - { + if (type.equals("twobox") || type.equals("qualdrop_value")) { String rpt = field.get("repeatable"); if ((rpt == null) || ((!rpt.equalsIgnoreCase("yes")) && - (!rpt.equalsIgnoreCase("true")))) - { - String msg = "The field \'"+field.get("label")+"\' must be repeatable"; + (!rpt.equalsIgnoreCase("true")))) { + String msg = "The field \'" + field.get("label") + "\' must be repeatable"; throw new SAXException(msg); } } @@ -458,93 +457,76 @@ public class DCInputsReader * Check that this is the only field with the name dc-element.dc-qualifier * If there is a duplicate, return an error message, else return null; */ - private String checkForDups(String formName, Map field, List>> pages) - { + private String checkForDups(String formName, Map field, List>> pages) { int matches = 0; String err = null; String schema = field.get("dc-schema"); String elem = field.get("dc-element"); String qual = field.get("dc-qualifier"); - if ((schema == null) || (schema.equals(""))) - { + if ((schema == null) || (schema.equals(""))) { schema = MetadataSchema.DC_SCHEMA; } String schemaTest; - - for (int i = 0; i < pages.size(); i++) - { + + for (int i = 0; i < pages.size(); i++) { List> pg = pages.get(i); - for (int j = 0; j < pg.size(); j++) - { + for (int j = 0; j < pg.size(); j++) { Map fld = pg.get(j); if ((fld.get("dc-schema") == null) || - ((fld.get("dc-schema")).equals(""))) - { + ((fld.get("dc-schema")).equals(""))) { schemaTest = MetadataSchema.DC_SCHEMA; - } - else - { + } else { schemaTest = fld.get("dc-schema"); } - + // Are the schema and element the same? If so, check the qualifier if (((fld.get("dc-element")).equals(elem)) && - (schemaTest.equals(schema))) - { + (schemaTest.equals(schema))) { String ql = fld.get("dc-qualifier"); - if (qual != null) - { - if ((ql != null) && ql.equals(qual)) - { + if (qual != null) { + if ((ql != null) && ql.equals(qual)) { matches++; } - } - else if (ql == null) - { + } else if (ql == null) { matches++; } } } } - if (matches > 1) - { + if (matches > 1) { err = "Duplicate field " + schema + "." + elem + "." + qual + " detected in form " + formName; } - + return err; } /** * Process the form-value-pairs section of the XML file. - * Each element is formed thusly: - * - * - * displayed name- - * stored name - * + * Each element is formed thusly: + * + * + * displayed name- + * stored name + * * For each value-pairs element, create a new vector, and extract all * the pairs contained within it. Put the display and storage values, * respectively, in the next slots in the vector. Store the vector * in the passed in hashmap. */ private void processValuePairs(Node e) - throws SAXException - { + throws SAXException { NodeList nl = e.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node nd = nl.item(i); String tagName = nd.getNodeName(); // process each value-pairs set - if (tagName.equals("value-pairs")) - { + if (tagName.equals("value-pairs")) { String pairsName = getAttribute(nd, PAIR_TYPE_NAME); String dcTerm = getAttribute(nd, "dc-term"); - if (pairsName == null) - { + if (pairsName == null) { String errString = "Missing name attribute for value-pairs for DC term " + dcTerm; throw new SAXException(errString); @@ -553,29 +535,22 @@ public class DCInputsReader valuePairs.put(pairsName, pairs); NodeList cl = nd.getChildNodes(); int lench = cl.getLength(); - for (int j = 0; j < lench; j++) - { + for (int j = 0; j < lench; j++) { Node nch = cl.item(j); String display = null; String storage = null; - if (nch.getNodeName().equals("pair")) - { + if (nch.getNodeName().equals("pair")) { NodeList pl = nch.getChildNodes(); int plen = pl.getLength(); - for (int k = 0; k < plen; k++) - { - Node vn= pl.item(k); + for (int k = 0; k < plen; k++) { + Node vn = pl.item(k); String vName = vn.getNodeName(); - if (vName.equals("displayed-value")) - { + if (vName.equals("displayed-value")) { display = getValue(vn); - } - else if (vName.equals("stored-value")) - { + } else if (vName.equals("stored-value")) { storage = getValue(vn); - if (storage == null) - { + if (storage == null) { storage = ""; } } // ignore any children that aren't 'display' or 'storage' @@ -597,65 +572,55 @@ public class DCInputsReader */ private void checkValues() - throws DCInputsReaderException - { + throws DCInputsReaderException { // Step through every field of every page of every form Iterator ki = formDefns.keySet().iterator(); - while (ki.hasNext()) - { + while (ki.hasNext()) { String idName = ki.next(); - List>> pages = formDefns.get(idName); - for (int i = 0; i < pages.size(); i++) - { - List> page = pages.get(i); - for (int j = 0; j < page.size(); j++) - { - Map fld = page.get(j); + List>> rows = formDefns.get(idName); + for (int j = 0; j < rows.size(); j++) { + List> fields = rows.get(j); + for (int i = 0; i < fields.size(); i++) { + Map fld = fields.get(i); // verify reference in certain input types String type = fld.get("input-type"); if (type.equals("dropdown") || type.equals("qualdrop_value") - || type.equals("list")) - { + || type.equals("list")) { String pairsName = fld.get(PAIR_TYPE_NAME); List v = valuePairs.get(pairsName); - if (v == null) - { + if (v == null) { String errString = "Cannot find value pairs for " + pairsName; throw new DCInputsReaderException(errString); } } - - // we omit the "required" and "visibility" validation, provided this must be checked in the processing class - // only when it makes sense (if the field isn't visible means that it is not applicable, therefore it can't be required) + + // we omit the "required" and "visibility" validation, provided this must be checked in the + // processing class + // only when it makes sense (if the field isn't visible means that it is not applicable, + // therefore it can't be required) } } } } - - private Node getElement(Node nd) - { + + private Node getElement(Node nd) { NodeList nl = nd.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE) - { + if (n.getNodeType() == Node.ELEMENT_NODE) { return n; } } return null; - } + } - private boolean isEmptyTextNode(Node nd) - { + private boolean isEmptyTextNode(Node nd) { boolean isEmpty = false; - if (nd.getNodeType() == Node.TEXT_NODE) - { + if (nd.getNodeType() == Node.TEXT_NODE) { String text = nd.getNodeValue().trim(); - if (text.length() == 0) - { + if (text.length() == 0) { isEmpty = true; } } @@ -665,18 +630,14 @@ public class DCInputsReader /** * Returns the value of the node's attribute named */ - private String getAttribute(Node e, String name) - { + private String getAttribute(Node e, String name) { NamedNodeMap attrs = e.getAttributes(); int len = attrs.getLength(); - if (len > 0) - { + if (len > 0) { int i; - for (i = 0; i < len; i++) - { + for (i = 0; i < len; i++) { Node attr = attrs.item(i); - if (name.equals(attr.getNodeName())) - { + if (name.equals(attr.getNodeName())) { return attr.getNodeValue().trim(); } } @@ -689,20 +650,37 @@ public class DCInputsReader * Returns the value found in the Text node (if any) in the * node list that's passed in. */ - private String getValue(Node nd) - { + private String getValue(Node nd) { NodeList nl = nd.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node n = nl.item(i); short type = n.getNodeType(); - if (type == Node.TEXT_NODE) - { + if (type == Node.TEXT_NODE) { return n.getNodeValue().trim(); } } // Didn't find a text node return null; } + + public String getInputFormNameByCollectionAndField(Collection collection, String field) + throws DCInputsReaderException { + List inputSets = getInputsByCollectionHandle(collection.getHandle()); + for (DCInputSet inputSet : inputSets) { + String[] tokenized = Utils.tokenize(field); + String schema = tokenized[0]; + String element = tokenized[1]; + String qualifier = tokenized[2]; + if (StringUtils.isBlank(qualifier)) { + qualifier = null; + } + String standardized = Utils.standardize(schema, element, qualifier, "."); + if (inputSet.isFieldPresent(standardized)) { + return inputSet.getFormName(); + } + } + throw new DCInputsReaderException("No field configuration found!"); + } + } diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReaderException.java b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReaderException.java index c13701367f..c55524f2e2 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReaderException.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReaderException.java @@ -16,41 +16,39 @@ package org.dspace.app.util; * @author Larry Stone * @version $Revision: 3761 $ */ -public class DCInputsReaderException extends Exception -{ +public class DCInputsReaderException extends Exception { /** * No-args constructor. */ - public DCInputsReaderException() - { + public DCInputsReaderException() { super(); } /** * Constructor for a given message. + * * @param message diagnostic message. */ - public DCInputsReaderException(String message) - { + public DCInputsReaderException(String message) { super(message); } /** * Constructor for a given cause. + * * @param cause throwable that caused this exception */ - public DCInputsReaderException(Throwable cause) - { + public DCInputsReaderException(Throwable cause) { super(cause); } /** * Constructor to create a new exception wrapping it around another exception. + * * @param message diagnostic message. - * @param cause throwable that caused this exception + * @param cause throwable that caused this exception */ - public DCInputsReaderException(String message, Throwable cause) - { + public DCInputsReaderException(String message, Throwable cause) { super(message, cause); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/DSpaceContextListener.java b/dspace-api/src/main/java/org/dspace/app/util/DSpaceContextListener.java index 03d70bbea6..f2dcd593dc 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DSpaceContextListener.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DSpaceContextListener.java @@ -7,89 +7,71 @@ */ package org.dspace.app.util; -import org.apache.log4j.Logger; - -import javax.servlet.ServletContextListener; -import javax.servlet.ServletContextEvent; - import java.beans.Introspector; import java.net.URL; import java.net.URLConnection; import java.sql.Driver; import java.sql.DriverManager; import java.util.Enumeration; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.apache.log4j.Logger; /** * Class to initialize / cleanup resources used by DSpace when the web application * is started or stopped. */ -public class DSpaceContextListener implements ServletContextListener -{ +public class DSpaceContextListener implements ServletContextListener { private static Logger log = Logger.getLogger(DSpaceContextListener.class); /** * Initialize any resources required by the application. - * @param event - * This is the event class for notifications about changes to the servlet context of a web application. + * + * @param event This is the event class for notifications about changes to the servlet context of a web application. */ @Override - public void contextInitialized(ServletContextEvent event) - { + public void contextInitialized(ServletContextEvent event) { // On Windows, URL caches can cause problems, particularly with undeployment // So, here we attempt to disable them if we detect that we are running on Windows - try - { + try { String osName = System.getProperty("os.name"); - if (osName != null && osName.toLowerCase().contains("windows")) - { + if (osName != null && osName.toLowerCase().contains("windows")) { URL url = new URL("http://localhost/"); URLConnection urlConn = url.openConnection(); urlConn.setDefaultUseCaches(false); } - } - // Any errors thrown in disabling the caches aren't significant to - // the normal execution of the application, so we ignore them - catch (RuntimeException e) - { + } catch (RuntimeException e) { + // Any errors thrown in disabling the caches aren't significant to + // the normal execution of the application, so we ignore them log.error(e.getMessage(), e); - } - catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); } } /** * Clean up resources used by the application when stopped - * - * @param event - 8 Event class for notifications about changes to the servlet context of a web application. + * + * @param event 8 Event class for notifications about changes to the servlet context of a web application. */ @Override - public void contextDestroyed(ServletContextEvent event) - { - try - { + public void contextDestroyed(ServletContextEvent event) { + try { // Clean out the introspector Introspector.flushCaches(); // Remove any drivers registered by this classloader - for (Enumeration e = DriverManager.getDrivers(); e.hasMoreElements();) - { + for (Enumeration e = DriverManager.getDrivers(); e.hasMoreElements(); ) { Driver driver = (Driver) e.nextElement(); - if (driver.getClass().getClassLoader() == getClass().getClassLoader()) - { + if (driver.getClass().getClassLoader() == getClass().getClassLoader()) { DriverManager.deregisterDriver(driver); } } - } - catch (RuntimeException e) - { + } catch (RuntimeException e) { log.error("Failed to cleanup ClassLoader for webapp", e); - } - catch (Exception e) - { + } catch (Exception e) { log.error("Failed to cleanup ClassLoader for webapp", e); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappListener.java b/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappListener.java index 760cf90ba3..875eda9813 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappListener.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappListener.java @@ -22,20 +22,20 @@ public class DSpaceWebappListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent event) { /* - * Register that this application is running. - */ + * Register that this application is running. + */ - try { - Class webappClass = Class.forName("org.dspace.utils.DSpaceWebapp"); - webApp = (AbstractDSpaceWebapp) webappClass.newInstance(); - webApp.register(); - } catch (ClassNotFoundException ex) { - event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); - } catch (InstantiationException ex) { - event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); - } catch (IllegalAccessException ex) { - event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); - } + try { + Class webappClass = Class.forName("org.dspace.utils.DSpaceWebapp"); + webApp = (AbstractDSpaceWebapp) webappClass.newInstance(); + webApp.register(); + } catch (ClassNotFoundException ex) { + event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); + } catch (InstantiationException ex) { + event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); + } catch (IllegalAccessException ex) { + event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); + } } @Override diff --git a/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappMXBean.java b/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappMXBean.java index 05edc7b54c..89c8d8cb95 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappMXBean.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappMXBean.java @@ -13,28 +13,31 @@ package org.dspace.app.util; * * @author mwood */ -public interface DSpaceWebappMXBean -{ - /** +public interface DSpaceWebappMXBean { + /** * Is this webapp a user interface? False if machine interface such as SWORD. - * @return true/false + * + * @return true/false */ public boolean isUI(); - /** + /** * What kind of webapp? XMLUI, OAI, etc. + * * @return kind of webapp */ public String getKind(); - /** + /** * What is the base URL of this application? + * * @return base url */ public String getURL(); - /** + /** * When did this application start? + * * @return start time */ public String getStarted(); diff --git a/dspace-api/src/main/java/org/dspace/app/util/DailyFileAppender.java b/dspace-api/src/main/java/org/dspace/app/util/DailyFileAppender.java index f4a152b547..db83bf19c4 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DailyFileAppender.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DailyFileAppender.java @@ -7,7 +7,6 @@ */ package org.dspace.app.util; - import java.io.File; import java.io.IOException; import java.net.UnknownHostException; @@ -38,10 +37,8 @@ import org.apache.log4j.spi.LoggingEvent; * log4j.appender.A1.MaxLogs=3 * log4j.appender.A1.layout=org.apache.log4j.PatternLayout * log4j.appender.A1.layout.ConversionPattern=%d %-5p %c @ %m%n - * */ -public class DailyFileAppender extends FileAppender -{ +public class DailyFileAppender extends FileAppender { /** * The fixed date pattern to be used if one is not specified. */ @@ -57,7 +54,7 @@ public class DailyFileAppender extends FileAppender /** * Used internally and contains the name of the date derived from current system date. */ - private Date mstrDate = new Date(System.currentTimeMillis()); + private Date mstrDate = new Date(System.currentTimeMillis()); /** * Holds the user specified DatePattern, @@ -79,8 +76,7 @@ public class DailyFileAppender extends FileAppender * Default constructor. This is required as the appender class is dynamically * loaded. */ - public DailyFileAppender() - { + public DailyFileAppender() { super(); } @@ -88,106 +84,87 @@ public class DailyFileAppender extends FileAppender * @see org.apache.log4j.FileAppender#activateOptions() */ @Override - public void activateOptions() - { + public void activateOptions() { setFileName(); cleanupOldFiles(); super.activateOptions(); } -/*------------------------------------------------------------------------------ - * Getters - *----------------------------------------------------------------------------*/ - public String getDatePattern() - { + /*------------------------------------------------------------------------------ + * Getters + *----------------------------------------------------------------------------*/ + public String getDatePattern() { return this.mstrDatePattern; } @Override - public String getFile() - { + public String getFile() { return this.mstrFileName; } - public boolean getWithHost() - { + public boolean getWithHost() { return mWithHostName; } - public int getMaxLogs() - { - return mMaxLogs; + public int getMaxLogs() { + return mMaxLogs; } -/*------------------------------------------------------------------------------ - * Setters - *----------------------------------------------------------------------------*/ - public void setDatePattern(String pstrPattern) - { + /*------------------------------------------------------------------------------ + * Setters + *----------------------------------------------------------------------------*/ + public void setDatePattern(String pstrPattern) { this.mstrDatePattern = checkPattern(pstrPattern); - if (mstrDatePattern.contains("dd") || mstrDatePattern.contains("DD")) - { + if (mstrDatePattern.contains("dd") || mstrDatePattern.contains("DD")) { mMonthOnly = false; - } - else - { + } else { mMonthOnly = true; } } @Override - public void setFile(String file) - { + public void setFile(String file) { // Trim spaces from both ends. The users probably does not want // trailing spaces in file names. String val = file.trim(); mstrFileName = val; - } + } - public void setWithHost(boolean wh) - { + public void setWithHost(boolean wh) { mWithHostName = wh; } - public void setMaxLogs(int ml) - { - mMaxLogs = ml; + public void setMaxLogs(int ml) { + mMaxLogs = ml; } -/*------------------------------------------------------------------------------ - * Methods - *----------------------------------------------------------------------------*/ + /*------------------------------------------------------------------------------ + * Methods + *----------------------------------------------------------------------------*/ /* (non-Javadoc) * @see org.apache.log4j.WriterAppender#subAppend(org.apache.log4j.spi.LoggingEvent) */ @Override - protected void subAppend(LoggingEvent pobjEvent) - { - Date dtNow = new Date(System.currentTimeMillis()); + protected void subAppend(LoggingEvent pobjEvent) { + Date dtNow = new Date(System.currentTimeMillis()); boolean rollover = false; - if (mMonthOnly) - { + if (mMonthOnly) { Calendar now = Calendar.getInstance(); Calendar cur = Calendar.getInstance(); now.setTime(dtNow); cur.setTime(mstrDate); - rollover = !(now.get(Calendar.YEAR) == cur.get(Calendar.YEAR) && now.get(Calendar.MONTH) == cur.get(Calendar.MONTH)); - } - else - { + rollover = !(now.get(Calendar.YEAR) == cur.get(Calendar.YEAR) && now.get(Calendar.MONTH) == cur + .get(Calendar.MONTH)); + } else { rollover = !(DateUtils.isSameDay(dtNow, mstrDate)); } - if (rollover) - { - try - { + if (rollover) { + try { rollOver(dtNow); - } - catch (IOException IOEx) - { + } catch (IOException IOEx) { LogLog.error("rollOver() failed!", IOEx); } } @@ -195,38 +172,32 @@ public class DailyFileAppender extends FileAppender super.subAppend(pobjEvent); } -/*------------------------------------------------------------------------------ - * Helpers - *----------------------------------------------------------------------------*/ + /*------------------------------------------------------------------------------ + * Helpers + *----------------------------------------------------------------------------*/ + /** * The helper function to validate the DatePattern. + * * @param pstrPattern The DatePattern to be validated. * @return The validated date pattern or defautlt DATE_PATTERN */ - private String checkPattern(String pstrPattern) - { + private String checkPattern(String pstrPattern) { String strRet = null; SimpleDateFormat objFmt = new SimpleDateFormat(DATE_PATTERN); - try - { + try { this.mobjSDF = new SimpleDateFormat(pstrPattern); strRet = pstrPattern; - } - catch (NullPointerException NPExIgnore) - { + } catch (NullPointerException NPExIgnore) { LogLog.error("Invalid DatePattern " + pstrPattern, NPExIgnore); this.mobjSDF = objFmt; strRet = DATE_PATTERN; - } - catch (IllegalArgumentException IlArgExIgnore) - { + } catch (IllegalArgumentException IlArgExIgnore) { LogLog.error("Invalid DatePattern " + pstrPattern, IlArgExIgnore); this.mobjSDF = objFmt; strRet = DATE_PATTERN; - } - finally - { + } finally { objFmt = null; } return strRet; @@ -234,98 +205,79 @@ public class DailyFileAppender extends FileAppender /** * This function is responsible for performing the actual file rollover. + * * @param pstrName The name of the new folder based on current system date. * @throws IOException if IO error */ private static boolean deletingFiles = false; - private void cleanupOldFiles() - { - // If we need to delete log files - if (mMaxLogs > 0 && !deletingFiles) - { - deletingFiles = true; - // Determine the final file extension with the hostname - String hostFileExt = null; - try - { + private void cleanupOldFiles() { + // If we need to delete log files + if (mMaxLogs > 0 && !deletingFiles) { + deletingFiles = true; + + // Determine the final file extension with the hostname + String hostFileExt = null; + try { hostFileExt = "." + java.net.InetAddress.getLocalHost().getHostName(); - } - catch (UnknownHostException e) - { + } catch (UnknownHostException e) { LogLog.error("Unable to retrieve host name"); } - try - { - // Array to hold the logs we are going to keep - File[] logsToKeep = new File[mMaxLogs]; + try { + // Array to hold the logs we are going to keep + File[] logsToKeep = new File[mMaxLogs]; - // Get a 'master' file handle, and the parent directory from it - File logMaster = new File(mstrFileName); - File logDir = logMaster.getParentFile(); - if (logDir.isDirectory()) - { - // Iterate all the files in that directory - File[] logArr = logDir.listFiles(); - for (File curLog : logArr) - { - LogLog.debug("Comparing '" + curLog.getAbsolutePath() + "' to '" + mstrFileName + "'"); - String name = curLog.getAbsolutePath(); + // Get a 'master' file handle, and the parent directory from it + File logMaster = new File(mstrFileName); + File logDir = logMaster.getParentFile(); + if (logDir.isDirectory()) { + // Iterate all the files in that directory + File[] logArr = logDir.listFiles(); + for (File curLog : logArr) { + LogLog.debug("Comparing '" + curLog.getAbsolutePath() + "' to '" + mstrFileName + "'"); + String name = curLog.getAbsolutePath(); - // First, see if we are not using hostname, or the log file ends with this host - if (!mWithHostName || (hostFileExt != null && name.endsWith(hostFileExt))) - { - // Check that the file is indeed one we want (contains the master file name) - if (name.contains(mstrFileName)) - { - // Iterate through the array of logs we are keeping - for (int i = 0; curLog != null && i < logsToKeep.length; i++) - { - // Have we exhausted the 'to keep' array? - if (logsToKeep[i] == null) - { - // Empty space, retain this log file - logsToKeep[i] = curLog; - curLog = null; - } - // If the 'kept' file is older than the current one - else if (logsToKeep[i].getName().compareTo(curLog.getName()) < 0) - { - // Replace tested entry with current file - File temp = logsToKeep[i]; - logsToKeep[i] = curLog; - curLog = temp; - } - } + // First, see if we are not using hostname, or the log file ends with this host + if (!mWithHostName || (hostFileExt != null && name.endsWith(hostFileExt))) { + // Check that the file is indeed one we want (contains the master file name) + if (name.contains(mstrFileName)) { + // Iterate through the array of logs we are keeping + for (int i = 0; curLog != null && i < logsToKeep.length; i++) { + // Have we exhausted the 'to keep' array? + if (logsToKeep[i] == null) { + // Empty space, retain this log file + logsToKeep[i] = curLog; + curLog = null; + } else if (logsToKeep[i].getName().compareTo(curLog.getName()) < 0) { + // If the 'kept' file is older than the current one + // Replace tested entry with current file + File temp = logsToKeep[i]; + logsToKeep[i] = curLog; + curLog = temp; + } + } - // If we have a 'current' entry at this point, it's a log we don't want - if (curLog != null) - { - LogLog.debug("Deleting log " + curLog.getName()); - if (! curLog.delete()) - { + // If we have a 'current' entry at this point, it's a log we don't want + if (curLog != null) { + LogLog.debug("Deleting log " + curLog.getName()); + if (!curLog.delete()) { LogLog.error("Unable to delete log file"); } - } - } - } - } - } - } - catch (Exception e) - { - // Don't worry about exceptions - } - finally - { - deletingFiles = false; - } + } + } + } + } + } + } catch (Exception e) { + // Don't worry about exceptions + } finally { + deletingFiles = false; + } } } - private void rollOver(Date dtNow) throws IOException - { + private void rollOver(Date dtNow) throws IOException { mstrDate = dtNow; setFileName(); this.setFile(fileName, true, bufferedIO, bufferSize); @@ -333,20 +285,15 @@ public class DailyFileAppender extends FileAppender cleanupOldFiles(); } - private void setFileName() - { + private void setFileName() { fileName = mstrFileName + "." + mobjSDF.format(mstrDate); - if (mWithHostName) - { - try - { + if (mWithHostName) { + try { fileName += "." + java.net.InetAddress.getLocalHost().getHostName(); - } - catch (UnknownHostException e) - { + } catch (UnknownHostException e) { LogLog.error("Unable to retrieve host name"); } } } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/app/util/GoogleBitstreamComparator.java b/dspace-api/src/main/java/org/dspace/app/util/GoogleBitstreamComparator.java index 26ceb5ebb7..821fd2f3b5 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/GoogleBitstreamComparator.java +++ b/dspace-api/src/main/java/org/dspace/app/util/GoogleBitstreamComparator.java @@ -7,22 +7,22 @@ */ package org.dspace.app.util; +import java.sql.SQLException; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + import org.apache.log4j.Logger; import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.core.Context; -import java.sql.SQLException; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; - /** * This comparator is used to order files of an item, so that they are ordered in a way that the first one * is the most useful for use in the citation_pdf_url for Google Scholar */ -public class GoogleBitstreamComparator implements Comparator{ +public class GoogleBitstreamComparator implements Comparator { private final static Logger log = Logger.getLogger(GoogleBitstreamComparator.class); @@ -33,45 +33,48 @@ public class GoogleBitstreamComparator implements Comparator{ public GoogleBitstreamComparator(Context context, Map googleScholarSettings) { this.context = context; String[] shortDescriptions; - if (googleScholarSettings.containsKey("citation.prioritized_types")){ + if (googleScholarSettings.containsKey("citation.prioritized_types")) { shortDescriptions = splitAndTrim(googleScholarSettings.get("citation.prioritized_types")); } else { log.warn("Please define citation.prioritized_types in google-metadata.properties"); shortDescriptions = new String[0]; } int priority = 1; - for(String s: shortDescriptions){ + for (String s : shortDescriptions) { try { - BitstreamFormat format = ContentServiceFactory.getInstance().getBitstreamFormatService().findByShortDescription(context, s); + BitstreamFormat format = ContentServiceFactory.getInstance().getBitstreamFormatService() + .findByShortDescription(context, s); if (format != null) { priorityMap.put(format.getMIMEType(), priority); } else { log.warn(s + " is not a valid short description, please add it to bitstream-formats.xml"); } priority++; - } catch (SQLException e){ + } catch (SQLException e) { log.error(e.getMessage()); } } } - private String[] splitAndTrim(String toSplit){ - if(toSplit != null) { + private String[] splitAndTrim(String toSplit) { + if (toSplit != null) { String[] splittedArray = toSplit.split(","); - for (int i = 0; i < splittedArray.length; i++) + for (int i = 0; i < splittedArray.length; i++) { splittedArray[i] = splittedArray[i].trim(); + } return splittedArray; - } - else { + } else { return new String[0]; } } /** - * Compares two bitstreams based on their mimetypes, if mimetypes are the same,then the largest bitstream comes first + * Compares two bitstreams based on their mimetypes, if mimetypes are the same,then the largest bitstream comes + * first * See google-metadata.properties to define the order + * * @param b1 first bitstream * @param b2 second bitstream * @return @@ -80,18 +83,15 @@ public class GoogleBitstreamComparator implements Comparator{ int priority1 = getPriorityFromBitstream(b1); int priority2 = getPriorityFromBitstream(b2); - if(priority1 > priority2){ + if (priority1 > priority2) { return 1; - } - else if(priority1 == priority2){ - if(b1.getSize() <= b2.getSize()){ + } else if (priority1 == priority2) { + if (b1.getSizeBytes() <= b2.getSizeBytes()) { return 1; - } - else { + } else { return -1; } - } - else { + } else { return -1; } } @@ -109,4 +109,4 @@ public class GoogleBitstreamComparator implements Comparator{ return Integer.MAX_VALUE; } } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/app/util/GoogleMetadata.java b/dspace-api/src/main/java/org/dspace/app/util/GoogleMetadata.java index e94811b08a..f012395de4 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/GoogleMetadata.java +++ b/dspace-api/src/main/java/org/dspace/app/util/GoogleMetadata.java @@ -7,11 +7,33 @@ */ package org.dspace.app.util; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import org.apache.log4j.Logger; import org.dspace.authorize.factory.AuthorizeServiceFactory; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +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; @@ -20,26 +42,14 @@ import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; import org.jdom.Element; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; -import java.sql.SQLException; -import java.util.*; -import java.util.Collection; -import java.util.Map.Entry; - /** * Configuration and mapping for Google Scholar output metadata + * * @author Sands Fish - * */ @SuppressWarnings("deprecation") -public class GoogleMetadata -{ +public class GoogleMetadata { private final static Logger log = Logger.getLogger(GoogleMetadata.class); @@ -123,79 +133,65 @@ public class GoogleMetadata private static GoogleBitstreamComparator googleBitstreamComparator = null; // Load configured fields from google-metadata.properties - static - { + static { File loadedFile = null; URL url = null; InputStream is = null; String googleConfigFile = ConfigurationManager - .getProperty("google-metadata.config"); + .getProperty("google-metadata.config"); log.info("Using [" + googleConfigFile - + "] for Google Metadata configuration"); + + "] for Google Metadata configuration"); loadedFile = new File(googleConfigFile); - try - { + try { url = loadedFile.toURL(); - } - catch (MalformedURLException mux) - { + } catch (MalformedURLException mux) { log.error("Can't find Google Metadata configuration file: " - + googleConfigFile, mux); + + googleConfigFile, mux); } Properties properties = new Properties(); - try - { + try { is = url.openStream(); properties.load(is); - } - catch (IOException iox) - { + } catch (IOException iox) { log.error("Could not read Google Metadata configuration file: " - + googleConfigFile, iox); + + googleConfigFile, iox); } Enumeration propertyNames = properties.propertyNames(); - while (propertyNames.hasMoreElements()) - { + while (propertyNames.hasMoreElements()) { String key = ((String) propertyNames.nextElement()).trim(); - if (key.startsWith(GOOGLE_PREFIX)) - { + if (key.startsWith(GOOGLE_PREFIX)) { String name = key.substring(GOOGLE_PREFIX.length()); String field = properties.getProperty(key); if (null != name && !name.equals("") && null != field - && !field.equals("")) - { + && !field.equals("")) { googleScholarSettings.put(name.trim(), field.trim()); } } } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { logConfiguration(); } } /** * Dump Metadata field mapping to log - * */ - public static void logConfiguration() - { + public static void logConfiguration() { log.debug("Google Metadata Configuration Mapping:"); - for (String name : googleScholarSettings.keySet()) - { + for (String name : googleScholarSettings.keySet()) { log.debug(" " + name + " => " + googleScholarSettings.get(name)); } } @@ -203,13 +199,12 @@ public class GoogleMetadata /** * Wrap the item, parse all configured fields and generate metadata field * values. - * + * * @param context context - * @param item The item being viewed to extract metadata from + * @param item The item being viewed to extract metadata from * @throws SQLException if database error */ - public GoogleMetadata(Context context, Item item) throws SQLException - { + public GoogleMetadata(Context context, Item item) throws SQLException { // Hold onto the item in case we need to refresh a stale parse this.item = item; @@ -222,61 +217,47 @@ public class GoogleMetadata /** * Add a single metadata value to the Google field, defaulting to the * first-encountered instance of the field for this Item. - * - * @param fieldName - * metadata field name + * + * @param fieldName metadata field name * @return successful? */ - protected boolean addSingleField(String fieldName) - { + protected boolean addSingleField(String fieldName) { String config = googleScholarSettings.get(fieldName); - if (null == config || config.equals("")) - { + if (null == config || config.equals("")) { return false; } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Processing " + fieldName); } - if (config.equals("$handle")) - { - if (null != itemURL && !itemURL.equals("")) - { + if (config.equals("$handle")) { + if (null != itemURL && !itemURL.equals("")) { metadataMappings.put(fieldName, itemURL); return true; - } - else - { + } else { return false; } } - if (config.equals("$simple-pdf")) - { + if (config.equals("$simple-pdf")) { String pdf_url = getPDFSimpleUrl(item); - if (pdf_url.length() > 0) - { + if (pdf_url.length() > 0) { metadataMappings.put(fieldName, pdf_url); return true; - } else - { + } else { return false; } } MetadataValue v = resolveMetadataField(config); - if (null != v && (null != v.getValue()) && !v.getValue().trim().equals("")) - { + if (null != v && (null != v.getValue()) && !v.getValue().trim().equals("")) { metadataMappings.put(fieldName, v.getValue()); return true; - } - else - { + } else { // No values found return false; } @@ -285,17 +266,14 @@ public class GoogleMetadata /** * A singular version of resolveMetadata to return only one field value * instead of an aggregate. - * - * @param configFilter - * list of DC metadata fields separated by "|" characters + * + * @param configFilter list of DC metadata fields separated by "|" characters * @return The first configured match of metadata field for the item. */ - protected MetadataValue resolveMetadataField(String configFilter) - { + protected MetadataValue resolveMetadataField(String configFilter) { ArrayList fields = resolveMetadata(configFilter, SINGLE); - if (null != fields && fields.size() > 0) - { + if (null != fields && fields.size() > 0) { return fields.get(0); } @@ -304,18 +282,15 @@ public class GoogleMetadata /** * A plural version of resolveMetadata for aggregate fields. - * - * @param configFilter - * list of DC metadata fields separated by "|" characters + * + * @param configFilter list of DC metadata fields separated by "|" characters * @return Aggregate of all matching metadata fields configured in the first - * option field-set to return any number of filter matches. + * option field-set to return any number of filter matches. */ - protected ArrayList resolveMetadataFields(String configFilter) - { + protected ArrayList resolveMetadataFields(String configFilter) { ArrayList fields = resolveMetadata(configFilter, MULTI); - if (null != fields && fields.size() > 0) - { + if (null != fields && fields.size() > 0) { return fields; } return null; @@ -324,40 +299,31 @@ public class GoogleMetadata /** * Aggregate an array of DCValues present on the current item that pass the * configuration filter. - * - * @param configFilter - * list of DC metadata fields separated by "|" characters - * @param returnType - * GoogleMetadata.SINGLE / GoogleMetadata.MULTI / GoogleMetadata.ALL_FIELDS_IN_OPTION + * + * @param configFilter list of DC metadata fields separated by "|" characters + * @param returnType GoogleMetadata.SINGLE / GoogleMetadata.MULTI / GoogleMetadata.ALL_FIELDS_IN_OPTION * @return Array of configuration to item-field matches */ protected ArrayList resolveMetadata(String configFilter, - int returnType) - { + int returnType) { if (null == configFilter || configFilter.trim().equals("") - || !configFilter.contains(".")) - { + || !configFilter.contains(".")) { log.error("The configuration string [" + configFilter - + "] is invalid."); + + "] is invalid."); return null; - } - else - { + } else { configFilter = configFilter.trim(); } ArrayList> parsedOptions = parseOptions(configFilter); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Resolved Fields For This Item Per Configuration Filter:"); - for (int i = 0; i < parsedOptions.size(); i++) - { + for (int i = 0; i < parsedOptions.size(); i++) { ArrayList optionFields = parsedOptions.get(i); log.debug("Option " + (i + 1) + ":"); - for (String f : optionFields) - { + for (String f : optionFields) { log.debug("{" + f + "}"); } } @@ -365,38 +331,30 @@ public class GoogleMetadata // Iterate through each configured option's field-set until // we have a match. - for (ArrayList optionFields : parsedOptions) - { + for (ArrayList optionFields : parsedOptions) { int optionMatches = 0; String[] components; List values; ArrayList resolvedFields = new ArrayList(); - for (String field : optionFields) - { + for (String field : optionFields) { components = parseComponents(field); values = itemService.getMetadata(item, components[0], components[1], - components[2], Item.ANY); + components[2], Item.ANY); - if (values.size() > 0) - { - for (MetadataValue v : values) - { + if (values.size() > 0) { + for (MetadataValue v : values) { resolvedFields.add(v); - if (returnType == SINGLE) - { - if (!resolvedFields.isEmpty()) - { - if (log.isDebugEnabled()) - { + if (returnType == SINGLE) { + if (!resolvedFields.isEmpty()) { + if (log.isDebugEnabled()) { log - .debug("Resolved Field Value For This Item:"); - for (MetadataValue r : resolvedFields) - { + .debug("Resolved Field Value For This Item:"); + for (MetadataValue r : resolvedFields) { log.debug("{" + r.getValue() + "}"); } } @@ -409,29 +367,22 @@ public class GoogleMetadata // If the item had any of the fields contained in this option, // return them, otherwise move on to the next option's field-set. - if (!resolvedFields.isEmpty()) - { - if (log.isDebugEnabled()) - { + if (!resolvedFields.isEmpty()) { + if (log.isDebugEnabled()) { log.debug("Resolved Field Values For This Item:"); - for (MetadataValue v : resolvedFields) - { + for (MetadataValue v : resolvedFields) { log.debug("{" + v.getValue() + "}"); } } // Check to see if this is a full option match - if (ALL_FIELDS_IN_OPTION == returnType) - { - if (resolvedFields.size() == optionMatches) - { + if (ALL_FIELDS_IN_OPTION == returnType) { + if (resolvedFields.size() == optionMatches) { return resolvedFields; } // Otherwise, if there are any matches for the option, // return them. - } - else if (MULTI == returnType) - { + } else if (MULTI == returnType) { return resolvedFields; } } @@ -442,34 +393,27 @@ public class GoogleMetadata /** * Parse first-match path of metadata field-group options for the given * configuration. - * - * @param configFilter - * list of DC metadata fields separated by "|" characters + * + * @param configFilter list of DC metadata fields separated by "|" characters * @return array of parsed options or null */ - protected ArrayList> parseOptions(String configFilter) - { + protected ArrayList> parseOptions(String configFilter) { ArrayList options = new ArrayList(); ArrayList> parsedOptions = new ArrayList>(); - if (null == configFilter || configFilter.equals("")) - { + if (null == configFilter || configFilter.equals("")) { return null; } - if (configFilter.contains("|")) - { + if (configFilter.contains("|")) { String[] configOptions = configFilter.split("\\|"); - for (String option : configOptions) - { + for (String option : configOptions) { options.add(option.trim()); } - } - else - { + } else { options = new ArrayList(); options.add(configFilter); } @@ -479,43 +423,32 @@ public class GoogleMetadata ArrayList parsedFields; // Parse the fields for each field-set in order. - for (String option : options) - { + for (String option : options) { ArrayList fields; parsedFields = new ArrayList(); - if (option.contains(",")) - { + if (option.contains(",")) { fields = parseFields(option); - } - else - { + } else { fields = new ArrayList(); fields.add(option); } // Parse field list for this field-set, expanding any wildcards. - for (String field : fields) - { + for (String field : fields) { - if (field.contains("*")) - { + if (field.contains("*")) { ArrayList wc = parseWildcard(field); - for (String wcField : wc) - { - if (!parsedFields.contains(wcField)) - { + for (String wcField : wc) { + if (!parsedFields.contains(wcField)) { parsedFields.add(wcField); } } - } - else - { - if (!parsedFields.contains(field)) - { + } else { + if (!parsedFields.contains(field)) { parsedFields.add(field); } } @@ -524,30 +457,24 @@ public class GoogleMetadata parsedOptions.add(parsedFields); } - if (null != parsedOptions) - { + if (null != parsedOptions) { return parsedOptions; - } - else - { + } else { return null; } } /** * Build a Vector of fields that can be added to when expanding wildcards. - * - * @param configString - * - Value of one metadata field configuration + * + * @param configString - Value of one metadata field configuration * @return A vector of raw field configurations. */ - protected ArrayList parseFields(String configString) - { + protected ArrayList parseFields(String configString) { ArrayList fields = new ArrayList(); - for (String field : configString.split("\\,")) - { + for (String field : configString.split("\\,")) { fields.add(field.trim()); } @@ -556,19 +483,16 @@ public class GoogleMetadata /** * Pull apart an individual field structure. - * - * @param field - * The configured field for one metadata field map + * + * @param field The configured field for one metadata field map * @return Schema, Element, Qualifier of metadata field */ - protected String[] parseComponents(String field) - { + protected String[] parseComponents(String field) { int index = 0; String[] components = new String[3]; - for (String c : field.split("\\.")) - { + for (String c : field.split("\\.")) { components[index] = c.trim(); index++; } @@ -579,50 +503,39 @@ public class GoogleMetadata /** * Expand any wildcard characters to an array of all matching fields for * this item. No order consistency is implied. - * - * @param field - * The field identifier containing a wildcard character. + * + * @param field The field identifier containing a wildcard character. * @return Expanded field list. */ - protected ArrayList parseWildcard(String field) - { + protected ArrayList parseWildcard(String field) { - if (!field.contains("*")) - { + if (!field.contains("*")) { return null; - } - else - { + } else { String[] components = parseComponents(field); - for (int i = 0; i < components.length; i++) - { - if (components[i].trim().equals("*")) - { + for (int i = 0; i < components.length; i++) { + if (components[i].trim().equals("*")) { components[i] = Item.ANY; } } List allMD = itemService.getMetadata(item, components[0], components[1], - components[2], Item.ANY); + components[2], Item.ANY); ArrayList expandedDC = new ArrayList(); - for (MetadataValue v : allMD) - { + for (MetadataValue v : allMD) { // De-dup multiple occurrences of field names in item - if (!expandedDC.contains(buildFieldName(v))) - { + if (!expandedDC.contains(buildFieldName(v))) { expandedDC.add(buildFieldName(v)); } } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Field Names From Expanded Wildcard \"" + field - + "\""); - for (String v : expandedDC) - { + + "\""); + for (String v : expandedDC) { log.debug(" " + v); } } @@ -633,21 +546,18 @@ public class GoogleMetadata /** * Construct metadata field name out of Metadatum components - * - * @param v - * The Metadatum to construct a name for. + * + * @param v The Metadatum to construct a name for. * @return The complete metadata field name. */ - protected String buildFieldName(MetadataValue v) - { + protected String buildFieldName(MetadataValue v) { StringBuilder name = new StringBuilder(); MetadataField metadataField = v.getMetadataField(); MetadataSchema metadataSchema = v.getMetadataField().getMetadataSchema(); name.append(metadataSchema.getName()).append(".").append(metadataField.getElement()); - if (null != metadataField.getQualifier()) - { + if (null != metadataField.getQualifier()) { name.append("." + metadataField.getQualifier()); } @@ -658,10 +568,8 @@ public class GoogleMetadata * Using metadata field mappings contained in the loaded configuration, * parse through configured metadata fields, building valid Google metadata * value strings. Field names and values contained in metadataMappings. - * */ - protected void parseItem() - { + protected void parseItem() { // TITLE addSingleField(TITLE); @@ -718,8 +626,7 @@ public class GoogleMetadata addSingleField(CONFERENCE); // Dissertations - if (itemIsDissertation()) - { + if (itemIsDissertation()) { if (log.isDebugEnabled()) { log.debug("ITEM TYPE: DISSERTATION"); } @@ -729,8 +636,7 @@ public class GoogleMetadata } // Patents - if (itemIsPatent()) - { + if (itemIsPatent()) { if (log.isDebugEnabled()) { log.debug("ITEM TYPE: PATENT"); } @@ -739,8 +645,7 @@ public class GoogleMetadata // Use config value for patent country. Should be a literal. String countryConfig = googleScholarSettings.get(PATENT_COUNTRY); - if (null != countryConfig && !countryConfig.trim().equals("")) - { + if (null != countryConfig && !countryConfig.trim().equals("")) { metadataMappings.put(PATENT_COUNTRY, countryConfig.trim()); } @@ -748,8 +653,7 @@ public class GoogleMetadata } // Tech Reports - if (itemIsTechReport()) - { + if (itemIsTechReport()) { if (log.isDebugEnabled()) { log.debug("ITEM TYPE: TECH REPORT"); } @@ -770,24 +674,22 @@ public class GoogleMetadata * * Usage: {@code GoogleMetadata gmd = new GoogleMetadata(item); for(Entry mapping : googlemd.getMappings()) ...} - * + * * @return Iterable of metadata fields mapped to Google-formatted values */ - public Collection> getMappings() - { + public Collection> getMappings() { return metadataMappings.entries(); } /** * Produce meta elements that can easily be put into the head. + * * @return List of elements */ - public List disseminateList() - { + public List disseminateList() { List metas = new ArrayList(); - for (Entry m : getMappings()) - { + for (Entry m : getMappings()) { Element e = new Element("meta"); e.setNamespace(null); e.setAttribute("name", m.getKey()); @@ -802,200 +704,175 @@ public class GoogleMetadata /** * @return the citation_title */ - public List getTitle() - { + public List getTitle() { return metadataMappings.get(TITLE); } /** * @return the citation_journal_title */ - public List getJournalTitle() - { + public List getJournalTitle() { return metadataMappings.get(JOURNAL_TITLE); } /** * @return the citation_publisher */ - public List getPublisher() - { + public List getPublisher() { return metadataMappings.get(PUBLISHER); } /** * @return the citation_authors */ - public List getAuthors() - { + public List getAuthors() { return metadataMappings.get(AUTHORS); } /** * @return the citation_date */ - public List getDate() - { + public List getDate() { return metadataMappings.get(DATE); } /** * @return the citation_volume */ - public List getVolume() - { + public List getVolume() { return metadataMappings.get(VOLUME); } /** * @return the citation_issue */ - public List getIssue() - { + public List getIssue() { return metadataMappings.get(ISSUE); } /** * @return the citation_firstpage */ - public List getFirstpage() - { + public List getFirstpage() { return metadataMappings.get(FIRSTPAGE); } /** * @return the citation_lastpage */ - public List getLastpage() - { + public List getLastpage() { return metadataMappings.get(LASTPAGE); } /** * @return the citation_doi */ - public List getDOI() - { + public List getDOI() { return metadataMappings.get(DOI); } /** * @return the citation_pmid */ - public List getPmid() - { + public List getPmid() { return metadataMappings.get(PMID); } /** * @return the citation_abstract_html_url */ - public List getAbstractHTMLURL() - { + public List getAbstractHTMLURL() { return metadataMappings.get(ABSTRACT); } /** * @return the citation_fulltext_html_url */ - public List getFulltextHTMLURL() - { + public List getFulltextHTMLURL() { return metadataMappings.get(FULLTEXT); } /** * @return the citation_pdf_url */ - public List getPDFURL() - { + public List getPDFURL() { return metadataMappings.get(PDF); } /** * @return the citation_issn */ - public List getISSN() - { + public List getISSN() { return metadataMappings.get(ISSN); } /** * @return the citation_isbn */ - public List getISBN() - { + public List getISBN() { return metadataMappings.get(ISBN); } /** * @return the citation_language */ - public List getLanguage() - { + public List getLanguage() { return metadataMappings.get(LANGUAGE); } /** * @return the citation_keywords */ - public List getKeywords() - { + public List getKeywords() { return metadataMappings.get(KEYWORDS); } /** * @return the citation_conference */ - public List getConference() - { + public List getConference() { return metadataMappings.get(CONFERENCE); } /** * @return the citation_dissertation_name */ - public List getDissertationName() - { + public List getDissertationName() { return metadataMappings.get(DISSERTATION_NAME); } /** * @return the citation_dissertation_institution */ - public List getDissertationInstitution() - { + public List getDissertationInstitution() { return metadataMappings.get(DISSERTATION_INSTITUTION); } /** * @return the citation_patent_number */ - public List getPatentNumber() - { + public List getPatentNumber() { return metadataMappings.get(PATENT_NUMBER); } /** * @return the citation_patent_country */ - public List getPatentCountry() - { + public List getPatentCountry() { return metadataMappings.get(PATENT_COUNTRY); } /** * @return the citation_technical_report_number */ - public List getTechnicalReportNumber() - { + public List getTechnicalReportNumber() { return metadataMappings.get(TECH_REPORT_NUMBER); } /** * @return the citation_technical_report_institution */ - public List getTechnicalReportInstitution() - { + public List getTechnicalReportInstitution() { return metadataMappings.get(TECH_REPORT_INSTITUTION); } @@ -1007,8 +884,7 @@ public class GoogleMetadata * @param item item to get PDF URL from * @return URL that the PDF can be directly downloaded from */ - protected String getPDFSimpleUrl(Item item) - { + protected String getPDFSimpleUrl(Item item) { try { Bitstream bitstream = findLinkableFulltext(item); if (bitstream != null) { @@ -1041,13 +917,12 @@ public class GoogleMetadata /** * A bitstream is considered linkable fulltext when it is either *
      - *
    • the item's only bitstream (in the ORIGINAL bundle); or
    • - *
    • the primary bitstream
    • + *
    • the item's only bitstream (in the ORIGINAL bundle); or
    • + *
    • the primary bitstream
    • *
    * Additionally, this bitstream must be publicly viewable. * - * @param item - * bitstream's parent item + * @param item bitstream's parent item * @return a linkable bitstream or null if none found * @throws SQLException if database error */ @@ -1065,7 +940,9 @@ public class GoogleMetadata return candidate; } } else { - if (bestSoFar == null && isPublic(candidate)) { //if bestSoFar is null but the candidate is not public you don't use it and try to find another + if (bestSoFar == null && isPublic( + candidate)) { //if bestSoFar is null but the candidate is not public you don't use it and try + // to find another bestSoFar = candidate; } } @@ -1077,9 +954,8 @@ public class GoogleMetadata /** * Find out whether bitstream is readable by the public. - * - * @param bitstream - * the target bitstream + * + * @param bitstream the target bitstream * @return whether bitstream is readable by the Anonymous group */ protected boolean isPublic(Bitstream bitstream) { @@ -1090,38 +966,33 @@ public class GoogleMetadata Context context = null; try { context = new Context(); - result = AuthorizeServiceFactory.getInstance().getAuthorizeService().authorizeActionBoolean(context, bitstream, Constants.READ, true); + result = AuthorizeServiceFactory.getInstance().getAuthorizeService() + .authorizeActionBoolean(context, bitstream, Constants.READ, true); } catch (SQLException e) { - log.error("Cannot determine whether bitstream is public, assuming it isn't. bitstream_id=" + bitstream.getID(), e); + log.error( + "Cannot determine whether bitstream is public, assuming it isn't. bitstream_id=" + bitstream.getID(), + e); } return result; } /** - * - * - * @param field - * to aggregate all values of in a matching option - * @param delimiter - * to delimit field values with + * @param field to aggregate all values of in a matching option + * @param delimiter to delimit field values with */ - protected void addAggregateValues(String field, String delimiter) - { + protected void addAggregateValues(String field, String delimiter) { String authorConfig = googleScholarSettings.get(field); ArrayList fields = resolveMetadataFields(authorConfig); - if (null != fields && !fields.isEmpty()) - { + if (null != fields && !fields.isEmpty()) { StringBuilder fieldMetadata = new StringBuilder(); int count = 0; - for (MetadataValue metadataValue : fields) - { + for (MetadataValue metadataValue : fields) { fieldMetadata.append(metadataValue.getValue()); - if (count < fields.size() - 1) - { + if (count < fields.size() - 1) { fieldMetadata.append(delimiter).append(" "); count++; } @@ -1132,77 +1003,62 @@ public class GoogleMetadata /** * If metadata field contains multiple values, then add each value to the map separately - * @param FIELD - * metadata field + * + * @param FIELD metadata field */ - protected void addMultipleValues(String FIELD) - { + protected void addMultipleValues(String FIELD) { String fieldConfig = googleScholarSettings.get(FIELD); ArrayList fields = resolveMetadataFields(fieldConfig); - if (null != fields && !fields.isEmpty()) - { - for (MetadataValue field : fields) - { + if (null != fields && !fields.isEmpty()) { + for (MetadataValue field : fields) { //TODO if this is author field, first-name first metadataMappings.put(FIELD, field.getValue()); } } } - + /** * Determine, based on config values, if this item is a dissertation. - * + * * @return boolean */ - protected boolean itemIsDissertation() - { + protected boolean itemIsDissertation() { String dConfig = googleScholarSettings.get(DISSERTATION_ID); - if (null == dConfig || dConfig.trim().equals("")) - { + if (null == dConfig || dConfig.trim().equals("")) { return false; - } - else - { + } else { return identifyItemType(dConfig); } } /** * Determine, based on config values, if this item is a patent. - * + * * @return boolean */ - protected boolean itemIsPatent() - { + protected boolean itemIsPatent() { String dConfig = googleScholarSettings.get(PATENT_ID); - if (null == dConfig || dConfig.trim().equals("")) - { + if (null == dConfig || dConfig.trim().equals("")) { return false; - } - else - { + } else { return identifyItemType(dConfig); } } /** * Determine, based on config values, if this item is a tech report. - * + * * @return boolean */ - protected boolean itemIsTechReport() - { + protected boolean itemIsTechReport() { String dConfig = googleScholarSettings.get(TECH_REPORT_ID); - if (null == dConfig || dConfig.trim().equals("")) - { + if (null == dConfig || dConfig.trim().equals("")) { return false; - } - else - { + } else { return identifyItemType(dConfig); } } @@ -1211,37 +1067,30 @@ public class GoogleMetadata * Identifies if this item matches a particular configuration of fields and * values for those fields to identify the type based on a type- cataloging * metadata practice. - * - * @param dConfig - * configured fields (from google-metadata.properties) + * + * @param dConfig configured fields (from google-metadata.properties) * @return item matches configuration */ - protected boolean identifyItemType(String dConfig) - { + protected boolean identifyItemType(String dConfig) { // FIXME: Shouldn't have to parse identifiers for every identification. ArrayList> options = parseOptions(dConfig); HashMap> mdPairs = new HashMap>(); // Parse field/value pairs from field identifier string - for (ArrayList option : options) - { + for (ArrayList option : options) { String pair = option.get(0); String[] parsedPair = pair.split("\\:"); - if (2 == parsedPair.length) - { + if (2 == parsedPair.length) { // If we've encountered this field before, add the value to the // list - if (mdPairs.containsKey(parsedPair[0].trim())) - { + if (mdPairs.containsKey(parsedPair[0].trim())) { mdPairs.get(parsedPair[0].trim()).add(parsedPair[1]); if (log.isDebugEnabled()) { log.debug("Registering Type Identifier: " + parsedPair[0] + " => " + parsedPair[1]); } - } - else - { + } else { // Otherwise, add it as the first occurrence of this field ArrayList newField = new ArrayList(); newField.add(parsedPair[1].trim()); @@ -1251,33 +1100,25 @@ public class GoogleMetadata log.debug("Registering Type Identifier: " + parsedPair[0] + " => " + parsedPair[1]); } } - } - else - { + } else { log.error("Malformed field identifier name/value pair"); } } // Build config string without values, only field names StringBuilder sb = new StringBuilder(); - for (String value : mdPairs.keySet()) - { + for (String value : mdPairs.keySet()) { sb.append(value).append(" | "); } // Check resolved/present metadata fields against configured values ArrayList presentMD = resolveMetadataFields(sb.toString()); - if (null != presentMD && presentMD.size() != 0) - { - for (MetadataValue v : presentMD) - { + if (null != presentMD && presentMD.size() != 0) { + for (MetadataValue v : presentMD) { String fieldName = buildFieldName(v); - if (mdPairs.containsKey(fieldName)) - { - for (String configValue : mdPairs.get(fieldName)) - { - if (configValue.equals(v.getValue())) - { + if (mdPairs.containsKey(fieldName)) { + for (String configValue : mdPairs.get(fieldName)) { + if (configValue.equals(v.getValue())) { return true; } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/IndexVersion.java b/dspace-api/src/main/java/org/dspace/app/util/IndexVersion.java index 3ef44fc11c..518d422994 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/IndexVersion.java +++ b/dspace-api/src/main/java/org/dspace/app/util/IndexVersion.java @@ -10,6 +10,7 @@ package org.dspace.app.util; import java.io.File; import java.io.IOException; import java.text.ParseException; + import org.apache.lucene.index.SegmentCommitInfo; import org.apache.lucene.index.SegmentInfos; import org.apache.lucene.store.Directory; @@ -25,17 +26,20 @@ import org.apache.lucene.util.Version; *

    * The response is simply a version number (e.g. 4.4), as this is utilized by * the {@code ant update_solr_indexes} target in {@code [src]/dspace/src/main/config/build.xml} - * + * * @author tdonohue */ -public class IndexVersion -{ +public class IndexVersion { + + /** + * Default constructor + */ + private IndexVersion() { } + public static void main(String[] argv) - throws IOException - { + throws IOException { // Usage checks - if (argv.length < 1) - { + if (argv.length < 1) { System.out.println("\nRequired Solr/Lucene index directory is missing."); System.out.println("Minimally, pass in the full path of the Solr/Lucene Index directory to analyze"); System.out.println("Usage: IndexVersion [full-path-to-solr-index] ([version-to-compare])"); @@ -44,27 +48,26 @@ public class IndexVersion System.out.println(" -1 if index dir version < version-to-compare"); System.out.println(" 0 if index dir version = version-to-compare"); System.out.println(" 1 if index dir version > version-to-compare"); - System.out.println("\nOptionally, passing just '-v' will return the version of Solr/Lucene in use by DSpace."); + System.out + .println("\nOptionally, passing just '-v' will return the version of Solr/Lucene in use by DSpace."); System.exit(1); } // If "-v" passed on commandline, just return the current version of Solr/Lucene - if(argv[0].equalsIgnoreCase("-v")) - { + if (argv[0].equalsIgnoreCase("-v")) { System.out.println(getLatestVersion()); System.exit(0); } // First argument is the Index path. Determine its version String indexVersion = getIndexVersion(argv[0]); - + // Second argumet is an optional version number to compare to String compareToVersion = argv.length > 1 ? argv[1] : null; - + // If indexVersion comes back as null, then it is not a valid index directory. // So, exit immediately. - if(indexVersion==null) - { + if (indexVersion == null) { System.out.println("\nRequired Solr/Lucene index directory is invalid."); System.out.println("The following path does NOT seem to be a valid index directory:"); System.out.println(argv[0]); @@ -75,54 +78,45 @@ public class IndexVersion // If empty string is returned as the indexVersion, this means it's an // empty index directory. So, it's technically "compatible" with any version of Lucene. - if (indexVersion.equals("")) - { + if (indexVersion.equals("")) { indexVersion = getLatestVersion(); } // If a compare-to-version was passed in, print the result of this comparison - if(compareToVersion!=null && !compareToVersion.isEmpty()) - { + if (compareToVersion != null && !compareToVersion.isEmpty()) { // If the string "LATEST" is passed, determine which version of Lucene API we are using. - if(compareToVersion.equalsIgnoreCase("LATEST")) - { + if (compareToVersion.equalsIgnoreCase("LATEST")) { compareToVersion = getLatestVersion(); } - System.out.println(compareSoftwareVersions(indexVersion,compareToVersion)); - } - // Otherwise, we'll just print the version of this index directory - else - { + System.out.println(compareSoftwareVersions(indexVersion, compareToVersion)); + } else { + // Otherwise, we'll just print the version of this index directory System.out.println(indexVersion); } System.exit(0); } - + /** * Determine the version of Solr/Lucene which was used to create a given index directory. - * - * @param indexDirPath - * Full path of the Solr/Lucene index directory + * + * @param indexDirPath Full path of the Solr/Lucene index directory * @return version as a string (e.g. "4.4"), empty string ("") if index directory is empty, - * or null if directory doesn't exist. + * or null if directory doesn't exist. * @throws IOException if IO error */ public static String getIndexVersion(String indexDirPath) - throws IOException - { + throws IOException { String indexVersion = null; - + // Make sure this directory exists File dir = new File(indexDirPath); - if(dir.exists() && dir.isDirectory()) - { + if (dir.exists() && dir.isDirectory()) { // Check if this index directory has any contents String[] dirContents = dir.list(); // If this directory is empty, return an empty string. // It is a valid directory, but it's an empty index. - if (dirContents!=null && dirContents.length==0) - { + if (dirContents != null && dirContents.length == 0) { return ""; } @@ -131,56 +125,46 @@ public class IndexVersion // Get info on the Lucene segment file(s) in index directory SegmentInfos sis = new SegmentInfos(); - try - { + try { sis.read(indexDir); - } - catch(IOException ie) - { + } catch (IOException ie) { // Wrap default IOException, providing more info about which directory cannot be read throw new IOException("Could not read Lucene segments files in " + dir.getAbsolutePath(), ie); } // If we have a valid Solr index dir, but it has no existing segments // then just return an empty string. It's a valid but empty index. - if(sis!=null && sis.size()==0) - { + if (sis != null && sis.size() == 0) { return ""; } - + // Loop through our Lucene segment files to locate the OLDEST // version. It is possible for individual segment files to be // created by different versions of Lucene. So, we just need // to find the oldest version of Lucene which created these - // index segment files. + // index segment files. // This logic borrowed from Lucene v.4.10 CheckIndex class: - // https://github.com/apache/lucene-solr/blob/lucene_solr_4_10/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java#L426 - // WARNING: It MAY require updating whenever we upgrade the + // https://github.com/apache/lucene-solr/blob/lucene_solr_4_10/lucene/core/src/java/org/apache/lucene + // /index/CheckIndex.java#L426 + // WARNING: It MAY require updating whenever we upgrade the // "lucene.version" in our DSpace Parent POM Version oldest = null; Version oldSegment = null; - for (SegmentCommitInfo si : sis) - { + for (SegmentCommitInfo si : sis) { // Get the version of Lucene which created this segment file Version version = si.info.getVersion(); - if(version == null) - { + if (version == null) { // If null, then this is a pre-3.1 segment file. - // For our purposes, we will just assume it is "3.0", + // For our purposes, we will just assume it is "3.0", // This lets us know we will need to upgrade it to 3.5 // before upgrading to Solr/Lucene 4.x or above - try - { + try { oldSegment = Version.parse("3.0"); - } - catch(ParseException pe) - { + } catch (ParseException pe) { throw new IOException(pe); } - } - // else if this segment is older than our oldest thus far - else if(oldest == null || version.onOrAfter(oldest) == false) - { + } else if (oldest == null || version.onOrAfter(oldest) == false) { + // else if this segment is older than our oldest thus far // We have a new oldest segment version oldest = version; } @@ -188,23 +172,21 @@ public class IndexVersion // If we found a really old segment, compare it to the oldest // to see which is actually older - if(oldSegment!=null && oldSegment.onOrAfter(oldest) == false) - { + if (oldSegment != null && oldSegment.onOrAfter(oldest) == false) { oldest = oldSegment; } // At this point, we should know what version of Lucene created our // oldest segment file. We will return this as the Index version // as it's the oldest segment we will need to upgrade. - if(oldest!=null) - { + if (oldest != null) { indexVersion = oldest.toString(); } } - + return indexVersion; } - + /** * Compare two software version numbers to see which is greater. ONLY does * a comparison of *major* and *minor* versions (any sub-minor versions are @@ -216,70 +198,58 @@ public class IndexVersion * However, since we ignore sub-minor versions, versions "4.2.1" and "4.2.5" * will be seen as EQUAL (as "4.2" = "4.2"). *

    - * NOTE: In case it is not obvious, software version numbering does NOT + * NOTE: In case it is not obvious, software version numbering does NOT * behave like normal decimal numbers. For example, in software versions * the following statement is TRUE: {@code 4.1 < 4.4 < 4.5 < 4.10 < 4.21 < 4.51} - * - * @param firstVersion - * First version to compare, as a String - * @param secondVersion - * Second version to compare as a String + * + * @param firstVersion First version to compare, as a String + * @param secondVersion Second version to compare as a String * @return -1 if first less than second, 1 if first greater than second, 0 if equal * @throws IOException if IO error */ public static int compareSoftwareVersions(String firstVersion, String secondVersion) - throws IOException - { + throws IOException { // Constants which represent our various return values for this comparison int GREATER_THAN = 1; int EQUAL = 0; int LESS_THAN = -1; - + // "null" is less than anything - if(firstVersion==null) + if (firstVersion == null) { return LESS_THAN; + } // Anything is newer than "null" - if(secondVersion==null) + if (secondVersion == null) { return GREATER_THAN; - + } + //Split the first version into it's parts (i.e. major & minor versions) String[] firstParts = firstVersion.split("\\."); String[] secondParts = secondVersion.split("\\."); - + // Get major / minor version numbers. Default to "0" if unspecified // NOTE: We are specifically IGNORING any sub-minor version numbers - int firstMajor = firstParts.length>=1 ? Integer.parseInt(firstParts[0]) : 0; - int firstMinor = firstParts.length>=2 ? Integer.parseInt(firstParts[1]) : 0; - int secondMajor = secondParts.length>=1 ? Integer.parseInt(secondParts[0]) : 0; - int secondMinor = secondParts.length>=2 ? Integer.parseInt(secondParts[1]) : 0; - + int firstMajor = firstParts.length >= 1 ? Integer.parseInt(firstParts[0]) : 0; + int firstMinor = firstParts.length >= 2 ? Integer.parseInt(firstParts[1]) : 0; + int secondMajor = secondParts.length >= 1 ? Integer.parseInt(secondParts[0]) : 0; + int secondMinor = secondParts.length >= 2 ? Integer.parseInt(secondParts[1]) : 0; + // Check for equality - if(firstMajor==secondMajor && firstMinor==secondMinor) - { + if (firstMajor == secondMajor && firstMinor == secondMinor) { return EQUAL; - } - // If first major version is greater than second - else if(firstMajor > secondMajor) - { + } else if (firstMajor > secondMajor) { + // If first major version is greater than second return GREATER_THAN; - } - // If first major version is less than second - else if(firstMajor < secondMajor) - { + } else if (firstMajor < secondMajor) { + // If first major version is less than second return LESS_THAN; - } - // If we get here, major versions must be EQUAL. Now, time to check our minor versions - else if(firstMinor > secondMinor) - { + } else if (firstMinor > secondMinor) { + // If we get here, major versions must be EQUAL. Now, time to check our minor versions return GREATER_THAN; - } - else if(firstMinor < secondMinor) - { + } else if (firstMinor < secondMinor) { return LESS_THAN; - } - else - { - // This is an impossible scenario. + } else { + // This is an impossible scenario. // This 'else' should never be triggered since we've checked for equality above already return EQUAL; } @@ -291,8 +261,7 @@ public class IndexVersion * * @return version as a string (e.g. "4.4") */ - public static String getLatestVersion() - { + public static String getLatestVersion() { // The current version of lucene is in the "LATEST" constant return org.apache.lucene.util.Version.LATEST.toString(); } diff --git a/dspace-api/src/main/java/org/dspace/app/util/LocalSchemaFilenameFilter.java b/dspace-api/src/main/java/org/dspace/app/util/LocalSchemaFilenameFilter.java index d624f3e065..b28b61c706 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/LocalSchemaFilenameFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/util/LocalSchemaFilenameFilter.java @@ -18,7 +18,7 @@ import java.util.regex.Pattern; public class LocalSchemaFilenameFilter implements FilenameFilter { static Pattern patt = Pattern.compile("^metadata_.*.xml$"); - + @Override public boolean accept(File arg0, String arg1) { return patt.matcher(arg1).matches(); diff --git a/dspace-api/src/main/java/org/dspace/app/util/MetadataExposureServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/util/MetadataExposureServiceImpl.java index bdf2c35965..3c3eb8ab4f 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/MetadataExposureServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/util/MetadataExposureServiceImpl.java @@ -7,16 +7,20 @@ */ package org.dspace.app.util; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.log4j.Logger; import org.dspace.app.util.service.MetadataExposureService; import org.dspace.authorize.service.AuthorizeService; -import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; +import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.*; - /** * Static utility class to manage configuration for exposure (hiding) of * certain Item metadata fields. @@ -35,71 +39,65 @@ import java.util.*; * scalable. * * Algorithm is as follows: - * 1. If a Context is provided and it has a user who is Administrator, - * always grant access (return false). - * 2. Return true if field is on the hidden list, false otherwise. + * 1. If a Context is provided and it has a user who is Administrator, + * always grant access (return false). + * 2. Return true if field is on the hidden list, false otherwise. * * The internal maps are populated from DSpace Configuration at the first * call, in case the properties are not available in the static context. * * Configuration Properties: - * ## hide a single metadata field - * #metadata.hide.SCHEMA.ELEMENT[.QUALIFIER] = true - * # example: dc.type - * metadata.hide.dc.type = true - * # example: dc.description.provenance - * metadata.hide.dc.description.provenance = true + * ## hide a single metadata field + * #metadata.hide.SCHEMA.ELEMENT[.QUALIFIER] = true + * # example: dc.type + * metadata.hide.dc.type = true + * # example: dc.description.provenance + * metadata.hide.dc.description.provenance = true * * @author Larry Stone * @version $Revision: 3734 $ */ -public class MetadataExposureServiceImpl implements MetadataExposureService -{ +public class MetadataExposureServiceImpl implements MetadataExposureService { protected Logger log = Logger.getLogger(MetadataExposureServiceImpl.class); - protected Map> hiddenElementSets = null; - protected Map>> hiddenElementMaps = null; + protected Map> hiddenElementSets = null; + protected Map>> hiddenElementMaps = null; protected final String CONFIG_PREFIX = "metadata.hide."; @Autowired(required = true) protected AuthorizeService authorizeService; - protected MetadataExposureServiceImpl() - { + @Autowired(required = true) + protected ConfigurationService configurationService; + + protected MetadataExposureServiceImpl() { } @Override public boolean isHidden(Context context, String schema, String element, String qualifier) - throws SQLException - { + throws SQLException { boolean hidden = false; // for schema.element, just check schema->elementSet - if (!isInitialized()) - { + if (!isInitialized()) { init(); } - if (qualifier == null) - { + if (qualifier == null) { Set elts = hiddenElementSets.get(schema); hidden = elts != null && elts.contains(element); - } - // for schema.element.qualifier, just schema->eltMap->qualSet - else - { - Map> elts = hiddenElementMaps.get(schema); - if (elts == null) - { + } else { // for schema.element.qualifier, just schema->eltMap->qualSet + Map> elts = hiddenElementMaps.get(schema); + if (elts == null) { return false; } Set quals = elts.get(element); hidden = quals != null && quals.contains(qualifier); } - if(hidden && context != null) { + if (hidden && context != null) { // the administrator's override hidden = !authorizeService.isAdmin(context); } @@ -113,8 +111,7 @@ public class MetadataExposureServiceImpl implements MetadataExposureService * * @return true (initialized) or false (not initialized) */ - protected boolean isInitialized() - { + protected boolean isInitialized() { return hiddenElementSets != null; } @@ -125,52 +122,38 @@ public class MetadataExposureServiceImpl implements MetadataExposureService * qualifier separated by dots and the value is true (hidden) * or false (exposed). */ - protected synchronized void init() - { - if (!isInitialized()) - { + protected synchronized void init() { + if (!isInitialized()) { hiddenElementSets = new HashMap<>(); hiddenElementMaps = new HashMap<>(); - Enumeration pne = ConfigurationManager.propertyNames(); - while (pne.hasMoreElements()) - { - String key = (String)pne.nextElement(); - if (key.startsWith(CONFIG_PREFIX)) - { - String mdField = key.substring(CONFIG_PREFIX.length()); - String segment[] = mdField.split("\\.", 3); + List propertyKeys = configurationService.getPropertyKeys(); + for (String key : propertyKeys) { + if (key.startsWith(CONFIG_PREFIX)) { + if (configurationService.getBooleanProperty(key, true)) { + String mdField = key.substring(CONFIG_PREFIX.length()); + String segment[] = mdField.split("\\.", 3); - // got schema.element.qualifier - if (segment.length == 3) - { - Map> eltMap = hiddenElementMaps.get(segment[0]); - if (eltMap == null) - { - eltMap = new HashMap>(); - hiddenElementMaps.put(segment[0], eltMap); + // got schema.element.qualifier + if (segment.length == 3) { + Map> eltMap = hiddenElementMaps.get(segment[0]); + if (eltMap == null) { + eltMap = new HashMap>(); + hiddenElementMaps.put(segment[0], eltMap); + } + if (!eltMap.containsKey(segment[1])) { + eltMap.put(segment[1], new HashSet()); + } + eltMap.get(segment[1]).add(segment[2]); + } else if (segment.length == 2) { // got schema.element + if (!hiddenElementSets.containsKey(segment[0])) { + hiddenElementSets.put(segment[0], new HashSet()); + } + hiddenElementSets.get(segment[0]).add(segment[1]); + } else { // oops.. + log.warn("Bad format in hidden metadata directive, field=\"" + mdField + "\", " + + "config property=" + key); } - if (!eltMap.containsKey(segment[1])) - { - eltMap.put(segment[1], new HashSet()); - } - eltMap.get(segment[1]).add(segment[2]); - } - - // got schema.element - else if (segment.length == 2) - { - if (!hiddenElementSets.containsKey(segment[0])) - { - hiddenElementSets.put(segment[0], new HashSet()); - } - hiddenElementSets.get(segment[0]).add(segment[1]); - } - - // oops.. - else - { - log.warn("Bad format in hidden metadata directive, field=\""+mdField+"\", config property="+key); } } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/OpenSearchServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/util/OpenSearchServiceImpl.java index a566fdeb41..d0824923c7 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/OpenSearchServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/util/OpenSearchServiceImpl.java @@ -7,40 +7,35 @@ */ package org.dspace.app.util; -import org.dspace.app.util.service.OpenSearchService; -import org.dspace.core.Constants; -import org.dspace.core.Context; - import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; -import java.net.URLEncoder; -import java.io.UnsupportedEncodingException; -import java.sql.SQLException; - -import org.dspace.handle.service.HandleService; -import org.dspace.services.factory.DSpaceServicesFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.w3c.dom.Document; - -import org.jdom.Element; -import org.jdom.JDOMException; -import org.jdom.Namespace; -import org.jdom.output.DOMOutputter; -import org.jdom.output.XMLOutputter; - -import org.apache.log4j.Logger; - -import org.dspace.content.DSpaceObject; import com.sun.syndication.feed.module.opensearch.OpenSearchModule; import com.sun.syndication.feed.module.opensearch.entity.OSQuery; import com.sun.syndication.feed.module.opensearch.impl.OpenSearchModuleImpl; import com.sun.syndication.io.FeedException; -import java.util.Arrays; +import org.apache.log4j.Logger; +import org.dspace.app.util.service.OpenSearchService; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.handle.service.HandleService; import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.Namespace; +import org.jdom.output.DOMOutputter; +import org.jdom.output.XMLOutputter; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.w3c.dom.Document; /** * Utility Class with static methods for producing OpenSearch-compliant search results, @@ -55,12 +50,10 @@ import org.dspace.services.ConfigurationService; * The value of the "scope" parameter should either be absent (which means no * scope restriction), or the handle of a community or collection. *

    - * - * @author Richard Rodgers * + * @author Richard Rodgers */ -public class OpenSearchServiceImpl implements OpenSearchService, InitializingBean -{ +public class OpenSearchServiceImpl implements OpenSearchService, InitializingBean { private static final Logger log = Logger.getLogger(OpenSearchServiceImpl.class); // are open search queries enabled? @@ -82,138 +75,120 @@ public class OpenSearchServiceImpl implements OpenSearchService, InitializingBea } @Override - public void afterPropertiesSet() throws Exception - { + public void afterPropertiesSet() throws Exception { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); enabled = config.getBooleanProperty("websvc.opensearch.enable"); svcUrl = config.getProperty("dspace.url") + "/" + - config.getProperty("websvc.opensearch.svccontext"); + config.getProperty("websvc.opensearch.svccontext"); uiUrl = config.getProperty("dspace.url") + "/" + - config.getProperty("websvc.opensearch.uicontext"); + config.getProperty("websvc.opensearch.uicontext"); // read rest of config info if enabled formats = new ArrayList(); - if (enabled) - { - String[] fmts = config.getArrayProperty("websvc.opensearch.formats"); + if (enabled) { + String[] fmts = config.getArrayProperty("websvc.opensearch.formats"); formats = Arrays.asList(fmts); } } @Override - public List getFormats() - { + public List getFormats() { return formats; } - + @Override - public String getContentType(String format) - { - return "html".equals(format) ? "text/html" : - "application/" + format + "+xml; charset=UTF-8"; + public String getContentType(String format) { + return "html".equals(format) ? "text/html" : + "application/" + format + "+xml; charset=UTF-8"; } - + @Override - public Document getDescriptionDoc(String scope) throws IOException - { + public Document getDescriptionDoc(String scope) throws IOException { return jDomToW3(getServiceDocument(scope)); } - + @Override - public String getDescription(String scope) - { + public String getDescription(String scope) { return new XMLOutputter().outputString(getServiceDocument(scope)); } @Override - public String getResultsString(Context context, String format, String query, int totalResults, int start, int pageSize, - DSpaceObject scope, List results, - Map labels) throws IOException - { - try - { - return getResults(context, format, query, totalResults, start, pageSize, scope, results, labels).outputString(); - } - catch (FeedException e) - { - log.error(e.toString(), e); - throw new IOException("Unable to generate feed", e); - } - } - - @Override - public Document getResultsDoc(Context context, String format, String query, int totalResults, int start, int pageSize, - DSpaceObject scope, List results, Map labels) - throws IOException - { - try - { - return getResults(context, format, query, totalResults, start, pageSize, scope, results, labels).outputW3CDom(); - } - catch (FeedException e) - { + public String getResultsString(Context context, String format, String query, int totalResults, int start, + int pageSize, + DSpaceObject scope, List results, + Map labels) throws IOException { + try { + return getResults(context, format, query, totalResults, start, pageSize, scope, results, labels) + .outputString(); + } catch (FeedException e) { log.error(e.toString(), e); throw new IOException("Unable to generate feed", e); } } - protected SyndicationFeed getResults(Context context, String format, String query, int totalResults, int start, int pageSize, - DSpaceObject scope, List results, Map labels) - { - // Encode results in requested format - if ("rss".equals(format)) - { - format = "rss_2.0"; + @Override + public Document getResultsDoc(Context context, String format, String query, int totalResults, int start, + int pageSize, + DSpaceObject scope, List results, Map labels) + throws IOException { + try { + return getResults(context, format, query, totalResults, start, pageSize, scope, results, labels) + .outputW3CDom(); + } catch (FeedException e) { + log.error(e.toString(), e); + throw new IOException("Unable to generate feed", e); } - else if ("atom".equals(format)) - { + } + + protected SyndicationFeed getResults(Context context, String format, String query, int totalResults, int start, + int pageSize, + DSpaceObject scope, List results, Map labels) { + // Encode results in requested format + if ("rss".equals(format)) { + format = "rss_2.0"; + } else if ("atom".equals(format)) { format = "atom_1.0"; } - + SyndicationFeed feed = new SyndicationFeed(labels.get(SyndicationFeed.MSG_UITYPE)); feed.populate(null, context, scope, results, labels); feed.setType(format); feed.addModule(openSearchMarkup(query, totalResults, start, pageSize)); return feed; } - + /* * Generates the OpenSearch elements which are added to the RSS or Atom feeds as foreign markup * wrapped in a module - * + * * @param query the search query * @param qRes the search results * @return module */ - protected OpenSearchModule openSearchMarkup(String query, int totalResults, int start, int pageSize) - { + protected OpenSearchModule openSearchMarkup(String query, int totalResults, int start, int pageSize) { OpenSearchModule osMod = new OpenSearchModuleImpl(); osMod.setTotalResults(totalResults); osMod.setStartIndex(start); osMod.setItemsPerPage(pageSize); OSQuery osq = new OSQuery(); osq.setRole("request"); - try - { + try { osq.setSearchTerms(URLEncoder.encode(query, "UTF-8")); - } - catch (UnsupportedEncodingException e) - { + } catch (UnsupportedEncodingException e) { log.error(e); } osq.setStartPage(1 + (start / pageSize)); osMod.addQuery(osq); return osMod; } - + /** * Returns as a document the OpenSearch service document - * + * * @param scope - null for the entire repository, or a collection/community handle * @return Service Document */ - protected org.jdom.Document getServiceDocument(String scope) - { + protected org.jdom.Document getServiceDocument(String scope) { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); Namespace ns = Namespace.getNamespace(osNs); @@ -225,51 +200,41 @@ public class OpenSearchServiceImpl implements OpenSearchService, InitializingBea root.addContent(new Element("OutputEncoding", ns).setText("UTF-8")); // optional elements String sample = config.getProperty("websvc.opensearch.samplequery"); - if (sample != null && sample.length() > 0) - { + if (sample != null && sample.length() > 0) { Element sq = new Element("Query", ns).setAttribute("role", "example"); root.addContent(sq.setAttribute("searchTerms", sample)); } String tags = config.getProperty("websvc.opensearch.tags"); - if (tags != null && tags.length() > 0) - { + if (tags != null && tags.length() > 0) { root.addContent(new Element("Tags", ns).setText(tags)); } String contact = config.getProperty("mail.admin"); - if (contact != null && contact.length() > 0) - { + if (contact != null && contact.length() > 0) { root.addContent(new Element("Contact", ns).setText(contact)); } String faviconUrl = config.getProperty("websvc.opensearch.faviconurl"); - if (faviconUrl != null && faviconUrl.length() > 0) - { + if (faviconUrl != null && faviconUrl.length() > 0) { String dim = String.valueOf(16); String type = faviconUrl.endsWith("ico") ? "image/vnd.microsoft.icon" : "image/png"; Element fav = new Element("Image", ns).setAttribute("height", dim).setAttribute("width", dim). - setAttribute("type", type).setText(faviconUrl); + setAttribute("type", type).setText(faviconUrl); root.addContent(fav); } // service URLs - for (String format : formats) - { + for (String format : formats) { Element url = new Element("Url", ns).setAttribute("type", getContentType(format)); StringBuilder template = new StringBuilder(); - if ("html".equals(format)) - { + if ("html".equals(format)) { template.append(uiUrl); - } - else - { + } else { template.append(svcUrl); } template.append("?query={searchTerms}"); - if(! "html".equals(format)) - { - template.append("&start={startIndex?}&rpp={count?}&format="); - template.append(format); + if (!"html".equals(format)) { + template.append("&start={startIndex?}&rpp={count?}&format="); + template.append(format); } - if (scope != null) - { + if (scope != null) { template.append("&scope="); template.append(scope); } @@ -278,37 +243,34 @@ public class OpenSearchServiceImpl implements OpenSearchService, InitializingBea } return new org.jdom.Document(root); } - + /** * Converts a JDOM document to a W3C one * - * @param jdomDoc - * jDOM document to convert + * @param jdomDoc jDOM document to convert * @return W3C Document object * @throws IOException if IO error */ - protected Document jDomToW3(org.jdom.Document jdomDoc) throws IOException - { + protected Document jDomToW3(org.jdom.Document jdomDoc) throws IOException { DOMOutputter domOut = new DOMOutputter(); - try - { + try { return domOut.output(jdomDoc); - } - catch (JDOMException jde) - { + } catch (JDOMException jde) { throw new IOException("JDOM output exception", jde); } } @Override - public DSpaceObject resolveScope(Context context, String scope) throws SQLException - { - if(scope == null || "".equals(scope)) + public DSpaceObject resolveScope(Context context, String scope) throws SQLException { + if (scope == null || "".equals(scope)) { return null; + } DSpaceObject dso = handleService.resolveToObject(context, scope); - if(dso == null || dso.getType() == Constants.ITEM) - throw new IllegalArgumentException("Scope handle "+scope+" should point to a valid Community or Collection"); + if (dso == null || dso.getType() == Constants.ITEM) { + throw new IllegalArgumentException( + "Scope handle " + scope + " should point to a valid Community or Collection"); + } return dso; } diff --git a/dspace-api/src/main/java/org/dspace/app/util/OptimizeSelectCollection.java b/dspace-api/src/main/java/org/dspace/app/util/OptimizeSelectCollection.java index a5a40e0a83..c717ac3014 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/OptimizeSelectCollection.java +++ b/dspace-api/src/main/java/org/dspace/app/util/OptimizeSelectCollection.java @@ -7,6 +7,10 @@ */ package org.dspace.app.util; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.factory.ContentServiceFactory; @@ -18,10 +22,6 @@ import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.springframework.util.StopWatch; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /** * @author peterdietz * A command line tool to verify/test the accuracy and speed gains of Collection.findAuthorizedOptimized() @@ -33,22 +33,28 @@ public class OptimizeSelectCollection { private static ArrayList brokenPeople; private static Long timeSavedMS = 0L; - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final CollectionService collectionService = + ContentServiceFactory.getInstance().getCollectionService(); private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); - public static void main(String[] argv) throws Exception - { + /** + * Default constructor + */ + private OptimizeSelectCollection() { } + + public static void main(String[] argv) throws Exception { System.out.println("OptimizeSelectCollection tool."); - System.out.println("We want to verify that the optimized version of select collection logic produces the same " + - "values as the legacy select-collection logic."); + System.out + .println("We want to verify that the optimized version of select collection logic produces the same " + + "values as the legacy select-collection logic."); context = new Context(); brokenPeople = new ArrayList(); int peopleChecked = 0; timeSavedMS = 0L; - if(argv != null && argv.length > 0) { - for(String email : argv) { + if (argv != null && argv.length > 0) { + for (String email : argv) { EPerson person = ePersonService.findByEmail(context, email); checkSelectCollectionForUser(person); peopleChecked++; @@ -56,19 +62,21 @@ public class OptimizeSelectCollection { } else { //default case, run as specific user, or run all... List people = ePersonService.findAll(context, EPerson.EMAIL); - for(EPerson person : people) { + for (EPerson person : people) { checkSelectCollectionForUser(person); peopleChecked++; } } - if(brokenPeople.size() > 0) { + if (brokenPeople.size() > 0) { System.out.println("NOT DONE YET!!! Some people don't have all their collections."); - for(EPerson person : brokenPeople) { + for (EPerson person : brokenPeople) { System.out.println("-- " + person.getEmail()); } } else { - System.out.println("All Good: " + peopleChecked + " people have been checked, with same submission powers. TimeSaved(ms): " + timeSavedMS); + System.out.println( + "All Good: " + peopleChecked + " people have been checked, with same submission powers. TimeSaved(ms)" + + ": " + timeSavedMS); } } @@ -115,7 +123,7 @@ public class OptimizeSelectCollection { System.out.println("===================================="); System.out.println("This user is permitted to submit to the following collections."); - for(Collection collection : collections) { + for (Collection collection : collections) { System.out.println(" - " + collection.getHandle() + " -- " + collection.getName()); } System.out.println("Total: " + collections.size()); diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfig.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfig.java index f29d10ed5b..c231955ad4 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfig.java +++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfig.java @@ -7,10 +7,10 @@ */ package org.dspace.app.util; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.io.Serializable; import org.apache.log4j.Logger; @@ -21,111 +21,87 @@ import org.apache.log4j.Logger; * * Note: Implements Serializable as it will be saved to the current session during submission. * Please ensure that nothing is added to this class that isn't also serializable - * - * @see org.dspace.app.util.SubmissionConfigReader - * @see org.dspace.app.util.SubmissionStepConfig - * + * * @author Tim Donohue, based on DCInputSet by Brian S. Hughes * @version $Revision$ + * @see org.dspace.app.util.SubmissionConfigReader + * @see org.dspace.app.util.SubmissionStepConfig */ -public class SubmissionConfig implements Serializable -{ - /** name of the item submission process */ +public class SubmissionConfig implements Serializable { + /** + * name of the item submission process + */ private String submissionName = null; - /** the configuration classes for the steps in this submission process */ + private boolean defaultConf = false; + + /** + * the configuration classes for the steps in this submission process + */ private SubmissionStepConfig[] submissionSteps = null; - /** whether or not this submission process is being used in a workflow * */ - private boolean isWorkflow = false; - - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(SubmissionConfig.class); /** * Constructs a new Submission Configuration object, based on the XML * configuration file (item-submission.xml) - * - * @param submissionName - * the submission process name - * @param steps - * the vector listing of step information to build - * SubmissionStepConfig objects for this submission process - * @param isWorkflowProcess - * whether this submission process is being used in a workflow or - * not. If it is a workflow process this may limit the steps that - * are available for editing. + * + * @param submissionName the submission process name + * @param steps the vector listing of step information to build + * SubmissionStepConfig objects for this submission process */ - public SubmissionConfig(String submissionName, List> steps, - boolean isWorkflowProcess) - { + public SubmissionConfig(boolean isDefault, String submissionName, List> steps) { this.submissionName = submissionName; - this.isWorkflow = isWorkflowProcess; + this.defaultConf = isDefault; // initialize a vector of SubmissionStepConfig objects List stepConfigs = new ArrayList(); // loop through our steps, and create SubmissionStepConfig objects - for (int stepNum = 0; stepNum < steps.size(); stepNum++) - { + for (int stepNum = 0; stepNum < steps.size(); stepNum++) { Map stepInfo = steps.get(stepNum); SubmissionStepConfig step = new SubmissionStepConfig(stepInfo); - // Only add this step to the process if either: - // (a) this is not a workflow process OR - // (b) this is a workflow process, and this step is editable in a - // workflow - if ((!this.isWorkflow) - || ((this.isWorkflow) && step.isWorkflowEditable())) - { - // set the number of the step (starts at 0) and add it - step.setStepNumber(stepConfigs.size()); - stepConfigs.add(step); + // set the number of the step (starts at 0) and add it + step.setStepNumber(stepNum); + stepConfigs.add(step); - log.debug("Added step '" + step.getProcessingClassName() - + "' as step #" + step.getStepNumber() - + " of submission process " + submissionName); - - } + log.debug("Added step '" + step.getProcessingClassName() + + "' as step #" + step.getStepNumber() + + " of submission process " + submissionName); } // get steps as an array of Strings submissionSteps = stepConfigs - .toArray(new SubmissionStepConfig[stepConfigs.size()]); + .toArray(new SubmissionStepConfig[stepConfigs.size()]); } /** * Return the name of the item submission process definition - * + * * @return the name of the submission process */ - public String getSubmissionName() - { + public String getSubmissionName() { return submissionName; } + public boolean isDefaultConf() { + return defaultConf; + } + /** * Return the number of steps in this submission process - * + * * @return number of steps */ - public int getNumberOfSteps() - { + public int getNumberOfSteps() { return submissionSteps.length; } - /** - * Return whether or not this submission process is being used in a - * workflow! - * - * @return true, if it's a workflow process. false, otherwise. - */ - public boolean isWorkflow() - { - return isWorkflow; - } - /** * Retrieve a particular Step configuration in this Item Submission Process * configuration. The first step is numbered "0" (although step #0 is the @@ -133,23 +109,17 @@ public class SubmissionConfig implements Serializable *

    * If you want to retrieve the step after the "select collection" step, you * should retrieve step #1. - * + * * If the specified step isn't found, null is returned. - * - * @param stepNum - * desired step to retrieve - * + * + * @param stepNum desired step to retrieve * @return the SubmissionStepConfig object for the step */ - public SubmissionStepConfig getStep(int stepNum) - { - if ((stepNum > submissionSteps.length - 1) || (stepNum < 0)) - { + public SubmissionStepConfig getStep(int stepNum) { + if ((stepNum > submissionSteps.length - 1) || (stepNum < 0)) { return null; - } - else - { + } else { return submissionSteps[stepNum]; } } @@ -158,15 +128,12 @@ public class SubmissionConfig implements Serializable * Returns whether or not there are more steps which follow the specified * "stepNum". For example, if you specify stepNum=4, then this method checks * to see if there is a Step #5. The first step is numbered "0". - * - * @param stepNum - * the current step. - * + * + * @param stepNum the current step. * @return true, if a step at "stepNum+1" exists. false, otherwise. */ - public boolean hasMoreSteps(int stepNum) - { + public boolean hasMoreSteps(int stepNum) { return (getStep(stepNum + 1) != null); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java index e2956b00a7..407d9c2bef 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java +++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java @@ -8,14 +8,28 @@ package org.dspace.app.util; import java.io.File; -import java.util.*; -import javax.servlet.ServletException; -import org.xml.sax.SAXException; -import org.w3c.dom.*; -import javax.xml.parsers.*; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; +import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; +import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.services.factory.DSpaceServicesFactory; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; /** * Item Submission configuration generator for DSpace. Reads and parses the @@ -24,42 +38,48 @@ import org.dspace.services.factory.DSpaceServicesFactory; * ordering of the steps (and number of steps) that occur during the Item * Submission Process. There may be multiple Item Submission processes defined, * where each definition is assigned a unique name. - * + * * The file also specifies which collections use which Item Submission process. * At a minimum, the definitions file must define a default mapping from the * placeholder collection # to the distinguished submission process 'default'. * Any collections that use a custom submission process are listed paired with * the name of the item submission process they use. - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * + * * @author Tim Donohue based on DCInputsReader by Brian S. Hughes * @version $Revision$ + * @see org.dspace.app.util.SubmissionConfig + * @see org.dspace.app.util.SubmissionStepConfig */ -public class SubmissionConfigReader -{ +public class SubmissionConfigReader { /** * The ID of the default collection. Will never be the ID of a named * collection */ public static final String DEFAULT_COLLECTION = "default"; - /** Prefix of the item submission definition XML file */ + /** + * Prefix of the item submission definition XML file + */ static final String SUBMIT_DEF_FILE_PREFIX = "item-submission"; - - /** Suffix of the item submission definition XML file */ + + /** + * Suffix of the item submission definition XML file + */ static final String SUBMIT_DEF_FILE_SUFFIX = ".xml"; - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(SubmissionConfigReader.class); - /** The fully qualified pathname of the directory containing the Item Submission Configuration file */ + /** + * The fully qualified pathname of the directory containing the Item Submission Configuration file + */ private String configDir = DSpaceServicesFactory.getInstance() - .getConfigurationService().getProperty("dspace.dir") - + File.separator + "config" + File.separator; - + .getConfigurationService().getProperty("dspace.dir") + + File.separator + "config" + File.separator; + /** * Hashmap which stores which submission process configuration is used by * which collection, computed from the item submission config file @@ -87,11 +107,18 @@ public class SubmissionConfigReader /** * Load Submission Configuration from the - * item-submission.xml configuration file - * @throws ServletException if servlet error + * item-submission.xml configuration file + * + * @throws SubmissionConfigReaderException if servlet error */ - public SubmissionConfigReader() throws ServletException - { + public SubmissionConfigReader() throws SubmissionConfigReaderException { + buildInputs(configDir + SUBMIT_DEF_FILE_PREFIX + SUBMIT_DEF_FILE_SUFFIX); + } + + public void reload() throws SubmissionConfigReaderException { + collectionToSubmissionConfig = null; + stepDefns = null; + submitDefns = null; buildInputs(configDir + SUBMIT_DEF_FILE_PREFIX + SUBMIT_DEF_FILE_SUFFIX); } @@ -106,17 +133,15 @@ public class SubmissionConfigReader * Submision Processes by name. *

*/ - private void buildInputs(String fileName) throws ServletException - { + private void buildInputs(String fileName) throws SubmissionConfigReaderException { collectionToSubmissionConfig = new HashMap(); submitDefns = new HashMap>>(); String uri = "file:" + new File(fileName).getAbsolutePath(); - try - { + try { DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -124,60 +149,89 @@ public class SubmissionConfigReader DocumentBuilder db = factory.newDocumentBuilder(); Document doc = db.parse(uri); doNodes(doc); + } catch (FactoryConfigurationError fe) { + throw new SubmissionConfigReaderException( + "Cannot create Item Submission Configuration parser", fe); + } catch (Exception e) { + throw new SubmissionConfigReaderException( + "Error creating Item Submission Configuration: " + e); } - catch (FactoryConfigurationError fe) - { - throw new ServletException( - "Cannot create Item Submission Configuration parser", fe); - } - catch (Exception e) - { - throw new ServletException( - "Error creating Item Submission Configuration: " + e); + } + + /** + * @return the name of the default submission configuration + */ + public String getDefaultSubmissionConfigName() { + return collectionToSubmissionConfig.get(DEFAULT_COLLECTION); + } + + /** + * Returns all the Item Submission process configs with pagination + * + * @param limit max number of SubmissionConfig to return + * @param offset number of SubmissionConfig to skip in the return + * @return the list of SubmissionConfig + */ + public List getAllSubmissionConfigs(Integer limit, Integer offset) { + int idx = 0; + int count = 0; + List subConfigs = new LinkedList(); + for (String key : submitDefns.keySet()) { + if (offset == null || idx >= offset) { + count++; + subConfigs.add(getSubmissionConfigByName(key)); + } + idx++; + if (count >= limit) { + break; + } } + return subConfigs; + } + + public int countSubmissionConfigs() { + return submitDefns.size(); } /** * Returns the Item Submission process config used for a particular * collection, or the default if none is defined for the collection - * - * @param collectionHandle - * collection's unique Handle - * @param isWorkflow - * whether or not we are loading the submission process for a - * workflow + * + * @param collectionHandle collection's unique Handle * @return the SubmissionConfig representing the item submission config - * - * @throws ServletException - * if no default submission process configuration defined + * @throws SubmissionConfigReaderException if no default submission process configuration defined */ - public SubmissionConfig getSubmissionConfig(String collectionHandle, - boolean isWorkflow) throws ServletException - { + public SubmissionConfig getSubmissionConfigByCollection(String collectionHandle) { // get the name of the submission process config for this collection String submitName = collectionToSubmissionConfig - .get(collectionHandle); - if (submitName == null) - { + .get(collectionHandle); + if (submitName == null) { submitName = collectionToSubmissionConfig - .get(DEFAULT_COLLECTION); + .get(DEFAULT_COLLECTION); } - if (submitName == null) - { - throw new ServletException( - "No item submission process configuration designated as 'default' in 'submission-map' section of 'item-submission.xml'."); + if (submitName == null) { + throw new IllegalStateException( + "No item submission process configuration designated as 'default' in 'submission-map' section of " + + "'item-submission.xml'."); } + return getSubmissionConfigByName(submitName); + } + /** + * Returns the Item Submission process config + * + * @param submitName submission process unique name + * @return the SubmissionConfig representing the item submission config + */ + public SubmissionConfig getSubmissionConfigByName(String submitName) { log.debug("Loading submission process config named '" + submitName - + "'"); + + "'"); // check mini-cache, and return if match if (lastSubmissionConfig != null - && lastSubmissionConfig.getSubmissionName().equals(submitName) - && lastSubmissionConfig.isWorkflow() == isWorkflow) - { + && lastSubmissionConfig.getSubmissionName().equals(submitName)) { log.debug("Found submission process config '" + submitName - + "' in cache."); + + "' in cache."); return lastSubmissionConfig; } @@ -185,21 +239,20 @@ public class SubmissionConfigReader // cache miss - construct new SubmissionConfig List> steps = submitDefns.get(submitName); - if (steps == null) - { - throw new ServletException( - "Missing the Item Submission process config '" + submitName - + "' (or unable to load) from 'item-submission.xml'."); + if (steps == null) { + throw new IllegalStateException( + "Missing the Item Submission process config '" + submitName + + "' (or unable to load) from 'item-submission.xml'."); } log.debug("Submission process config '" + submitName - + "' not in cache. Reloading from scratch."); + + "' not in cache. Reloading from scratch."); - lastSubmissionConfig = new SubmissionConfig(submitName, steps, - isWorkflow); + lastSubmissionConfig = new SubmissionConfig(StringUtils.equals(getDefaultSubmissionConfigName(), submitName), + submitName, steps); log.debug("Submission process config has " - + lastSubmissionConfig.getNumberOfSteps() + " steps listed."); + + lastSubmissionConfig.getNumberOfSteps() + " steps listed."); return lastSubmissionConfig; } @@ -209,26 +262,19 @@ public class SubmissionConfigReader *

* Global step definitions are those defined in the {@code } * section of the configuration file. - * - * @param stepID - * step's identifier - * + * + * @param stepID step's identifier * @return the SubmissionStepConfig representing the step - * - * @throws ServletException - * if no default submission process configuration defined + * @throws SubmissionConfigReaderException if no default submission process configuration defined */ public SubmissionStepConfig getStepConfig(String stepID) - throws ServletException - { + throws SubmissionConfigReaderException { // We should already have the step definitions loaded - if (stepDefns != null) - { + if (stepDefns != null) { // retreive step info Map stepInfo = stepDefns.get(stepID); - if (stepInfo != null) - { + if (stepInfo != null) { return new SubmissionStepConfig(stepInfo); } } @@ -241,10 +287,8 @@ public class SubmissionConfigReader * should correspond to the collection-form maps, the form definitions, and * the display/storage word pairs. */ - private void doNodes(Node n) throws SAXException, ServletException - { - if (n == null) - { + private void doNodes(Node n) throws SAXException, SubmissionConfigReaderException { + if (n == null) { return; } Node e = getElement(n); @@ -253,44 +297,34 @@ public class SubmissionConfigReader boolean foundMap = false; boolean foundStepDefs = false; boolean foundSubmitDefs = false; - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node nd = nl.item(i); - if ((nd == null) || isEmptyTextNode(nd)) - { + if ((nd == null) || isEmptyTextNode(nd)) { continue; } String tagName = nd.getNodeName(); - if (tagName.equals("submission-map")) - { + if (tagName.equals("submission-map")) { processMap(nd); foundMap = true; - } - else if (tagName.equals("step-definitions")) - { + } else if (tagName.equals("step-definitions")) { processStepDefinition(nd); foundStepDefs = true; - } - else if (tagName.equals("submission-definitions")) - { + } else if (tagName.equals("submission-definitions")) { processSubmissionDefinition(nd); foundSubmitDefs = true; } // Ignore unknown nodes } - if (!foundMap) - { - throw new ServletException( - "No collection to item submission map ('submission-map') found in 'item-submission.xml'"); + if (!foundMap) { + throw new SubmissionConfigReaderException( + "No collection to item submission map ('submission-map') found in 'item-submission.xml'"); } - if (!foundStepDefs) - { - throw new ServletException("No 'step-definitions' section found in 'item-submission.xml'"); + if (!foundStepDefs) { + throw new SubmissionConfigReaderException("No 'step-definitions' section found in 'item-submission.xml'"); } - if (!foundSubmitDefs) - { - throw new ServletException( - "No 'submission-definitions' section found in 'item-submission.xml'"); + if (!foundSubmitDefs) { + throw new SubmissionConfigReaderException( + "No 'submission-definitions' section found in 'item-submission.xml'"); } } @@ -300,32 +334,26 @@ public class SubmissionConfigReader * the collection handle and item submission name, put name in hashmap keyed * by the collection handle. */ - private void processMap(Node e) throws SAXException - { + private void processMap(Node e) throws SAXException { NodeList nl = e.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node nd = nl.item(i); - if (nd.getNodeName().equals("name-map")) - { + if (nd.getNodeName().equals("name-map")) { String id = getAttribute(nd, "collection-handle"); String value = getAttribute(nd, "submission-name"); String content = getValue(nd); - if (id == null) - { + if (id == null) { throw new SAXException( - "name-map element is missing collection-handle attribute in 'item-submission.xml'"); + "name-map element is missing collection-handle attribute in 'item-submission.xml'"); } - if (value == null) - { + if (value == null) { throw new SAXException( - "name-map element is missing submission-name attribute in 'item-submission.xml'"); + "name-map element is missing submission-name attribute in 'item-submission.xml'"); } - if (content != null && content.length() > 0) - { + if (content != null && content.length() > 0) { throw new SAXException( - "name-map element has content in 'item-submission.xml', it should be empty."); + "name-map element has content in 'item-submission.xml', it should be empty."); } collectionToSubmissionConfig.put(id, value); } // ignore any child node that isn't a "name-map" @@ -341,28 +369,23 @@ public class SubmissionConfigReader * HashMap whose key is the step's unique id. */ private void processStepDefinition(Node e) throws SAXException, - ServletException - { + SubmissionConfigReaderException { stepDefns = new HashMap>(); NodeList nl = e.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node nd = nl.item(i); // process each step definition - if (nd.getNodeName().equals("step")) - { + if (nd.getNodeName().equals("step")) { String stepID = getAttribute(nd, "id"); - if (stepID == null) - { + if (stepID == null) { throw new SAXException( - "step element has no 'id' attribute in 'item-submission.xml', which is required in the 'step-definitions' section"); - } - else if (stepDefns.containsKey(stepID)) - { + "step element has no 'id' attribute in 'item-submission.xml', which is required in the " + + "'step-definitions' section"); + } else if (stepDefns.containsKey(stepID)) { throw new SAXException( - "There are two step elements with the id '" + stepID + "' in 'item-submission.xml'"); + "There are two step elements with the id '" + stepID + "' in 'item-submission.xml'"); } Map stepInfo = processStepChildNodes("step-definition", nd); @@ -372,29 +395,12 @@ public class SubmissionConfigReader } // Sanity check number of step definitions - if (stepDefns.size() < 1) - { - throw new ServletException( - "step-definition section has no steps! A step with id='collection' is required in 'item-submission.xml'!"); + if (stepDefns.size() < 1) { + throw new SubmissionConfigReaderException( + "step-definition section has no steps! A step with id='collection' is required in 'item-submission" + + ".xml'!"); } - // Sanity check to see that the required "collection" step is defined - if (!stepDefns.containsKey(SubmissionStepConfig.SELECT_COLLECTION_STEP)) - { - throw new ServletException( - "The step-definition section is REQUIRED to have a step with id='" - + SubmissionStepConfig.SELECT_COLLECTION_STEP - + "' in 'item-submission.xml'! This step is used to ensure that a new item submission is assigned to a collection."); - } - - // Sanity check to see that the required "complete" step is defined - if (!stepDefns.containsKey(SubmissionStepConfig.COMPLETE_STEP)) - { - throw new ServletException( - "The step-definition section is REQUIRED to have a step with id='" - + SubmissionStepConfig.COMPLETE_STEP - + "' in 'item-submission.xml'! This step is used to perform all processing necessary at the completion of the submission (e.g. starting workflow)."); - } } /** @@ -408,8 +414,7 @@ public class SubmissionConfigReader * whose key is the submission-process's unique name. */ private void processSubmissionDefinition(Node e) throws SAXException, - ServletException - { + SubmissionConfigReaderException { int numSubmitProcesses = 0; List submitNames = new ArrayList(); @@ -417,25 +422,20 @@ public class SubmissionConfigReader // through NodeList nl = e.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node nd = nl.item(i); // process each 'submission-process' node - if (nd.getNodeName().equals("submission-process")) - { + if (nd.getNodeName().equals("submission-process")) { numSubmitProcesses++; String submitName = getAttribute(nd, "name"); - if (submitName == null) - { + if (submitName == null) { throw new SAXException( - "'submission-process' element has no 'name' attribute in 'item-submission.xml'"); - } - else if (submitNames.contains(submitName)) - { + "'submission-process' element has no 'name' attribute in 'item-submission.xml'"); + } else if (submitNames.contains(submitName)) { throw new SAXException( - "There are two 'submission-process' elements with the name '" - + submitName + "' in 'item-submission.xml'."); + "There are two 'submission-process' elements with the name '" + + submitName + "' in 'item-submission.xml'."); } submitNames.add(submitName); @@ -446,13 +446,11 @@ public class SubmissionConfigReader // loop through all the 'step' nodes of the 'submission-process' NodeList pl = nd.getChildNodes(); int lenStep = pl.getLength(); - for (int j = 0; j < lenStep; j++) - { + for (int j = 0; j < lenStep; j++) { Node nStep = pl.item(j); // process each 'step' definition - if (nStep.getNodeName().equals("step")) - { + if (nStep.getNodeName().equals("step")) { // check for an 'id' attribute String stepID = getAttribute(nStep, "id"); @@ -460,33 +458,28 @@ public class SubmissionConfigReader // if this step has an id, load its information from the // step-definition section - if ((stepID != null) && (stepID.length() > 0)) - { - if (stepDefns.containsKey(stepID)) - { + if ((stepID != null) && (stepID.length() > 0)) { + if (stepDefns.containsKey(stepID)) { // load the step information from the // step-definition stepInfo = stepDefns.get(stepID); - } - else - { - throw new SAXException( - "The Submission process config named " - + submitName - + " contains a step with id=" - + stepID - + ". There is no step with this 'id' defined in the 'step-definition' section of 'item-submission.xml'."); + } else { + throw new SubmissionConfigReaderException( + "The Submission process config named " + + submitName + + " contains a step with id=" + + stepID + + ". There is no step with this 'id' defined in the 'step-definition' " + + "section of 'item-submission.xml'."); } // Ignore all children of a step element with an // "id" - } - else - { + } else { // get information about step from its children // nodes stepInfo = processStepChildNodes( - "submission-process", nStep); + "submission-process", nStep); } steps.add(stepInfo); @@ -495,36 +488,17 @@ public class SubmissionConfigReader } // sanity check number of steps - if (steps.size() < 1) - { - throw new ServletException( - "Item Submission process config named " - + submitName + " has no steps defined in 'item-submission.xml'"); + if (steps.size() < 1) { + throw new SubmissionConfigReaderException( + "Item Submission process config named " + + submitName + " has no steps defined in 'item-submission.xml'"); } - // ALL Item Submission processes MUST BEGIN with selecting a - // Collection. So, automatically insert in the "collection" step - // (from the 'step-definition' section) - // Note: we already did a sanity check that this "collection" - // step exists. - steps.add(0, stepDefns - .get(SubmissionStepConfig.SELECT_COLLECTION_STEP)); - - // ALL Item Submission processes MUST END with the - // "Complete" processing step. - // So, automatically append in the "complete" step - // (from the 'step-definition' section) - // Note: we already did a sanity check that this "complete" - // step exists. - steps.add(stepDefns - .get(SubmissionStepConfig.COMPLETE_STEP)); - } } - if (numSubmitProcesses == 0) - { - throw new ServletException( - "No 'submission-process' elements/definitions found in 'item-submission.xml'"); + if (numSubmitProcesses == 0) { + throw new SubmissionConfigReaderException( + "No 'submission-process' elements/definitions found in 'item-submission.xml'"); } } @@ -532,76 +506,75 @@ public class SubmissionConfigReader * Process the children of the "step" tag of the XML file. Returns a HashMap * of all the fields under that "step" tag, where the key is the field name, * and the value is the field value. - * */ private Map processStepChildNodes(String configSection, Node nStep) - throws SAXException, ServletException - { + throws SubmissionConfigReaderException { // initialize the HashMap of step Info Map stepInfo = new HashMap(); NodeList flds = nStep.getChildNodes(); int lenflds = flds.getLength(); - for (int k = 0; k < lenflds; k++) - { + for (int k = 0; k < lenflds; k++) { // process each child node of a tag Node nfld = flds.item(k); - if (!isEmptyTextNode(nfld)) - { - String tagName = nfld.getNodeName(); + String tagName = nfld.getNodeName(); + if (!isEmptyTextNode(nfld)) { String value = getValue(nfld); stepInfo.put(tagName, value); } - }// end for each field + + for (int idx = 0; idx < nfld.getAttributes().getLength(); idx++) { + Node nAttr = nfld.getAttributes().item(idx); + String attrName = nAttr.getNodeName(); + String attrValue = nAttr.getNodeValue(); + stepInfo.put(tagName + "." + attrName, attrValue); + } + } // end for each field // check for ID attribute & save to step info String stepID = getAttribute(nStep, "id"); - if (stepID != null && stepID.length() > 0) - { + if (StringUtils.isNotBlank(stepID)) { stepInfo.put("id", stepID); } + String mandatory = getAttribute(nStep, "mandatory"); + if (StringUtils.isNotBlank(mandatory)) { + stepInfo.put("mandatory", mandatory); + } + // look for REQUIRED 'step' information String missing = null; - if (stepInfo.get("processing-class") == null) - { + if (stepInfo.get("processing-class") == null) { missing = "'processing-class'"; } - if (missing != null) - { + if (missing != null) { String msg = "Required field " + missing - + " missing in a 'step' in the " + configSection - + " of the item submission configuration file ('item-submission.xml')"; - throw new SAXException(msg); + + " missing in a 'step' in the " + configSection + + " of the item submission configuration file ('item-submission.xml')"; + throw new SubmissionConfigReaderException(msg); } return stepInfo; } - private Node getElement(Node nd) - { + private Node getElement(Node nd) { NodeList nl = nd.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE) - { + if (n.getNodeType() == Node.ELEMENT_NODE) { return n; } } return null; } - private boolean isEmptyTextNode(Node nd) - { + private boolean isEmptyTextNode(Node nd) { boolean isEmpty = false; - if (nd.getNodeType() == Node.TEXT_NODE) - { + if (nd.getNodeType() == Node.TEXT_NODE) { String text = nd.getNodeValue().trim(); - if (text.length() == 0) - { + if (text.length() == 0) { isEmpty = true; } } @@ -611,18 +584,14 @@ public class SubmissionConfigReader /** * Returns the value of the node's attribute named */ - private String getAttribute(Node e, String name) - { + private String getAttribute(Node e, String name) { NamedNodeMap attrs = e.getAttributes(); int len = attrs.getLength(); - if (len > 0) - { + if (len > 0) { int i; - for (i = 0; i < len; i++) - { + for (i = 0; i < len; i++) { Node attr = attrs.item(i); - if (name.equals(attr.getNodeName())) - { + if (name.equals(attr.getNodeName())) { return attr.getNodeValue().trim(); } } @@ -635,20 +604,35 @@ public class SubmissionConfigReader * Returns the value found in the Text node (if any) in the node list that's * passed in. */ - private String getValue(Node nd) - { + private String getValue(Node nd) { NodeList nl = nd.getChildNodes(); int len = nl.getLength(); - for (int i = 0; i < len; i++) - { + for (int i = 0; i < len; i++) { Node n = nl.item(i); short type = n.getNodeType(); - if (type == Node.TEXT_NODE) - { + if (type == Node.TEXT_NODE) { return n.getNodeValue().trim(); } } // Didn't find a text node return null; } + + public List getCollectionsBySubmissionConfig(Context context, String submitName) + throws IllegalStateException, SQLException { + List results = new ArrayList<>(); + // get the submission-map keys + for (String handle : collectionToSubmissionConfig.keySet()) { + if (!DEFAULT_COLLECTION.equals(handle)) { + if (collectionToSubmissionConfig.get(handle).equals(submitName)) { + DSpaceObject result = HandleServiceFactory.getInstance().getHandleService() + .resolveToObject(context, handle); + if (result != null) { + results.add((Collection) result); + } + } + } + } + return results; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReaderException.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReaderException.java new file mode 100644 index 0000000000..3a148166df --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReaderException.java @@ -0,0 +1,52 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.util; + +/** + * This is a superclass for exceptions representing a failure when + * loading the item submission configuration. E.g., missing mandatory + * information, inconsistent data, etc + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + */ +public class SubmissionConfigReaderException extends Exception { + /** + * No-args constructor. + */ + public SubmissionConfigReaderException() { + super(); + } + + /** + * Constructor for a given message. + * + * @param message diagnostic message. + */ + public SubmissionConfigReaderException(String message) { + super(message); + } + + /** + * Constructor for a given cause. + * + * @param cause throwable that caused this exception + */ + public SubmissionConfigReaderException(Throwable cause) { + super(cause); + } + + /** + * Constructor to create a new exception wrapping it around another exception. + * + * @param message diagnostic message. + * @param cause throwable that caused this exception + */ + public SubmissionConfigReaderException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionInfo.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionInfo.java deleted file mode 100644 index 14f0037ed9..0000000000 --- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionInfo.java +++ /dev/null @@ -1,702 +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.util; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.log4j.Logger; -import org.dspace.content.Bitstream; -import org.dspace.content.Bundle; -import org.dspace.content.InProgressSubmission; - -import org.dspace.submit.AbstractProcessingStep; -import org.dspace.workflow.WorkflowItem; - -/** - * Information about an item being editing with the submission UI - * - * @author Robert Tansley - * @version $Revision$ - */ -public class SubmissionInfo extends HashMap -{ - /** log4j logger */ - private static Logger log = Logger.getLogger(SubmissionInfo.class); - - /** The item which is being submitted */ - private InProgressSubmission submissionItem = null; - - /** - * The Submission process config, which holds all info about the submission - * process that this item is going through (including all steps, etc) - */ - private SubmissionConfig submissionConfig = null; - - /** - * Handle of the collection where this item is being submitted - */ - private String collectionHandle = null; - - /*************************************************************************** - * Holds all information used to build the Progress Bar in a key,value set. - * Keys are the number of the step, followed by the number of the page - * within the step (e.g. "2.1" = The first page of Step 2) (e.g. "5.2" = The - * second page of Step 5) Values are the Headings to display for each step - * (e.g. "Describe") - **************************************************************************/ - private Map progressBar = null; - - /** The element or element_qualifier to show more input boxes for */ - private String moreBoxesFor; - - /** The element or element_qualifier to scroll to initially using anchor */ - private String jumpToField; - - /** If non-empty, form-relative indices of missing fields */ - private List missingFields; - - /** Specific bundle we're dealing with */ - private Bundle bundle; - - /** Specific bitstream we're dealing with */ - private Bitstream bitstream; - - /** Reader for submission process configuration file * */ - private static SubmissionConfigReader submissionConfigReader; - - /** - * Default Constructor - PRIVATE - *

- * Create a SubmissionInfo object - * using the load() method! - * - */ - private SubmissionInfo() - { - } - - /** - * Loads all known submission information based on the given in progress - * submission and request object. - *

- * If subItem is null, then just loads the default submission information - * for a new submission. - * - * @param request - * The HTTP Servlet Request object - * @param subItem - * The in-progress submission we are loading information for - * - * @return a SubmissionInfo object - * - * @throws ServletException - * if an error occurs - */ - public static SubmissionInfo load(HttpServletRequest request, InProgressSubmission subItem) throws ServletException - { - boolean forceReload = false; - SubmissionInfo subInfo = new SubmissionInfo(); - - // load SubmissionConfigReader only the first time - // or if we're using a different UI now. - if (submissionConfigReader == null) - { - submissionConfigReader = new SubmissionConfigReader(); - forceReload=true; - } - - // save the item which is going through the submission process - subInfo.setSubmissionItem(subItem); - - // Only if the submission item is created can we set its collection - String collectionHandle = SubmissionConfigReader.DEFAULT_COLLECTION; - if (subItem != null) - { - collectionHandle = subItem.getCollection().getHandle(); - } - - // save this collection handle to this submission info object - subInfo.setCollectionHandle(collectionHandle); - - // load Submission Process config for this item's collection - // (Note: this also loads the Progress Bar info, since it is - // dependent on the Submission config) - loadSubmissionConfig(request, subInfo, forceReload); - - return subInfo; - } - - /** - * Is this submission in the workflow process? - * - * @return true if the current submission is in the workflow process - */ - public boolean isInWorkflow() - { - return ((this.submissionItem != null) && this.submissionItem instanceof WorkflowItem); - } - - /** - * Return the current in progress submission - * - * @return the InProgressSubmission object representing the current - * submission - */ - public InProgressSubmission getSubmissionItem() - { - return this.submissionItem; - } - - /** - * Updates the current in progress submission item - * - * @param subItem - * the new InProgressSubmission object - */ - public void setSubmissionItem(InProgressSubmission subItem) - { - this.submissionItem = subItem; - } - - /** - * Return the current submission process config (which includes all steps - * which need to be completed for the submission to be successful) - * - * @return the SubmissionConfig object, which contains info on all the steps - * in the current submission process - */ - public SubmissionConfig getSubmissionConfig() - { - return this.submissionConfig; - } - - /** - * Causes the SubmissionConfig to be completely reloaded from the XML - * configuration file (item-submission.xml). - *

- * Note: This also reloads the progress bar info, since the progress bar - * depends entirely on the submission process (and its steps). - * - * @param request - * The HTTP Servlet Request object - * - * @throws ServletException - * if an error occurs - */ - public void reloadSubmissionConfig(HttpServletRequest request) - throws ServletException - { - // Only if the submission item is created can we set its collection - String collectionHandle = SubmissionConfigReader.DEFAULT_COLLECTION; - if (this.submissionItem != null) - { - collectionHandle = submissionItem.getCollection().getHandle(); - } - this.setCollectionHandle(collectionHandle); - - // force a reload of the submission process configuration - loadSubmissionConfig(request, this, true); - } - - /** - * Returns a particular global step definition based on its ID. - *

- * Global step definitions are those defined in the {@code } - * section of the configuration file. - * - * @param stepID - * step's identifier - * - * @return the SubmissionStepConfig representing the step - * - * @throws ServletException - * if no default submission process configuration defined - */ - public SubmissionStepConfig getStepConfig(String stepID) - throws ServletException - { - return submissionConfigReader.getStepConfig(stepID); - } - - - /** - * Return text information suitable for logging. - *

- * This method is used by several of the Step classes - * to log major events during the submission process (e.g. when - * license agreement was accepted, when item was submitted, - * when it was available in DSpace, etc.) - * - * @return the type and ID of the submission, bundle and/or bitstream for - * logging - */ - public String getSubmissionLogInfo() - { - String info = ""; - - if (isInWorkflow()) - { - info = info + "workflow_id=" + getSubmissionItem().getID(); - } - else - { - info = info + "workspace_item_id" + getSubmissionItem().getID(); - } - - if (getBundle() != null) - { - info = info + ",bundle_id=" + getBundle().getID(); - } - - if (getBitstream() != null) - { - info = info + ",bitstream_id=" + getBitstream().getID(); - } - - return info; - } - - /** - * Gets the handle of the collection to which this item is being submitted - * - * @return the collection handle - */ - public String getCollectionHandle() - { - return this.collectionHandle; - } - - /** - * Sets the handle of the collection to which this item is being submitted - * - * @param handle - * the new collection handle - */ - public void setCollectionHandle(String handle) - { - this.collectionHandle = handle; - } - - /** - * Return the information used to build the progress bar (this includes all - * the steps in this submission, as well as the ordering and names of the - * steps). - *

- * Returns a Hashmap, with the following specifics: - *

- * Keys are the number of the step, followed by the number of the page - * within the step - *

- * (e.g. "2.1" = The first page of Step 2) - *

- * (e.g. "5.2" = The second page of Step 5) - *

- * Values are the Headings to display for each step (e.g. "Describe") - * - * @return a Hashmap of Progress Bar information. - */ - public Map getProgressBarInfo() - { - return this.progressBar; - } - - /** - * Return the current bitstream we're working with (This is used during - * upload processes, or user interfaces that are dealing with bitstreams) - * - * @return the Bitstream object for the bitstream - */ - public Bitstream getBitstream() - { - return this.bitstream; - } - - /** - * Sets the current bitstream we're working with (This is used during upload - * processes, or user interfaces that are dealing with bitstreams) - * - * @param bits - * the bitstream - */ - public void setBitstream(Bitstream bits) - { - this.bitstream = bits; - } - - /** - * Return the current bundle we're working with (This is used during upload - * processes, or user interfaces that are dealing with bundles/bitstreams) - * - * @return the Bundle object for the bundle - */ - public Bundle getBundle() - { - return this.bundle; - } - - /** - * Sets the current bundle we're working with (This is used during upload - * processes, or user interfaces that are dealing with bundles/bitstreams) - * - * @param bund - * the bundle - */ - public void setBundle(Bundle bund) - { - this.bundle = bund; - } - - /** - * Return form related indices of the required fields which were not filled - * out by the user. - * - * @return a List of empty fields which are required - */ - public List getMissingFields() - { - return this.missingFields; - } - - /** - * Sets the form related indices of the required fields which were not - * filled out by the user. - * - * @param missing - * the List of empty fields which are required - */ - public void setMissingFields(List missing) - { - this.missingFields = missing; - } - - /** - * Return metadata field which user has requested more input boxes be - * displayed (by pressing "Add More" on one of the "Describe" pages) - * - * @return the String name of the field element - */ - public String getMoreBoxesFor() - { - return this.moreBoxesFor; - } - - /** - * Sets the metadata field which user has requested more input boxes be - * displayed (by pressing "Add More" on one of the "Describe" pages) - * - * @param fieldname - * the name of the field element on the page - */ - public void setMoreBoxesFor(String fieldname) - { - this.moreBoxesFor = fieldname; - } - - /** - * Return metadata field which JSP should "jump to" (i.e. set focus on) when - * the JSP next loads. This is used during the Describe step. - * - * @return the String name of the field element - */ - public String getJumpToField() - { - return this.jumpToField; - } - - /** - * Sets metadata field which JSP should "jump to" (i.e. set focus on) when - * the JSP next loads. This is used during the Describe step. - * - * @param fieldname - * the name of the field on the page - */ - public void setJumpToField(String fieldname) - { - this.jumpToField = fieldname; - } - - /** - * Load necessary information to build the Progress Bar for the Item - * Submission Progress. - * - * This information is returned in the form of a HashMap (which is then - * stored as a part of the SubmissionInfo). The HashMap takes the following - * form: - * - * Keys - the number of the step, followed by the number of the page within - * the step (e.g. "2.1" = The first page of Step 2) (e.g. "5.2" = The second - * page of Step 5) - * - * Values - the headings to display for each step (e.g. "Describe", - * "Verify") - * - * @param request - * The HTTP Servlet Request object - * @param subInfo - * the SubmissionInfo object we are loading into - * @param forceReload - * If true, this method reloads from scratch (and overwrites - * cached progress bar info) - * - */ - private static void loadProgressBar(HttpServletRequest request, - SubmissionInfo subInfo, boolean forceReload) - { - Map progressBarInfo = null; - - log.debug("Loading Progress Bar Info"); - - if (!forceReload) - { - // first, attempt to load from cache - progressBarInfo = loadProgressBarFromCache(request - .getSession()); - } - - if (progressBarInfo != null && log.isDebugEnabled()) - { - log.debug("Found Progress Bar Info in cache: " - + progressBarInfo.size() - + " pages to display in progress bar"); - } - // if unable to load from cache, must load from scratch - else - { - progressBarInfo = new LinkedHashMap(); - - // loop through all steps - for (int i = 0; i < subInfo.submissionConfig.getNumberOfSteps(); i++) - { - // get the current step info - SubmissionStepConfig currentStep = subInfo.submissionConfig - .getStep(i); - String stepNumber = Integer.toString(currentStep - .getStepNumber()); - String stepHeading = currentStep.getHeading(); - - // as long as this step is visible, include it in - // the Progress Bar - if (currentStep.isVisible()) - { - // default to just one page in this step - int numPages = 1; - - try - { - // load the processing class for this step - ClassLoader loader = subInfo.getClass() - .getClassLoader(); - Class stepClass = (Class)loader.loadClass(currentStep.getProcessingClassName()); - - // call the "getNumberOfPages()" method of the class - // to get it's number of pages - AbstractProcessingStep step = stepClass.newInstance(); - - // get number of pages from servlet - numPages = step.getNumberOfPages(request, subInfo); - } - catch (Exception e) - { - log.error( - "Error loading progress bar information from Step Class '" - + currentStep.getProcessingClassName() - + "' Error:", e); - } - - // save each of the step's pages to the progress bar - for (int j = 1; j <= numPages; j++) - { - String pageNumber = Integer.toString(j); - - // store ("stepNumber.pageNumber", Heading) for each - // page in the step - progressBarInfo.put(stepNumber + "." + pageNumber, - stepHeading); - }// end for each page - } - }// end for each step - - log.debug("Loaded Progress Bar Info from scratch: " - + progressBarInfo.size() - + " pages to display in progress bar"); - - // cache this new progress bar - saveProgressBarToCache(request.getSession(), progressBarInfo); - }// end if null - - // save progressBarInfo to submission Info - subInfo.progressBar = progressBarInfo; - } - - /** - * Saves all progress bar information into session cache. This saves us from - * having to reload this same progress bar over and over again. - * - * @param session - * The HTTP Session object - * @param progressBarInfo - * The progress bar info to cache - * - */ - private static void saveProgressBarToCache(HttpSession session, - Map progressBarInfo) - { - // cache progress bar info to Session - session.setAttribute("submission.progressbar", progressBarInfo); - } - - /** - * Attempts to retrieve progress bar information (for a particular - * collection) from session cache. - * - * If the progress bar info cannot be found, returns null - * - * @param session - * The HTTP Session object - * - * @return progressBarInfo HashMap (if found), or null (if not) - * - */ - private static Map loadProgressBarFromCache(HttpSession session) - { - return (Map) session.getAttribute("submission.progressbar"); - } - - /** - * Loads SubmissionConfig object for the given submission info object. If a - * SubmissionConfig object cannot be loaded, a Servlet Error is thrown. - *

- * This method just loads this SubmissionConfig object internally, so that - * it is available via a call to "getSubmissionConfig()" - * - * @param request - * The HTTP Servlet Request object - * @param subInfo - * the SubmissionInfo object we are loading into - * @param forceReload - * If true, this method reloads from scratch (and overwrites - * cached SubmissionConfig) - * - */ - private static void loadSubmissionConfig(HttpServletRequest request, - SubmissionInfo subInfo, boolean forceReload) - throws ServletException - { - - log.debug("Loading Submission Config information"); - - if (!forceReload) - { - // first, try to load from cache - subInfo.submissionConfig = loadSubmissionConfigFromCache(request - .getSession(), subInfo.getCollectionHandle(), subInfo - .isInWorkflow()); - } - - if (subInfo.submissionConfig == null || forceReload) - { - // reload the proper Submission process config - // (by reading the XML config file) - subInfo.submissionConfig = submissionConfigReader - .getSubmissionConfig(subInfo.getCollectionHandle(), subInfo - .isInWorkflow()); - - // cache this new submission process configuration - saveSubmissionConfigToCache(request.getSession(), - subInfo.submissionConfig, subInfo.getCollectionHandle(), - subInfo.isInWorkflow()); - - // also must force reload Progress Bar info, - // since it's based on the Submission config - loadProgressBar(request, subInfo, true); - } - else - { - log.debug("Found Submission Config in session cache!"); - - // try and reload progress bar from cache - loadProgressBar(request, subInfo, false); - } - } - - /** - * Saves SubmissionConfig object into session cache. This saves us from - * having to reload this object during every "Step". - * - * @param session - * The HTTP Session object - * @param subConfig - * The SubmissionConfig to cache - * @param collectionHandle - * The Collection handle this SubmissionConfig corresponds to - * @param isWorkflow - * Whether this SubmissionConfig corresponds to a workflow - * - * - */ - private static void saveSubmissionConfigToCache(HttpSession session, - SubmissionConfig subConfig, String collectionHandle, - boolean isWorkflow) - { - // cache the submission process config - // and the collection it corresponds to - session.setAttribute("submission.config", subConfig); - session.setAttribute("submission.config.collection", collectionHandle); - session.setAttribute("submission.config.isWorkflow", Boolean.valueOf( - isWorkflow)); - } - - /** - * Loads SubmissionConfig object from session cache for the given - * Collection. If a SubmissionConfig object cannot be found, null is - * returned. - * - * @param session - * The HTTP Session object - * @param collectionHandle - * The Collection handle of the SubmissionConfig to load - * @param isWorkflow - * whether or not we loading the Submission process for a - * workflow item - * - * @return The cached SubmissionConfig for this collection - */ - private static SubmissionConfig loadSubmissionConfigFromCache( - HttpSession session, String collectionHandle, boolean isWorkflow) - { - // attempt to load submission process config - // from cache for the current collection - String cachedHandle = (String) session - .getAttribute("submission.config.collection"); - - Boolean cachedIsWorkflow = (Boolean) session - .getAttribute("submission.config.isWorkflow"); - - // only load from cache if the collection handle and - // workflow item status both match! - if (collectionHandle.equals(cachedHandle) - && isWorkflow == cachedIsWorkflow.booleanValue()) - - { - return (SubmissionConfig) session.getAttribute("submission.config"); - } - else - { - return null; - } - } - -} - diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionStepConfig.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionStepConfig.java index 8edf7cf3ad..7cd9dacd03 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionStepConfig.java +++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionStepConfig.java @@ -7,8 +7,10 @@ */ package org.dspace.app.util; -import java.util.Map; import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.lang3.BooleanUtils; /** * Class representing configuration for a single step within an Item Submission @@ -18,15 +20,17 @@ import java.io.Serializable; * * Note: Implements Serializable as it will be saved to the current session during submission. * Please ensure that nothing is added to this class that isn't also serializable - * - * @see org.dspace.app.util.SubmissionConfigReader - * @see org.dspace.app.util.SubmissionConfig - * + * * @author Tim Donohue * @version $Revision$ + * @see org.dspace.app.util.SubmissionConfigReader + * @see org.dspace.app.util.SubmissionConfig */ -public class SubmissionStepConfig implements Serializable -{ +public class SubmissionStepConfig implements Serializable { + + public static final String INPUT_FORM_STEP_NAME = "submission-form"; + public static final String UPLOAD_STEP_NAME = "upload"; + /* * The identifier for the Select Collection step */ @@ -43,70 +47,80 @@ public class SubmissionStepConfig implements Serializable */ private String id = null; - /** the heading for this step */ - private String heading = null; - - /** the name of the java processing class for this step */ - private String processingClassName = null; - - /** whether or not this step is editable during workflow (default=true) */ - private boolean workflowEditable = true; - - /** - * The full name of the JSP-UI binding class for this step. This field is - * ONLY used by the JSP-UI. - **/ - private String jspBindingClassName = null; + private boolean mandatory = true; /** - * The full name of the Manakin XML-UI Transformer class which will generate - * the necessary DRI for displaying this class in Manakin. This field is - * ONLY used by the Manakin XML-UI. + * the heading for this step */ - private String xmlBindingClassName = null; + private String heading = null; - /** The number of this step in the current SubmissionConfig */ + /** + * the name of the java processing class for this step + */ + private String processingClassName = null; + + /** + * The name of the UI components for this step. + **/ + private String type = null; + + + /** + * The scope restriction for this step (submission or workflow). + **/ + private String scope = null; + + /** + * visibility in the main scope (default=editable, eventually read-only) + */ + private String visibility = null; + + /** + * visibility outside the main scope (default=hidden, eventually read-only) + */ + private String visibilityOutside = null; + + /** + * The number of this step in the current SubmissionConfig + */ private int number = -1; /** * Class constructor for creating an empty SubmissionStepConfig object */ - public SubmissionStepConfig() - { + public SubmissionStepConfig() { } /** * Class constructor for creating a SubmissionStepConfig object based on the * contents of a HashMap initialized by the SubmissionConfig object. - * - * @param stepMap - * the HashMap containing all required information about this - * step + * + * @param stepMap the HashMap containing all required information about this + * step */ - public SubmissionStepConfig(Map stepMap) - { + public SubmissionStepConfig(Map stepMap) { id = stepMap.get("id"); + String s = stepMap.get("mandatory"); + // only set if explicitly configured + if (s != null) { + mandatory = BooleanUtils.toBoolean(s); + } heading = stepMap.get("heading"); processingClassName = stepMap.get("processing-class"); - jspBindingClassName = stepMap.get("jspui-binding"); - xmlBindingClassName = stepMap.get("xmlui-binding"); - - String wfEditString = stepMap.get("workflow-editable"); - if (wfEditString != null && wfEditString.length() > 0) - { - workflowEditable = Boolean.parseBoolean(wfEditString); - } + type = stepMap.get("type"); + scope = stepMap.get("scope"); + visibility = stepMap.get("scope.visibility"); + visibilityOutside = stepMap.get("scope.visibilityOutside"); } /** * Get the ID for this step. An ID is only defined if the step exists in the * {@code } section. This ID field is used to reference special * steps (like the required step with {@code id="collection"}) - * + * * @return the step ID */ - public String getId() - { + public String getId() { return id; } @@ -114,11 +128,10 @@ public class SubmissionStepConfig implements Serializable * Get the heading for this step. This can either be a property from * Messages.properties, or the actual heading text. If this "heading" * contains a period(.) it is assumed to reference Messages.properties. - * + * * @return the heading */ - public String getHeading() - { + public String getHeading() { return heading; } @@ -127,58 +140,46 @@ public class SubmissionStepConfig implements Serializable *

* This class must extend the org.dspace.submit.AbstractProcessingStep class, * and provide processing for BOTH the JSP-UI and XML-UI - * + * * @return the class's full class path (e.g. - * "org.dspace.submit.step.MySampleStep") + * "org.dspace.submit.step.MySampleStep") */ - public String getProcessingClassName() - { + public String getProcessingClassName() { return processingClassName; } /** - * Retrieve the full class name of the Manakin Transformer which will - * generate this step's DRI, for display in Manakin XML-UI. - *

- * This class must extend the - * org.dspace.app.xmlui.aspect.submission.StepTransformer class. - *

- * This property is only used by the Manakin XML-UI, and therefore is not - * relevant if you are using the JSP-UI. - * - * @return the full java class name of the Transformer to use for this step + * Retrieve the name of the component used by this step in the UI + * + * @return the name of the UI component to use for this step */ - public String getXMLUIClassName() - { - return xmlBindingClassName; + public String getType() { + return type; } - + /** - * Retrieve the full class name of the JSP-UI "binding" class which will - * initialize and call the necessary JSPs for display in the JSP-UI - *

- * This class must extend the - * org.dspace.app.webui.submit.JSPStep class. - *

- * This property is only used by the JSP-UI, and therefore is not - * relevant if you are using the XML-UI (aka. Manakin). - * - * @return the full java class name of the JSPStep to use for this step + * @return the scope restriction for this step */ - public String getJSPUIClassName() - { - return jspBindingClassName; + public String getScope() { + return scope; + } + + public String getVisibility() { + return visibility; + } + + public String getVisibilityOutside() { + return visibilityOutside; } /** * Get the number of this step in the current Submission process config. * Step numbers start with #0 (although step #0 is ALWAYS the special * "select collection" step) - * + * * @return the number of this step in the current SubmissionConfig */ - public int getStepNumber() - { + public int getStepNumber() { return number; } @@ -186,35 +187,24 @@ public class SubmissionStepConfig implements Serializable * Sets the number of this step in the current Submission process config. * Step numbers start with #0 (although step #0 is ALWAYS the special * "select collection" step) - * - * @param stepNum - * the step number. + * + * @param stepNum the step number. */ - protected void setStepNumber(int stepNum) - { + protected void setStepNumber(int stepNum) { this.number = stepNum; } - /** - * Whether or not this step is editable during workflow processing. If - * "true", then this step will appear in the "Edit Metadata" stage of the - * workflow process. - * - * @return if step is editable in a workflow process - */ - public boolean isWorkflowEditable() - { - return workflowEditable; - } - /** * Whether or not this step is visible within the Progress Bar. A step is * only visible if it has been assigned a Heading, otherwise it's invisible - * + * * @return if step is visible within the progress bar */ - public boolean isVisible() - { + public boolean isVisible() { return ((heading != null) && (heading.length() > 0)); } + + public boolean isMandatory() { + return mandatory; + } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java b/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java index b492e1851e..5e79b69202 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java +++ b/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java @@ -12,46 +12,50 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; - import javax.servlet.http.HttpServletRequest; -import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.lang.StringUtils; -import org.dspace.content.*; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.CollectionService; -import org.dspace.content.service.CommunityService; -import org.dspace.content.service.ItemService; -import org.dspace.core.Context; -import org.dspace.handle.factory.HandleServiceFactory; -import org.w3c.dom.Document; - -import org.dspace.core.ConfigurationManager; -import org.dspace.core.Constants; - -import com.sun.syndication.feed.synd.SyndFeed; -import com.sun.syndication.feed.synd.SyndFeedImpl; -import com.sun.syndication.feed.synd.SyndEntry; -import com.sun.syndication.feed.synd.SyndEntryImpl; +import com.sun.syndication.feed.module.DCModule; +import com.sun.syndication.feed.module.DCModuleImpl; +import com.sun.syndication.feed.module.Module; +import com.sun.syndication.feed.module.itunes.EntryInformation; +import com.sun.syndication.feed.module.itunes.EntryInformationImpl; +import com.sun.syndication.feed.module.itunes.types.Duration; +import com.sun.syndication.feed.synd.SyndContent; +import com.sun.syndication.feed.synd.SyndContentImpl; import com.sun.syndication.feed.synd.SyndEnclosure; import com.sun.syndication.feed.synd.SyndEnclosureImpl; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndEntryImpl; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.feed.synd.SyndFeedImpl; import com.sun.syndication.feed.synd.SyndImage; import com.sun.syndication.feed.synd.SyndImageImpl; import com.sun.syndication.feed.synd.SyndPerson; import com.sun.syndication.feed.synd.SyndPersonImpl; -import com.sun.syndication.feed.synd.SyndContent; -import com.sun.syndication.feed.synd.SyndContentImpl; -import com.sun.syndication.feed.module.DCModuleImpl; -import com.sun.syndication.feed.module.DCModule; -import com.sun.syndication.feed.module.Module; -import com.sun.syndication.feed.module.itunes.*; -import com.sun.syndication.feed.module.itunes.types.Duration; -import com.sun.syndication.io.SyndFeedOutput; import com.sun.syndication.io.FeedException; - +import com.sun.syndication.io.SyndFeedOutput; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DCDate; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.ItemService; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; +import org.w3c.dom.Document; /** * Invoke ROME library to assemble a generic model of a syndication @@ -64,12 +68,13 @@ import org.dspace.services.factory.DSpaceServicesFactory; * * @author Larry Stone */ -public class SyndicationFeed -{ - protected final Logger log = Logger.getLogger(SyndicationFeed.class); +public class SyndicationFeed { + protected final Logger log = Logger.getLogger(SyndicationFeed.class); - /** i18n key values */ + /** + * i18n key values + */ public static final String MSG_UNTITLED = "notitle"; public static final String MSG_LOGO_TITLE = "logo.title"; public static final String MSG_FEED_TITLE = "feed.title"; @@ -82,33 +87,40 @@ public class SyndicationFeed public static final String UITYPE_JSPUI = "jspui"; // default DC fields for entry - protected String defaultTitleField = "dc.title"; - protected String defaultAuthorField = "dc.contributor.author"; - protected String defaultDateField = "dc.date.issued"; - private static final String[] defaultDescriptionFields = new String[]{"dc.description.abstract", "dc.description", "dc.title.alternative", "dc.title"}; - protected String defaultExternalMedia = "dc.source.uri"; + protected String defaultTitleField = "dc.title"; + protected String defaultAuthorField = "dc.contributor.author"; + protected String defaultDateField = "dc.date.issued"; + private static final String[] defaultDescriptionFields = + new String[] { + "dc.description.abstract", + "dc.description", + "dc.title.alternative", + "dc.title" + }; + protected String defaultExternalMedia = "dc.source.uri"; - private final ConfigurationService configurationService = - DSpaceServicesFactory.getInstance().getConfigurationService(); + private final ConfigurationService configurationService = + DSpaceServicesFactory.getInstance().getConfigurationService(); // metadata field for Item title in entry: - protected String titleField = - configurationService.getProperty("webui.feed.item.title", defaultTitleField); + protected String titleField = + configurationService.getProperty("webui.feed.item.title", defaultTitleField); // metadata field for Item publication date in entry: protected String dateField = - configurationService.getProperty("webui.feed.item.date", defaultDateField); + configurationService.getProperty("webui.feed.item.date", defaultDateField); // metadata field for Item description in entry: private static final String descriptionFields[] = - DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("webui.feed.item.description", defaultDescriptionFields); - + DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("webui.feed.item.description", defaultDescriptionFields); + protected String authorField = - configurationService.getProperty("webui.feed.item.author", defaultAuthorField); + configurationService.getProperty("webui.feed.item.author", defaultAuthorField); // metadata field for Podcast external media source url - protected String externalSourceField = - configurationService.getProperty("webui.feed.podcast.sourceuri", defaultExternalMedia); + protected String externalSourceField = + configurationService.getProperty("webui.feed.podcast.sourceuri", defaultExternalMedia); // metadata field for Item dc:creator field in entry's DCModule (no default) protected String dcCreatorField = configurationService.getProperty("webui.feed.item.dc.creator"); @@ -121,7 +133,7 @@ public class SyndicationFeed // List of available mimetypes that we'll add to podcast feed. Multiple values separated by commas protected String[] podcastableMIMETypes = - configurationService.getArrayProperty("webui.feed.podcast.mimetypes", new String[]{"audio/x-mpeg"}); + configurationService.getArrayProperty("webui.feed.podcast.mimetypes", new String[] {"audio/x-mpeg"}); // -------- Instance variables: @@ -140,10 +152,10 @@ public class SyndicationFeed /** * Constructor. + * * @param ui either "xmlui" or "jspui" */ - public SyndicationFeed(String ui) - { + public SyndicationFeed(String ui) { feed = new SyndFeedImpl(); uiType = ui; ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance(); @@ -157,23 +169,22 @@ public class SyndicationFeed * * @return selector list - format 'schema.element[.qualifier]' */ - public static String[] getDescriptionSelectors() - { + public static String[] getDescriptionSelectors() { return (String[]) ArrayUtils.clone(descriptionFields); } /** * Fills in the feed and entry-level metadata from DSpace objects. + * * @param request request * @param context context - * @param dso DSpaceObject - * @param items array of objects - * @param labels label map + * @param dso DSpaceObject + * @param items array of objects + * @param labels label map */ public void populate(HttpServletRequest request, Context context, DSpaceObject dso, - List items, Map labels) - { + List items, Map labels) { String logoURL = null; String objectURL = null; String defaultTitle = null; @@ -181,53 +192,45 @@ public class SyndicationFeed this.request = request; // dso is null for the whole site, or a search without scope - if (dso == null) - { + if (dso == null) { defaultTitle = ConfigurationManager.getProperty("dspace.name"); feed.setDescription(localize(labels, MSG_FEED_DESCRIPTION)); objectURL = resolveURL(request, null); logoURL = ConfigurationManager.getProperty("webui.feed.logo.url"); - } - else - { + } else { Bitstream logo = null; - if (dso.getType() == Constants.COLLECTION) - { - Collection col = (Collection)dso; + if (dso.getType() == Constants.COLLECTION) { + Collection col = (Collection) dso; defaultTitle = col.getName(); feed.setDescription(collectionService.getMetadata(col, "short_description")); logo = col.getLogo(); String cols = ConfigurationManager.getProperty("webui.feed.podcast.collections"); - if(cols != null && cols.length() > 1 && cols.contains(col.getHandle()) ) { + if (cols != null && cols.length() > 1 && cols.contains(col.getHandle())) { podcastFeed = true; } - } - else if (dso.getType() == Constants.COMMUNITY) - { - Community comm = (Community)dso; + } else if (dso.getType() == Constants.COMMUNITY) { + Community comm = (Community) dso; defaultTitle = comm.getName(); feed.setDescription(communityService.getMetadata(comm, "short_description")); logo = comm.getLogo(); String comms = ConfigurationManager.getProperty("webui.feed.podcast.communities"); - if(comms != null && comms.length() > 1 && comms.contains(comm.getHandle()) ){ + if (comms != null && comms.length() > 1 && comms.contains(comm.getHandle())) { podcastFeed = true; } } objectURL = resolveURL(request, dso); - if (logo != null) - { + if (logo != null) { logoURL = urlOfBitstream(request, logo); } } feed.setTitle(labels.containsKey(MSG_FEED_TITLE) ? - localize(labels, MSG_FEED_TITLE) : defaultTitle); + localize(labels, MSG_FEED_TITLE) : defaultTitle); feed.setLink(objectURL); feed.setPublishedDate(new Date()); feed.setUri(objectURL); // add logo if we found one: - if (logoURL != null) - { + if (logoURL != null) { // we use the path to the logo for this, the logo itself cannot // be contained in the rdf. Not all RSS-viewers show this logo. SyndImage image = new SyndImageImpl(); @@ -242,64 +245,52 @@ public class SyndicationFeed } // add entries for items - if (items != null) - { + if (items != null) { List entries = new ArrayList(); - for (DSpaceObject itemDSO : items) - { - if (itemDSO.getType() != Constants.ITEM) - { + for (DSpaceObject itemDSO : items) { + if (itemDSO.getType() != Constants.ITEM) { continue; } - Item item = (Item)itemDSO; + Item item = (Item) itemDSO; boolean hasDate = false; SyndEntry entry = new SyndEntryImpl(); entries.add(entry); - + String entryURL = resolveURL(request, item); entry.setLink(entryURL); entry.setUri(entryURL); - + String title = getOneDC(item, titleField); entry.setTitle(title == null ? localize(labels, MSG_UNTITLED) : title); - + // "published" date -- should be dc.date.issued String pubDate = getOneDC(item, dateField); - if (pubDate != null) - { + if (pubDate != null) { entry.setPublishedDate((new DCDate(pubDate)).toDate()); hasDate = true; } // date of last change to Item entry.setUpdatedDate(item.getLastModified()); - + StringBuffer db = new StringBuffer(); - for (String df : descriptionFields) - { + for (String df : descriptionFields) { // Special Case: "(date)" in field name means render as date boolean isDate = df.indexOf("(date)") > 0; - if (isDate) - { + if (isDate) { df = df.replaceAll("\\(date\\)", ""); } - + List dcv = itemService.getMetadataByMetadataString(item, df); - if (dcv.size() > 0) - { + if (dcv.size() > 0) { String fieldLabel = labels.get(MSG_METADATA + df); - if (fieldLabel != null && fieldLabel.length()>0) - { + if (fieldLabel != null && fieldLabel.length() > 0) { db.append(fieldLabel).append(": "); } boolean first = true; - for (MetadataValue v : dcv) - { - if (first) - { + for (MetadataValue v : dcv) { + if (first) { first = false; - } - else - { + } else { db.append("; "); } db.append(isDate ? new DCDate(v.getValue()).toString() : v.getValue()); @@ -307,8 +298,7 @@ public class SyndicationFeed db.append("\n"); } } - if (db.length() > 0) - { + if (db.length() > 0) { SyndContent desc = new SyndContentImpl(); desc.setType("text/plain"); desc.setValue(db.toString()); @@ -317,11 +307,9 @@ public class SyndicationFeed // This gets the authors into an ATOM feed List authors = itemService.getMetadataByMetadataString(item, authorField); - if (authors.size() > 0) - { + if (authors.size() > 0) { List creators = new ArrayList(); - for (MetadataValue author : authors) - { + for (MetadataValue author : authors) { SyndPerson sp = new SyndPersonImpl(); sp.setName(author.getValue()); creators.add(sp); @@ -331,40 +319,30 @@ public class SyndicationFeed // only add DC module if any DC fields are configured if (dcCreatorField != null || dcDateField != null || - dcDescriptionField != null) - { + dcDescriptionField != null) { DCModule dc = new DCModuleImpl(); - if (dcCreatorField != null) - { + if (dcCreatorField != null) { List dcAuthors = itemService.getMetadataByMetadataString(item, dcCreatorField); - if (dcAuthors.size() > 0) - { + if (dcAuthors.size() > 0) { List creators = new ArrayList(); - for (MetadataValue author : dcAuthors) - { + for (MetadataValue author : dcAuthors) { creators.add(author.getValue()); } dc.setCreators(creators); } } - if (dcDateField != null && !hasDate) - { + if (dcDateField != null && !hasDate) { List v = itemService.getMetadataByMetadataString(item, dcDateField); - if (v.size() > 0) - { + if (v.size() > 0) { dc.setDate((new DCDate(v.get(0).getValue())).toDate()); } } - if (dcDescriptionField != null) - { + if (dcDescriptionField != null) { List v = itemService.getMetadataByMetadataString(item, dcDescriptionField); - if (v.size() > 0) - { + if (v.size() > 0) { StringBuffer descs = new StringBuffer(); - for (MetadataValue d : v) - { - if (descs.length() > 0) - { + for (MetadataValue d : v) { + if (descs.length() > 0) { descs.append("\n\n"); } descs.append(d.getValue()); @@ -376,8 +354,7 @@ public class SyndicationFeed } //iTunes Podcast Support - START - if (podcastFeed) - { + if (podcastFeed) { // Add enclosure(s) List enclosures = new ArrayList(); try { @@ -386,10 +363,10 @@ public class SyndicationFeed List bits = bunds.get(0).getBitstreams(); for (Bitstream bit : bits) { String mime = bit.getFormat(context).getMIMEType(); - if (ArrayUtils.contains(podcastableMIMETypes,mime)) { + if (ArrayUtils.contains(podcastableMIMETypes, mime)) { SyndEnclosure enc = new SyndEnclosureImpl(); enc.setType(bit.getFormat(context).getMIMEType()); - enc.setLength(bit.getSize()); + enc.setLength(bit.getSizeBytes()); enc.setUrl(urlOfBitstream(request, bit)); enclosures.add(enc); } else { @@ -399,12 +376,14 @@ public class SyndicationFeed } //Also try to add an external value from dc.identifier.other // We are assuming that if this is set, then it is a media file - List externalMedia = itemService.getMetadataByMetadataString(item, externalSourceField); - if(externalMedia.size() > 0) - { + List externalMedia = itemService + .getMetadataByMetadataString(item, externalSourceField); + if (externalMedia.size() > 0) { for (MetadataValue anExternalMedia : externalMedia) { SyndEnclosure enc = new SyndEnclosureImpl(); - enc.setType("audio/x-mpeg"); //We can't determine MIME of external file, so just picking one. + enc.setType( + "audio/x-mpeg"); //We can't determine MIME of external file, so just + // picking one. enc.setLength(1); enc.setUrl(anExternalMedia.getValue()); enclosures.add(enc); @@ -430,7 +409,9 @@ public class SyndicationFeed itunes.setSummary(db.toString()); // } - String extent = getOneDC(item, "dc.format.extent"); // assumed that user will enter this field with length of song in seconds + String extent = getOneDC(item, + "dc.format.extent"); // assumed that user will enter this field + // with length of song in seconds if (extent != null && extent.length() > 0) { extent = extent.split(" ")[0]; Integer duration = Integer.parseInt(extent); @@ -455,14 +436,13 @@ public class SyndicationFeed * Sets the feed type for XML delivery, e.g. "rss_1.0", "atom_1.0" * Must match one of ROME's configured generators, see rome.properties * (currently rss_1.0, rss_2.0, atom_1.0, atom_0.3) + * * @param feedType feed type */ - public void setType(String feedType) - { + public void setType(String feedType) { feed.setFeedType(feedType); // XXX FIXME: workaround ROME 1.0 bug, it puts invalid image element in rss1.0 - if ("rss_1.0".equals(feedType)) - { + if ("rss_1.0".equals(feedType)) { feed.setImage(null); } } @@ -472,15 +452,11 @@ public class SyndicationFeed * @throws FeedException if feed error */ public Document outputW3CDom() - throws FeedException - { - try - { + throws FeedException { + try { SyndFeedOutput feedWriter = new SyndFeedOutput(); return feedWriter.outputW3CDom(feed); - } - catch (FeedException e) - { + } catch (FeedException e) { log.error(e); throw e; } @@ -491,51 +467,49 @@ public class SyndicationFeed * @throws FeedException if feed error */ public String outputString() - throws FeedException - { + throws FeedException { SyndFeedOutput feedWriter = new SyndFeedOutput(); return feedWriter.outputString(feed); } /** * send the output to designated Writer + * * @param writer Writer * @throws FeedException if feed error - * @throws IOException if IO error + * @throws IOException if IO error */ public void output(java.io.Writer writer) - throws FeedException, IOException - { + throws FeedException, IOException { SyndFeedOutput feedWriter = new SyndFeedOutput(); feedWriter.output(feed, writer); } /** * Add a ROME plugin module (e.g. for OpenSearch) at the feed level. + * * @param m module */ - public void addModule(Module m) - { + public void addModule(Module m) { feed.getModules().add(m); } // utility to get config property with default value when not set. - protected static String getDefaultedConfiguration(String key, String dfl) - { + protected static String getDefaultedConfiguration(String key, String dfl) { String result = ConfigurationManager.getProperty(key); return (result == null) ? dfl : result; } // returns absolute URL to download content of bitstream (which might not belong to any Item) - protected String urlOfBitstream(HttpServletRequest request, Bitstream logo) - { + protected String urlOfBitstream(HttpServletRequest request, Bitstream logo) { String name = logo.getName(); - return resolveURL(request,null) + - (uiType.equalsIgnoreCase(UITYPE_XMLUI) ?"/bitstream/id/":"/retrieve/") + - logo.getID()+"/"+(name == null?"":name); + return resolveURL(request, null) + + (uiType.equalsIgnoreCase(UITYPE_XMLUI) ? "/bitstream/id/" : "/retrieve/") + + logo.getID() + "/" + (name == null ? "" : name); } protected String baseURL = null; // cache the result for null + /** * Return a url to the DSpace object, either use the official * handle for the item or build a url based upon the current server. @@ -543,23 +517,17 @@ public class SyndicationFeed * If the dspaceobject is null then a local url to the repository is generated. * * @param request current servlet request - * @param dso The object to reference, null if to the repository. + * @param dso The object to reference, null if to the repository. * @return URL */ - protected String resolveURL(HttpServletRequest request, DSpaceObject dso) - { + protected String resolveURL(HttpServletRequest request, DSpaceObject dso) { // If no object given then just link to the whole repository, // since no offical handle exists so we have to use local resolution. - if (dso == null) - { - if (baseURL == null) - { - if (request == null) - { + if (dso == null) { + if (baseURL == null) { + if (request == null) { baseURL = ConfigurationManager.getProperty("dspace.url"); - } - else - { + } else { baseURL = (request.isSecure()) ? "https://" : "http://"; baseURL += ConfigurationManager.getProperty("dspace.hostname"); baseURL += ":" + request.getServerPort(); @@ -567,30 +535,22 @@ public class SyndicationFeed } } return baseURL; - } - - // return a link to handle in repository - else if (ConfigurationManager.getBooleanProperty("webui.feed.localresolve")) - { + } else if (ConfigurationManager.getBooleanProperty("webui.feed.localresolve")) { + // return a link to handle in repository return resolveURL(request, null) + "/handle/" + dso.getHandle(); - } - - // link to the Handle server or other persistent URL source - else - { + } else { + // link to the Handle server or other persistent URL source return HandleServiceFactory.getInstance().getHandleService().getCanonicalForm(dso.getHandle()); } } // retrieve text for localization key, or mark untranslated - protected String localize(Map labels, String s) - { - return labels.containsKey(s) ? labels.get(s) : ("Untranslated:"+s); + protected String localize(Map labels, String s) { + return labels.containsKey(s) ? labels.get(s) : ("Untranslated:" + s); } // spoonful of syntactic sugar when we only need first value - protected String getOneDC(Item item, String field) - { + protected String getOneDC(Item item, String field) { List dcv = itemService.getMetadataByMetadataString(item, field); return (dcv.size() > 0) ? dcv.get(0).getValue() : null; } diff --git a/dspace-api/src/main/java/org/dspace/app/util/Util.java b/dspace-api/src/main/java/org/dspace/app/util/Util.java index b355e9df93..b3b6049b00 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/Util.java +++ b/dspace-api/src/main/java/org/dspace/app/util/Util.java @@ -14,20 +14,23 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Properties; +import java.util.Set; import java.util.UUID; - import javax.servlet.http.HttpServletRequest; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.core.Constants; import org.dspace.core.I18nUtil; +import org.dspace.core.Utils; /** @@ -38,201 +41,180 @@ import org.dspace.core.I18nUtil; * @version $Revision$ */ public class Util { - // cache for source version result - private static String sourceVersion = null; + // cache for source version result + private static String sourceVersion = null; - private static Logger log = Logger.getLogger(Util.class); - - /** - * Utility method to convert spaces in a string to HTML non-break space - * elements. - * - * @param s - * string to change spaces in - * @return the string passed in with spaces converted to HTML non-break - * spaces - */ - public static String nonBreakSpace(String s) { - StringBuffer newString = new StringBuffer(); - - for (int i = 0; i < s.length(); i++) - { - char ch = s.charAt(i); - - if (ch == ' ') - { - newString.append(" "); - } - else - { - newString.append(ch); - } + private static Logger log = Logger.getLogger(Util.class); + + /** + * Default constructor. Must be protected as org.dspace.xmlworkflow.WorkflowUtils extends it + */ + protected Util() { } + + /** + * Utility method to convert spaces in a string to HTML non-break space + * elements. + * + * @param s string to change spaces in + * @return the string passed in with spaces converted to HTML non-break + * spaces + */ + public static String nonBreakSpace(String s) { + StringBuffer newString = new StringBuffer(); + + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + + if (ch == ' ') { + newString.append(" "); + } else { + newString.append(ch); } - - return newString.toString(); } - /** - * Encode a bitstream name for inclusion in a URL in an HTML document. This - * differs from the usual URL-encoding, since we want pathname separators to - * be passed through verbatim; this is required so that relative paths in - * bitstream names and HTML references work correctly. - *

- * If the link to a bitstream is generated with the pathname separators - * escaped (e.g. "%2F" instead of "/") then the Web user agent perceives it - * to be one pathname element, and relative URI paths within that document - * containing ".." elements will be handled incorrectly. - *

- * - * @param stringIn - * input string to encode - * @param encoding - * character encoding, e.g. UTF-8 - * @return the encoded string - * @throws java.io.UnsupportedEncodingException if encoding error - */ - public static String encodeBitstreamName(String stringIn, String encoding) throws java.io.UnsupportedEncodingException { - // FIXME: This should be moved elsewhere, as it is used outside the UI - if (stringIn == null) - { - return ""; - } + return newString.toString(); + } - StringBuffer out = new StringBuffer(); - - final String[] pctEncoding = { "%00", "%01", "%02", "%03", "%04", - "%05", "%06", "%07", "%08", "%09", "%0a", "%0b", "%0c", "%0d", - "%0e", "%0f", "%10", "%11", "%12", "%13", "%14", "%15", "%16", - "%17", "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f", - "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", "%28", - "%29", "%2a", "%2b", "%2c", "%2d", "%2e", "%2f", "%30", "%31", - "%32", "%33", "%34", "%35", "%36", "%37", "%38", "%39", "%3a", - "%3b", "%3c", "%3d", "%3e", "%3f", "%40", "%41", "%42", "%43", - "%44", "%45", "%46", "%47", "%48", "%49", "%4a", "%4b", "%4c", - "%4d", "%4e", "%4f", "%50", "%51", "%52", "%53", "%54", "%55", - "%56", "%57", "%58", "%59", "%5a", "%5b", "%5c", "%5d", "%5e", - "%5f", "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67", - "%68", "%69", "%6a", "%6b", "%6c", "%6d", "%6e", "%6f", "%70", - "%71", "%72", "%73", "%74", "%75", "%76", "%77", "%78", "%79", - "%7a", "%7b", "%7c", "%7d", "%7e", "%7f", "%80", "%81", "%82", - "%83", "%84", "%85", "%86", "%87", "%88", "%89", "%8a", "%8b", - "%8c", "%8d", "%8e", "%8f", "%90", "%91", "%92", "%93", "%94", - "%95", "%96", "%97", "%98", "%99", "%9a", "%9b", "%9c", "%9d", - "%9e", "%9f", "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", - "%a7", "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af", - "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", "%b8", - "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", "%c0", "%c1", - "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", "%c8", "%c9", "%ca", - "%cb", "%cc", "%cd", "%ce", "%cf", "%d0", "%d1", "%d2", "%d3", - "%d4", "%d5", "%d6", "%d7", "%d8", "%d9", "%da", "%db", "%dc", - "%dd", "%de", "%df", "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", - "%e6", "%e7", "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", - "%ef", "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", - "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff" }; - - byte[] bytes = stringIn.getBytes(encoding); - - for (int i = 0; i < bytes.length; i++) - { - // Any unreserved char or "/" goes through unencoded - if ((bytes[i] >= 'A' && bytes[i] <= 'Z') - || (bytes[i] >= 'a' && bytes[i] <= 'z') - || (bytes[i] >= '0' && bytes[i] <= '9') || bytes[i] == '-' - || bytes[i] == '.' || bytes[i] == '_' || bytes[i] == '~' - || bytes[i] == '/') - { - out.append((char) bytes[i]); - } - else if (bytes[i] >= 0) - { - // encode other chars (byte code < 128) - out.append(pctEncoding[bytes[i]]); - } - else - { - // encode other chars (byte code > 127, so it appears as - // negative in Java signed byte data type) - out.append(pctEncoding[256 + bytes[i]]); - } - } - log.debug("encoded \"" + stringIn + "\" to \"" + out.toString() + "\""); - - return out.toString(); + /** + * Encode a bitstream name for inclusion in a URL in an HTML document. This + * differs from the usual URL-encoding, since we want pathname separators to + * be passed through verbatim; this is required so that relative paths in + * bitstream names and HTML references work correctly. + *

+ * If the link to a bitstream is generated with the pathname separators + * escaped (e.g. "%2F" instead of "/") then the Web user agent perceives it + * to be one pathname element, and relative URI paths within that document + * containing ".." elements will be handled incorrectly. + *

+ * + * @param stringIn input string to encode + * @param encoding character encoding, e.g. UTF-8 + * @return the encoded string + * @throws java.io.UnsupportedEncodingException if encoding error + */ + public static String encodeBitstreamName(String stringIn, String encoding) + throws java.io.UnsupportedEncodingException { + // FIXME: This should be moved elsewhere, as it is used outside the UI + if (stringIn == null) { + return ""; } - /** Version of encodeBitstreamName with one parameter, uses default encoding - *

- * @param stringIn - * input string to encode - * @return the encoded string - * @throws java.io.UnsupportedEncodingException if encoding error - */ - public static String encodeBitstreamName(String stringIn) throws java.io.UnsupportedEncodingException { - return encodeBitstreamName(stringIn, Constants.DEFAULT_ENCODING); - } + StringBuffer out = new StringBuffer(); - /** - * Formats the file size. Examples: - * - * - 50 = 50B - * - 1024 = 1KB - * - 1,024,000 = 1MB etc - * - * The numbers are formatted using java Locales - * - * @param in The number to convert - * @return the file size as a String - */ - public static String formatFileSize(double in) { - // Work out the size of the file, and format appropriatly - // FIXME: When full i18n support is available, use the user's Locale - // rather than the default Locale. - NumberFormat nf = NumberFormat.getNumberInstance(Locale.getDefault()); - DecimalFormat df = (DecimalFormat)nf; - df.applyPattern("###,###.##"); - if (in < 1024) - { - df.applyPattern("0"); - return df.format(in) + " " + "B"; - } - else if (in < 1024000) - { - in = in / 1024; - return df.format(in) + " " + "kB"; - } - else if (in < 1024000000) - { - in = in / 1024000; - return df.format(in) + " " + "MB"; - } - else - { - in = in / 1024000000; - return df.format(in) + " " + "GB"; - } - } + final String[] pctEncoding = {"%00", "%01", "%02", "%03", "%04", + "%05", "%06", "%07", "%08", "%09", "%0a", "%0b", "%0c", "%0d", + "%0e", "%0f", "%10", "%11", "%12", "%13", "%14", "%15", "%16", + "%17", "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f", + "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", "%28", + "%29", "%2a", "%2b", "%2c", "%2d", "%2e", "%2f", "%30", "%31", + "%32", "%33", "%34", "%35", "%36", "%37", "%38", "%39", "%3a", + "%3b", "%3c", "%3d", "%3e", "%3f", "%40", "%41", "%42", "%43", + "%44", "%45", "%46", "%47", "%48", "%49", "%4a", "%4b", "%4c", + "%4d", "%4e", "%4f", "%50", "%51", "%52", "%53", "%54", "%55", + "%56", "%57", "%58", "%59", "%5a", "%5b", "%5c", "%5d", "%5e", + "%5f", "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67", + "%68", "%69", "%6a", "%6b", "%6c", "%6d", "%6e", "%6f", "%70", + "%71", "%72", "%73", "%74", "%75", "%76", "%77", "%78", "%79", + "%7a", "%7b", "%7c", "%7d", "%7e", "%7f", "%80", "%81", "%82", + "%83", "%84", "%85", "%86", "%87", "%88", "%89", "%8a", "%8b", + "%8c", "%8d", "%8e", "%8f", "%90", "%91", "%92", "%93", "%94", + "%95", "%96", "%97", "%98", "%99", "%9a", "%9b", "%9c", "%9d", + "%9e", "%9f", "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", + "%a7", "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af", + "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", "%b8", + "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", "%c0", "%c1", + "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", "%c8", "%c9", "%ca", + "%cb", "%cc", "%cd", "%ce", "%cf", "%d0", "%d1", "%d2", "%d3", + "%d4", "%d5", "%d6", "%d7", "%d8", "%d9", "%da", "%db", "%dc", + "%dd", "%de", "%df", "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", + "%e6", "%e7", "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", + "%ef", "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff"}; + + byte[] bytes = stringIn.getBytes(encoding); + + for (int i = 0; i < bytes.length; i++) { + // Any unreserved char or "/" goes through unencoded + if ((bytes[i] >= 'A' && bytes[i] <= 'Z') + || (bytes[i] >= 'a' && bytes[i] <= 'z') + || (bytes[i] >= '0' && bytes[i] <= '9') || bytes[i] == '-' + || bytes[i] == '.' || bytes[i] == '_' || bytes[i] == '~' + || bytes[i] == '/') { + out.append((char) bytes[i]); + } else if (bytes[i] >= 0) { + // encode other chars (byte code < 128) + out.append(pctEncoding[bytes[i]]); + } else { + // encode other chars (byte code > 127, so it appears as + // negative in Java signed byte data type) + out.append(pctEncoding[256 + bytes[i]]); + } + } + log.debug("encoded \"" + stringIn + "\" to \"" + out.toString() + "\""); + + return out.toString(); + } + + /** + * Version of encodeBitstreamName with one parameter, uses default encoding + *

+ * + * @param stringIn input string to encode + * @return the encoded string + * @throws java.io.UnsupportedEncodingException if encoding error + */ + public static String encodeBitstreamName(String stringIn) throws java.io.UnsupportedEncodingException { + return encodeBitstreamName(stringIn, Constants.DEFAULT_ENCODING); + } + + /** + * Formats the file size. Examples: + * + * - 50 = 50B + * - 1024 = 1KB + * - 1,024,000 = 1MB etc + * + * The numbers are formatted using java Locales + * + * @param in The number to convert + * @return the file size as a String + */ + public static String formatFileSize(double in) { + // Work out the size of the file, and format appropriatly + // FIXME: When full i18n support is available, use the user's Locale + // rather than the default Locale. + NumberFormat nf = NumberFormat.getNumberInstance(Locale.getDefault()); + DecimalFormat df = (DecimalFormat) nf; + df.applyPattern("###,###.##"); + if (in < 1024) { + df.applyPattern("0"); + return df.format(in) + " " + "B"; + } else if (in < 1024000) { + in = in / 1024; + return df.format(in) + " " + "kB"; + } else if (in < 1024000000) { + in = in / 1024000; + return df.format(in) + " " + "MB"; + } else { + in = in / 1024000000; + return df.format(in) + " " + "GB"; + } + } /** * Obtain a parameter from the given request as an int. -1 is * returned if the parameter is garbled or does not exist. * - * @param request - * the HTTP request - * @param param - * the name of the parameter - * + * @param request the HTTP request + * @param param the name of the parameter * @return the integer value of the parameter, or -1 */ - public static int getIntParameter(HttpServletRequest request, String param) - { + public static int getIntParameter(HttpServletRequest request, String param) { String val = request.getParameter(param); - try - { + try { return Integer.parseInt(val.trim()); - } - catch (Exception e) - { + } catch (Exception e) { // Problem with parameter return -1; } @@ -242,70 +224,53 @@ public class Util { * Obtain a parameter from the given request as a UUID. null is * returned if the parameter is garbled or does not exist. * - * @param request - * the HTTP request - * @param param - * the name of the parameter - * + * @param request the HTTP request + * @param param the name of the parameter * @return the integer value of the parameter, or -1 */ - public static UUID getUUIDParameter(HttpServletRequest request, String param) - { + public static UUID getUUIDParameter(HttpServletRequest request, String param) { String val = request.getParameter(param); - if (StringUtils.isEmpty(val)) - { + if (StringUtils.isEmpty(val)) { return null; } - try - { + try { return UUID.fromString(val.trim()); - } - catch (Exception e) - { + } catch (Exception e) { // at least log this error to make debugging easier // do not silently return null only. - log.warn("Unable to recoginze UUID from String \"" - + val + "\". Will return null.", e); + log.warn("Unable to recoginze UUID from String \"" + + val + "\". Will return null.", e); // Problem with parameter return null; } } - + /** * Obtain a List of UUID parameters from the given request as an UUID. null * is returned if parameter doesn't exist. null is returned in * position of the list if that particular value is garbled. * - * @param request - * the HTTP request - * @param param - * the name of the parameter - * + * @param request the HTTP request + * @param param the name of the parameter * @return list of UUID or null */ public static List getUUIDParameters(HttpServletRequest request, - String param) - { + String param) { String[] request_values = request.getParameterValues(param); - if (request_values == null) - { + if (request_values == null) { return null; } List return_values = new ArrayList(request_values.length); - for (String s : request_values) - { - try - { + for (String s : request_values) { + try { return_values.add(UUID.fromString(s.trim())); - } - catch (Exception e) - { + } catch (Exception e) { // Problem with parameter, stuff null in the list - return_values.add(null); + return_values.add(null); } } @@ -318,33 +283,24 @@ public class Util { * is returned if parameter doesn't exist. -1 is returned in * array locations if that particular value is garbled. * - * @param request - * the HTTP request - * @param param - * the name of the parameter - * + * @param request the HTTP request + * @param param the name of the parameter * @return array of integers or null */ public static int[] getIntParameters(HttpServletRequest request, - String param) - { + String param) { String[] request_values = request.getParameterValues(param); - if (request_values == null) - { + if (request_values == null) { return null; } int[] return_values = new int[request_values.length]; - for (int x = 0; x < return_values.length; x++) - { - try - { + for (int x = 0; x < return_values.length; x++) { + try { return_values[x] = Integer.parseInt(request_values[x]); - } - catch (Exception e) - { + } catch (Exception e) { // Problem with parameter, stuff -1 in this slot return_values[x] = -1; } @@ -358,18 +314,14 @@ public class Util { * false is returned if the parameter is garbled or does not * exist. * - * @param request - * the HTTP request - * @param param - * the name of the parameter - * + * @param request the HTTP request + * @param param the name of the parameter * @return the integer value of the parameter, or -1 */ public static boolean getBoolParameter(HttpServletRequest request, - String param) - { + String param) { return ((request.getParameter(param) != null) && request.getParameter( - param).equals("true")); + param).equals("true")); } /** @@ -378,23 +330,17 @@ public class Util { * should be supplied, since often the browser will submit a form with no * submit button pressed if the user presses enter. * - * @param request - * the HTTP request - * @param def - * the default button - * + * @param request the HTTP request + * @param def the default button * @return the button pressed */ - public static String getSubmitButton(HttpServletRequest request, String def) - { + public static String getSubmitButton(HttpServletRequest request, String def) { Enumeration e = request.getParameterNames(); - while (e.hasMoreElements()) - { + while (e.hasMoreElements()) { String parameterName = (String) e.nextElement(); - if (parameterName.startsWith("submit")) - { + if (parameterName.startsWith("submit")) { return parameterName; } } @@ -404,34 +350,24 @@ public class Util { /** * Gets Maven version string of the source that built this instance. + * * @return string containing version, e.g. "1.5.2"; ends in "-SNAPSHOT" for development versions. */ - public static String getSourceVersion() - { - if (sourceVersion == null) - { + public static String getSourceVersion() { + if (sourceVersion == null) { Properties constants = new Properties(); InputStream cis = null; - try - { + try { cis = Util.class.getResourceAsStream("/META-INF/maven/org.dspace/dspace-api/pom.properties"); constants.load(cis); - } - catch(Exception e) - { - log.error(e.getMessage(),e); - } - finally - { - if (cis != null) - { - try - { + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + if (cis != null) { + try { cis.close(); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Unable to close input stream", e); } } @@ -445,29 +381,23 @@ public class Util { /** * Get a list of all the respective "displayed-value(s)" from the given * "stored-value(s)" for a specific metadata field of a DSpace Item, by - * reading input-forms.xml - * - * @param item - * The Dspace Item - * @param values - * A Metadatum[] array of the specific "stored-value(s)" - * @param schema - * A String with the schema name of the metadata field - * @param element - * A String with the element name of the metadata field - * @param qualifier - * A String with the qualifier name of the metadata field - * @param locale locale + * reading submission-forms.xml + * + * @param item The Dspace Item + * @param values A Metadatum[] array of the specific "stored-value(s)" + * @param schema A String with the schema name of the metadata field + * @param element A String with the element name of the metadata field + * @param qualifier A String with the qualifier name of the metadata field + * @param locale locale * @return A list of the respective "displayed-values" - * @throws SQLException if database error + * @throws SQLException if database error * @throws DCInputsReaderException if reader error */ public static List getControlledVocabulariesDisplayValueLocalized( - Item item, List values, String schema, String element, - String qualifier, Locale locale) throws SQLException, - DCInputsReaderException - { + Item item, List values, String schema, String element, + String qualifier, Locale locale) throws SQLException, + DCInputsReaderException { List toReturn = new ArrayList(); DCInput myInputs = null; boolean myInputsFound = false; @@ -476,79 +406,96 @@ public class Util { Collection collection = item.getOwningCollection(); - if (collection == null) - { + if (collection == null) { // set an empty handle so to get the default input set col_handle = ""; - } - else - { + } else { col_handle = collection.getHandle(); } // Read the input form file for the specific collection DCInputsReader inputsReader = new DCInputsReader(formFileName); - DCInputSet inputSet = inputsReader.getInputs(col_handle); + List inputSets = inputsReader.getInputsByCollectionHandle(col_handle); - // Replace the values of Metadatum[] with the correct ones in case of + // Replace the values of Metadatum[] with the correct ones in case + // of // controlled vocabularies - String currentField = schema + "." + element - + (qualifier == null ? "" : "." + qualifier); + String currentField = Utils.standardize(schema, element, qualifier, "."); - if (inputSet != null) - { + for (DCInputSet inputSet : inputSets) { - int pageNums = inputSet.getNumberPages(); + if (inputSet != null) { - for (int p = 0; p < pageNums; p++) - { + int fieldsNums = inputSet.getNumberFields(); - DCInput[] inputs = inputSet.getPageRows(p, false, false); + for (int p = 0; p < fieldsNums; p++) { - if (inputs != null) - { + DCInput[][] inputs = inputSet.getFields(); - for (int i = 0; i < inputs.length; i++) - { - String inputField = inputs[i].getSchema() - + "." - + inputs[i].getElement() - + (inputs[i].getQualifier() == null ? "" : "." - + inputs[i].getQualifier()); - if (currentField.equals(inputField)) - { - - myInputs = inputs[i]; - myInputsFound = true; - break; + if (inputs != null) { + for (int i = 0; i < inputs.length; i++) { + for (int j = 0; j < inputs[i].length; j++) { + String inputField = Utils + .standardize(inputs[i][j].getSchema(), inputs[i][j].getElement(), + inputs[i][j].getQualifier(), "."); + if (currentField.equals(inputField)) { + myInputs = inputs[i][j]; + myInputsFound = true; + break; + } + } } } + if (myInputsFound) { + break; + } + } + } + + if (myInputsFound) { + + for (MetadataValue value : values) { + + String pairsName = myInputs.getPairsType(); + String stored_value = value.getValue(); + String displayVal = myInputs.getDisplayString(pairsName, stored_value); + + if (displayVal != null && !"".equals(displayVal)) { + + toReturn.add(displayVal); + } + } - if (myInputsFound) - break; } } - - if (myInputsFound) - { - - for (MetadataValue value : values) { - - String pairsName = myInputs.getPairsType(); - String stored_value = value.getValue(); - String displayVal = myInputs.getDisplayString(pairsName, - stored_value); - - if (displayVal != null && !"".equals(displayVal)) { - - toReturn.add(displayVal); - } - - } - } - return toReturn; } + + public static List differenceInSubmissionFields(Collection fromCollection, Collection toCollection) + throws DCInputsReaderException { + DCInputsReader reader = new DCInputsReader(); + List from = reader.getInputsByCollectionHandle(fromCollection.getHandle()); + List to = reader.getInputsByCollectionHandle(toCollection.getHandle()); + + Set fromFieldName = new HashSet<>(); + Set toFieldName = new HashSet<>(); + for (DCInputSet ff : from) { + for (DCInput[] fdcrow : ff.getFields()) { + for (DCInput fdc : fdcrow) { + fromFieldName.add(fdc.getFieldName()); + } + } + } + for (DCInputSet tt : to) { + for (DCInput[] tdcrow : tt.getFields()) { + for (DCInput tdc : tdcrow) { + toFieldName.add(tdc.getFieldName()); + } + } + } + + return ListUtils.removeAll(fromFieldName, toFieldName); + } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/Version.java b/dspace-api/src/main/java/org/dspace/app/util/Version.java index 3f50ec877f..095cc90f10 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/Version.java +++ b/dspace-api/src/main/java/org/dspace/app/util/Version.java @@ -9,7 +9,6 @@ package org.dspace.app.util; import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; import java.util.List; import java.util.Properties; @@ -22,11 +21,15 @@ import org.dspace.services.factory.DSpaceServicesFactory; * * @author mwood */ -public class Version -{ +public class Version { + + /** + * Default constructor + */ + private Version() { } + public static void main(String[] argv) - throws IOException - { + throws IOException { InputStream propStream; Properties sys = System.getProperties(); @@ -38,8 +41,7 @@ public class Version // SCM revision Properties scm = new Properties(); propStream = Version.class.getResourceAsStream("/scm.properties"); - if (null != propStream) - { + if (null != propStream) { scm.load(propStream); } System.out.printf(" SCM revision: %s\n", scm.get("revision")); @@ -54,10 +56,9 @@ public class Version // UIs used List apps = UtilServiceFactory.getInstance().getWebAppService().getApps(); System.out.println(" Applications:"); - for (WebApp app : apps) - { + for (WebApp app : apps) { System.out.printf(" %s at %s\n", - app.getAppName(), app.getUrl()); + app.getAppName(), app.getUrl()); } // Is Discovery available? @@ -65,8 +66,7 @@ public class Version String[] consumers = config.getArrayProperty("event.dispatcher.default.consumers"); String discoveryStatus = "not enabled."; for (String consumer : consumers) { - if (consumer.equals("discovery")) - { + if (consumer.equals("discovery")) { discoveryStatus = "enabled."; break; } @@ -81,8 +81,7 @@ public class Version // ant version Properties ant = new Properties(); propStream = Version.class.getResourceAsStream("/ant.properties"); - if (null != propStream) - { + if (null != propStream) { ant.load(propStream); } System.out.printf(" Ant version: %s\n", @@ -91,8 +90,7 @@ public class Version // maven version Properties maven = new Properties(); propStream = Version.class.getResourceAsStream("/maven.properties"); - if (null != propStream) - { + if (null != propStream) { maven.load(propStream); } System.out.printf(" Maven version: %s\n", diff --git a/dspace-api/src/main/java/org/dspace/app/util/WebApp.java b/dspace-api/src/main/java/org/dspace/app/util/WebApp.java index cb1aaf003e..7cd2bd8fea 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/WebApp.java +++ b/dspace-api/src/main/java/org/dspace/app/util/WebApp.java @@ -7,26 +7,34 @@ */ package org.dspace.app.util; +import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; -import javax.persistence.*; -import java.util.Date; - /** * Database entity representation of the webApp table * * @author kevinvandevelde at atmire.com */ @Entity -@Table(name="webapp") +@Table(name = "webapp") public class WebApp implements ReloadableEntity { @Id - @Column(name="webapp_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="webapp_seq") - @SequenceGenerator(name="webapp_seq", sequenceName="webapp_seq", allocationSize = 1) + @Column(name = "webapp_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "webapp_seq") + @SequenceGenerator(name = "webapp_seq", sequenceName = "webapp_seq", allocationSize = 1) private Integer id; @Column(name = "appname", unique = true, length = 32) @@ -46,8 +54,7 @@ public class WebApp implements ReloadableEntity { * Protected constructor, create object using: * {@link org.dspace.app.util.service.WebAppService#create(Context, String, String, Date, int)} */ - protected WebApp() - { + protected WebApp() { } diff --git a/dspace-api/src/main/java/org/dspace/app/util/WebAppServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/util/WebAppServiceImpl.java index a50b798a34..84cc21e642 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/WebAppServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/util/WebAppServiceImpl.java @@ -7,6 +7,12 @@ */ package org.dspace.app.util; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; @@ -18,12 +24,6 @@ import org.dspace.app.util.service.WebAppService; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - /** * Service implementation for the WebApp object. * This class is responsible for all business logic calls for the WebApp object and is autowired by spring. @@ -39,8 +39,7 @@ public class WebAppServiceImpl implements WebAppService { protected WebAppDAO webAppDAO; - protected WebAppServiceImpl() - { + protected WebAppServiceImpl() { } @@ -66,8 +65,7 @@ public class WebAppServiceImpl implements WebAppService { } @Override - public List getApps() - { + public List getApps() { ArrayList apps = new ArrayList<>(); Context context = null; @@ -76,14 +74,12 @@ public class WebAppServiceImpl implements WebAppService { context = new Context(); List webApps = findAll(context); - for (WebApp app : webApps) - { + for (WebApp app : webApps) { method = new HttpHead(app.getUrl()); HttpClient client = new DefaultHttpClient(); HttpResponse response = client.execute(method); int status = response.getStatusLine().getStatusCode(); - if (status != HttpStatus.SC_OK) - { + if (status != HttpStatus.SC_OK) { delete(context, app ); @@ -97,12 +93,10 @@ public class WebAppServiceImpl implements WebAppService { } catch (IOException e) { log.error("Failure checking for a running webapp", e); } finally { - if (null != method) - { + if (null != method) { method.releaseConnection(); } - if (null != context) - { + if (null != context) { context.abort(); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/XMLUtils.java b/dspace-api/src/main/java/org/dspace/app/util/XMLUtils.java index b5533767ca..7f1b72a565 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/XMLUtils.java +++ b/dspace-api/src/main/java/org/dspace/app/util/XMLUtils.java @@ -17,30 +17,28 @@ import org.w3c.dom.NodeList; /** * Simple class to read information from small XML using DOM manipulation - * + * * @author Andrea Bollini - * */ -public class XMLUtils -{ +public class XMLUtils { + /** - * - * @param dataRoot - * the starting node - * @param name - * the name of the subelement to find - * @return the list of all DOM Element with the provided name direct child - * of the starting node + * Default constructor */ - public static List getElementList(Element dataRoot, String name) - { + private XMLUtils() { } + + /** + * @param dataRoot the starting node + * @param name the name of the subelement to find + * @return the list of all DOM Element with the provided name direct child + * of the starting node + */ + public static List getElementList(Element dataRoot, String name) { NodeList list = dataRoot.getElementsByTagName(name); List listElements = new ArrayList(); - for (int i = 0; i < list.getLength(); i++) - { + for (int i = 0; i < list.getLength(); i++) { Element item = (Element) list.item(i); - if (item.getParentNode().equals(dataRoot)) - { + if (item.getParentNode().equals(dataRoot)) { listElements.add(item); } } @@ -48,105 +46,84 @@ public class XMLUtils } /** - * - * @param dataRoot - * the starting node - * @param name - * the name of the sub element - * @param attr - * the attribute to get + * @param dataRoot the starting node + * @param name the name of the sub element + * @param attr the attribute to get * @return the value of the attribute for the sub element with the specified - * name in the starting node + * name in the starting node */ public static String getElementAttribute(Element dataRoot, String name, - String attr) - { + String attr) { Element element = getSingleElement(dataRoot, name); String attrValue = null; - if (element != null) - { + if (element != null) { attrValue = element.getAttribute(attr); - if (StringUtils.isNotBlank(attrValue)) - { + if (StringUtils.isNotBlank(attrValue)) { attrValue = attrValue.trim(); - } - else + } else { attrValue = null; + } } return attrValue; } /** - * - * @param dataRoot - * the starting node - * @param name - * the name of the sub element + * @param dataRoot the starting node + * @param name the name of the sub element * @return the text content of the sub element with the specified name in - * the starting node + * the starting node */ - public static String getElementValue(Element dataRoot, String name) - { + public static String getElementValue(Element dataRoot, String name) { Element element = getSingleElement(dataRoot, name); String elementValue = null; - if (element != null) - { + if (element != null) { elementValue = element.getTextContent(); - if (StringUtils.isNotBlank(elementValue)) - { + if (StringUtils.isNotBlank(elementValue)) { elementValue = elementValue.trim(); - } - else + } else { elementValue = null; + } } return elementValue; } /** * Return the first element child with the specified name - * - * @param dataRoot - * the starting node - * @param name - * the name of sub element to look for + * + * @param dataRoot the starting node + * @param name the name of sub element to look for * @return the first child element or null if no present */ - public static Element getSingleElement(Element dataRoot, String name) - { + public static Element getSingleElement(Element dataRoot, String name) { List nodeList = getElementList(dataRoot, name); Element element = null; - if (nodeList != null && nodeList.size() > 0) - { + if (nodeList != null && nodeList.size() > 0) { element = (Element) nodeList.get(0); } return element; } /** - * - * @param rootElement - * the starting node - * @param subElementName - * the name of the subelement to find + * @param rootElement the starting node + * @param subElementName the name of the subelement to find * @return a list of string including all the text contents of the sub - * element with the specified name. If there are not sub element - * with the supplied name the method will return null + * element with the specified name. If there are not sub element + * with the supplied name the method will return null */ public static List getElementValueList(Element rootElement, - String subElementName) - { - if (rootElement == null) + String subElementName) { + if (rootElement == null) { return null; + } List subElements = getElementList(rootElement, subElementName); - if (subElements == null) + if (subElements == null) { return null; + } List result = new LinkedList(); - for (Element el : subElements) - { - if (StringUtils.isNotBlank(el.getTextContent())) - { + for (Element el : subElements) { + if (StringUtils.isNotBlank(el.getTextContent())) { result.add(el.getTextContent().trim()); } } @@ -155,38 +132,34 @@ public class XMLUtils /** * root/subElement[]/field1, field2, fieldN - * - * @param rootElement - * the starting node - * @param subElementName - * the name of the sub element to work on - * @param fieldsName - * the names of the sub-sub-elements from which get the text - * content + * + * @param rootElement the starting node + * @param subElementName the name of the sub element to work on + * @param fieldsName the names of the sub-sub-elements from which get the text + * content * @return a list of array strings. The length of the array is equals to the - * number of fields required. For any fields the first textual value - * found in the sub element is used, null if no value is present + * number of fields required. For any fields the first textual value + * found in the sub element is used, null if no value is present */ public static List getElementValueArrayList(Element rootElement, - String subElementName, String... fieldsName) - { - if (rootElement == null) + String subElementName, String... fieldsName) { + if (rootElement == null) { return null; + } List subElements = getElementList(rootElement, subElementName); - if (subElements == null) + if (subElements == null) { return null; + } List result = new LinkedList(); - for (Element el : subElements) - { + for (Element el : subElements) { String[] tmp = new String[fieldsName.length]; - for (int idx = 0; idx < fieldsName.length; idx++) - { + for (int idx = 0; idx < fieldsName.length; idx++) { tmp[idx] = XMLUtils.getElementValue(el, fieldsName[idx]); } result.add(tmp); } return result; } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/app/util/dao/WebAppDAO.java b/dspace-api/src/main/java/org/dspace/app/util/dao/WebAppDAO.java index 671ebc6287..fbade45c19 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/dao/WebAppDAO.java +++ b/dspace-api/src/main/java/org/dspace/app/util/dao/WebAppDAO.java @@ -12,13 +12,13 @@ import org.dspace.core.GenericDAO; /** * Database Access Object interface class for the WebApp object. - * The implementation of this class is responsible for all database calls for the WebApp object and is autowired by spring + * The implementation of this class is responsible for all database calls for the WebApp object and is autowired by + * spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com */ -public interface WebAppDAO extends GenericDAO -{ +public interface WebAppDAO extends GenericDAO { } diff --git a/dspace-api/src/main/java/org/dspace/app/util/dao/impl/WebAppDAOImpl.java b/dspace-api/src/main/java/org/dspace/app/util/dao/impl/WebAppDAOImpl.java index 4b9edecf77..c8c5014b54 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/dao/impl/WebAppDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/util/dao/impl/WebAppDAOImpl.java @@ -18,10 +18,8 @@ import org.dspace.core.AbstractHibernateDAO; * * @author kevinvandevelde at atmire.com */ -public class WebAppDAOImpl extends AbstractHibernateDAO implements WebAppDAO -{ - protected WebAppDAOImpl() - { +public class WebAppDAOImpl extends AbstractHibernateDAO implements WebAppDAO { + protected WebAppDAOImpl() { super(); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/factory/UtilServiceFactory.java b/dspace-api/src/main/java/org/dspace/app/util/factory/UtilServiceFactory.java index 86f8456ea9..3b2dcaf646 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/factory/UtilServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/app/util/factory/UtilServiceFactory.java @@ -13,21 +13,21 @@ import org.dspace.app.util.service.WebAppService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the util package, use UtilServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the util package, use UtilServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ -public abstract class UtilServiceFactory -{ +public abstract class UtilServiceFactory { public abstract WebAppService getWebAppService(); public abstract OpenSearchService getOpenSearchService(); public abstract MetadataExposureService getMetadataExposureService(); - public static UtilServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("appUtilServiceFactory", UtilServiceFactory.class); + public static UtilServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("appUtilServiceFactory", UtilServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/factory/UtilServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/app/util/factory/UtilServiceFactoryImpl.java index 68ccd5a55d..f301926a67 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/factory/UtilServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/util/factory/UtilServiceFactoryImpl.java @@ -13,7 +13,8 @@ import org.dspace.app.util.service.WebAppService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the util package, use UtilServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the util package, use UtilServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/app/util/package-info.java b/dspace-api/src/main/java/org/dspace/app/util/package-info.java index faf86e7289..a234610122 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/package-info.java +++ b/dspace-api/src/main/java/org/dspace/app/util/package-info.java @@ -7,8 +7,9 @@ */ /** - *

Miscellaneous utility classes. Includes supporting classes for AuthorizeManager, input forms, submission process, webapp init/cleanup, Google Scholar metadata, metadata visibility, OpenSearch, syndication feeds and more.

- * + *

Miscellaneous utility classes. Includes supporting classes for AuthorizeManager, input forms, + * submission process, webapp init/cleanup, Google Scholar metadata, metadata visibility, OpenSearch, + * syndication feeds and more.

*/ package org.dspace.app.util; diff --git a/dspace-api/src/main/java/org/dspace/app/util/service/MetadataExposureService.java b/dspace-api/src/main/java/org/dspace/app/util/service/MetadataExposureService.java index dfd646ff2c..4e2dc18bc4 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/service/MetadataExposureService.java +++ b/dspace-api/src/main/java/org/dspace/app/util/service/MetadataExposureService.java @@ -7,10 +7,10 @@ */ package org.dspace.app.util.service; -import org.dspace.core.Context; - import java.sql.SQLException; +import org.dspace.core.Context; + /** * Static utility class to manage configuration for exposure (hiding) of * certain Item metadata fields. @@ -29,20 +29,20 @@ import java.sql.SQLException; * scalable. * * Algorithm is as follows: - * 1. If a Context is provided and it has a user who is Administrator, - * always grant access (return false). - * 2. Return true if field is on the hidden list, false otherwise. + * 1. If a Context is provided and it has a user who is Administrator, + * always grant access (return false). + * 2. Return true if field is on the hidden list, false otherwise. * * The internal maps are populated from DSpace Configuration at the first * call, in case the properties are not available in the static context. * * Configuration Properties: - * ## hide a single metadata field - * #metadata.hide.SCHEMA.ELEMENT[.QUALIFIER] = true - * # example: dc.type - * metadata.hide.dc.type = true - * # example: dc.description.provenance - * metadata.hide.dc.description.provenance = true + * ## hide a single metadata field + * #metadata.hide.SCHEMA.ELEMENT[.QUALIFIER] = true + * # example: dc.type + * metadata.hide.dc.type = true + * # example: dc.description.provenance + * metadata.hide.dc.description.provenance = true * * @author Larry Stone * @version $Revision: 3734 $ @@ -50,16 +50,16 @@ import java.sql.SQLException; public interface MetadataExposureService { /** - * Returns whether the given metadata field should be exposed (visible). The metadata field is in the DSpace's DC notation: schema.element.qualifier + * Returns whether the given metadata field should be exposed (visible). The metadata field is in the DSpace's DC + * notation: schema.element.qualifier * - * @param context DSpace context - * @param schema metadata field schema (namespace), e.g. "dc" - * @param element metadata field element + * @param context DSpace context + * @param schema metadata field schema (namespace), e.g. "dc" + * @param element metadata field element * @param qualifier metadata field qualifier - * * @return true (hidden) or false (exposed) * @throws SQLException if database error */ public boolean isHidden(Context context, String schema, String element, String qualifier) - throws SQLException; + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/app/util/service/OpenSearchService.java b/dspace-api/src/main/java/org/dspace/app/util/service/OpenSearchService.java index 9b41d9c6f2..5b54bfcddd 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/service/OpenSearchService.java +++ b/dspace-api/src/main/java/org/dspace/app/util/service/OpenSearchService.java @@ -7,15 +7,15 @@ */ package org.dspace.app.util.service; -import org.dspace.content.DSpaceObject; -import org.dspace.core.Context; -import org.w3c.dom.Document; - import java.io.IOException; import java.sql.SQLException; import java.util.List; import java.util.Map; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; +import org.w3c.dom.Document; + /** * Utility Class with static methods for producing OpenSearch-compliant search results, * and the OpenSearch description document. @@ -31,7 +31,6 @@ import java.util.Map; *

* * @author Richard Rodgers - * */ public interface OpenSearchService { @@ -71,39 +70,42 @@ public interface OpenSearchService { /** * Returns a formatted set of search results as a string * - * @param context DSpace Context - * @param format results format - html, rss or atom - * @param query - the search query + * @param context DSpace Context + * @param format results format - html, rss or atom + * @param query - the search query * @param totalResults - the hit count - * @param start - start result index - * @param pageSize - page size - * @param scope - search scope, null or community/collection handle - * @param results the retreived DSpace objects satisfying search - * @param labels labels to apply - format specific + * @param start - start result index + * @param pageSize - page size + * @param scope - search scope, null or community/collection handle + * @param results the retreived DSpace objects satisfying search + * @param labels labels to apply - format specific * @return formatted search results * @throws IOException if IO error */ - public String getResultsString(Context context, String format, String query, int totalResults, int start, int pageSize, - DSpaceObject scope, List results, - Map labels) throws IOException; + public String getResultsString(Context context, String format, String query, int totalResults, int start, + int pageSize, + DSpaceObject scope, List results, + Map labels) throws IOException; + /** * Returns a formatted set of search results as a document * - * @param context DSpace Context - * @param format results format - html, rss or atom - * @param query - the search query + * @param context DSpace Context + * @param format results format - html, rss or atom + * @param query - the search query * @param totalResults - the hit count - * @param start - start result index - * @param pageSize - page size - * @param scope - search scope, null or community/collection handle - * @param results the retreived DSpace objects satisfying search - * @param labels labels to apply - format specific + * @param start - start result index + * @param pageSize - page size + * @param scope - search scope, null or community/collection handle + * @param results the retreived DSpace objects satisfying search + * @param labels labels to apply - format specific * @return formatted search results * @throws IOException if IO error */ - public Document getResultsDoc(Context context, String format, String query, int totalResults, int start, int pageSize, - DSpaceObject scope, List results, Map labels) - throws IOException; + public Document getResultsDoc(Context context, String format, String query, int totalResults, int start, + int pageSize, + DSpaceObject scope, List results, Map labels) + throws IOException; public DSpaceObject resolveScope(Context context, String scope) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/app/util/service/WebAppService.java b/dspace-api/src/main/java/org/dspace/app/util/service/WebAppService.java index 5f58554718..15802461e4 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/service/WebAppService.java +++ b/dspace-api/src/main/java/org/dspace/app/util/service/WebAppService.java @@ -7,16 +7,17 @@ */ package org.dspace.app.util.service; -import org.dspace.app.util.WebApp; -import org.dspace.core.Context; - import java.sql.SQLException; import java.util.Date; import java.util.List; +import org.dspace.app.util.WebApp; +import org.dspace.core.Context; + /** * Service interface class for the WebApp object. - * The implementation of this class is responsible for all business logic calls for the WebApp object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the WebApp object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -29,7 +30,6 @@ public interface WebAppService { public void delete(Context context, WebApp webApp) throws SQLException; /** - * * @return Return the list of running applications. */ public List getApps(); diff --git a/dspace-api/src/main/java/org/dspace/authenticate/AuthenticationMethod.java b/dspace-api/src/main/java/org/dspace/authenticate/AuthenticationMethod.java index 7424a11fe7..12c925b485 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/AuthenticationMethod.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/AuthenticationMethod.java @@ -7,10 +7,10 @@ */ package org.dspace.authenticate; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.sql.SQLException; import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -33,10 +33,9 @@ import org.dspace.eperson.Group; * and validate the credentials and fail gracefully if they are not * appropriate for it. The next method in the stack is then called. * - * @see org.dspace.authenticate.service.AuthenticationService - * * @author Larry Stone * @version $Revision$ + * @see org.dspace.authenticate.service.AuthenticationService */ public interface AuthenticationMethod { @@ -44,19 +43,29 @@ public interface AuthenticationMethod { * Symbolic return values for authenticate() method: */ - /** Authenticated OK, EPerson has been set. */ + /** + * Authenticated OK, EPerson has been set. + */ public static final int SUCCESS = 1; - /** User exists, but credentials (e.g. passwd) don't match. */ + /** + * User exists, but credentials (e.g. passwd) don't match. + */ public static final int BAD_CREDENTIALS = 2; - /** Not allowed to login this way without X.509 certificate. */ + /** + * Not allowed to login this way without X.509 certificate. + */ public static final int CERT_REQUIRED = 3; - /** User not found using this method. */ + /** + * User not found using this method. + */ public static final int NO_SUCH_USER = 4; - /** User or password is not appropriate for this method. */ + /** + * User or password is not appropriate for this method. + */ public static final int BAD_ARGS = 5; @@ -67,12 +76,9 @@ public interface AuthenticationMethod { * corresponding EPerson in DSpace yet. * The EPerson is only created if authentication succeeds. * - * @param context - * DSpace context - * @param request - * HTTP request, in case it's needed. May be null. - * @param username - * Username, if available. May be null. + * @param context DSpace context + * @param request HTTP request, in case it's needed. May be null. + * @param username Username, if available. May be null. * @return true if new ePerson should be created. * @throws SQLException if database error */ @@ -86,13 +92,10 @@ public interface AuthenticationMethod { * Set any data in the EPerson that is specific to this authentication * method. * - * @param context - * DSpace context - * @param request - * HTTP request, in case it's needed. May be null. - * @param eperson - * newly created EPerson record - email + information from the - * registration form will have been filled out. + * @param context DSpace context + * @param request HTTP request, in case it's needed. May be null. + * @param eperson newly created EPerson record - email + information from the + * registration form will have been filled out. * @throws SQLException if database error */ public void initEPerson(Context context, @@ -106,12 +109,9 @@ public interface AuthenticationMethod { * any method in the stack returns true, the user is * allowed to change it. * - * @param context - * DSpace context - * @param request - * HTTP request, in case it's needed. May be null. - * @param username - * Username, if available. May be null. + * @param context DSpace context + * @param request HTTP request, in case it's needed. May be null. + * @param username Username, if available. May be null. * @return true if this method allows user to change ePerson password. * @throws SQLException if database error */ @@ -142,16 +142,12 @@ public interface AuthenticationMethod { * belong with any existing auth method. The stackable authentication system * was designed expressly to separate functions into "stacked" methods to * keep your site-specific code modular and tidy. - * - * @param context - * A valid DSpace context. - * - * @param request - * The request that started this operation, or null if not - * applicable. - * + * + * @param context A valid DSpace context. + * @param request The request that started this operation, or null if not + * applicable. * @return array of EPerson-group IDs, possibly 0-length, but never - * null. + * null. * @throws SQLException if database error */ public List getSpecialGroups(Context context, HttpServletRequest request) @@ -164,25 +160,15 @@ public interface AuthenticationMethod { * (or optionally, create) an EPerson. If an EPerson is found it is * set in the Context that was passed. * - * @param context - * DSpace context, will be modified (ePerson set) upon success. - * - * @param username - * Username (or email address) when method is explicit. Use null for - * implicit method. - * - * @param password - * Password for explicit auth, or null for implicit method. - * - * @param realm - * Realm is an extra parameter used by some authentication methods, leave null if - * not applicable. - * - * @param request - * The HTTP request that started this operation, or null if not applicable. - * + * @param context DSpace context, will be modified (ePerson set) upon success. + * @param username Username (or email address) when method is explicit. Use null for + * implicit method. + * @param password Password for explicit auth, or null for implicit method. + * @param realm Realm is an extra parameter used by some authentication methods, leave null if + * not applicable. + * @param request The HTTP request that started this operation, or null if not applicable. * @return One of: - * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS + * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS *

Meaning: *
SUCCESS - authenticated OK. *
BAD_CREDENTIALS - user exists, but credentials (e.g. passwd) don't match @@ -200,11 +186,16 @@ public interface AuthenticationMethod { throws SQLException; /** - * Get login page to which to redirect. + * Get an external login page to which to redirect. + * * Returns URL (as string) to which to redirect to obtain * credentials (either password prompt or e.g. HTTPS port for client * cert.); null means no redirect. * + * Note: Starting with DSpace 7, session logins will be managed through the REST + * API. Therefore, only authn providers with external login pages (such as Shibboleth) + * should return a login page. + * * @param context * DSpace context, will be modified (ePerson set) upon success. * @@ -217,20 +208,12 @@ public interface AuthenticationMethod { * @return fully-qualified URL or null */ public String loginPageURL(Context context, - HttpServletRequest request, - HttpServletResponse response); + HttpServletRequest request, + HttpServletResponse response); /** - * Get title of login page to which to redirect. - * Returns a message key that gets translated into the title - * or label for "login page" (or null, if not implemented) This - * title may be used to identify the link to the login page in a - * selection menu, when there are multiple ways to login. - * - * @param context - * DSpace context, will be modified (ePerson set) upon success. - * - * @return title text. + * Returns a short name that uniquely identifies this authentication method + * @return The authentication method name */ - public String loginPageTitle(Context context); + public String getName(); } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/AuthenticationServiceImpl.java b/dspace-api/src/main/java/org/dspace/authenticate/AuthenticationServiceImpl.java index 4c8652291d..eb5e0a03f9 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/AuthenticationServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/AuthenticationServiceImpl.java @@ -7,13 +7,13 @@ */ package org.dspace.authenticate; -import javax.servlet.http.HttpServletRequest; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Iterator; import java.util.List; +import javax.servlet.http.HttpServletRequest; import org.dspace.authenticate.service.AuthenticationService; import org.dspace.authorize.AuthorizeException; @@ -48,27 +48,27 @@ import org.springframework.beans.factory.annotation.Autowired; * The "stack" is always traversed in order, with the methods * specified first (in the configuration) thus getting highest priority. * - * @see AuthenticationMethod - * * @author Larry Stone * @version $Revision$ + * @see AuthenticationMethod */ -public class AuthenticationServiceImpl implements AuthenticationService -{ +public class AuthenticationServiceImpl implements AuthenticationService { - /** SLF4J logging category */ + /** + * SLF4J logging category + */ private final Logger log = (Logger) LoggerFactory.getLogger(AuthenticationServiceImpl.class); @Autowired(required = true) protected EPersonService ePersonService; - protected AuthenticationServiceImpl() - { + protected AuthenticationServiceImpl() { } public List getAuthenticationMethodStack() { - return Arrays.asList((AuthenticationMethod[])CoreServiceFactory.getInstance().getPluginService().getPluginSequence(AuthenticationMethod.class)); + return Arrays.asList((AuthenticationMethod[]) CoreServiceFactory.getInstance().getPluginService() + .getPluginSequence(AuthenticationMethod.class)); } @Override @@ -76,30 +76,27 @@ public class AuthenticationServiceImpl implements AuthenticationService String username, String password, String realm, - HttpServletRequest request) - { + HttpServletRequest request) { return authenticateInternal(context, username, password, realm, - request, false); + request, false); } @Override public int authenticateImplicit(Context context, - String username, - String password, - String realm, - HttpServletRequest request) - { + String username, + String password, + String realm, + HttpServletRequest request) { return authenticateInternal(context, username, password, realm, - request, true); + request, true); } protected int authenticateInternal(Context context, - String username, - String password, - String realm, - HttpServletRequest request, - boolean implicitOnly) - { + String username, + String password, + String realm, + HttpServletRequest request, + boolean implicitOnly) { // better is lowest, so start with the highest. int bestRet = AuthenticationMethod.BAD_ARGS; @@ -113,15 +110,7 @@ public class AuthenticationServiceImpl implements AuthenticationService ret = AuthenticationMethod.NO_SUCH_USER; } if (ret == AuthenticationMethod.SUCCESS) { - EPerson me = context.getCurrentUser(); - me.setLastActive(new Date()); - try { - ePersonService.update(context, me); - } catch (SQLException ex) { - log.error("Could not update last-active stamp", ex); - } catch (AuthorizeException ex) { - log.error("Could not update last-active stamp", ex); - } + updateLastActiveDate(context); return ret; } if (ret < bestRet) { @@ -132,16 +121,27 @@ public class AuthenticationServiceImpl implements AuthenticationService return bestRet; } + public void updateLastActiveDate(Context context) { + EPerson me = context.getCurrentUser(); + if (me != null) { + me.setLastActive(new Date()); + try { + ePersonService.update(context, me); + } catch (SQLException ex) { + log.error("Could not update last-active stamp", ex); + } catch (AuthorizeException ex) { + log.error("Could not update last-active stamp", ex); + } + } + } + @Override public boolean canSelfRegister(Context context, HttpServletRequest request, String username) - throws SQLException - { - for (AuthenticationMethod method : getAuthenticationMethodStack()) - { - if (method.canSelfRegister(context, request, username)) - { + throws SQLException { + for (AuthenticationMethod method : getAuthenticationMethodStack()) { + if (method.canSelfRegister(context, request, username)) { return true; } } @@ -152,12 +152,9 @@ public class AuthenticationServiceImpl implements AuthenticationService public boolean allowSetPassword(Context context, HttpServletRequest request, String username) - throws SQLException - { - for (AuthenticationMethod method : getAuthenticationMethodStack()) - { - if (method.allowSetPassword(context, request, username)) - { + throws SQLException { + for (AuthenticationMethod method : getAuthenticationMethodStack()) { + if (method.allowSetPassword(context, request, username)) { return true; } } @@ -166,29 +163,24 @@ public class AuthenticationServiceImpl implements AuthenticationService @Override public void initEPerson(Context context, - HttpServletRequest request, - EPerson eperson) - throws SQLException - { - for (AuthenticationMethod method : getAuthenticationMethodStack()) - { + HttpServletRequest request, + EPerson eperson) + throws SQLException { + for (AuthenticationMethod method : getAuthenticationMethodStack()) { method.initEPerson(context, request, eperson); } } @Override public List getSpecialGroups(Context context, - HttpServletRequest request) - throws SQLException - { + HttpServletRequest request) + throws SQLException { List result = new ArrayList<>(); int totalLen = 0; - for (AuthenticationMethod method : getAuthenticationMethodStack()) - { + for (AuthenticationMethod method : getAuthenticationMethodStack()) { List gl = method.getSpecialGroups(context, request); - if (gl.size() > 0) - { + if (gl.size() > 0) { result.addAll(gl); totalLen += gl.size(); } @@ -198,8 +190,7 @@ public class AuthenticationServiceImpl implements AuthenticationService } @Override - public Iterator authenticationMethodIterator() - { + public Iterator authenticationMethodIterator() { return getAuthenticationMethodStack().iterator(); } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/IPAuthentication.java b/dspace-api/src/main/java/org/dspace/authenticate/IPAuthentication.java index 5ac947b720..9a8dcf7d55 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/IPAuthentication.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/IPAuthentication.java @@ -9,15 +9,14 @@ package org.dspace.authenticate; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.collections.ListUtils; import org.apache.log4j.Logger; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; @@ -42,27 +41,34 @@ import org.dspace.services.factory.DSpaceServicesFactory; * 111.222,-111.222.333. *

* For supported IP ranges see {@link org.dspace.authenticate.IPMatcher}. - * - * @version $Revision$ + * * @author Robert Tansley + * @version $Revision$ */ -public class IPAuthentication implements AuthenticationMethod -{ - /** Our logger */ +public class IPAuthentication implements AuthenticationMethod { + /** + * Our logger + */ private static Logger log = Logger.getLogger(IPAuthentication.class); - /** Whether to look for x-forwarded headers for logging IP addresses */ + /** + * Whether to look for x-forwarded headers for logging IP addresses + */ protected static Boolean useProxies; - /** All the IP matchers */ + /** + * All the IP matchers + */ protected List ipMatchers; - /** All the negative IP matchers */ + /** + * All the negative IP matchers + */ protected List ipNegativeMatchers; protected GroupService groupService; - + /** * Maps IPMatchers to group names when we don't know group DB ID yet. When * the DB ID is known, the IPMatcher is moved to ipMatcherGroupIDs and then @@ -70,113 +76,95 @@ public class IPAuthentication implements AuthenticationMethod */ protected Map ipMatcherGroupNames; - /** Maps IPMatchers to group IDs (Integers) where we know the group DB ID */ + /** + * Maps IPMatchers to group IDs (Integers) where we know the group DB ID + */ protected Map ipMatcherGroupIDs; /** * Initialize an IP authenticator, reading in the configuration. Note this * will never fail if the configuration is bad -- a warning will be logged. */ - public IPAuthentication() - { + public IPAuthentication() { ipMatchers = new ArrayList(); ipNegativeMatchers = new ArrayList(); ipMatcherGroupIDs = new HashMap<>(); ipMatcherGroupNames = new HashMap<>(); groupService = EPersonServiceFactory.getInstance().getGroupService(); - List propNames = DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys("authentication-ip"); + List propNames = DSpaceServicesFactory.getInstance().getConfigurationService() + .getPropertyKeys("authentication-ip"); - for(String propName : propNames) - { + for (String propName : propNames) { String[] nameParts = propName.split("\\."); - if (nameParts.length == 2) - { - addMatchers(nameParts[1], DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty(propName)); - } - else - { + if (nameParts.length == 2) { + addMatchers(nameParts[1], + DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty(propName)); + } else { log.warn("Malformed configuration property name: " - + propName); + + propName); } } } /** * Add matchers for the given comma-delimited IP ranges and group. - * - * @param groupName - * name of group - * @param ipRanges - * IP ranges + * + * @param groupName name of group + * @param ipRanges IP ranges */ - protected void addMatchers(String groupName, String[] ipRanges) - { - for (String entry : ipRanges) - { - try - { + protected void addMatchers(String groupName, String[] ipRanges) { + for (String entry : ipRanges) { + try { IPMatcher ipm; - if (entry.startsWith("-")) - { + if (entry.startsWith("-")) { ipm = new IPMatcher(entry.substring(1)); ipNegativeMatchers.add(ipm); - } - else - { + } else { ipm = new IPMatcher(entry); ipMatchers.add(ipm); } ipMatcherGroupNames.put(ipm, groupName); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Configured " + entry + " for special group " - + groupName); + + groupName); } - } - catch (IPMatcherException ipme) - { + } catch (IPMatcherException ipme) { log.warn("Malformed IP range specified for group " + groupName, - ipme); + ipme); } } } @Override public boolean canSelfRegister(Context context, HttpServletRequest request, - String username) throws SQLException - { + String username) throws SQLException { return false; } @Override public void initEPerson(Context context, HttpServletRequest request, - EPerson eperson) throws SQLException - { + EPerson eperson) throws SQLException { } @Override public boolean allowSetPassword(Context context, - HttpServletRequest request, String username) throws SQLException - { + HttpServletRequest request, String username) throws SQLException { return false; } @Override - public boolean isImplicit() - { + public boolean isImplicit() { return true; } @Override public List getSpecialGroups(Context context, HttpServletRequest request) - throws SQLException - { - if (request == null) - { - return ListUtils.EMPTY_LIST; + throws SQLException { + if (request == null) { + return Collections.EMPTY_LIST; } List groups = new ArrayList(); @@ -185,119 +173,93 @@ public class IPAuthentication implements AuthenticationMethod if (useProxies == null) { useProxies = ConfigurationManager.getBooleanProperty("useProxies", false); } - if (useProxies && request.getHeader("X-Forwarded-For") != null) - { + if (useProxies && request.getHeader("X-Forwarded-For") != null) { /* This header is a comma delimited list */ - for(String xfip : request.getHeader("X-Forwarded-For").split(",")) - { - if(!request.getHeader("X-Forwarded-For").contains(addr)) - { + for (String xfip : request.getHeader("X-Forwarded-For").split(",")) { + if (!request.getHeader("X-Forwarded-For").contains(addr)) { addr = xfip.trim(); } } } - for (IPMatcher ipm : ipMatchers) - { - try - { - if (ipm.match(addr)) - { + for (IPMatcher ipm : ipMatchers) { + try { + if (ipm.match(addr)) { // Do we know group ID? UUID g = ipMatcherGroupIDs.get(ipm); - if (g != null) - { + if (g != null) { groups.add(groupService.find(context, g)); - } - else - { + } else { // See if we have a group name String groupName = ipMatcherGroupNames.get(ipm); - if (groupName != null) - { + if (groupName != null) { Group group = groupService.findByName(context, groupName); - if (group != null) - { + if (group != null) { // Add ID so we won't have to do lookup again ipMatcherGroupIDs.put(ipm, (group.getID())); ipMatcherGroupNames.remove(ipm); groups.add(group); - } - else - { + } else { log.warn(LogManager.getHeader(context, - "configuration_error", "unknown_group=" - + groupName)); + "configuration_error", "unknown_group=" + + groupName)); } } } } - } - catch (IPMatcherException ipme) - { + } catch (IPMatcherException ipme) { log.warn(LogManager.getHeader(context, "configuration_error", - "bad_ip=" + addr), ipme); + "bad_ip=" + addr), ipme); } } // Now remove any negative matches - for (IPMatcher ipm : ipNegativeMatchers) - { - try - { - if (ipm.match(addr)) - { + for (IPMatcher ipm : ipNegativeMatchers) { + try { + if (ipm.match(addr)) { // Do we know group ID? UUID g = ipMatcherGroupIDs.get(ipm); - if (g != null) - { + if (g != null) { groups.remove(groupService.find(context, g)); - } - else - { + } else { // See if we have a group name String groupName = ipMatcherGroupNames.get(ipm); - if (groupName != null) - { + if (groupName != null) { Group group = groupService.findByName(context, groupName); - if (group != null) - { + if (group != null) { // Add ID so we won't have to do lookup again ipMatcherGroupIDs.put(ipm, group.getID()); ipMatcherGroupNames.remove(ipm); groups.remove(group); - } - else - { + } else { log.warn(LogManager.getHeader(context, - "configuration_error", "unknown_group=" - + groupName)); + "configuration_error", "unknown_group=" + + groupName)); } } } } - } - catch (IPMatcherException ipme) - { + } catch (IPMatcherException ipme) { log.warn(LogManager.getHeader(context, "configuration_error", - "bad_ip=" + addr), ipme); + "bad_ip=" + addr), ipme); } } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { StringBuilder gsb = new StringBuilder(); for (Group group : groups) { gsb.append(group.getID()).append(", "); } log.debug(LogManager.getHeader(context, "authenticated", - "special_groups=" + gsb.toString())); + "special_groups=" + gsb.toString() + + " (by IP=" + addr + ", useProxies=" + useProxies.toString() + ")" + )); } return groups; @@ -305,21 +267,18 @@ public class IPAuthentication implements AuthenticationMethod @Override public int authenticate(Context context, String username, String password, - String realm, HttpServletRequest request) throws SQLException - { + String realm, HttpServletRequest request) throws SQLException { return BAD_ARGS; } @Override public String loginPageURL(Context context, HttpServletRequest request, - HttpServletResponse response) - { + HttpServletResponse response) { return null; } @Override - public String loginPageTitle(Context context) - { - return null; + public String getName() { + return "ip"; } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/IPMatcher.java b/dspace-api/src/main/java/org/dspace/authenticate/IPMatcher.java index b58a2b748d..02825589cb 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/IPMatcher.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/IPMatcher.java @@ -7,11 +7,11 @@ */ package org.dspace.authenticate; -import org.apache.log4j.Logger; - import java.net.Inet6Address; import java.net.UnknownHostException; +import org.apache.log4j.Logger; + /** *

* Quickly tests whether a given IP address matches an IP range. An @@ -31,169 +31,158 @@ import java.net.UnknownHostException; *

  • IPv4 or IPv6 CIDR slash notation, e.g. {@code 18.25.0.0/16}, * {@code 2001:18e8:3:171::/64}
  • * - * - * @version $Revision$ + * * @author Robert Tansley * @author Ben Bosman * @author Roeland Dillen + * @version $Revision$ */ -public class IPMatcher -{ +public class IPMatcher { private static Logger log = Logger.getLogger(IPMatcher.class); - /** Network to match */ + /** + * Network to match + */ private byte[] network; - /** Network mask */ + /** + * Network mask + */ private byte[] netmask; /** * Construct an IPMatcher that will test for the given IP specification - * - * @param ipSpec - * IP specification (full or partial address, network/netmask, - * network/cidr) - * @throws IPMatcherException - * if there is an error parsing the specification (i.e. it is - * somehow malformed) + * + * @param ipSpec IP specification (full or partial address, network/netmask, + * network/cidr) + * @throws IPMatcherException if there is an error parsing the specification (i.e. it is + * somehow malformed) */ - public IPMatcher(String ipSpec) throws IPMatcherException - { + public IPMatcher(String ipSpec) throws IPMatcherException { // Boil all specs down to network + mask String ipPart = ipSpec; String[] parts = ipSpec.split("/"); - if (parts[0].indexOf(':') >= 0) - { // looks like IPv6 - try - { + if (parts[0].indexOf(':') >= 0) { // looks like IPv6 + try { network = Inet6Address.getByName(parts[0]).getAddress(); - } - catch (UnknownHostException e) - { + } catch (UnknownHostException e) { throw new IPMatcherException( - "Malformed IP range specification " + ipSpec, e); + "Malformed IP range specification " + ipSpec, e); } netmask = new byte[16]; - switch(parts.length) - { - case 2: // CIDR notation: calculate the mask - int maskBits; - try { - maskBits = Integer.parseInt(parts[1]); - } catch (NumberFormatException nfe) { - throw new IPMatcherException( + switch (parts.length) { + case 2: // CIDR notation: calculate the mask + int maskBits; + try { + maskBits = Integer.parseInt(parts[1]); + } catch (NumberFormatException nfe) { + throw new IPMatcherException( "Malformed IP range specification " + ipSpec, nfe); - } - if (maskBits < 0 || maskBits > 128) - throw new IPMatcherException("Mask bits out of range 0-128 " - + ipSpec); + } + if (maskBits < 0 || maskBits > 128) { + throw new IPMatcherException("Mask bits out of range 0-128 " + + ipSpec); + } - int maskBytes = maskBits/8; - for (int i = 0; i < maskBytes; i++) - netmask[i] = (byte) 0Xff; - netmask[maskBytes] = (byte) ((byte) 0Xff << 8-(maskBits % 8)); // FIXME test! - for (int i = maskBytes+1; i < (128/8); i++) - netmask[i] = 0; - break; - case 1: // No explicit mask: fill the mask with 1s - for (int i = 0; i < netmask.length; i++) - netmask[i] = (byte) 0Xff; - break; - default: - throw new IPMatcherException("Malformed IP range specification " - + ipSpec); + int maskBytes = maskBits / 8; + for (int i = 0; i < maskBytes; i++) { + netmask[i] = (byte) 0Xff; + } + netmask[maskBytes] = (byte) ((byte) 0Xff << 8 - (maskBits % 8)); // FIXME test! + for (int i = maskBytes + 1; i < (128 / 8); i++) { + netmask[i] = 0; + } + break; + case 1: // No explicit mask: fill the mask with 1s + for (int i = 0; i < netmask.length; i++) { + netmask[i] = (byte) 0Xff; + } + break; + default: + throw new IPMatcherException("Malformed IP range specification " + + ipSpec); } - } - else - { // assume IPv4 + } else { // assume IPv4 // Allow partial IP boolean mustHave4 = false; network = new byte[4]; netmask = new byte[4]; - switch (parts.length) - { - case 2: - // Some kind of slash notation -- we'll need a full network IP - ipPart = parts[0]; - mustHave4 = true; - - String[] maskParts = parts[1].split("\\."); - if (maskParts.length == 1) - { - // CIDR slash notation - int x; - - try - { - x = Integer.parseInt(maskParts[0]); - } - catch (NumberFormatException nfe) - { - throw new IPMatcherException( - "Malformed IP range specification " + ipSpec, nfe); - } - - if (x < 0 || x > 32) - { - throw new IPMatcherException(); - } - - int fullMask = -1 << (32 - x); - netmask[0] = (byte) ((fullMask & 0xFF000000) >>> 24); - netmask[1] = (byte) ((fullMask & 0x00FF0000) >>> 16); - netmask[2] = (byte) ((fullMask & 0x0000FF00) >>> 8); - netmask[3] = (byte) (fullMask & 0x000000FF); - ipToBytes(ipPart, network, mustHave4); - if (log.isDebugEnabled()) { - log.debug("fullMask: "+fullMask); - for (int i = 0; i < network.length; i++) { - log.debug("network[" + i + "]: "+network[i]); - } - for (int i = 0; i < netmask.length; i++) { - log.debug("netmask[" + i + "]: "+netmask[i]); - } - } - } - else - { - // full netmask specified - ipToBytes(parts[0],network,true); - ipToBytes(parts[1], netmask, true); - } - - break; + switch (parts.length) { + case 2: + // Some kind of slash notation -- we'll need a full network IP + ipPart = parts[0]; + mustHave4 = true; - case 1: - // Get IP - for (int i = 0; i < netmask.length; i++) - netmask[i] = -1; - int partCount = ipToBytes(ipPart, network, mustHave4); - - // If partial IP, set mask for remaining bytes - for (int i = 3; i >= partCount; i--) - { - netmask[i] = 0; - } - - break; - - default: - throw new IPMatcherException("Malformed IP range specification " - + ipSpec); + String[] maskParts = parts[1].split("\\."); + if (maskParts.length == 1) { + // CIDR slash notation + int x; + + try { + x = Integer.parseInt(maskParts[0]); + } catch (NumberFormatException nfe) { + throw new IPMatcherException( + "Malformed IP range specification " + ipSpec, nfe); + } + + if (x < 0 || x > 32) { + throw new IPMatcherException(); + } + + int fullMask = -1 << (32 - x); + netmask[0] = (byte) ((fullMask & 0xFF000000) >>> 24); + netmask[1] = (byte) ((fullMask & 0x00FF0000) >>> 16); + netmask[2] = (byte) ((fullMask & 0x0000FF00) >>> 8); + netmask[3] = (byte) (fullMask & 0x000000FF); + ipToBytes(ipPart, network, mustHave4); + if (log.isDebugEnabled()) { + log.debug("fullMask: " + fullMask); + for (int i = 0; i < network.length; i++) { + log.debug("network[" + i + "]: " + network[i]); + } + for (int i = 0; i < netmask.length; i++) { + log.debug("netmask[" + i + "]: " + netmask[i]); + } + } + } else { + // full netmask specified + ipToBytes(parts[0], network, true); + ipToBytes(parts[1], netmask, true); + } + + break; + + case 1: + // Get IP + for (int i = 0; i < netmask.length; i++) { + netmask[i] = -1; + } + int partCount = ipToBytes(ipPart, network, mustHave4); + + // If partial IP, set mask for remaining bytes + for (int i = 3; i >= partCount; i--) { + netmask[i] = 0; + } + + break; + + default: + throw new IPMatcherException("Malformed IP range specification " + + ipSpec); } network = ip4ToIp6(network); netmask = ip4MaskToIp6(netmask); if (log.isDebugEnabled()) { for (int i = 0; i < network.length; i++) { - log.debug("network[" + i + "]: "+network[i]); - } + log.debug("network[" + i + "]: " + network[i]); + } for (int i = 0; i < netmask.length; i++) { - log.debug("netmask[" + i + "]: "+netmask[i]); - } + log.debug("netmask[" + i + "]: " + netmask[i]); + } } } } @@ -201,51 +190,40 @@ public class IPMatcher /** * Fill out a given four-byte array with the IPv4 address specified in the * given String - * - * @param ip - * IPv4 address as a dot-delimited String - * @param bytes - * 4-byte array to fill out - * @param mustHave4 - * if true, will require that the given IP string specify all - * four bytes + * + * @param ip IPv4 address as a dot-delimited String + * @param bytes 4-byte array to fill out + * @param mustHave4 if true, will require that the given IP string specify all + * four bytes * @return the number of actual IP bytes found in the given IP address - * String - * @throws IPMatcherException - * if there is a problem parsing the IP string -- e.g. number - * outside of range 0-255, too many numbers, less than 4 numbers - * if {@code mustHave4} is true + * String + * @throws IPMatcherException if there is a problem parsing the IP string -- e.g. number + * outside of range 0-255, too many numbers, less than 4 numbers + * if {@code mustHave4} is true */ private static int ipToBytes(String ip, byte[] bytes, boolean mustHave4) - throws IPMatcherException - { + throws IPMatcherException { String[] parts = ip.split("\\."); - if (parts.length > 4 || mustHave4 && parts.length != 4) - { + if (parts.length > 4 || mustHave4 && parts.length != 4) { throw new IPMatcherException("Malformed IP specification " + ip); } - try - { + try { - for (int i = 0; i < parts.length; i++) - { + for (int i = 0; i < parts.length; i++) { int p = Integer.parseInt(parts[i]); - if (p < 0 || p > 255) - { + if (p < 0 || p > 255) { throw new IPMatcherException("Malformed IP specification " - + ip); + + ip); } bytes[i] = (byte) (p < 128 ? p : p - 256); } - } - catch (NumberFormatException nfe) - { + } catch (NumberFormatException nfe) { throw new IPMatcherException("Malformed IP specification " + ip, - nfe); + nfe); } return parts.length; @@ -254,46 +232,37 @@ public class IPMatcher /** * Determine whether the given full IP falls within the range this * {@code IPMatcher} was initialized with. - * - * @param ipIn - * IP address as dot-delimited String + * + * @param ipIn IP address as dot-delimited String * @return {@code true} if the IP matches the range of this - * {@code IPMatcher}; {@code false} otherwise - * @throws IPMatcherException - * if the IP passed in cannot be parsed correctly (i.e. is - * malformed) + * {@code IPMatcher}; {@code false} otherwise + * @throws IPMatcherException if the IP passed in cannot be parsed correctly (i.e. is + * malformed) */ - public boolean match(String ipIn) throws IPMatcherException - { - log.debug("ipIn: "+ipIn); + public boolean match(String ipIn) throws IPMatcherException { + log.debug("ipIn: " + ipIn); byte[] candidate; - if (ipIn.indexOf(':') < 0) - { + if (ipIn.indexOf(':') < 0) { candidate = new byte[4]; ipToBytes(ipIn, candidate, true); candidate = ip4ToIp6(candidate); - } - else - try - { + } else { + try { candidate = Inet6Address.getByName(ipIn).getAddress(); + } catch (UnknownHostException e) { + throw new IPMatcherException("Malformed IPv6 address ", e); } - catch (UnknownHostException e) - { - throw new IPMatcherException("Malformed IPv6 address ",e); - } + } - for (int i = 0; i < netmask.length; i++) - { - if ((candidate[i] & netmask[i]) != (network[i] & netmask[i])) - { + for (int i = 0; i < netmask.length; i++) { + if ((candidate[i] & netmask[i]) != (network[i] & netmask[i])) { if (log.isDebugEnabled()) { - log.debug("candidate[i]: "+candidate[i]); - log.debug("netmask[i]: "+netmask[i]); - log.debug("candidate[i] & netmask[i]: "+(candidate[i] & netmask[i])); - log.debug("network[i]: "+network[i]); - log.debug("network[i] & netmask[i]: "+(network[i] & netmask[i])); + log.debug("candidate[i]: " + candidate[i]); + log.debug("netmask[i]: " + netmask[i]); + log.debug("candidate[i] & netmask[i]: " + (candidate[i] & netmask[i])); + log.debug("network[i]: " + network[i]); + log.debug("network[i] & netmask[i]: " + (network[i] & netmask[i])); } return false; } @@ -304,39 +273,45 @@ public class IPMatcher /** * Convert an IPv4 address to an IPv6 IPv4-compatible address. + * * @param ip4 an IPv4 address * @return the corresponding IPv6 address * @throws IllegalArgumentException if ip4 is not exactly four octets long. */ - private static byte[] ip4ToIp6(byte[] ip4) - { - if (ip4.length != 4) + private static byte[] ip4ToIp6(byte[] ip4) { + if (ip4.length != 4) { throw new IllegalArgumentException("IPv4 address must be four octets"); + } byte[] ip6 = new byte[16]; - for (int i = 0; i < 16-4; i++) + for (int i = 0; i < 16 - 4; i++) { ip6[i] = 0; - for (int i = 0; i < 4; i++) - ip6[12+i] = ip4[i]; + } + for (int i = 0; i < 4; i++) { + ip6[12 + i] = ip4[i]; + } return ip6; } /** * Convert an IPv4 mask to the equivalent IPv6 mask. + * * @param ip4 an IPv4 mask * @return the corresponding IPv6 mask * @throws IllegalArgumentException if ip4 is not exactly four octets long. */ - private static byte[] ip4MaskToIp6(byte[] ip4) - { - if (ip4.length != 4) + private static byte[] ip4MaskToIp6(byte[] ip4) { + if (ip4.length != 4) { throw new IllegalArgumentException("IPv4 mask must be four octets"); + } byte[] ip6 = new byte[16]; - for (int i = 0; i < 16-4; i++) + for (int i = 0; i < 16 - 4; i++) { ip6[i] = (byte) 0Xff; - for (int i = 0; i < 4; i++) - ip6[12+i] = ip4[i]; + } + for (int i = 0; i < 4; i++) { + ip6[12 + i] = ip4[i]; + } return ip6; } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/IPMatcherException.java b/dspace-api/src/main/java/org/dspace/authenticate/IPMatcherException.java index 5d291f5c67..8caa77786d 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/IPMatcherException.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/IPMatcherException.java @@ -9,29 +9,24 @@ package org.dspace.authenticate; /** * Thrown when there is a problem parsing an IP matcher specification. - * - * @version $Revision$ + * * @author Robert Tansley + * @version $Revision$ */ -public class IPMatcherException extends Exception -{ - public IPMatcherException() - { +public class IPMatcherException extends Exception { + public IPMatcherException() { super(); } - public IPMatcherException(String message) - { + public IPMatcherException(String message) { super(message); } - public IPMatcherException(Throwable cause) - { + public IPMatcherException(Throwable cause) { super(cause); } - public IPMatcherException(String message, Throwable cause) - { + public IPMatcherException(String message, Throwable cause) { super(message, cause); } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java b/dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java index 55a80adec8..13ba180c0f 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java @@ -10,9 +10,9 @@ package org.dspace.authenticate; import java.io.IOException; import java.sql.SQLException; import java.util.Arrays; +import java.util.Collections; import java.util.Hashtable; import java.util.List; - import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; @@ -28,7 +28,6 @@ import javax.naming.ldap.StartTlsResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.collections.ListUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authenticate.factory.AuthenticateServiceFactory; @@ -47,11 +46,11 @@ import org.dspace.eperson.service.GroupService; * This combined LDAP authentication method supersedes both the 'LDAPAuthentication' * and the 'LDAPHierarchicalAuthentication' methods. It's capable of both: * - authenticaton against a flat LDAP tree where all users are in the same unit - * (if search.user or search.password is not set) - * - authentication against structured hierarchical LDAP trees of users. - * An initial bind is required using a user name and password in order to - * search the tree and find the DN of the user. A second bind is then required to - * check the credentials of the user by binding directly to their DN. + * (if search.user or search.password is not set) + * - authentication against structured hierarchical LDAP trees of users. + * An initial bind is required using a user name and password in order to + * search the tree and find the DN of the user. A second bind is then required to + * check the credentials of the user by binding directly to their DN. * * @author Stuart Lewis, Chris Yates, Alex Barbieri, Flavio Botelho, Reuben Pasquini, Samuel Ottenhoff, Ivan Masár * @version $Revision$ @@ -59,51 +58,54 @@ import org.dspace.eperson.service.GroupService; public class LDAPAuthentication implements AuthenticationMethod { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(LDAPAuthentication.class); - protected AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance().getAuthenticationService(); + protected AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance() + .getAuthenticationService(); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); /** * Let a real auth method return true if it wants. + * * @throws SQLException if database error */ @Override public boolean canSelfRegister(Context context, HttpServletRequest request, String username) - throws SQLException - { + throws SQLException { // Looks to see if autoregister is set or not return ConfigurationManager.getBooleanProperty("authentication-ldap", "autoregister"); } /** * Nothing here, initialization is done when auto-registering. + * * @throws SQLException if database error */ @Override public void initEPerson(Context context, HttpServletRequest request, - EPerson eperson) - throws SQLException - { + EPerson eperson) + throws SQLException { // XXX should we try to initialize netid based on email addr, // XXX for eperson created by some other method?? } /** * Cannot change LDAP password through dspace, right? + * * @throws SQLException if database error */ @Override public boolean allowSetPassword(Context context, HttpServletRequest request, String username) - throws SQLException - { + throws SQLException { // XXX is this right? return false; } @@ -112,8 +114,7 @@ public class LDAPAuthentication * This is an explicit method. */ @Override - public boolean isImplicit() - { + public boolean isImplicit() { return false; } @@ -122,36 +123,29 @@ public class LDAPAuthentication * the login.specialgroup key. */ @Override - public List getSpecialGroups(Context context, HttpServletRequest request) - { + public List getSpecialGroups(Context context, HttpServletRequest request) { // Prevents anonymous users from being added to this group, and the second check // ensures they are LDAP users - try - { - if (!context.getCurrentUser().getNetid().equals("")) - { + try { + if (!context.getCurrentUser().getNetid().equals("")) { String groupName = ConfigurationManager.getProperty("authentication-ldap", "login.specialgroup"); - if ((groupName != null) && (!groupName.trim().equals(""))) - { + if ((groupName != null) && (!groupName.trim().equals(""))) { Group ldapGroup = groupService.findByName(context, groupName); - if (ldapGroup == null) - { + if (ldapGroup == null) { // Oops - the group isn't there. log.warn(LogManager.getHeader(context, - "ldap_specialgroup", - "Group defined in login.specialgroup does not exist")); - return ListUtils.EMPTY_LIST; - } else - { + "ldap_specialgroup", + "Group defined in login.specialgroup does not exist")); + return Collections.EMPTY_LIST; + } else { return Arrays.asList(ldapGroup); } } } - } - catch (Exception npe) { + } catch (Exception npe) { // The user is not an LDAP user, so we don't need to worry about them } - return ListUtils.EMPTY_LIST; + return Collections.EMPTY_LIST; } /* @@ -193,24 +187,20 @@ public class LDAPAuthentication String password, String realm, HttpServletRequest request) - throws SQLException - { - log.info(LogManager.getHeader(context, "auth", "attempting trivial auth of user="+netid)); + throws SQLException { + log.info(LogManager.getHeader(context, "auth", "attempting trivial auth of user=" + netid)); // Skip out when no netid or password is given. - if (netid == null || password == null) - { + if (netid == null || password == null) { return BAD_ARGS; } // Locate the eperson EPerson eperson = null; - try - { - eperson = ePersonService.findByNetid(context, netid.toLowerCase()); - } - catch (SQLException e) - { + try { + eperson = ePersonService.findByNetid(context, netid.toLowerCase()); + } catch (SQLException e) { + // ignore } SpeakerToLDAP ldap = new SpeakerToLDAP(log); @@ -222,93 +212,77 @@ public class LDAPAuthentication String idField = ConfigurationManager.getProperty("authentication-ldap", "id_field"); String dn = ""; - // If adminUser is blank and anonymous search is not allowed, then we can't search so construct the DN instead of searching it - if ((StringUtils.isBlank(adminUser) || StringUtils.isBlank(adminPassword)) && !anonymousSearch) - { + // If adminUser is blank and anonymous search is not allowed, then we can't search so construct the DN + // instead of searching it + if ((StringUtils.isBlank(adminUser) || StringUtils.isBlank(adminPassword)) && !anonymousSearch) { dn = idField + "=" + netid + "," + objectContext; - } - else - { + } else { dn = ldap.getDNOfUser(adminUser, adminPassword, context, netid); } // Check a DN was found - if ((dn == null) || (dn.trim().equals(""))) - { + if ((dn == null) || (dn.trim().equals(""))) { log.info(LogManager - .getHeader(context, "failed_login", "no DN found for user " + netid)); + .getHeader(context, "failed_login", "no DN found for user " + netid)); return BAD_CREDENTIALS; } // if they entered a netid that matches an eperson - if (eperson != null) - { + if (eperson != null) { // e-mail address corresponds to active account - if (eperson.getRequireCertificate()) - { + if (eperson.getRequireCertificate()) { return CERT_REQUIRED; - } - else if (!eperson.canLogIn()) - { + } else if (!eperson.canLogIn()) { return BAD_ARGS; } - if (ldap.ldapAuthenticate(dn, password, context)) - { + if (ldap.ldapAuthenticate(dn, password, context)) { context.setCurrentUser(eperson); // assign user to groups based on ldap dn assignGroups(dn, ldap.ldapGroup, context); - + log.info(LogManager - .getHeader(context, "authenticate", "type=ldap")); + .getHeader(context, "authenticate", "type=ldap")); return SUCCESS; - } - else - { + } else { return BAD_CREDENTIALS; } - } - else - { + } else { // the user does not already exist so try and authenticate them // with ldap and create an eperson for them - if (ldap.ldapAuthenticate(dn, password, context)) - { + if (ldap.ldapAuthenticate(dn, password, context)) { // Register the new user automatically log.info(LogManager.getHeader(context, - "autoregister", "netid=" + netid)); + "autoregister", "netid=" + netid)); String email = ldap.ldapEmail; // Check if we were able to determine an email address from LDAP - if (StringUtils.isEmpty(email)) - { - // If no email, check if we have a "netid_email_domain". If so, append it to the netid to create email - if (StringUtils.isNotEmpty(ConfigurationManager.getProperty("authentication-ldap", "netid_email_domain"))) - { + if (StringUtils.isEmpty(email)) { + // If no email, check if we have a "netid_email_domain". If so, append it to the netid to create + // email + if (StringUtils + .isNotEmpty(ConfigurationManager.getProperty("authentication-ldap", "netid_email_domain"))) { email = netid + ConfigurationManager.getProperty("authentication-ldap", "netid_email_domain"); - } - else - { + } else { // We don't have a valid email address. We'll default it to 'netid' but log a warning log.warn(LogManager.getHeader(context, "autoregister", - "Unable to locate email address for account '" + netid + "', so it has been set to '" + netid + "'. " + - "Please check the LDAP 'email_field' OR consider configuring 'netid_email_domain'.")); + "Unable to locate email address for account '" + netid + "', so" + + " it has been set to '" + netid + "'. " + + "Please check the LDAP 'email_field' OR consider " + + "configuring 'netid_email_domain'.")); email = netid; } } - if (StringUtils.isNotEmpty(email)) - { - try - { + if (StringUtils.isNotEmpty(email)) { + try { eperson = ePersonService.findByEmail(context, email); - if (eperson!=null) - { + if (eperson != null) { log.info(LogManager.getHeader(context, - "type=ldap-login", "type=ldap_but_already_email")); + "type=ldap-login", "type=ldap_but_already_email")); context.turnOffAuthorisationSystem(); eperson.setNetid(netid.toLowerCase()); ePersonService.update(context, eperson); @@ -320,30 +294,22 @@ public class LDAPAuthentication assignGroups(dn, ldap.ldapGroup, context); return SUCCESS; - } - else - { - if (canSelfRegister(context, request, netid)) - { + } else { + if (canSelfRegister(context, request, netid)) { // TEMPORARILY turn off authorisation - try - { + try { context.turnOffAuthorisationSystem(); eperson = ePersonService.create(context); - if (StringUtils.isNotEmpty(email)) - { + if (StringUtils.isNotEmpty(email)) { eperson.setEmail(email); } - if (StringUtils.isNotEmpty(ldap.ldapGivenName)) - { + if (StringUtils.isNotEmpty(ldap.ldapGivenName)) { eperson.setFirstName(context, ldap.ldapGivenName); } - if (StringUtils.isNotEmpty(ldap.ldapSurname)) - { + if (StringUtils.isNotEmpty(ldap.ldapSurname)) { eperson.setLastName(context, ldap.ldapSurname); } - if (StringUtils.isNotEmpty(ldap.ldapPhone)) - { + if (StringUtils.isNotEmpty(ldap.ldapPhone)) { ePersonService.setMetadata(context, eperson, "phone", ldap.ldapPhone); } eperson.setNetid(netid.toLowerCase()); @@ -355,35 +321,25 @@ public class LDAPAuthentication // assign user to groups based on ldap dn assignGroups(dn, ldap.ldapGroup, context); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { return NO_SUCH_USER; - } - finally - { + } finally { context.restoreAuthSystemState(); } log.info(LogManager.getHeader(context, "authenticate", - "type=ldap-login, created ePerson")); + "type=ldap-login, created ePerson")); return SUCCESS; - } - else - { + } else { // No auto-registration for valid certs log.info(LogManager.getHeader(context, - "failed_login", "type=ldap_but_no_record")); + "failed_login", "type=ldap_but_no_record")); return NO_SUCH_USER; } } - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { eperson = null; - } - finally - { + } finally { context.restoreAuthSystemState(); } } @@ -406,7 +362,9 @@ public class LDAPAuthentication protected String ldapPhone = null; protected String ldapGroup = null; - /** LDAP settings */ + /** + * LDAP settings + */ String ldap_provider_url = ConfigurationManager.getProperty("authentication-ldap", "provider_url"); String ldap_id_field = ConfigurationManager.getProperty("authentication-ldap", "id_field"); String ldap_search_context = ConfigurationManager.getProperty("authentication-ldap", "search_context"); @@ -416,33 +374,27 @@ public class LDAPAuthentication String ldap_givenname_field = ConfigurationManager.getProperty("authentication-ldap", "givenname_field"); String ldap_surname_field = ConfigurationManager.getProperty("authentication-ldap", "surname_field"); String ldap_phone_field = ConfigurationManager.getProperty("authentication-ldap", "phone_field"); - String ldap_group_field = ConfigurationManager.getProperty("authentication-ldap", "login.groupmap.attribute"); - + String ldap_group_field = ConfigurationManager.getProperty("authentication-ldap", "login.groupmap.attribute"); + boolean useTLS = ConfigurationManager.getBooleanProperty("authentication-ldap", "starttls", false); - SpeakerToLDAP(Logger thelog) - { + SpeakerToLDAP(Logger thelog) { log = thelog; } - protected String getDNOfUser(String adminUser, String adminPassword, Context context, String netid) - { + protected String getDNOfUser(String adminUser, String adminPassword, Context context, String netid) { // The resultant DN String resultDN; // The search scope to use (default to 0) int ldap_search_scope_value = 0; - try - { + try { ldap_search_scope_value = Integer.parseInt(ldap_search_scope.trim()); - } - catch (NumberFormatException e) - { + } catch (NumberFormatException e) { // Log the error if it has been set but is invalid - if (ldap_search_scope != null) - { + if (ldap_search_scope != null) { log.warn(LogManager.getHeader(context, - "ldap_authentication", "invalid search scope: " + ldap_search_scope)); + "ldap_authentication", "invalid search scope: " + ldap_search_scope)); } } @@ -450,45 +402,38 @@ public class LDAPAuthentication Hashtable env = new Hashtable(); env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(javax.naming.Context.PROVIDER_URL, ldap_provider_url); - + LdapContext ctx = null; StartTlsResponse startTLSResponse = null; - try - { + try { if ((adminUser != null) && (!adminUser.trim().equals("")) && - (adminPassword != null) && (!adminPassword.trim().equals(""))) - { - if(useTLS) - { + (adminPassword != null) && (!adminPassword.trim().equals(""))) { + if (useTLS) { ctx = new InitialLdapContext(env, null); // start TLS startTLSResponse = (StartTlsResponse) ctx - .extendedOperation(new StartTlsRequest()); - + .extendedOperation(new StartTlsRequest()); + startTLSResponse.negotiate(); - + // perform simple client authentication ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "simple"); ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, - adminUser); + adminUser); ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, - adminPassword); - } - else - { + adminPassword); + } else { // Use admin credentials for search// Authenticate env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple"); env.put(javax.naming.Context.SECURITY_PRINCIPAL, adminUser); env.put(javax.naming.Context.SECURITY_CREDENTIALS, adminPassword); } - } - else - { + } else { // Use anonymous authentication env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "none"); } - + if (ctx == null) { // Create initial context ctx = new InitialLdapContext(env, null); @@ -498,24 +443,20 @@ public class LDAPAuthentication matchAttrs.put(new BasicAttribute(ldap_id_field, netid)); // look up attributes - try - { + try { SearchControls ctrls = new SearchControls(); ctrls.setSearchScope(ldap_search_scope_value); String searchName = ""; - if(useTLS) - { + if (useTLS) { searchName = ldap_search_context; - } - else - { + } else { searchName = ldap_provider_url + ldap_search_context; } NamingEnumeration answer = ctx.search( - searchName, - "(&({0}={1}))", new Object[] { ldap_id_field, - netid }, ctrls); + searchName, + "(&({0}={1}))", new Object[] {ldap_id_field, + netid}, ctrls); while (answer.hasMoreElements()) { SearchResult sr = answer.next(); @@ -526,46 +467,41 @@ public class LDAPAuthentication } String attlist[] = {ldap_email_field, ldap_givenname_field, - ldap_surname_field, ldap_phone_field, ldap_group_field}; + ldap_surname_field, ldap_phone_field, ldap_group_field}; Attributes atts = sr.getAttributes(); Attribute att; if (attlist[0] != null) { att = atts.get(attlist[0]); - if (att != null) - { + if (att != null) { ldapEmail = (String) att.get(); } } if (attlist[1] != null) { att = atts.get(attlist[1]); - if (att != null) - { + if (att != null) { ldapGivenName = (String) att.get(); } } if (attlist[2] != null) { att = atts.get(attlist[2]); - if (att != null) - { + if (att != null) { ldapSurname = (String) att.get(); } } if (attlist[3] != null) { att = atts.get(attlist[3]); - if (att != null) - { + if (att != null) { ldapPhone = (String) att.get(); } } - + if (attlist[4] != null) { att = atts.get(attlist[4]); - if (att != null) - { + if (att != null) { ldapGroup = (String) att.get(); } } @@ -579,37 +515,27 @@ public class LDAPAuthentication return resultDN; } } - } - catch (NamingException e) - { + } catch (NamingException e) { // if the lookup fails go ahead and create a new record for them because the authentication // succeeded log.warn(LogManager.getHeader(context, - "ldap_attribute_lookup", "type=failed_search " - + e)); + "ldap_attribute_lookup", "type=failed_search " + + e)); } - } - catch (NamingException | IOException e) - { + } catch (NamingException | IOException e) { log.warn(LogManager.getHeader(context, - "ldap_authentication", "type=failed_auth " + e)); - } - finally - { + "ldap_authentication", "type=failed_auth " + e)); + } finally { // Close the context when we're done - try - { - if (startTLSResponse != null) - { + try { + if (startTLSResponse != null) { startTLSResponse.close(); } - if (ctx != null) - { + if (ctx != null) { ctx.close(); } - } - catch (NamingException | IOException e) - { + } catch (NamingException | IOException e) { + // ignore } } @@ -621,87 +547,79 @@ public class LDAPAuthentication * contact the ldap server and attempt to authenticate */ protected boolean ldapAuthenticate(String netid, String password, - Context context) { + Context context) { if (!password.equals("")) { - + LdapContext ctx = null; StartTlsResponse startTLSResponse = null; - - + + // Set up environment for creating initial context Hashtable env = new Hashtable(); env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(javax.naming.Context.PROVIDER_URL, ldap_provider_url); - try - { - if(useTLS) - { + try { + if (useTLS) { ctx = new InitialLdapContext(env, null); // start TLS startTLSResponse = (StartTlsResponse) ctx - .extendedOperation(new StartTlsRequest()); - + .extendedOperation(new StartTlsRequest()); + startTLSResponse.negotiate(); - + // perform simple client authentication ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "simple"); ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, - netid); + netid); ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, - password); + password); ctx.addToEnvironment(javax.naming.Context.AUTHORITATIVE, "true"); ctx.addToEnvironment(javax.naming.Context.REFERRAL, "follow"); // dummy operation to check if authentication has succeeded ctx.getAttributes(""); - } - - else if (!useTLS) - { + } else if (!useTLS) { // Authenticate env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "Simple"); env.put(javax.naming.Context.SECURITY_PRINCIPAL, netid); env.put(javax.naming.Context.SECURITY_CREDENTIALS, password); env.put(javax.naming.Context.AUTHORITATIVE, "true"); env.put(javax.naming.Context.REFERRAL, "follow"); - + // Try to bind ctx = new InitialLdapContext(env, null); } - } - catch (NamingException | IOException e) - { + } catch (NamingException | IOException e) { // something went wrong (like wrong password) so return false log.warn(LogManager.getHeader(context, - "ldap_authentication", "type=failed_auth " + e)); + "ldap_authentication", "type=failed_auth " + e)); return false; - } finally - { + } finally { // Close the context when we're done try { - if (startTLSResponse != null) - { + if (startTLSResponse != null) { startTLSResponse.close(); } - if (ctx != null) - { + if (ctx != null) { ctx.close(); } - } catch (NamingException | IOException e) {} + } catch (NamingException | IOException e) { + // ignore + } } - } else - { + } else { return false; } return true; - } + } } /* - * Returns URL to which to redirect to obtain credentials (either password - * prompt or e.g. HTTPS port for client cert.); null means no redirect. + * Returns the URL of an external login page which is not applicable for this authn method. + * + * Note: Prior to DSpace 7, this method return the page of login servlet. * * @param context * DSpace context, will be modified (ePerson set) upon success. @@ -716,81 +634,61 @@ public class LDAPAuthentication */ @Override public String loginPageURL(Context context, - HttpServletRequest request, - HttpServletResponse response) - { - return response.encodeRedirectURL(request.getContextPath() + - "/ldap-login"); + HttpServletRequest request, + HttpServletResponse response) { + return null; } - /** - * Returns message key for title of the "login" page, to use - * in a menu showing the choice of multiple login methods. - * - * @param context - * DSpace context, will be modified (ePerson set) upon success. - * - * @return Message key to look up in i18n message catalog. - */ @Override - public String loginPageTitle(Context context) - { - return "org.dspace.eperson.LDAPAuthentication.title"; + public String getName() { + return "ldap"; } - /* * Add authenticated users to the group defined in dspace.cfg by * the authentication-ldap.login.groupmap.* key. */ - private void assignGroups(String dn, String group, Context context) - { - if (StringUtils.isNotBlank(dn)) - { + private void assignGroups(String dn, String group, Context context) { + if (StringUtils.isNotBlank(dn)) { System.out.println("dn:" + dn); int i = 1; String groupMap = ConfigurationManager.getProperty("authentication-ldap", "login.groupmap." + i); - + boolean cmp; - - while (groupMap != null) - { + + while (groupMap != null) { String t[] = groupMap.split(":"); String ldapSearchString = t[0]; String dspaceGroupName = t[1]; - + if (group == null) { cmp = StringUtils.containsIgnoreCase(dn, ldapSearchString + ","); } else { cmp = StringUtils.equalsIgnoreCase(group, ldapSearchString); } - if (cmp) - { - // assign user to this group - try - { + if (cmp) { + // assign user to this group + try { Group ldapGroup = groupService.findByName(context, dspaceGroupName); - if (ldapGroup != null) - { + if (ldapGroup != null) { groupService.addMember(context, ldapGroup, context.getCurrentUser()); groupService.update(context, ldapGroup); - } - else - { + } else { // The group does not exist log.warn(LogManager.getHeader(context, - "ldap_assignGroupsBasedOnLdapDn", - "Group defined in authentication-ldap.login.groupmap." + i + " does not exist :: " + dspaceGroupName)); + "ldap_assignGroupsBasedOnLdapDn", + "Group defined in authentication-ldap.login.groupmap." + i + + " does not exist :: " + dspaceGroupName)); } - } - catch (AuthorizeException ae) - { - log.debug(LogManager.getHeader(context, "assignGroupsBasedOnLdapDn could not authorize addition to group", dspaceGroupName)); - } - catch (SQLException e) - { - log.debug(LogManager.getHeader(context, "assignGroupsBasedOnLdapDn could not find group", dspaceGroupName)); + } catch (AuthorizeException ae) { + log.debug(LogManager.getHeader(context, + "assignGroupsBasedOnLdapDn could not authorize addition to " + + "group", + dspaceGroupName)); + } catch (SQLException e) { + log.debug(LogManager.getHeader(context, "assignGroupsBasedOnLdapDn could not find group", + dspaceGroupName)); } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/PasswordAuthentication.java b/dspace-api/src/main/java/org/dspace/authenticate/PasswordAuthentication.java index c2050f1844..a111be30ce 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/PasswordAuthentication.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/PasswordAuthentication.java @@ -9,12 +9,11 @@ package org.dspace.authenticate; import java.sql.SQLException; import java.util.Arrays; +import java.util.Collections; import java.util.List; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.collections.ListUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.core.Context; @@ -47,7 +46,9 @@ import org.dspace.services.factory.DSpaceServicesFactory; public class PasswordAuthentication implements AuthenticationMethod { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(PasswordAuthentication.class); @@ -59,6 +60,7 @@ public class PasswordAuthentication *

    * Example - aber.ac.uk domain : @aber.ac.uk * Example - MIT domain and all .ac.uk domains: @mit.edu, .ac.uk + * * @param email email * @throws SQLException if database error */ @@ -66,67 +68,62 @@ public class PasswordAuthentication public boolean canSelfRegister(Context context, HttpServletRequest request, String email) - throws SQLException - { + throws SQLException { // Is there anything set in domain.valid? - String[] domains = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("authentication-password.domain.valid"); - if ((domains == null) || (domains.length==0)) - { + String[] domains = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("authentication-password.domain.valid"); + if ((domains == null) || (domains.length == 0)) { // No conditions set, so must be able to self register return true; - } - else - { + } else { // Itterate through all domains String check; email = email.trim().toLowerCase(); - for (int i = 0; i < domains.length; i++) - { + for (int i = 0; i < domains.length; i++) { check = domains[i].trim().toLowerCase(); - if (email.endsWith(check)) - { + if (email.endsWith(check)) { // A match, so we can register this user return true; } } - + // No match return false; - } + } } /** - * Nothing extra to initialize. + * Nothing extra to initialize. + * * @throws SQLException if database error */ @Override public void initEPerson(Context context, HttpServletRequest request, - EPerson eperson) - throws SQLException - { + EPerson eperson) + throws SQLException { } /** * We always allow the user to change their password. + * * @throws SQLException if database error */ @Override public boolean allowSetPassword(Context context, HttpServletRequest request, String username) - throws SQLException - { + throws SQLException { return true; } /** * This is an explicit method, since it needs username and password * from some source. + * * @return false */ @Override - public boolean isImplicit() - { + public boolean isImplicit() { return false; } @@ -135,37 +132,35 @@ public class PasswordAuthentication * the login.specialgroup key. */ @Override - public List getSpecialGroups(Context context, HttpServletRequest request) - { + public List getSpecialGroups(Context context, HttpServletRequest request) { // Prevents anonymous users from being added to this group, and the second check - // ensures they are password users - try - { + // ensures they are password users + try { if (context.getCurrentUser() != null - && StringUtils.isNotBlank(EPersonServiceFactory.getInstance().getEPersonService().getPasswordHash(context.getCurrentUser()).toString())) - { - String groupName = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("authentication-password.login.specialgroup"); - if ((groupName != null) && (!groupName.trim().equals(""))) - { - Group specialGroup = EPersonServiceFactory.getInstance().getGroupService().findByName(context, groupName); - if (specialGroup == null) - { - // Oops - the group isn't there. - log.warn(LogManager.getHeader(context, - "password_specialgroup", - "Group defined in modules/authentication-password.cfg login.specialgroup does not exist")); - return ListUtils.EMPTY_LIST; - } else - { - return Arrays.asList(specialGroup); - } - } - } - } - catch (Exception e) { - log.error(LogManager.getHeader(context,"getSpecialGroups",""),e); - } - return ListUtils.EMPTY_LIST; + && StringUtils.isNotBlank( + EPersonServiceFactory.getInstance().getEPersonService().getPasswordHash(context.getCurrentUser()) + .toString())) { + String groupName = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("authentication-password.login.specialgroup"); + if ((groupName != null) && (!groupName.trim().equals(""))) { + Group specialGroup = EPersonServiceFactory.getInstance().getGroupService() + .findByName(context, groupName); + if (specialGroup == null) { + // Oops - the group isn't there. + log.warn(LogManager.getHeader(context, + "password_specialgroup", + "Group defined in modules/authentication-password.cfg login" + + ".specialgroup does not exist")); + return Collections.EMPTY_LIST; + } else { + return Arrays.asList(specialGroup); + } + } + } + } catch (Exception e) { + log.error(LogManager.getHeader(context, "getSpecialGroups", ""), e); + } + return Collections.EMPTY_LIST; } /** @@ -175,25 +170,15 @@ public class PasswordAuthentication * is only allowed to login via an implicit method * and returns CERT_REQUIRED if that is the case. * - * @param context - * DSpace context, will be modified (EPerson set) upon success. - * - * @param username - * Username (or email address) when method is explicit. Use null for - * implicit method. - * - * @param password - * Password for explicit auth, or null for implicit method. - * - * @param realm - * Realm is an extra parameter used by some authentication methods, leave null if - * not applicable. - * - * @param request - * The HTTP request that started this operation, or null if not applicable. - * + * @param context DSpace context, will be modified (EPerson set) upon success. + * @param username Username (or email address) when method is explicit. Use null for + * implicit method. + * @param password Password for explicit auth, or null for implicit method. + * @param realm Realm is an extra parameter used by some authentication methods, leave null if + * not applicable. + * @param request The HTTP request that started this operation, or null if not applicable. * @return One of: - * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS + * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS *

    Meaning: *
    SUCCESS - authenticated OK. *
    BAD_CREDENTIALS - user exists, but assword doesn't match @@ -208,47 +193,37 @@ public class PasswordAuthentication String password, String realm, HttpServletRequest request) - throws SQLException - { - if (username != null && password != null) - { + throws SQLException { + if (username != null && password != null) { EPerson eperson = null; - log.info(LogManager.getHeader(context, "authenticate", "attempting password auth of user="+username)); - eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, username.toLowerCase()); + log.info(LogManager.getHeader(context, "authenticate", "attempting password auth of user=" + username)); + eperson = EPersonServiceFactory.getInstance().getEPersonService() + .findByEmail(context, username.toLowerCase()); - if (eperson == null) - { + if (eperson == null) { // lookup failed. return NO_SUCH_USER; - } - else if (!eperson.canLogIn()) - { + } else if (!eperson.canLogIn()) { // cannot login this way return BAD_ARGS; - } - else if (eperson.getRequireCertificate()) - { + } else if (eperson.getRequireCertificate()) { // this user can only login with x.509 certificate - log.warn(LogManager.getHeader(context, "authenticate", "rejecting PasswordAuthentication because "+username+" requires certificate.")); + log.warn(LogManager.getHeader(context, "authenticate", + "rejecting PasswordAuthentication because " + username + " requires " + + "certificate.")); return CERT_REQUIRED; - } - else if (EPersonServiceFactory.getInstance().getEPersonService().checkPassword(context, eperson, password)) - { + } else if (EPersonServiceFactory.getInstance().getEPersonService() + .checkPassword(context, eperson, password)) { // login is ok if password matches: context.setCurrentUser(eperson); log.info(LogManager.getHeader(context, "authenticate", "type=PasswordAuthentication")); return SUCCESS; - } - else - { + } else { return BAD_CREDENTIALS; } - } - - // BAD_ARGS always defers to the next authentication method. - // It means this method cannot use the given credentials. - else - { + } else { + // BAD_ARGS always defers to the next authentication method. + // It means this method cannot use the given credentials. return BAD_ARGS; } } @@ -256,38 +231,20 @@ public class PasswordAuthentication /** * Returns URL of password-login servlet. * - * @param context - * DSpace context, will be modified (EPerson set) upon success. - * - * @param request - * The HTTP request that started this operation, or null if not applicable. - * - * @param response - * The HTTP response from the servlet method. - * + * @param context DSpace context, will be modified (EPerson set) upon success. + * @param request The HTTP request that started this operation, or null if not applicable. + * @param response The HTTP response from the servlet method. * @return fully-qualified URL */ @Override public String loginPageURL(Context context, - HttpServletRequest request, - HttpServletResponse response) - { - return response.encodeRedirectURL(request.getContextPath() + - "/password-login"); + HttpServletRequest request, + HttpServletResponse response) { + return null; } - /** - * Returns message key for title of the "login" page, to use - * in a menu showing the choice of multiple login methods. - * - * @param context - * DSpace context, will be modified (EPerson set) upon success. - * - * @return Message key to look up in i18n message catalog. - */ @Override - public String loginPageTitle(Context context) - { - return "org.dspace.eperson.PasswordAuthentication.title"; + public String getName() { + return "password"; } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/ShibAuthentication.java b/dspace-api/src/main/java/org/dspace/authenticate/ShibAuthentication.java index d23c934f3a..cdea32a183 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/ShibAuthentication.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/ShibAuthentication.java @@ -10,19 +10,23 @@ package org.dspace.authenticate; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.sql.SQLException; - +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import javax.servlet.http.HttpServletRequest; - -import java.util.*; - import javax.servlet.http.HttpServletResponse; -import org.apache.commons.collections.ListUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authenticate.factory.AuthenticateServiceFactory; import org.dspace.authorize.AuthorizeException; - import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; import org.dspace.content.NonUniqueMetadataException; @@ -40,212 +44,213 @@ import org.dspace.services.factory.DSpaceServicesFactory; /** * Shibboleth authentication for DSpace - * + * * Shibboleth is a distributed authentication system for securely authenticating * users and passing attributes about the user from one or more identity * providers. In the Shibboleth terminology DSpace is a Service Provider which - * receives authentication information and then based upon that provides a - * service to the user. With Shibboleth DSpace will require that you use + * receives authentication information and then based upon that provides a + * service to the user. With Shibboleth DSpace will require that you use * Apache installed with the mod_shib module acting as a proxy for all HTTP * requests for your servlet container (typically Tomcat). DSpace will receive - * authentication information from the mod_shib module through HTTP headers. + * authentication information from the mod_shib module through HTTP headers. * - * See for more information on installing and configuring a Shibboleth + * See for more information on installing and configuring a Shibboleth * Service Provider: * https://wiki.shibboleth.net/confluence/display/SHIB2/Installation - * + * * See the DSpace.cfg or DSpace manual for information on how to configure * this authentication module. - * + * * @author Bruc Liong, MELCOE * @author Xiang Kevin Li, MELCOE * @author Scott Phillips * @version $Revision$ */ -public class ShibAuthentication implements AuthenticationMethod -{ - /** log4j category */ - private static Logger log = Logger.getLogger(ShibAuthentication.class); +public class ShibAuthentication implements AuthenticationMethod { + /** + * log4j category + */ + private static Logger log = Logger.getLogger(ShibAuthentication.class); - /** Additional metadata mappings **/ - protected Map metadataHeaderMap = null; + /** + * Additional metadata mappings + **/ + protected Map metadataHeaderMap = null; - /** Maximum length for eperson metadata fields **/ + /** + * Maximum length for eperson metadata fields + **/ protected final int NAME_MAX_SIZE = 64; protected final int PHONE_MAX_SIZE = 32; - /** Maximum length for eperson additional metadata fields **/ + /** + * Maximum length for eperson additional metadata fields + **/ protected final int METADATA_MAX_SIZE = 1024; protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); - protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - /** - * Authenticate the given or implicit credentials. This is the heart of the - * authentication method: test the credentials for authenticity, and if - * accepted, attempt to match (or optionally, create) an - * EPerson. If an EPerson is found it is set in - * the Context that was passed. - * - * DSpace supports authentication using NetID, or email address. A user's NetID - * is a unique identifier from the IdP that identifies a particular user. The - * NetID can be of almost any form such as a unique integer, string, or with - * Shibboleth 2.0 you can use "targeted ids". You will need to coordinate with - * your Shibboleth federation or identity provider. There are three ways to - * supply identity information to DSpace: - * - * 1) NetID from Shibboleth Header (best) - * - * The NetID-based method is superior because users may change their email - * address with the identity provider. When this happens DSpace will not be - * able to associate their new address with their old account. - * - * 2) Email address from Shibboleth Header (okay) - * - * In the case where a NetID header is not available or not found DSpace - * will fall back to identifying a user based-upon their email address. - * - * 3) Tomcat's Remote User (worst) - * - * In the event that neither Shibboleth headers are found then as a last - * resort DSpace will look at Tomcat's remote user field. This is the least - * attractive option because Tomcat has no way to supply additional - * attributes about a user. Because of this the autoregister option is not - * supported if this method is used. - * - * Identity Scheme Migration Strategies: - * - * If you are currently using Email based authentication (either 1 or 2) and - * want to upgrade to NetID based authentication then there is an easy path. - * Simply enable Shibboleth to pass the NetID attribute and set the netid-header - * below to the correct value. When a user attempts to log in to DSpace first - * DSpace will look for an EPerson with the passed NetID, however when this - * fails DSpace will fall back to email based authentication. Then DSpace will - * update the user's EPerson account record to set their netid so all future - * authentications for this user will be based upon netid. One thing to note - * is that DSpace will prevent an account from switching NetIDs. If an account - * already has a NetID set and then they try and authenticate with a - * different NetID the authentication will fail. - * - * @param context - * DSpace context, will be modified (ePerson set) upon success. - * - * @param username - * Username (or email address) when method is explicit. Use null - * for implicit method. - * - * @param password - * Password for explicit auth, or null for implicit method. - * - * @param realm - * Not used by Shibboleth-based authentication - * - * @param request - * The HTTP request that started this operation, or null if not - * applicable. - * - * @return One of: SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, - * BAD_ARGS - *

    - * Meaning:
    - * SUCCESS - authenticated OK.
    - * BAD_CREDENTIALS - user exists, but credentials (e.g. passwd) - * don't match
    - * CERT_REQUIRED - not allowed to login this way without X.509 cert. - *
    - * NO_SUCH_USER - user not found using this method.
    - * BAD_ARGS - user/pw not appropriate for this method - * @throws SQLException if database error - */ - @Override + /** + * Authenticate the given or implicit credentials. This is the heart of the + * authentication method: test the credentials for authenticity, and if + * accepted, attempt to match (or optionally, create) an + * EPerson. If an EPerson is found it is set in + * the Context that was passed. + * + * DSpace supports authentication using NetID, or email address. A user's NetID + * is a unique identifier from the IdP that identifies a particular user. The + * NetID can be of almost any form such as a unique integer, string, or with + * Shibboleth 2.0 you can use "targeted ids". You will need to coordinate with + * your Shibboleth federation or identity provider. There are three ways to + * supply identity information to DSpace: + * + * 1) NetID from Shibboleth Header (best) + * + * The NetID-based method is superior because users may change their email + * address with the identity provider. When this happens DSpace will not be + * able to associate their new address with their old account. + * + * 2) Email address from Shibboleth Header (okay) + * + * In the case where a NetID header is not available or not found DSpace + * will fall back to identifying a user based-upon their email address. + * + * 3) Tomcat's Remote User (worst) + * + * In the event that neither Shibboleth headers are found then as a last + * resort DSpace will look at Tomcat's remote user field. This is the least + * attractive option because Tomcat has no way to supply additional + * attributes about a user. Because of this the autoregister option is not + * supported if this method is used. + * + * Identity Scheme Migration Strategies: + * + * If you are currently using Email based authentication (either 1 or 2) and + * want to upgrade to NetID based authentication then there is an easy path. + * Simply enable Shibboleth to pass the NetID attribute and set the netid-header + * below to the correct value. When a user attempts to log in to DSpace first + * DSpace will look for an EPerson with the passed NetID, however when this + * fails DSpace will fall back to email based authentication. Then DSpace will + * update the user's EPerson account record to set their netid so all future + * authentications for this user will be based upon netid. One thing to note + * is that DSpace will prevent an account from switching NetIDs. If an account + * already has a NetID set and then they try and authenticate with a + * different NetID the authentication will fail. + * + * @param context DSpace context, will be modified (ePerson set) upon success. + * @param username Username (or email address) when method is explicit. Use null + * for implicit method. + * @param password Password for explicit auth, or null for implicit method. + * @param realm Not used by Shibboleth-based authentication + * @param request The HTTP request that started this operation, or null if not + * applicable. + * @return One of: SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, + * BAD_ARGS + *

    + * Meaning:
    + * SUCCESS - authenticated OK.
    + * BAD_CREDENTIALS - user exists, but credentials (e.g. passwd) + * don't match
    + * CERT_REQUIRED - not allowed to login this way without X.509 cert. + *
    + * NO_SUCH_USER - user not found using this method.
    + * BAD_ARGS - user/pw not appropriate for this method + * @throws SQLException if database error + */ + @Override public int authenticate(Context context, String username, String password, - String realm, HttpServletRequest request) throws SQLException { + String realm, HttpServletRequest request) throws SQLException { - // Check if sword compatibility is allowed, and if so see if we can - // authenticate based upon a username and password. This is really helpful - // if your repo uses Shibboleth but you want some accounts to be able use - // sword. This allows this compatibility without installing the password-based - // authentication method which has side effects such as allowing users to login - // with a username and password from the webui. - boolean swordCompatibility = configurationService.getBooleanProperty("authentication-shibboleth.sword.compatibility", true); - if ( swordCompatibility && - username != null && username.length() > 0 && - password != null && password.length() > 0 ) { - return swordCompatibility(context, username, password, request); - } - - if (request == null) { - log.warn("Unable to authenticate using Shibboleth because the request object is null."); - return BAD_ARGS; - } + // Check if sword compatibility is allowed, and if so see if we can + // authenticate based upon a username and password. This is really helpful + // if your repo uses Shibboleth but you want some accounts to be able use + // sword. This allows this compatibility without installing the password-based + // authentication method which has side effects such as allowing users to login + // with a username and password from the webui. + boolean swordCompatibility = configurationService + .getBooleanProperty("authentication-shibboleth.sword.compatibility", true); + if (swordCompatibility && + username != null && username.length() > 0 && + password != null && password.length() > 0) { + return swordCompatibility(context, username, password, request); + } - // Initialize the additional EPerson metadata. - initialize(context); + if (request == null) { + log.warn("Unable to authenticate using Shibboleth because the request object is null."); + return BAD_ARGS; + } - // Log all headers received if debugging is turned on. This is enormously - // helpful when debugging shibboleth related problems. - if (log.isDebugEnabled()) { - log.debug("Starting Shibboleth Authentication"); + // Initialize the additional EPerson metadata. + initialize(context); - String message = "Received the following headers:\n"; - @SuppressWarnings("unchecked") - Enumeration headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - @SuppressWarnings("unchecked") - Enumeration headerValues = request.getHeaders(headerName); - while (headerValues.hasMoreElements()) { - String headerValue = headerValues.nextElement(); - message += ""+headerName+"='"+headerValue+"'\n"; - } - } - log.debug(message); - } + // Log all headers received if debugging is turned on. This is enormously + // helpful when debugging shibboleth related problems. + if (log.isDebugEnabled()) { + log.debug("Starting Shibboleth Authentication"); - // Should we auto register new users. - boolean autoRegister = configurationService.getBooleanProperty("authentication-shibboleth.autoregister", true); + String message = "Received the following headers:\n"; + @SuppressWarnings("unchecked") + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + @SuppressWarnings("unchecked") + Enumeration headerValues = request.getHeaders(headerName); + while (headerValues.hasMoreElements()) { + String headerValue = headerValues.nextElement(); + message += "" + headerName + "='" + headerValue + "'\n"; + } + } + log.debug(message); + } - // Four steps to authenticate a user - try { - // Step 1: Identify User - EPerson eperson = findEPerson(context, request); + // Should we auto register new users. + boolean autoRegister = configurationService.getBooleanProperty("authentication-shibboleth.autoregister", true); - // Step 2: Register New User, if necessary - if (eperson == null && autoRegister) - eperson = registerNewEPerson(context, request); + // Four steps to authenticate a user + try { + // Step 1: Identify User + EPerson eperson = findEPerson(context, request); - if (eperson == null) - return AuthenticationMethod.NO_SUCH_USER; + // Step 2: Register New User, if necessary + if (eperson == null && autoRegister) { + eperson = registerNewEPerson(context, request); + } - // Step 3: Update User's Metadata - updateEPerson(context, request, eperson); + if (eperson == null) { + return AuthenticationMethod.NO_SUCH_USER; + } - // Step 4: Log the user in. - context.setCurrentUser(eperson); - request.getSession().setAttribute("shib.authenticated", true); - AuthenticateServiceFactory.getInstance().getAuthenticationService().initEPerson(context, request, eperson); + // Step 3: Update User's Metadata + updateEPerson(context, request, eperson); - log.info(eperson.getEmail()+" has been authenticated via shibboleth."); - return AuthenticationMethod.SUCCESS; + // Step 4: Log the user in. + context.setCurrentUser(eperson); + request.getSession().setAttribute("shib.authenticated", true); + AuthenticateServiceFactory.getInstance().getAuthenticationService().initEPerson(context, request, eperson); - } catch (Throwable t) { - // Log the error, and undo the authentication before returning a failure. - log.error("Unable to successfully authenticate using shibboleth for user because of an exception.",t); - context.setCurrentUser(null); - return AuthenticationMethod.NO_SUCH_USER; - } - } + log.info(eperson.getEmail() + " has been authenticated via shibboleth."); + return AuthenticationMethod.SUCCESS; + + } catch (Throwable t) { + // Log the error, and undo the authentication before returning a failure. + log.error("Unable to successfully authenticate using shibboleth for user because of an exception.", t); + context.setCurrentUser(null); + return AuthenticationMethod.NO_SUCH_USER; + } + } /** * Get list of extra groups that user implicitly belongs to. Note that this * method will be invoked regardless of the authentication status of the * user (logged-in or not) e.g. a group that depends on the client * network-address. - * + * * DSpace is able to place users into pre-defined groups based upon values * received from Shibboleth. Using this option you can place all faculty members * into a DSpace group when the correct affiliation's attribute is provided. @@ -254,7 +259,7 @@ public class ShibAuthentication implements AuthenticationMethod * database. Each time a user authenticates they are automatically placed within * the pre-defined DSpace group, so if the user loses their affiliation then the * next time they login they will no longer be in the group. - * + * * Depending upon the shibboleth attributed use in the role-header, it may be * scoped. Scoped is shibboleth terminology for identifying where an attribute * originated from. For example a students affiliation may be encoded as @@ -264,757 +269,806 @@ public class ShibAuthentication implements AuthenticationMethod * different than students at another institution. Or if you turn on * ignore-scope you could ignore the institution and place all students into * one group. - * + * * The values extracted (a user may have multiple roles) will be used to look * up which groups to place the user into. The groups are defined as * {@code authentication.shib.role.} which is a comma separated list of - * DSpace groups. - * - * @param context - * A valid DSpace context. - * - * @param request - * The request that started this operation, or null if not - * applicable. - * + * DSpace groups. + * + * @param context A valid DSpace context. + * @param request The request that started this operation, or null if not + * applicable. * @return array of EPerson-group IDs, possibly 0-length, but never - * null. + * null. */ - @Override - public List getSpecialGroups(Context context, HttpServletRequest request) - { - try { - // User has not successfuly authenticated via shibboleth. - if ( request == null || - context.getCurrentUser() == null || - request.getSession().getAttribute("shib.authenticated") == null ) { - return ListUtils.EMPTY_LIST; - } + @Override + public List getSpecialGroups(Context context, HttpServletRequest request) { + try { + // User has not successfuly authenticated via shibboleth. + if (request == null || + context.getCurrentUser() == null || + request.getSession().getAttribute("shib.authenticated") == null) { + return Collections.EMPTY_LIST; + } - // If we have already calculated the special groups then return them. - if (request.getSession().getAttribute("shib.specialgroup") != null) - { - log.debug("Returning cached special groups."); + // If we have already calculated the special groups then return them. + if (request.getSession().getAttribute("shib.specialgroup") != null) { + log.debug("Returning cached special groups."); List sessionGroupIds = (List) request.getSession().getAttribute("shib.specialgroup"); List result = new ArrayList<>(); for (UUID uuid : sessionGroupIds) { result.add(groupService.find(context, uuid)); } return result; - } + } - log.debug("Starting to determine special groups"); - String[] defaultRoles = configurationService.getArrayProperty("authentication-shibboleth.default-roles"); - String roleHeader = configurationService.getProperty("authentication-shibboleth.role-header"); - boolean ignoreScope = configurationService.getBooleanProperty("authentication-shibboleth.role-header.ignore-scope", true); - boolean ignoreValue = configurationService.getBooleanProperty("authentication-shibboleth.role-header.ignore-value", false); + log.debug("Starting to determine special groups"); + String[] defaultRoles = configurationService.getArrayProperty("authentication-shibboleth.default-roles"); + String roleHeader = configurationService.getProperty("authentication-shibboleth.role-header"); + boolean ignoreScope = configurationService + .getBooleanProperty("authentication-shibboleth.role-header.ignore-scope", true); + boolean ignoreValue = configurationService + .getBooleanProperty("authentication-shibboleth.role-header.ignore-value", false); - if (ignoreScope && ignoreValue) { - throw new IllegalStateException("Both config parameters for ignoring an roll attributes scope and value are turned on, this is not a permissable configuration. (Note: ignore-scope defaults to true) The configuration parameters are: 'authentication.shib.role-header.ignore-scope' and 'authentication.shib.role-header.ignore-value'"); - } + if (ignoreScope && ignoreValue) { + throw new IllegalStateException( + "Both config parameters for ignoring an roll attributes scope and value are turned on, this is " + + "not a permissable configuration. (Note: ignore-scope defaults to true) The configuration " + + "parameters are: 'authentication.shib.role-header.ignore-scope' and 'authentication.shib" + + ".role-header.ignore-value'"); + } - // Get the Shib supplied affiliation or use the default affiliation - List affiliations = findMultipleAttributes(request, roleHeader); - if (affiliations == null) { - if (defaultRoles != null) - affiliations = Arrays.asList(defaultRoles); - log.debug("Failed to find Shibboleth role header, '"+roleHeader+"', falling back to the default roles: '"+ StringUtils.join(defaultRoles, ",") + "'"); - } else { - log.debug("Found Shibboleth role header: '"+roleHeader+"' = '"+affiliations+"'"); - } + // Get the Shib supplied affiliation or use the default affiliation + List affiliations = findMultipleAttributes(request, roleHeader); + if (affiliations == null) { + if (defaultRoles != null) { + affiliations = Arrays.asList(defaultRoles); + } + log.debug( + "Failed to find Shibboleth role header, '" + roleHeader + "', falling back to the default roles: " + + "'" + StringUtils + .join(defaultRoles, ",") + "'"); + } else { + log.debug("Found Shibboleth role header: '" + roleHeader + "' = '" + affiliations + "'"); + } - // Loop through each affiliation - Set groups = new HashSet<>(); - if (affiliations != null) { - for ( String affiliation : affiliations) { - // If we ignore the affiliation's scope then strip the scope if it exists. - if (ignoreScope) { - int index = affiliation.indexOf('@'); - if (index != -1) { - affiliation = affiliation.substring(0, index); - } - } - // If we ignore the value, then strip it out so only the scope remains. - if (ignoreValue) { - int index = affiliation.indexOf('@'); - if (index != -1) { - affiliation = affiliation.substring(index+1, affiliation.length()); - } - } + // Loop through each affiliation + Set groups = new HashSet<>(); + if (affiliations != null) { + for (String affiliation : affiliations) { + // If we ignore the affiliation's scope then strip the scope if it exists. + if (ignoreScope) { + int index = affiliation.indexOf('@'); + if (index != -1) { + affiliation = affiliation.substring(0, index); + } + } + // If we ignore the value, then strip it out so only the scope remains. + if (ignoreValue) { + int index = affiliation.indexOf('@'); + if (index != -1) { + affiliation = affiliation.substring(index + 1, affiliation.length()); + } + } - // Get the group names - String[] groupNames = configurationService.getArrayProperty("authentication-shibboleth.role." + affiliation); - if (groupNames == null || groupNames.length == 0) { - groupNames = configurationService.getArrayProperty("authentication-shibboleth.role." + affiliation.toLowerCase()); - } + // Get the group names + String[] groupNames = configurationService + .getArrayProperty("authentication-shibboleth.role." + affiliation); + if (groupNames == null || groupNames.length == 0) { + groupNames = configurationService + .getArrayProperty("authentication-shibboleth.role." + affiliation.toLowerCase()); + } - if (groupNames == null) { - log.debug("Unable to find role mapping for the value, '"+affiliation+"', there should be a mapping in config/modules/authentication-shibboleth.cfg: role."+affiliation+" = "); - continue; - } else { - log.debug("Mapping role affiliation to DSpace group: '"+ StringUtils.join(groupNames, ",") +"'"); - } + if (groupNames == null) { + log.debug( + "Unable to find role mapping for the value, '" + affiliation + "', there should be a " + + "mapping in config/modules/authentication-shibboleth.cfg: role." + affiliation + " =" + + " "); + continue; + } else { + log.debug( + "Mapping role affiliation to DSpace group: '" + StringUtils.join(groupNames, ",") + "'"); + } - // Add each group to the list. - for (int i = 0; i < groupNames.length; i++) { - try { - Group group = groupService.findByName(context,groupNames[i].trim()); - if (group != null) - groups.add(group); - else - log.debug("Unable to find group: '"+groupNames[i].trim()+"'"); - } catch (SQLException sqle) { - log.error("Exception thrown while trying to lookup affiliation role for group name: '"+groupNames[i].trim()+"'",sqle); - } - } // for each groupNames - } // foreach affiliations - } // if affiliations + // Add each group to the list. + for (int i = 0; i < groupNames.length; i++) { + try { + Group group = groupService.findByName(context, groupNames[i].trim()); + if (group != null) { + groups.add(group); + } else { + log.debug("Unable to find group: '" + groupNames[i].trim() + "'"); + } + } catch (SQLException sqle) { + log.error( + "Exception thrown while trying to lookup affiliation role for group name: '" + + groupNames[i] + .trim() + "'", sqle); + } + } // for each groupNames + } // foreach affiliations + } // if affiliations - log.info("Added current EPerson to special groups: "+groups); + log.info("Added current EPerson to special groups: " + groups); List groupIds = new ArrayList<>(); - for(Group group : groups) - { + for (Group group : groups) { groupIds.add(group.getID()); } - // Cache the special groups, so we don't have to recalculate them again - // for this session. - request.getSession().setAttribute("shib.specialgroup", groupIds); + // Cache the special groups, so we don't have to recalculate them again + // for this session. + request.getSession().setAttribute("shib.specialgroup", groupIds); - return new ArrayList<>(groups); - } catch (Throwable t) { - log.error("Unable to validate any sepcial groups this user may belong too because of an exception.",t); - return ListUtils.EMPTY_LIST; - } - } + return new ArrayList<>(groups); + } catch (Throwable t) { + log.error("Unable to validate any sepcial groups this user may belong too because of an exception.", t); + return Collections.EMPTY_LIST; + } + } - /** - * Indicate whether or not a particular self-registering user can set - * themselves a password in the profile info form. - * - * @param context - * DSpace context - * @param request - * HTTP request, in case anything in that is used to decide - * @param email - * e-mail address of user attempting to register - * @throws SQLException if database error - * - */ - @Override + /** + * Indicate whether or not a particular self-registering user can set + * themselves a password in the profile info form. + * + * @param context DSpace context + * @param request HTTP request, in case anything in that is used to decide + * @param email e-mail address of user attempting to register + * @throws SQLException if database error + */ + @Override public boolean allowSetPassword(Context context, - HttpServletRequest request, String email) throws SQLException { - // don't use password at all - return false; - } + HttpServletRequest request, String email) throws SQLException { + // don't use password at all + return false; + } - /** - * Predicate, is this an implicit authentication method. An implicit method - * gets credentials from the environment (such as an HTTP request or even - * Java system properties) rather than the explicit username and password. - * For example, a method that reads the X.509 certificates in an HTTPS - * request is implicit. - * - * @return true if this method uses implicit authentication. - */ - @Override - public boolean isImplicit() - { - return false; - } + /** + * Predicate, is this an implicit authentication method. An implicit method + * gets credentials from the environment (such as an HTTP request or even + * Java system properties) rather than the explicit username and password. + * For example, a method that reads the X.509 certificates in an HTTPS + * request is implicit. + * + * @return true if this method uses implicit authentication. + */ + @Override + public boolean isImplicit() { + return false; + } - /** - * Indicate whether or not a particular user can self-register, based on - * e-mail address. - * - * @param context - * DSpace context - * @param request - * HTTP request, in case anything in that is used to decide - * @param username - * e-mail address of user attempting to register - * @throws SQLException if database error - * - */ - @Override + /** + * Indicate whether or not a particular user can self-register, based on + * e-mail address. + * + * @param context DSpace context + * @param request HTTP request, in case anything in that is used to decide + * @param username e-mail address of user attempting to register + * @throws SQLException if database error + */ + @Override public boolean canSelfRegister(Context context, HttpServletRequest request, - String username) throws SQLException { + String username) throws SQLException { - // Shibboleth will auto create accounts if configured to do so, but that is not - // the same as self register. Self register means that the user can sign up for - // an account from the web. This is not supported with shibboleth. - return false; - } + // Shibboleth will auto create accounts if configured to do so, but that is not + // the same as self register. Self register means that the user can sign up for + // an account from the web. This is not supported with shibboleth. + return false; + } - /** - * Initialize a new e-person record for a self-registered new user. - * - * @param context - * DSpace context - * @param request - * HTTP request, in case it's needed - * @param eperson - * newly created EPerson record - email + information from the - * registration form will have been filled out. - * @throws SQLException if database error - * - */ - @Override + /** + * Initialize a new e-person record for a self-registered new user. + * + * @param context DSpace context + * @param request HTTP request, in case it's needed + * @param eperson newly created EPerson record - email + information from the + * registration form will have been filled out. + * @throws SQLException if database error + */ + @Override public void initEPerson(Context context, HttpServletRequest request, - EPerson eperson) throws SQLException { - // We don't do anything because all our work is done authenticate and special groups. - } + EPerson eperson) throws SQLException { + // We don't do anything because all our work is done authenticate and special groups. + } - /** - * Get login page to which to redirect. Returns URL (as string) to which to - * redirect to obtain credentials (either password prompt or e.g. HTTPS port - * for client cert.); null means no redirect. - * - * @param context - * DSpace context, will be modified (ePerson set) upon success. - * - * @param request - * The HTTP request that started this operation, or null if not - * applicable. - * - * @param response - * The HTTP response from the servlet method. - * - * @return fully-qualified URL or null - */ - @Override - public String loginPageURL(Context context, HttpServletRequest request, - HttpServletResponse response) - { - // If this server is configured for lazy sessions then use this to - // login, otherwise default to the protected shibboleth url. + /** + * Get login page to which to redirect. Returns URL (as string) to which to + * redirect to obtain credentials (either password prompt or e.g. HTTPS port + * for client cert.); null means no redirect. + * + * @param context DSpace context, will be modified (ePerson set) upon success. + * @param request The HTTP request that started this operation, or null if not + * applicable. + * @param response The HTTP response from the servlet method. + * @return fully-qualified URL or null + */ + @Override + public String loginPageURL(Context context, HttpServletRequest request, HttpServletResponse response) { + // If this server is configured for lazy sessions then use this to + // login, otherwise default to the protected shibboleth url. - boolean lazySession = configurationService.getBooleanProperty("authentication-shibboleth.lazysession", false); + boolean lazySession = configurationService.getBooleanProperty("authentication-shibboleth.lazysession", false); - if ( lazySession ) { - String shibURL = configurationService.getProperty("authentication-shibboleth.lazysession.loginurl"); - boolean forceHTTPS = configurationService.getBooleanProperty("authentication-shibboleth.lazysession.secure",true); + if ( lazySession ) { + String shibURL = configurationService.getProperty("authentication-shibboleth.lazysession.loginurl"); + boolean forceHTTPS = + configurationService.getBooleanProperty("authentication-shibboleth.lazysession.secure",true); - // Shibboleth authentication initiator - if (shibURL == null || shibURL.length() == 0) - shibURL = "/Shibboleth.sso/Login"; - shibURL = shibURL.trim(); + // Shibboleth authentication initiator + if (shibURL == null || shibURL.length() == 0) { + shibURL = "/Shibboleth.sso/Login"; + } + shibURL = shibURL.trim(); - // Determine the return URL, where shib will send the user after authenticating. We need it to go back - // to DSpace's shibboleth-login url so the we will extract the user's information and locally - // authenticate them. - String host = request.getServerName(); - int port = request.getServerPort(); - String contextPath = request.getContextPath(); + // Determine the return URL, where shib will send the user after authenticating. We need it to go back + // to DSpace's shibboleth-login url so the we will extract the user's information and locally + // authenticate them. + String host = request.getServerName(); + int port = request.getServerPort(); + String contextPath = request.getContextPath(); - String returnURL; - if (request.isSecure() || forceHTTPS) - returnURL = "https://"; - else - returnURL = "http://"; + String returnURL = request.getHeader("Referer"); + if (returnURL == null) { + if (request.isSecure() || forceHTTPS) { + returnURL = "https://"; + } else { + returnURL = "http://"; + } + returnURL += host; + if (!(port == 443 || port == 80)) { + returnURL += ":" + port; + } + } - returnURL += host; - if (!(port == 443 || port == 80)) - returnURL += ":" + port; - returnURL += "/" + contextPath + "/shibboleth-login"; + try { + shibURL += "?target=" + URLEncoder.encode(returnURL, "UTF-8"); + } catch (UnsupportedEncodingException uee) { + log.error("Unable to generate lazysession authentication",uee); + } - try { - shibURL += "?target="+URLEncoder.encode(returnURL, "UTF-8"); - } catch (UnsupportedEncodingException uee) { - log.error("Unable to generate lazysession authentication",uee); - } + log.debug("Redirecting user to Shibboleth initiator: " + shibURL); - log.debug("Redirecting user to Shibboleth initiator: "+shibURL); + return response.encodeRedirectURL(shibURL); + } else { + // If we are not using lazy sessions rely on the protected URL. + return response.encodeRedirectURL(request.getContextPath() + + "/shibboleth-login"); + } + } - return response.encodeRedirectURL(shibURL); - } else { - // If we are not using lazy sessions rely on the protected URL. - return response.encodeRedirectURL(request.getContextPath() - + "/shibboleth-login"); - } - } + @Override + public String getName() { + return "shibboleth"; + } - /** - * Get title of login page to which to redirect. Returns a message - * key that gets translated into the title or label for "login page" (or - * null, if not implemented) This title may be used to identify the link to - * the login page in a selection menu, when there are multiple ways to - * login. - * - * @param context - * DSpace context, will be modified (ePerson set) upon success. - * - * @return title text. - */ - @Override - public String loginPageTitle(Context context) - { - return "org.dspace.authenticate.ShibAuthentication.title"; - } - - - /** - * Identify an existing EPerson based upon the shibboleth attributes provided on - * the request object. There are three cases where this can occurr, each as - * a fallback for the previous method. - * - * 1) NetID from Shibboleth Header (best) - * The NetID-based method is superior because users may change their email - * address with the identity provider. When this happens DSpace will not be - * able to associate their new address with their old account. - * - * 2) Email address from Shibboleth Header (okay) - * In the case where a NetID header is not available or not found DSpace - * will fall back to identifying a user based upon their email address. - * - * 3) Tomcat's Remote User (worst) - * In the event that neither Shibboleth headers are found then as a last - * resort DSpace will look at Tomcat's remote user field. This is the least - * attractive option because Tomcat has no way to supply additional - * attributes about a user. Because of this the autoregister option is not - * supported if this method is used. - * - * If successful then the identified EPerson will be returned, otherwise null. - * - * @param context The DSpace database context - * @param request The current HTTP Request - * @return The EPerson identified or null. - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - */ + /** + * Identify an existing EPerson based upon the shibboleth attributes provided on + * the request object. There are three cases where this can occurr, each as + * a fallback for the previous method. + * + * 1) NetID from Shibboleth Header (best) + * The NetID-based method is superior because users may change their email + * address with the identity provider. When this happens DSpace will not be + * able to associate their new address with their old account. + * + * 2) Email address from Shibboleth Header (okay) + * In the case where a NetID header is not available or not found DSpace + * will fall back to identifying a user based upon their email address. + * + * 3) Tomcat's Remote User (worst) + * In the event that neither Shibboleth headers are found then as a last + * resort DSpace will look at Tomcat's remote user field. This is the least + * attractive option because Tomcat has no way to supply additional + * attributes about a user. Because of this the autoregister option is not + * supported if this method is used. + * + * If successful then the identified EPerson will be returned, otherwise null. + * + * @param context The DSpace database context + * @param request The current HTTP Request + * @return The EPerson identified or null. + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ protected EPerson findEPerson(Context context, HttpServletRequest request) throws SQLException, AuthorizeException { - boolean isUsingTomcatUser = configurationService.getBooleanProperty("authentication-shibboleth.email-use-tomcat-remote-user"); - String netidHeader = configurationService.getProperty("authentication-shibboleth.netid-header"); - String emailHeader = configurationService.getProperty("authentication-shibboleth.email-header"); + boolean isUsingTomcatUser = configurationService + .getBooleanProperty("authentication-shibboleth.email-use-tomcat-remote-user"); + String netidHeader = configurationService.getProperty("authentication-shibboleth.netid-header"); + String emailHeader = configurationService.getProperty("authentication-shibboleth.email-header"); - EPerson eperson = null; - boolean foundNetID = false; - boolean foundEmail = false; - boolean foundRemoteUser = false; + EPerson eperson = null; + boolean foundNetID = false; + boolean foundEmail = false; + boolean foundRemoteUser = false; - // 1) First, look for a netid header. - if (netidHeader != null) { - String netid = findSingleAttribute(request,netidHeader); + // 1) First, look for a netid header. + if (netidHeader != null) { + String netid = findSingleAttribute(request, netidHeader); - if (netid != null) { - foundNetID = true; - eperson = ePersonService.findByNetid(context, netid); + if (netid != null) { + foundNetID = true; + eperson = ePersonService.findByNetid(context, netid); - if (eperson == null) - log.info("Unable to identify EPerson based upon Shibboleth netid header: '"+netidHeader+"'='"+netid+"'."); - else - log.debug("Identified EPerson based upon Shibboleth netid header: '"+netidHeader+"'='"+netid+"'."); - } - } + if (eperson == null) { + log.info( + "Unable to identify EPerson based upon Shibboleth netid header: '" + netidHeader + "'='" + + netid + "'."); + } else { + log.debug( + "Identified EPerson based upon Shibboleth netid header: '" + netidHeader + "'='" + netid + "'" + + "."); + } + } + } - // 2) Second, look for an email header. - if (eperson == null && emailHeader != null) { - String email = findSingleAttribute(request,emailHeader); + // 2) Second, look for an email header. + if (eperson == null && emailHeader != null) { + String email = findSingleAttribute(request, emailHeader); - if (email != null) { - foundEmail = true; - email = email.toLowerCase(); - eperson = ePersonService.findByEmail(context, email); + if (email != null) { + foundEmail = true; + email = email.toLowerCase(); + eperson = ePersonService.findByEmail(context, email); - if (eperson == null) - log.info("Unable to identify EPerson based upon Shibboleth email header: '"+emailHeader+"'='"+email+"'."); - else - log.info("Identified EPerson based upon Shibboleth email header: '"+emailHeader+"'='"+email+"'."); + if (eperson == null) { + log.info( + "Unable to identify EPerson based upon Shibboleth email header: '" + emailHeader + "'='" + + email + "'."); + } else { + log.info( + "Identified EPerson based upon Shibboleth email header: '" + emailHeader + "'='" + email + "'" + + "."); + } - if (eperson != null && eperson.getNetid() != null) { - // If the user has a netID it has been locked to that netid, don't let anyone else try and steal the account. - log.error("The identified EPerson based upon Shibboleth email header, '"+emailHeader+"'='"+email+"', is locked to another netid: '"+eperson.getNetid()+"'. This might be a possible hacking attempt to steal another users credentials. If the user's netid has changed you will need to manually change it to the correct value or unset it in the database."); - eperson = null; - } - } - } + if (eperson != null && eperson.getNetid() != null) { + // If the user has a netID it has been locked to that netid, don't let anyone else try and steal + // the account. + log.error( + "The identified EPerson based upon Shibboleth email header, '" + emailHeader + "'='" + email + + "', is locked to another netid: '" + eperson + .getNetid() + "'. This might be a possible hacking attempt to steal another users " + + "credentials. If the user's netid has changed you will need to manually change it to the " + + "correct value or unset it in the database."); + eperson = null; + } + } + } - // 3) Last, check to see if tomcat is passing a user. - if (eperson == null && isUsingTomcatUser) { - String email = request.getRemoteUser(); + // 3) Last, check to see if tomcat is passing a user. + if (eperson == null && isUsingTomcatUser) { + String email = request.getRemoteUser(); - if (email != null) { - foundRemoteUser = true; - email = email.toLowerCase(); - eperson = ePersonService.findByEmail(context, email); + if (email != null) { + foundRemoteUser = true; + email = email.toLowerCase(); + eperson = ePersonService.findByEmail(context, email); - if (eperson == null) - log.info("Unable to identify EPerson based upon Tomcat's remote user: '"+email+"'."); - else - log.info("Identified EPerson based upon Tomcat's remote user: '"+email+"'."); + if (eperson == null) { + log.info("Unable to identify EPerson based upon Tomcat's remote user: '" + email + "'."); + } else { + log.info("Identified EPerson based upon Tomcat's remote user: '" + email + "'."); + } - if (eperson != null && eperson.getNetid() != null) { - // If the user has a netID it has been locked to that netid, don't let anyone else try and steal the account. - log.error("The identified EPerson based upon Tomcat's remote user, '"+email+"', is locked to another netid: '"+eperson.getNetid()+"'. This might be a possible hacking attempt to steal another users credentials. If the user's netid has changed you will need to manually change it to the correct value or unset it in the database."); - eperson = null; - } - } - } + if (eperson != null && eperson.getNetid() != null) { + // If the user has a netID it has been locked to that netid, don't let anyone else try and steal + // the account. + log.error( + "The identified EPerson based upon Tomcat's remote user, '" + email + "', is locked to " + + "another netid: '" + eperson + .getNetid() + "'. This might be a possible hacking attempt to steal another users " + + "credentials. If the user's netid has changed you will need to manually change it to the " + + "correct value or unset it in the database."); + eperson = null; + } + } + } - if (!foundNetID && !foundEmail && !foundRemoteUser) { - log.error("Shibboleth authentication was not able to find a NetId, Email, or Tomcat Remote user for which to indentify a user from."); - } + if (!foundNetID && !foundEmail && !foundRemoteUser) { + log.error( + "Shibboleth authentication was not able to find a NetId, Email, or Tomcat Remote user for which to " + + "indentify a user from."); + } - return eperson; - } + return eperson; + } - /** - * Register a new eperson object. This method is called when no existing user was - * found for the NetID or Email and autoregister is enabled. When these conditions - * are met this method will create a new eperson object. - * - * In order to create a new eperson object there is a minimal set of metadata - * required: Email, First Name, and Last Name. If we don't have access to these - * three pieces of information then we will be unable to create a new eperson - * object, such as the case when Tomcat's Remote User field is used to identify - * a particular user. - * - * Note, that this method only adds the minimal metadata. Any additional metadata - * will need to be added by the updateEPerson method. - * - * @param context The current DSpace database context - * @param request The current HTTP Request - * @return A new eperson object or null if unable to create a new eperson. - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - */ - protected EPerson registerNewEPerson(Context context, HttpServletRequest request) throws SQLException, AuthorizeException { + /** + * Register a new eperson object. This method is called when no existing user was + * found for the NetID or Email and autoregister is enabled. When these conditions + * are met this method will create a new eperson object. + * + * In order to create a new eperson object there is a minimal set of metadata + * required: Email, First Name, and Last Name. If we don't have access to these + * three pieces of information then we will be unable to create a new eperson + * object, such as the case when Tomcat's Remote User field is used to identify + * a particular user. + * + * Note, that this method only adds the minimal metadata. Any additional metadata + * will need to be added by the updateEPerson method. + * + * @param context The current DSpace database context + * @param request The current HTTP Request + * @return A new eperson object or null if unable to create a new eperson. + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + protected EPerson registerNewEPerson(Context context, HttpServletRequest request) + throws SQLException, AuthorizeException { - // Header names - String netidHeader = configurationService.getProperty("authentication-shibboleth.netid-header"); - String emailHeader = configurationService.getProperty("authentication-shibboleth.email-header"); - String fnameHeader = configurationService.getProperty("authentication-shibboleth.firstname-header"); - String lnameHeader = configurationService.getProperty("authentication-shibboleth.lastname-header"); + // Header names + String netidHeader = configurationService.getProperty("authentication-shibboleth.netid-header"); + String emailHeader = configurationService.getProperty("authentication-shibboleth.email-header"); + String fnameHeader = configurationService.getProperty("authentication-shibboleth.firstname-header"); + String lnameHeader = configurationService.getProperty("authentication-shibboleth.lastname-header"); - // Header values - String netid = findSingleAttribute(request,netidHeader); - String email = findSingleAttribute(request,emailHeader); - String fname = findSingleAttribute(request,fnameHeader); - String lname = findSingleAttribute(request,lnameHeader); + // Header values + String netid = findSingleAttribute(request, netidHeader); + String email = findSingleAttribute(request, emailHeader); + String fname = findSingleAttribute(request, fnameHeader); + String lname = findSingleAttribute(request, lnameHeader); - if ( email == null || (fnameHeader != null && fname == null) || (lnameHeader != null && lname == null)) { - // We require that there be an email, first name, and last name. If we - // don't have at least these three pieces of information then we fail. - String message = "Unable to register new eperson because we are unable to find an email address along with first and last name for the user.\n"; - message += " NetId Header: '"+netidHeader+"'='"+netid+"' (Optional) \n"; - message += " Email Header: '"+emailHeader+"'='"+email+"' \n"; - message += " First Name Header: '"+fnameHeader+"'='"+fname+"' \n"; - message += " Last Name Header: '"+lnameHeader+"'='"+lname+"'"; - log.error(message); + if (email == null || (fnameHeader != null && fname == null) || (lnameHeader != null && lname == null)) { + // We require that there be an email, first name, and last name. If we + // don't have at least these three pieces of information then we fail. + String message = "Unable to register new eperson because we are unable to find an email address along " + + "with first and last name for the user.\n"; + message += " NetId Header: '" + netidHeader + "'='" + netid + "' (Optional) \n"; + message += " Email Header: '" + emailHeader + "'='" + email + "' \n"; + message += " First Name Header: '" + fnameHeader + "'='" + fname + "' \n"; + message += " Last Name Header: '" + lnameHeader + "'='" + lname + "'"; + log.error(message); - return null; // TODO should this throw an exception? - } + return null; // TODO should this throw an exception? + } - // Truncate values of parameters that are too big. - if (fname != null && fname.length() > NAME_MAX_SIZE) { - log.warn("Truncating eperson's first name because it is longer than "+NAME_MAX_SIZE+": '"+fname+"'"); - fname = fname.substring(0,NAME_MAX_SIZE); - } - if (lname != null && lname.length() > NAME_MAX_SIZE) { - log.warn("Truncating eperson's last name because it is longer than "+NAME_MAX_SIZE+": '"+lname+"'"); - lname = lname.substring(0,NAME_MAX_SIZE); - } + // Truncate values of parameters that are too big. + if (fname != null && fname.length() > NAME_MAX_SIZE) { + log.warn( + "Truncating eperson's first name because it is longer than " + NAME_MAX_SIZE + ": '" + fname + "'"); + fname = fname.substring(0, NAME_MAX_SIZE); + } + if (lname != null && lname.length() > NAME_MAX_SIZE) { + log.warn("Truncating eperson's last name because it is longer than " + NAME_MAX_SIZE + ": '" + lname + "'"); + lname = lname.substring(0, NAME_MAX_SIZE); + } - // Turn off authorizations to create a new user - context.turnOffAuthorisationSystem(); - EPerson eperson = ePersonService.create(context); + // Turn off authorizations to create a new user + context.turnOffAuthorisationSystem(); + EPerson eperson = ePersonService.create(context); - // Set the minimum attributes for the new eperson - if (netid != null) - eperson.setNetid(netid); - eperson.setEmail(email.toLowerCase()); - if ( fname != null ) - eperson.setFirstName(context, fname); - if ( lname != null ) - eperson.setLastName(context, lname); - eperson.setCanLogIn(true); + // Set the minimum attributes for the new eperson + if (netid != null) { + eperson.setNetid(netid); + } + eperson.setEmail(email.toLowerCase()); + if (fname != null) { + eperson.setFirstName(context, fname); + } + if (lname != null) { + eperson.setLastName(context, lname); + } + eperson.setCanLogIn(true); - // Commit the new eperson - AuthenticateServiceFactory.getInstance().getAuthenticationService().initEPerson(context, request, eperson); - ePersonService.update(context, eperson); - context.dispatchEvents(); - - // Turn authorizations back on. - context.restoreAuthSystemState(); - - if (log.isInfoEnabled()) { - String message = "Auto registered new eperson using Shibboleth-based attributes:"; - if (netid != null) - message += " NetId: '"+netid+"'\n"; - message += " Email: '"+email+"' \n"; - message += " First Name: '"+fname+"' \n"; - message += " Last Name: '"+lname+"'"; - log.info(message); - } - - return eperson; - } - - - - - - /** - * After we successfully authenticated a user, this method will update the user's attributes. The - * user's email, name, or other attribute may have been changed since the last time they - * logged into DSpace. This method will update the database with their most recent information. - * - * This method handles the basic DSpace metadata (email, first name, last name) along with - * additional metadata set using the setMetadata() methods on the eperson object. The - * additional metadata are defined by a mapping created in the dspace.cfg. - * - * @param context The current DSpace database context - * @param request The current HTTP Request - * @param eperson The eperson object to update. - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - */ - protected void updateEPerson(Context context, HttpServletRequest request, EPerson eperson) throws SQLException, AuthorizeException { - - // Header names & values - String netidHeader = configurationService.getProperty("authentication-shibboleth.netid-header"); - String emailHeader = configurationService.getProperty("authentication-shibboleth.email-header"); - String fnameHeader = configurationService.getProperty("authentication-shibboleth.firstname-header"); - String lnameHeader = configurationService.getProperty("authentication-shibboleth.lastname-header"); - - String netid = findSingleAttribute(request,netidHeader); - String email = findSingleAttribute(request,emailHeader); - String fname = findSingleAttribute(request,fnameHeader); - String lname = findSingleAttribute(request,lnameHeader); - - // Truncate values of parameters that are too big. - if (fname != null && fname.length() > NAME_MAX_SIZE) { - log.warn("Truncating eperson's first name because it is longer than "+NAME_MAX_SIZE+": '"+fname+"'"); - fname = fname.substring(0,NAME_MAX_SIZE); - } - if (lname != null && lname.length() > NAME_MAX_SIZE) { - log.warn("Truncating eperson's last name because it is longer than "+NAME_MAX_SIZE+": '"+lname+"'"); - lname = lname.substring(0,NAME_MAX_SIZE); - } - - context.turnOffAuthorisationSystem(); - - // 1) Update the minimum metadata - if (netid != null && eperson.getNetid() == null) - // Only update the netid if none has been previously set. This can occur when a repo switches - // to netid based authentication. The current users do not have netids and fall back to email-based - // identification but once they login we update their record and lock the account to a particular netid. - eperson.setNetid(netid); - if (email != null) - // The email could have changed if using netid based lookup. - eperson.setEmail(email.toLowerCase()); - if (fname != null) - eperson.setFirstName(context, fname); - if (lname != null) - eperson.setLastName(context, lname); - - if (log.isDebugEnabled()) { - String message = "Updated the eperson's minimal metadata: \n"; - message += " Email Header: '"+emailHeader+"' = '"+email+"' \n"; - message += " First Name Header: '"+fnameHeader+"' = '"+fname+"' \n"; - message += " Last Name Header: '"+fnameHeader+"' = '"+lname+"'"; - log.debug(message); - } - - // 2) Update additional eperson metadata - for (String header : metadataHeaderMap.keySet()) { - - String field = metadataHeaderMap.get(header); - String value = findSingleAttribute(request, header); - - // Truncate values - if (value == null) { - log.warn("Unable to update the eperson's '"+field+"' metadata because the header '"+header+"' does not exist."); - continue; - } else if ("phone".equals(field) && value.length() > PHONE_MAX_SIZE) { - log.warn("Truncating eperson phone metadata because it is longer than "+PHONE_MAX_SIZE+": '"+value+"'"); - value = value.substring(0,PHONE_MAX_SIZE); - } else if (value.length() > METADATA_MAX_SIZE) { - log.warn("Truncating eperson "+field+" metadata because it is longer than "+METADATA_MAX_SIZE+": '"+value+"'"); - value = value.substring(0,METADATA_MAX_SIZE); - } - - ePersonService.setMetadata(context, eperson, field, value); - log.debug("Updated the eperson's '"+field+"' metadata using header: '"+header+"' = '"+value+"'."); - } + // Commit the new eperson + AuthenticateServiceFactory.getInstance().getAuthenticationService().initEPerson(context, request, eperson); ePersonService.update(context, eperson); context.dispatchEvents(); - context.restoreAuthSystemState(); - } - /** - * Provide password-based authentication to enable sword compatibility. - * - * Sword compatibility will allow this authentication method to work when using - * sword. Sword relies on username and password based authentication and is - * entirely incapable of supporting shibboleth. This option allows you to - * authenticate username and passwords for sword sessions without adding - * another authentication method onto the stack. You will need to ensure that - * a user has a password. One way to do that is to create the user via the - * create-administrator command line command and then edit their permissions. - * - * @param context The DSpace database context - * @param username The username - * @param password The password - * @param request The HTTP Request - * @return A valid DSpace Authentication Method status code. - * @throws SQLException if database error - */ - protected int swordCompatibility(Context context, String username, String password, HttpServletRequest request) throws SQLException { + // Turn authorizations back on. + context.restoreAuthSystemState(); - EPerson eperson = null; + if (log.isInfoEnabled()) { + String message = "Auto registered new eperson using Shibboleth-based attributes:"; + if (netid != null) { + message += " NetId: '" + netid + "'\n"; + } + message += " Email: '" + email + "' \n"; + message += " First Name: '" + fname + "' \n"; + message += " Last Name: '" + lname + "'"; + log.info(message); + } - log.debug("Shibboleth Sword compatibility activated."); + return eperson; + } + + + /** + * After we successfully authenticated a user, this method will update the user's attributes. The + * user's email, name, or other attribute may have been changed since the last time they + * logged into DSpace. This method will update the database with their most recent information. + * + * This method handles the basic DSpace metadata (email, first name, last name) along with + * additional metadata set using the setMetadata() methods on the eperson object. The + * additional metadata are defined by a mapping created in the dspace.cfg. + * + * @param context The current DSpace database context + * @param request The current HTTP Request + * @param eperson The eperson object to update. + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + protected void updateEPerson(Context context, HttpServletRequest request, EPerson eperson) + throws SQLException, AuthorizeException { + + // Header names & values + String netidHeader = configurationService.getProperty("authentication-shibboleth.netid-header"); + String emailHeader = configurationService.getProperty("authentication-shibboleth.email-header"); + String fnameHeader = configurationService.getProperty("authentication-shibboleth.firstname-header"); + String lnameHeader = configurationService.getProperty("authentication-shibboleth.lastname-header"); + + String netid = findSingleAttribute(request, netidHeader); + String email = findSingleAttribute(request, emailHeader); + String fname = findSingleAttribute(request, fnameHeader); + String lname = findSingleAttribute(request, lnameHeader); + + // Truncate values of parameters that are too big. + if (fname != null && fname.length() > NAME_MAX_SIZE) { + log.warn( + "Truncating eperson's first name because it is longer than " + NAME_MAX_SIZE + ": '" + fname + "'"); + fname = fname.substring(0, NAME_MAX_SIZE); + } + if (lname != null && lname.length() > NAME_MAX_SIZE) { + log.warn("Truncating eperson's last name because it is longer than " + NAME_MAX_SIZE + ": '" + lname + "'"); + lname = lname.substring(0, NAME_MAX_SIZE); + } + + context.turnOffAuthorisationSystem(); + + // 1) Update the minimum metadata + + // Only update the netid if none has been previously set. This can occur when a repo switches + // to netid based authentication. The current users do not have netids and fall back to email-based + // identification but once they login we update their record and lock the account to a particular netid. + if (netid != null && eperson.getNetid() == null) { + eperson.setNetid(netid); + } + // The email could have changed if using netid based lookup. + if (email != null) { + eperson.setEmail(email.toLowerCase()); + } + if (fname != null) { + eperson.setFirstName(context, fname); + } + if (lname != null) { + eperson.setLastName(context, lname); + } + + if (log.isDebugEnabled()) { + String message = "Updated the eperson's minimal metadata: \n"; + message += " Email Header: '" + emailHeader + "' = '" + email + "' \n"; + message += " First Name Header: '" + fnameHeader + "' = '" + fname + "' \n"; + message += " Last Name Header: '" + fnameHeader + "' = '" + lname + "'"; + log.debug(message); + } + + // 2) Update additional eperson metadata + for (String header : metadataHeaderMap.keySet()) { + + String field = metadataHeaderMap.get(header); + String value = findSingleAttribute(request, header); + + // Truncate values + if (value == null) { + log.warn( + "Unable to update the eperson's '" + field + "' metadata because the header '" + header + "' does" + + " not exist."); + continue; + } else if ("phone".equals(field) && value.length() > PHONE_MAX_SIZE) { + log.warn( + "Truncating eperson phone metadata because it is longer than " + PHONE_MAX_SIZE + ": '" + value + + "'"); + value = value.substring(0, PHONE_MAX_SIZE); + } else if (value.length() > METADATA_MAX_SIZE) { + log.warn( + "Truncating eperson " + field + " metadata because it is longer than " + METADATA_MAX_SIZE + ": " + + "'" + value + "'"); + value = value.substring(0, METADATA_MAX_SIZE); + } + + ePersonService.setMetadata(context, eperson, field, value); + log.debug( + "Updated the eperson's '" + field + "' metadata using header: '" + header + "' = '" + value + "'."); + } + ePersonService.update(context, eperson); + context.dispatchEvents(); + context.restoreAuthSystemState(); + } + + /** + * Provide password-based authentication to enable sword compatibility. + * + * Sword compatibility will allow this authentication method to work when using + * sword. Sword relies on username and password based authentication and is + * entirely incapable of supporting shibboleth. This option allows you to + * authenticate username and passwords for sword sessions without adding + * another authentication method onto the stack. You will need to ensure that + * a user has a password. One way to do that is to create the user via the + * create-administrator command line command and then edit their permissions. + * + * @param context The DSpace database context + * @param username The username + * @param password The password + * @param request The HTTP Request + * @return A valid DSpace Authentication Method status code. + * @throws SQLException if database error + */ + protected int swordCompatibility(Context context, String username, String password, HttpServletRequest request) + throws SQLException { + + EPerson eperson = null; + + log.debug("Shibboleth Sword compatibility activated."); eperson = ePersonService.findByEmail(context, username.toLowerCase()); - if (eperson == null) { - // lookup failed. - log.error("Shibboleth-based password authentication failed for user "+username+" because no such user exists."); - return NO_SUCH_USER; - } else if (!eperson.canLogIn()) { - // cannot login this way - log.error("Shibboleth-based password authentication failed for user "+username+" because the eperson object is not allowed to login."); - return BAD_ARGS; - } else if (eperson.getRequireCertificate()) { - // this user can only login with x.509 certificate - log.error("Shibboleth-based password authentication failed for user "+username+" because the eperson object requires a certificate to authenticate.."); - return CERT_REQUIRED; - } + if (eperson == null) { + // lookup failed. + log.error( + "Shibboleth-based password authentication failed for user " + username + " because no such user " + + "exists."); + return NO_SUCH_USER; + } else if (!eperson.canLogIn()) { + // cannot login this way + log.error( + "Shibboleth-based password authentication failed for user " + username + " because the eperson object" + + " is not allowed to login."); + return BAD_ARGS; + } else if (eperson.getRequireCertificate()) { + // this user can only login with x.509 certificate + log.error( + "Shibboleth-based password authentication failed for user " + username + " because the eperson object" + + " requires a certificate to authenticate.."); + return CERT_REQUIRED; + } else if (ePersonService.checkPassword(context, eperson, password)) { + // Password matched + AuthenticateServiceFactory.getInstance().getAuthenticationService().initEPerson(context, request, eperson); + context.setCurrentUser(eperson); + log.info(eperson + .getEmail() + " has been authenticated via shibboleth using password-based sword " + + "compatibility mode."); + return SUCCESS; + } else { + // Passsword failure + log.error( + "Shibboleth-based password authentication failed for user " + username + " because a bad password was" + + " supplied."); + return BAD_CREDENTIALS; + } - else if (ePersonService.checkPassword(context, eperson, password)) { - // Password matched - AuthenticateServiceFactory.getInstance().getAuthenticationService().initEPerson(context, request, eperson); - context.setCurrentUser(eperson); - log.info(eperson.getEmail()+" has been authenticated via shibboleth using password-based sword compatibility mode."); - return SUCCESS; - } else { - // Passsword failure - log.error("Shibboleth-based password authentication failed for user "+username+" because a bad password was supplied."); - return BAD_CREDENTIALS; - } - - } + } - - /** - * Initialize Shibboleth Authentication. - * - * During initalization the mapping of additional eperson metadata will be loaded from the DSpace.cfg - * and cached. While loading the metadata mapping this method will check the EPerson object to see - * if it supports the metadata field. If the field is not supported and autocreate is turned on then - * the field will be automatically created. - * - * It is safe to call this methods multiple times. - * @param context context - * @throws SQLException if database error - */ + /** + * Initialize Shibboleth Authentication. + * + * During initalization the mapping of additional eperson metadata will be loaded from the DSpace.cfg + * and cached. While loading the metadata mapping this method will check the EPerson object to see + * if it supports the metadata field. If the field is not supported and autocreate is turned on then + * the field will be automatically created. + * + * It is safe to call this methods multiple times. + * + * @param context context + * @throws SQLException if database error + */ protected synchronized void initialize(Context context) throws SQLException { - if (metadataHeaderMap != null) - return; + if (metadataHeaderMap != null) { + return; + } - HashMap map = new HashMap(); + HashMap map = new HashMap(); - String[] mappingString = configurationService.getArrayProperty("authentication-shibboleth.eperson.metadata"); - boolean autoCreate = configurationService.getBooleanProperty("authentication-shibboleth.eperson.metadata.autocreate", true); + String[] mappingString = configurationService.getArrayProperty("authentication-shibboleth.eperson.metadata"); + boolean autoCreate = configurationService + .getBooleanProperty("authentication-shibboleth.eperson.metadata.autocreate", true); - // Bail out if not set, returning an empty map. - if (mappingString == null || mappingString.length == 0) { - log.debug("No additional eperson metadata mapping found: authentication.shib.eperson.metadata"); + // Bail out if not set, returning an empty map. + if (mappingString == null || mappingString.length == 0) { + log.debug("No additional eperson metadata mapping found: authentication.shib.eperson.metadata"); - metadataHeaderMap = map; - return; - } + metadataHeaderMap = map; + return; + } - log.debug("Loading additional eperson metadata from: 'authentication.shib.eperson.metadata' = '"+ StringUtils.join(mappingString, ",") +"'"); + log.debug("Loading additional eperson metadata from: 'authentication.shib.eperson.metadata' = '" + StringUtils + .join(mappingString, ",") + "'"); - for (String metadataString : mappingString) { - metadataString = metadataString.trim(); + for (String metadataString : mappingString) { + metadataString = metadataString.trim(); - String[] metadataParts = metadataString.split("=>"); + String[] metadataParts = metadataString.split("=>"); - if (metadataParts.length != 2) { - log.error("Unable to parse metadat mapping string: '"+metadataString+"'"); - continue; - } + if (metadataParts.length != 2) { + log.error("Unable to parse metadat mapping string: '" + metadataString + "'"); + continue; + } - String header = metadataParts[0].trim(); - String name = metadataParts[1].trim().toLowerCase(); + String header = metadataParts[0].trim(); + String name = metadataParts[1].trim().toLowerCase(); - boolean valid = checkIfEpersonMetadataFieldExists(context, name); + boolean valid = checkIfEpersonMetadataFieldExists(context, name); - if ( ! valid && autoCreate) { - valid = autoCreateEpersonMetadataField(context, name); - } + if (!valid && autoCreate) { + valid = autoCreateEpersonMetadataField(context, name); + } - if (valid) { - // The eperson field is fine, we can use it. - log.debug("Loading additional eperson metadata mapping for: '"+header+"' = '"+name+"'"); - map.put(header, name); - } else { - // The field doesn't exist, and we can't use it. - log.error("Skipping the additional eperson metadata mapping for: '"+header+"' = '"+name+"' because the field is not supported by the current configuration."); - } - } // foreach metadataStringList + if (valid) { + // The eperson field is fine, we can use it. + log.debug("Loading additional eperson metadata mapping for: '" + header + "' = '" + name + "'"); + map.put(header, name); + } else { + // The field doesn't exist, and we can't use it. + log.error( + "Skipping the additional eperson metadata mapping for: '" + header + "' = '" + name + "' because " + + "the field is not supported by the current configuration."); + } + } // foreach metadataStringList - metadataHeaderMap = map; - return; - } + metadataHeaderMap = map; + return; + } - /** + /** * Check if a MetadataField for an eperson is available. - * - * @param metadataName The name of the metadata field. - * @param context context - * @return True if a valid metadata field, otherwise false. - * @throws SQLException if database error - */ - protected synchronized boolean checkIfEpersonMetadataFieldExists(Context context, String metadataName) throws SQLException { + * + * @param metadataName The name of the metadata field. + * @param context context + * @return True if a valid metadata field, otherwise false. + * @throws SQLException if database error + */ + protected synchronized boolean checkIfEpersonMetadataFieldExists(Context context, String metadataName) + throws SQLException { - if (metadataName == null) - return false; + if (metadataName == null) { + return false; + } - if ("phone".equals(metadataName)) - // The phone is a predefined field - return true; + // The phone is a predefined field + if ("phone".equals(metadataName)) { + return true; + } MetadataField metadataField = metadataFieldService.findByElement(context, "eperson", metadataName, null); return metadataField != null; - } + } - /** Validate Postgres Column Names */ + /** + * Validate Postgres Column Names + */ protected final String COLUMN_NAME_REGEX = "^[_A-Za-z0-9]+$"; - - /** - * Automatically create a new metadataField for an eperson - * - * @param context context - * @param metadataName The name of the new metadata field. - * @return True if successful, otherwise false. - * @throws SQLException if database error - */ - protected synchronized boolean autoCreateEpersonMetadataField(Context context, String metadataName) throws SQLException { - if (metadataName == null) - return false; + /** + * Automatically create a new metadataField for an eperson + * + * @param context context + * @param metadataName The name of the new metadata field. + * @return True if successful, otherwise false. + * @throws SQLException if database error + */ + protected synchronized boolean autoCreateEpersonMetadataField(Context context, String metadataName) + throws SQLException { - if ("phone".equals(metadataName)) - // The phone is a predefined field - return true; + if (metadataName == null) { + return false; + } - if ( ! metadataName.matches(COLUMN_NAME_REGEX)) - return false; + // The phone is a predefined field + if ("phone".equals(metadataName)) { + return true; + } + + if (!metadataName.matches(COLUMN_NAME_REGEX)) { + return false; + } MetadataSchema epersonSchema = metadataSchemaService.find(context, "eperson"); MetadataField metadataField = null; @@ -1027,166 +1081,182 @@ public class ShibAuthentication implements AuthenticationMethod } catch (NonUniqueMetadataException e) { log.error(e.getMessage(), e); return false; - }finally { + } finally { context.restoreAuthSystemState(); } return metadataField != null; } - /** - * Find a particular Shibboleth header value and return the all values. - * The header name uses a bit of fuzzy logic, so it will first try case - * sensitive, then it will try lowercase, and finally it will try uppercase. - * - * This method will not interpret the header value in any way. - * - * - * @param request The HTTP request to look for values in. - * @param name The name of the attribute or header - * @return The value of the attribute or header requested, or null if none found. - */ + /** + * Find a particular Shibboleth header value and return the all values. + * The header name uses a bit of fuzzy logic, so it will first try case + * sensitive, then it will try lowercase, and finally it will try uppercase. + * + * This method will not interpret the header value in any way. + * + * This method will return null if value is empty. + * + * @param request The HTTP request to look for values in. + * @param name The name of the attribute or header + * @return The value of the attribute or header requested, or null if none found. + */ protected String findAttribute(HttpServletRequest request, String name) { - if ( name == null ) { - return null; - } - // First try to get the value from the attribute - String value = (String) request.getAttribute(name); - if (StringUtils.isEmpty(value)) - value = (String) request.getAttribute(name.toLowerCase()); - if (StringUtils.isEmpty(value)) - value = (String) request.getAttribute(name.toUpperCase()); + if (name == null) { + return null; + } + // First try to get the value from the attribute + String value = (String) request.getAttribute(name); + if (StringUtils.isEmpty(value)) { + value = (String) request.getAttribute(name.toLowerCase()); + } + if (StringUtils.isEmpty(value)) { + value = (String) request.getAttribute(name.toUpperCase()); + } - // Second try to get the value from the header - if (StringUtils.isEmpty(value)) - value = request.getHeader(name); - if (StringUtils.isEmpty(value)) - value = request.getHeader(name.toLowerCase()); - if (StringUtils.isEmpty(value)) - value = request.getHeader(name.toUpperCase()); - - boolean reconvertAttributes = - configurationService.getBooleanProperty( - "authentication-shibboleth.reconvert.attributes", - false); - - if (!StringUtils.isEmpty(value) && reconvertAttributes) - { - try { - value = new String(value.getBytes("ISO-8859-1"), "UTF-8"); - } catch (UnsupportedEncodingException ex) { - log.warn("Failed to reconvert shibboleth attribute (" - + name + ").", ex); - } - } - - return value; - } + // Second try to get the value from the header + if (StringUtils.isEmpty(value)) { + value = request.getHeader(name); + } + if (StringUtils.isEmpty(value)) { + value = request.getHeader(name.toLowerCase()); + } + if (StringUtils.isEmpty(value)) { + value = request.getHeader(name.toUpperCase()); + } + + // Added extra check for empty value of an attribute. + // In case that value is Empty, it should not be returned, return 'null' instead. + // This prevents passing empty value to other methods, stops the authentication process + // and prevents creation of 'empty' DSpace EPerson if autoregister == true and it subsequent + // authentication. + if (StringUtils.isEmpty(value)) { + log.debug("ShibAuthentication - attribute " + name + " is empty!"); + return null; + } + + boolean reconvertAttributes = + configurationService.getBooleanProperty( + "authentication-shibboleth.reconvert.attributes", + false); + + if (!StringUtils.isEmpty(value) && reconvertAttributes) { + try { + value = new String(value.getBytes("ISO-8859-1"), "UTF-8"); + } catch (UnsupportedEncodingException ex) { + log.warn("Failed to reconvert shibboleth attribute (" + + name + ").", ex); + } + } + + return value; + } - /** - * Find a particular Shibboleth header value and return the first value. - * The header name uses a bit of fuzzy logic, so it will first try case - * sensitive, then it will try lowercase, and finally it will try uppercase. - * - * Shibboleth attributes may contain multiple values separated by a - * semicolon. This method will return the first value in the attribute. If - * you need multiple values use findMultipleAttributes instead. - * - * If no attribute is found then null is returned. - * - * @param request The HTTP request to look for headers values on. - * @param name The name of the header - * @return The value of the header requested, or null if none found. - */ + /** + * Find a particular Shibboleth header value and return the first value. + * The header name uses a bit of fuzzy logic, so it will first try case + * sensitive, then it will try lowercase, and finally it will try uppercase. + * + * Shibboleth attributes may contain multiple values separated by a + * semicolon. This method will return the first value in the attribute. If + * you need multiple values use findMultipleAttributes instead. + * + * If no attribute is found then null is returned. + * + * @param request The HTTP request to look for headers values on. + * @param name The name of the header + * @return The value of the header requested, or null if none found. + */ protected String findSingleAttribute(HttpServletRequest request, String name) { - if ( name == null) { - return null; - } + if (name == null) { + return null; + } - String value = findAttribute(request, name); + String value = findAttribute(request, name); - if (value != null) { - // If there are multiple values encoded in the shibboleth attribute - // they are separated by a semicolon, and any semicolons in the - // attribute are escaped with a backslash. For this case we are just - // looking for the first attribute so we scan the value until we find - // the first unescaped semicolon and chop off everything else. - int idx = 0; - do { - idx = value.indexOf(';',idx); - if ( idx != -1 && value.charAt(idx-1) != '\\') { - value = value.substring(0,idx); - break; - } - } while (idx >= 0); + if (value != null) { + // If there are multiple values encoded in the shibboleth attribute + // they are separated by a semicolon, and any semicolons in the + // attribute are escaped with a backslash. For this case we are just + // looking for the first attribute so we scan the value until we find + // the first unescaped semicolon and chop off everything else. + int idx = 0; + do { + idx = value.indexOf(';', idx); + if (idx != -1 && value.charAt(idx - 1) != '\\') { + value = value.substring(0, idx); + break; + } + } while (idx >= 0); - // Unescape the semicolon after splitting - value = value.replaceAll("\\;", ";"); - } + // Unescape the semicolon after splitting + value = value.replaceAll("\\;", ";"); + } - return value; - } + return value; + } - /** - * Find a particular Shibboleth hattributeeader value and return the values. - * The attribute name uses a bit of fuzzy logic, so it will first try case - * sensitive, then it will try lowercase, and finally it will try uppercase. - * - * Shibboleth attributes may contain multiple values separated by a - * semicolon and semicolons are escaped with a backslash. This method will - * split all the attributes into a list and unescape semicolons. - * - * If no attributes are found then null is returned. - * - * @param request The HTTP request to look for headers values on. - * @param name The name of the attribute - * @return The list of values found, or null if none found. - */ + /** + * Find a particular Shibboleth hattributeeader value and return the values. + * The attribute name uses a bit of fuzzy logic, so it will first try case + * sensitive, then it will try lowercase, and finally it will try uppercase. + * + * Shibboleth attributes may contain multiple values separated by a + * semicolon and semicolons are escaped with a backslash. This method will + * split all the attributes into a list and unescape semicolons. + * + * If no attributes are found then null is returned. + * + * @param request The HTTP request to look for headers values on. + * @param name The name of the attribute + * @return The list of values found, or null if none found. + */ protected List findMultipleAttributes(HttpServletRequest request, String name) { - String values = findAttribute(request, name); + String values = findAttribute(request, name); - if (values == null) - return null; + if (values == null) { + return null; + } - // Shibboleth attributes are separated by semicolons (and semicolons are - // escaped with a backslash). So here we will scan through the string and - // split on any unescaped semicolons. - List valueList = new ArrayList(); - int idx = 0; - do { - idx = values.indexOf(';',idx); + // Shibboleth attributes are separated by semicolons (and semicolons are + // escaped with a backslash). So here we will scan through the string and + // split on any unescaped semicolons. + List valueList = new ArrayList(); + int idx = 0; + do { + idx = values.indexOf(';', idx); - if ( idx == 0 ) { - // if the string starts with a semicolon just remove it. This will - // prevent an endless loop in an error condition. - values = values.substring(1,values.length()); + if (idx == 0) { + // if the string starts with a semicolon just remove it. This will + // prevent an endless loop in an error condition. + values = values.substring(1, values.length()); - } else if (idx > 0 && values.charAt(idx-1) == '\\' ) { - // The attribute starts with an escaped semicolon - idx++; - } else if ( idx > 0) { - // First extract the value and store it on the list. - String value = values.substring(0,idx); - value = value.replaceAll("\\\\;", ";"); - valueList.add(value); + } else if (idx > 0 && values.charAt(idx - 1) == '\\') { + // The attribute starts with an escaped semicolon + idx++; + } else if (idx > 0) { + // First extract the value and store it on the list. + String value = values.substring(0, idx); + value = value.replaceAll("\\\\;", ";"); + valueList.add(value); - // Next, remove the value from the string and continue to scan. - values = values.substring(idx+1,values.length()); - idx = 0; - } - } while (idx >= 0); + // Next, remove the value from the string and continue to scan. + values = values.substring(idx + 1, values.length()); + idx = 0; + } + } while (idx >= 0); - // The last attribute will still be left on the values string, put it - // into the list. - if (values.length() > 0) { - values = values.replaceAll("\\\\;", ";"); - valueList.add(values); - } + // The last attribute will still be left on the values string, put it + // into the list. + if (values.length() > 0) { + values = values.replaceAll("\\\\;", ";"); + valueList.add(values); + } - return valueList; - } + return valueList; + } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/X509Authentication.java b/dspace-api/src/main/java/org/dspace/authenticate/X509Authentication.java index 5a6a2019a4..da2097d0dd 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/X509Authentication.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/X509Authentication.java @@ -21,15 +21,14 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.StringTokenizer; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.apache.commons.collections.ListUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.log4j.Logger; import org.dspace.authenticate.factory.AuthenticateServiceFactory; @@ -55,7 +54,7 @@ import org.dspace.services.factory.DSpaceServicesFactory; * See the AuthenticationMethod interface for more details. *

    * Configuration: - * + * *

      *   x509.keystore.path =
      * 
    @@ -79,11 +78,11 @@ import org.dspace.services.factory.DSpaceServicesFactory;
      * 
      *   emaildomain =
      * 
    - * email address domain (after the 'at' symbol) to match before allowing 
    + * email address domain (after the 'at' symbol) to match before allowing
      * membership in special groups.
      * 
      * 
    - * + * * Only one of the "keystore.path" or "ca.cert" * options is required. If you supply a keystore, then all of the "trusted" * certificates in the keystore represent CAs whose client certificates will be @@ -97,31 +96,37 @@ import org.dspace.services.factory.DSpaceServicesFactory; * canSelfRegister() method returns. It also allows an EPerson * record to be created automatically when the presented certificate is * acceptable but there is no corresponding EPerson. - * + * * @author Larry Stone * @version $Revision$ */ -public class X509Authentication implements AuthenticationMethod -{ +public class X509Authentication implements AuthenticationMethod { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(X509Authentication.class); - /** public key of CA to check client certs against. */ + /** + * public key of CA to check client certs against. + */ private static PublicKey caPublicKey = null; - /** key store for CA certs if we use that */ + /** + * key store for CA certs if we use that + */ private static KeyStore caCertKeyStore = null; private static String loginPageTitle = null; private static String loginPageURL = null; - protected AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance().getAuthenticationService(); + protected AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance() + .getAuthenticationService(); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - protected ConfigurationService configurationService = - DSpaceServicesFactory.getInstance().getConfigurationService(); + protected ConfigurationService configurationService = + DSpaceServicesFactory.getInstance().getConfigurationService(); /** @@ -129,116 +134,88 @@ public class X509Authentication implements AuthenticationMethod * information needed to check if a client cert presented is valid and * acceptable. */ - static - { - ConfigurationService configurationService = + static { + ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); /* * allow identification of alternative entry points for certificate * authentication when selected by the user rather than implicitly. */ loginPageTitle = configurationService - .getProperty("authentication-x509.chooser.title.key"); + .getProperty("authentication-x509.chooser.title.key"); loginPageURL = configurationService - .getProperty("authentication-x509.chooser.uri"); + .getProperty("authentication-x509.chooser.uri"); String keystorePath = configurationService - .getProperty("authentication-x509.keystore.path"); + .getProperty("authentication-x509.keystore.path"); String keystorePassword = configurationService - .getProperty("authentication-x509.keystore.password"); + .getProperty("authentication-x509.keystore.password"); String caCertPath = configurationService - .getProperty("authentication-x509.ca.cert"); + .getProperty("authentication-x509.ca.cert"); // First look for keystore full of trusted certs. - if (keystorePath != null) - { + if (keystorePath != null) { FileInputStream fis = null; - if (keystorePassword == null) - { + if (keystorePassword == null) { keystorePassword = ""; } - try - { + try { KeyStore ks = KeyStore.getInstance("JKS"); fis = new FileInputStream(keystorePath); ks.load(fis, keystorePassword.toCharArray()); caCertKeyStore = ks; - } - catch (IOException e) - { + } catch (IOException e) { log - .error("X509Authentication: Failed to load CA keystore, file=" - + keystorePath + ", error=" + e.toString()); - } - catch (GeneralSecurityException e) - { + .error("X509Authentication: Failed to load CA keystore, file=" + + keystorePath + ", error=" + e.toString()); + } catch (GeneralSecurityException e) { log - .error("X509Authentication: Failed to extract CA keystore, file=" - + keystorePath + ", error=" + e.toString()); - } - finally - { - if (fis != null) - { - try - { + .error("X509Authentication: Failed to extract CA keystore, file=" + + keystorePath + ", error=" + e.toString()); + } finally { + if (fis != null) { + try { fis.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } } // Second, try getting public key out of CA cert, if that's configured. - if (caCertPath != null) - { + if (caCertPath != null) { InputStream is = null; FileInputStream fis = null; - try - { + try { fis = new FileInputStream(caCertPath); is = new BufferedInputStream(fis); X509Certificate cert = (X509Certificate) CertificateFactory - .getInstance("X.509").generateCertificate(is); - if (cert != null) - { + .getInstance("X.509").generateCertificate(is); + if (cert != null) { caPublicKey = cert.getPublicKey(); } - } - catch (IOException e) - { + } catch (IOException e) { log.error("X509Authentication: Failed to load CA cert, file=" - + caCertPath + ", error=" + e.toString()); - } - catch (CertificateException e) - { + + caCertPath + ", error=" + e.toString()); + } catch (CertificateException e) { log - .error("X509Authentication: Failed to extract CA cert, file=" - + caCertPath + ", error=" + e.toString()); - } - finally - { - if (is != null) - { - try - { + .error("X509Authentication: Failed to extract CA cert, file=" + + caCertPath + ", error=" + e.toString()); + } finally { + if (is != null) { + try { is.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } - if (fis != null) - { - try - { + if (fis != null) { + try { fis.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } @@ -251,41 +228,35 @@ public class X509Authentication implements AuthenticationMethod *

    * Note that the certificate parsing has only been tested with certificates * granted by the MIT Certification Authority, and may not work elsewhere. - * + * * @param certificate - - * An X509 certificate object + * An X509 certificate object * @return - The email address found in certificate, or null if an email - * address cannot be found in the certificate. + * address cannot be found in the certificate. */ private static String getEmail(X509Certificate certificate) - throws SQLException - { + throws SQLException { Principal principal = certificate.getSubjectDN(); - if (principal == null) - { + if (principal == null) { return null; } String dn = principal.getName(); - if (dn == null) - { + if (dn == null) { return null; } StringTokenizer tokenizer = new StringTokenizer(dn, ","); String token = null; - while (tokenizer.hasMoreTokens()) - { + while (tokenizer.hasMoreTokens()) { int len = "emailaddress=".length(); token = (String) tokenizer.nextToken(); - if (token.toLowerCase().startsWith("emailaddress=")) - { + if (token.toLowerCase().startsWith("emailaddress=")) { // Make sure the token actually contains something - if (token.length() <= len) - { + if (token.length() <= len) { return null; } @@ -300,82 +271,64 @@ public class X509Authentication implements AuthenticationMethod * Verify CERTIFICATE against KEY. Return true if and only if CERTIFICATE is * valid and can be verified against KEY. * - * @param context - * The current DSpace context + * @param context The current DSpace context * @param certificate - - * An X509 certificate object + * An X509 certificate object * @return - True if CERTIFICATE is valid and can be verified against KEY, - * false otherwise. + * false otherwise. */ - private static boolean isValid(Context context, X509Certificate certificate) - { - if (certificate == null) - { + private static boolean isValid(Context context, X509Certificate certificate) { + if (certificate == null) { return false; } // This checks that current time is within cert's validity window: - try - { + try { certificate.checkValidity(); - } - catch (CertificateException e) - { + } catch (CertificateException e) { log.info(LogManager.getHeader(context, "authentication", - "X.509 Certificate is EXPIRED or PREMATURE: " - + e.toString())); + "X.509 Certificate is EXPIRED or PREMATURE: " + + e.toString())); return false; } // Try CA public key, if available. - if (caPublicKey != null) - { - try - { + if (caPublicKey != null) { + try { certificate.verify(caPublicKey); return true; - } - catch (GeneralSecurityException e) - { + } catch (GeneralSecurityException e) { log.info(LogManager.getHeader(context, "authentication", - "X.509 Certificate FAILED SIGNATURE check: " - + e.toString())); + "X.509 Certificate FAILED SIGNATURE check: " + + e.toString())); } } // Try it with keystore, if available. - if (caCertKeyStore != null) - { - try - { + if (caCertKeyStore != null) { + try { Enumeration ke = caCertKeyStore.aliases(); - while (ke.hasMoreElements()) - { + while (ke.hasMoreElements()) { String alias = (String) ke.nextElement(); - if (caCertKeyStore.isCertificateEntry(alias)) - { + if (caCertKeyStore.isCertificateEntry(alias)) { Certificate ca = caCertKeyStore.getCertificate(alias); - try - { + try { certificate.verify(ca.getPublicKey()); return true; - } - catch (CertificateException ce) - { + } catch (CertificateException ce) { + // ignore } } } log - .info(LogManager - .getHeader(context, "authentication", - "Keystore method FAILED SIGNATURE check on client cert.")); - } - catch (GeneralSecurityException e) - { + .info(LogManager + .getHeader(context, "authentication", + "Keystore method FAILED SIGNATURE check on client cert.")); + } catch (GeneralSecurityException e) { log.info(LogManager.getHeader(context, "authentication", - "X.509 Certificate FAILED SIGNATURE check: " - + e.toString())); + "X.509 Certificate FAILED SIGNATURE check: " + + e.toString())); } } @@ -387,34 +340,34 @@ public class X509Authentication implements AuthenticationMethod * configuration value. You'll probably want this to be true to take * advantage of a Web certificate infrastructure with many more users than * are already known by DSpace. + * * @throws SQLException if database error */ @Override public boolean canSelfRegister(Context context, HttpServletRequest request, - String username) throws SQLException - { + String username) throws SQLException { return configurationService - .getBooleanProperty("authentication-x509.autoregister"); + .getBooleanProperty("authentication-x509.autoregister"); } /** * Nothing extra to initialize. + * * @throws SQLException if database error */ @Override public void initEPerson(Context context, HttpServletRequest request, - EPerson eperson) throws SQLException - { + EPerson eperson) throws SQLException { } /** * We don't use EPerson password so there is no reason to change it. + * * @throws SQLException if database error */ @Override public boolean allowSetPassword(Context context, - HttpServletRequest request, String username) throws SQLException - { + HttpServletRequest request, String username) throws SQLException { return false; } @@ -422,28 +375,24 @@ public class X509Authentication implements AuthenticationMethod * Returns true, this is an implicit method. */ @Override - public boolean isImplicit() - { + public boolean isImplicit() { return true; } /** * Returns a list of group names that the user should be added to upon * successful authentication, configured in dspace.cfg. - * + * * @return List of special groups configured for this authenticator */ - private List getX509Groups() - { + private List getX509Groups() { List groupNames = new ArrayList(); String[] groups = configurationService - .getArrayProperty("authentication-x509.groups"); + .getArrayProperty("authentication-x509.groups"); - if(ArrayUtils.isNotEmpty(groups)) - { - for (String group : groups) - { + if (ArrayUtils.isNotEmpty(groups)) { + for (String group : groups) { groupNames.add(group.trim()); } } @@ -455,30 +404,25 @@ public class X509Authentication implements AuthenticationMethod * Checks for configured email domain required to grant special groups * membership. If no email domain is configured to verify, special group * membership is simply granted. - * + * * @param request - - * The current request object - * @param email - - * The email address from the x509 certificate + * The current request object + * @param email - + * The email address from the x509 certificate */ - private void setSpecialGroupsFlag(HttpServletRequest request, String email) - { + private void setSpecialGroupsFlag(HttpServletRequest request, String email) { String emailDomain = null; emailDomain = (String) request - .getAttribute("authentication.x509.emaildomain"); + .getAttribute("authentication.x509.emaildomain"); HttpSession session = request.getSession(true); - if (null != emailDomain && !"".equals(emailDomain)) - { + if (null != emailDomain && !"".equals(emailDomain)) { if (email.substring(email.length() - emailDomain.length()).equals( - emailDomain)) - { + emailDomain)) { session.setAttribute("x509Auth", Boolean.TRUE); } - } - else - { + } else { // No configured email domain to verify. Just flag // as authenticated so special groups are granted. session.setAttribute("x509Auth", Boolean.TRUE); @@ -488,22 +432,17 @@ public class X509Authentication implements AuthenticationMethod /** * Return special groups configured in dspace.cfg for X509 certificate * authentication. - * + * * @param context context - * @param request - * object potentially containing the cert - * + * @param request object potentially containing the cert * @return An int array of group IDs * @throws SQLException if database error - * */ @Override public List getSpecialGroups(Context context, HttpServletRequest request) - throws SQLException - { - if (request == null) - { - return ListUtils.EMPTY_LIST; + throws SQLException { + if (request == null) { + return Collections.EMPTY_LIST; } Boolean authenticated = false; @@ -511,27 +450,20 @@ public class X509Authentication implements AuthenticationMethod authenticated = (Boolean) session.getAttribute("x509Auth"); authenticated = (null == authenticated) ? false : authenticated; - if (authenticated) - { + if (authenticated) { List groupNames = getX509Groups(); List groups = new ArrayList<>(); - if (groupNames != null) - { - for (String groupName : groupNames) - { - if (groupName != null) - { + if (groupNames != null) { + for (String groupName : groupNames) { + if (groupName != null) { Group group = groupService.findByName(context, groupName); - if (group != null) - { + if (group != null) { groups.add(group); - } - else - { + } else { log.warn(LogManager.getHeader(context, - "configuration_error", "unknown_group=" - + groupName)); + "configuration_error", "unknown_group=" + + groupName)); } } } @@ -540,7 +472,7 @@ public class X509Authentication implements AuthenticationMethod return groups; } - return ListUtils.EMPTY_LIST; + return Collections.EMPTY_LIST; } /** @@ -560,56 +492,46 @@ public class X509Authentication implements AuthenticationMethod * * * - * + * * @return One of: SUCCESS, BAD_CREDENTIALS, NO_SUCH_USER, BAD_ARGS * @throws SQLException if database error */ @Override public int authenticate(Context context, String username, String password, - String realm, HttpServletRequest request) throws SQLException - { + String realm, HttpServletRequest request) throws SQLException { // Obtain the certificate from the request, if any X509Certificate[] certs = null; - if (request != null) - { + if (request != null) { certs = (X509Certificate[]) request - .getAttribute("javax.servlet.request.X509Certificate"); + .getAttribute("javax.servlet.request.X509Certificate"); } - if ((certs == null) || (certs.length == 0)) - { + if ((certs == null) || (certs.length == 0)) { return BAD_ARGS; - } - else - { + } else { // We have a cert -- check it and get username from it. - try - { - if (!isValid(context, certs[0])) - { + try { + if (!isValid(context, certs[0])) { log - .warn(LogManager - .getHeader(context, "authenticate", - "type=x509certificate, status=BAD_CREDENTIALS (not valid)")); + .warn(LogManager + .getHeader(context, "authenticate", + "type=x509certificate, status=BAD_CREDENTIALS (not valid)")); return BAD_CREDENTIALS; } // And it's valid - try and get an e-person String email = getEmail(certs[0]); EPerson eperson = null; - if (email != null) - { + if (email != null) { eperson = ePersonService.findByEmail(context, email); } - if (eperson == null) - { + if (eperson == null) { // Cert is valid, but no record. if (email != null - && canSelfRegister(context, request, null)) - { + && canSelfRegister(context, request, null)) { // Register the new user automatically log.info(LogManager.getHeader(context, "autoregister", - "from=x.509, email=" + email)); + "from=x.509, email=" + email)); // TEMPORARILY turn off authorisation context.turnOffAuthorisationSystem(); @@ -617,47 +539,36 @@ public class X509Authentication implements AuthenticationMethod eperson.setEmail(email); eperson.setCanLogIn(true); authenticationService.initEPerson(context, request, - eperson); + eperson); ePersonService.update(context, eperson); context.dispatchEvents(); context.restoreAuthSystemState(); context.setCurrentUser(eperson); setSpecialGroupsFlag(request, email); return SUCCESS; - } - else - { + } else { // No auto-registration for valid certs log - .warn(LogManager - .getHeader(context, "authenticate", - "type=cert_but_no_record, cannot auto-register")); + .warn(LogManager + .getHeader(context, "authenticate", + "type=cert_but_no_record, cannot auto-register")); return NO_SUCH_USER; } - } - - // make sure this is a login account - else if (!eperson.canLogIn()) - { + } else if (!eperson.canLogIn()) { // make sure this is a login account log.warn(LogManager.getHeader(context, "authenticate", - "type=x509certificate, email=" + email - + ", canLogIn=false, rejecting.")); + "type=x509certificate, email=" + email + + ", canLogIn=false, rejecting.")); return BAD_ARGS; - } - - else - { + } else { log.info(LogManager.getHeader(context, "login", - "type=x509certificate")); + "type=x509certificate")); context.setCurrentUser(eperson); setSpecialGroupsFlag(request, email); return SUCCESS; } - } - catch (AuthorizeException ce) - { + } catch (AuthorizeException ce) { log.warn(LogManager.getHeader(context, "authorize_exception", - ""), ce); + ""), ce); } return BAD_ARGS; @@ -666,38 +577,21 @@ public class X509Authentication implements AuthenticationMethod /** * Returns URL of password-login servlet. - * - * @param context - * DSpace context, will be modified (EPerson set) upon success. - * - * @param request - * The HTTP request that started this operation, or null if not - * applicable. - * - * @param response - * The HTTP response from the servlet method. - * + * + * @param context DSpace context, will be modified (EPerson set) upon success. + * @param request The HTTP request that started this operation, or null if not + * applicable. + * @param response The HTTP response from the servlet method. * @return fully-qualified URL */ @Override public String loginPageURL(Context context, HttpServletRequest request, - HttpServletResponse response) - { + HttpServletResponse response) { return loginPageURL; } - /** - * Returns message key for title of the "login" page, to use in a menu - * showing the choice of multiple login methods. - * - * @param context - * DSpace context, will be modified (EPerson set) upon success. - * - * @return Message key to look up in i18n message catalog. - */ @Override - public String loginPageTitle(Context context) - { - return loginPageTitle; + public String getName() { + return "x509"; } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/factory/AuthenticateServiceFactory.java b/dspace-api/src/main/java/org/dspace/authenticate/factory/AuthenticateServiceFactory.java index f2e873b466..4acb998816 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/factory/AuthenticateServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/factory/AuthenticateServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.authenticate.service.AuthenticationService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the authenticate package, use AuthenticateServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the authenticate package, use AuthenticateServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class AuthenticateServiceFactory { public abstract AuthenticationService getAuthenticationService(); - public static AuthenticateServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("authenticateServiceFactory", AuthenticateServiceFactory.class); + public static AuthenticateServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("authenticateServiceFactory", AuthenticateServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/authenticate/factory/AuthenticateServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/authenticate/factory/AuthenticateServiceFactoryImpl.java index 14f8902a8a..4f7a914ca6 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/factory/AuthenticateServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/factory/AuthenticateServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.authenticate.service.AuthenticationService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the authenticate package, use AuthenticateServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the authenticate package, use AuthenticateServiceFactory.getInstance() + * to retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/authenticate/service/AuthenticationService.java b/dspace-api/src/main/java/org/dspace/authenticate/service/AuthenticationService.java index a402fb26d6..d4a1cd5d0d 100644 --- a/dspace-api/src/main/java/org/dspace/authenticate/service/AuthenticationService.java +++ b/dspace-api/src/main/java/org/dspace/authenticate/service/AuthenticationService.java @@ -7,16 +7,16 @@ */ package org.dspace.authenticate.service; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; +import javax.servlet.http.HttpServletRequest; + import org.dspace.authenticate.AuthenticationMethod; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import javax.servlet.http.HttpServletRequest; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Access point for the stackable authentication methods. *

    @@ -39,10 +39,9 @@ import java.util.List; * The "stack" is always traversed in order, with the methods * specified first (in the configuration) thus getting highest priority. * - * @see AuthenticationMethod - * * @author Larry Stone * @version $Revision$ + * @see AuthenticationMethod */ public interface AuthenticationService { @@ -53,25 +52,15 @@ public interface AuthenticationService { * the stack. Returns upon the first SUCCESS, or otherwise * returns the most favorable outcome from one of the methods. * - * @param context - * DSpace context, will be modified (ePerson set) upon success. - * - * @param username - * Username (or email address) when method is explicit. Use null for - * implicit method. - * - * @param password - * Password for explicit auth, or null for implicit method. - * - * @param realm - * Realm is an extra parameter used by some authentication methods, leave null if - * not applicable. - * - * @param request - * The HTTP request that started this operation, or null if not applicable. - * + * @param context DSpace context, will be modified (ePerson set) upon success. + * @param username Username (or email address) when method is explicit. Use null for + * implicit method. + * @param password Password for explicit auth, or null for implicit method. + * @param realm Realm is an extra parameter used by some authentication methods, leave null if + * not applicable. + * @param request The HTTP request that started this operation, or null if not applicable. * @return One of: - * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS + * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS *

    Meaning: *
    SUCCESS - authenticated OK. *
    BAD_CREDENTIALS - user exists, but credentials (e.g. password) don't match @@ -80,35 +69,25 @@ public interface AuthenticationService { *
    BAD_ARGS - user/password not appropriate for this method */ public int authenticate(Context context, - String username, - String password, - String realm, - HttpServletRequest request); + String username, + String password, + String realm, + HttpServletRequest request); /** * Test credentials for authenticity, using only Implicit methods. * Just like authenticate(), except it only invokes the * implicit authentication methods the stack. * - * @param context - * DSpace context, will be modified (ePerson set) upon success. - * - * @param username - * Username (or email address) when method is explicit. Use null for - * implicit method. - * - * @param password - * Password for explicit auth, or null for implicit method. - * - * @param realm - * Realm is an extra parameter used by some authentication methods, leave null if - * not applicable. - * - * @param request - * The HTTP request that started this operation, or null if not applicable. - * + * @param context DSpace context, will be modified (ePerson set) upon success. + * @param username Username (or email address) when method is explicit. Use null for + * implicit method. + * @param password Password for explicit auth, or null for implicit method. + * @param realm Realm is an extra parameter used by some authentication methods, leave null if + * not applicable. + * @param request The HTTP request that started this operation, or null if not applicable. * @return One of: - * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS + * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS *

    Meaning: *
    SUCCESS - authenticated OK. *
    BAD_CREDENTIALS - user exists, but credentials (e.g. password) don't match @@ -117,10 +96,10 @@ public interface AuthenticationService { *
    BAD_ARGS - user/password not appropriate for this method */ public int authenticateImplicit(Context context, - String username, - String password, - String realm, - HttpServletRequest request); + String username, + String password, + String realm, + HttpServletRequest request); /** @@ -128,8 +107,8 @@ public interface AuthenticationService { * Invokes canSelfRegister() of every authentication * method in the stack, and returns true if any of them is true. * - * @param context DSpace context - * @param request HTTP request, in case it's needed. Can be null. + * @param context DSpace context + * @param request HTTP request, in case it's needed. Can be null. * @param username Username, if available. Can be null. * @return true if new ePerson should be created. * @throws SQLException if database error @@ -143,8 +122,8 @@ public interface AuthenticationService { * Returns true if the allowSetPassword() method of any * member of the stack returns true. * - * @param context DSpace context - * @param request HTTP request, in case it's needed. Can be null. + * @param context DSpace context + * @param request HTTP request, in case it's needed. Can be null. * @param username Username, if available. Can be null. * @return true if this method allows user to change ePerson password. * @throws SQLException if database error @@ -156,8 +135,14 @@ public interface AuthenticationService { public void initEPerson(Context context, HttpServletRequest request, EPerson eperson) - throws SQLException; + throws SQLException; + /** + * Update the last active (login) timestamp on the current authenticated user + * + * @param context The authenticated context + */ + public void updateLastActiveDate(Context context); /** * Get list of extra groups that user implicitly belongs to. @@ -165,16 +150,14 @@ public interface AuthenticationService { * methods in the stack. * * @param context A valid DSpace context. - * * @param request The request that started this operation, or null if not applicable. - * * @return Returns IDs of any groups the user authenticated by this * request is in implicitly -- checks for e.g. network-address dependent * groups. * @throws SQLException if database error */ public List getSpecialGroups(Context context, - HttpServletRequest request) throws SQLException; + HttpServletRequest request) throws SQLException; /** * Get stack of authentication methods. diff --git a/dspace-api/src/main/java/org/dspace/authority/AuthoritySearchService.java b/dspace-api/src/main/java/org/dspace/authority/AuthoritySearchService.java index 68bae36fec..42dd567fd6 100644 --- a/dspace-api/src/main/java/org/dspace/authority/AuthoritySearchService.java +++ b/dspace-api/src/main/java/org/dspace/authority/AuthoritySearchService.java @@ -7,15 +7,14 @@ */ package org.dspace.authority; +import java.net.MalformedURLException; +import java.util.List; + import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.response.QueryResponse; -import java.net.MalformedURLException; -import java.util.List; - /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) diff --git a/dspace-api/src/main/java/org/dspace/authority/AuthorityServiceImpl.java b/dspace-api/src/main/java/org/dspace/authority/AuthorityServiceImpl.java index c9799ab408..647fa23289 100644 --- a/dspace-api/src/main/java/org/dspace/authority/AuthorityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authority/AuthorityServiceImpl.java @@ -7,6 +7,9 @@ */ package org.dspace.authority; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authority.indexer.AuthorityIndexerInterface; import org.dspace.authority.indexer.AuthorityIndexingService; import org.dspace.authority.service.AuthorityService; @@ -15,9 +18,6 @@ import org.dspace.content.Item; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.List; - /** * Service implementation for the Metadata Authority @@ -26,7 +26,7 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class AuthorityServiceImpl implements AuthorityService{ +public class AuthorityServiceImpl implements AuthorityService { @Autowired(required = true) @@ -34,42 +34,35 @@ public class AuthorityServiceImpl implements AuthorityService{ @Autowired(required = true) protected List indexers; - protected AuthorityServiceImpl() - { + protected AuthorityServiceImpl() { } @Override public void indexItem(Context context, Item item) throws SQLException, AuthorizeException { - if(!isConfigurationValid()){ + if (!isConfigurationValid()) { //Cannot index, configuration not valid return; } for (AuthorityIndexerInterface indexerInterface : indexers) { - - indexerInterface.init(context , item); - while (indexerInterface.hasMore()) { - AuthorityValue authorityValue = indexerInterface.nextValue(); - if(authorityValue != null) - indexingService.indexContent(authorityValue, true); + List authorityValues = indexerInterface.getAuthorityValues(context , item); + for (AuthorityValue authorityValue : authorityValues) { + indexingService.indexContent(authorityValue); } - //Close up - indexerInterface.close(); } //Commit to our server indexingService.commit(); } @Override - public boolean isConfigurationValid() - { - if(!indexingService.isConfiguredProperly()){ + public boolean isConfigurationValid() { + if (!indexingService.isConfiguredProperly()) { return false; } for (AuthorityIndexerInterface indexerInterface : indexers) { - if(!indexerInterface.isConfiguredProperly()){ + if (!indexerInterface.isConfiguredProperly()) { return false; } } diff --git a/dspace-api/src/main/java/org/dspace/authority/AuthoritySolrServiceImpl.java b/dspace-api/src/main/java/org/dspace/authority/AuthoritySolrServiceImpl.java index 84a553ffb1..56521ac950 100644 --- a/dspace-api/src/main/java/org/dspace/authority/AuthoritySolrServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authority/AuthoritySolrServiceImpl.java @@ -7,7 +7,11 @@ */ package org.dspace.authority; -import org.dspace.authority.indexer.AuthorityIndexingService; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.List; + import org.apache.log4j.Logger; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; @@ -15,15 +19,10 @@ import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.response.FacetField; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrInputDocument; +import org.dspace.authority.indexer.AuthorityIndexingService; import org.dspace.core.ConfigurationManager; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.List; - /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -33,8 +32,7 @@ public class AuthoritySolrServiceImpl implements AuthorityIndexingService, Autho private static final Logger log = Logger.getLogger(AuthoritySolrServiceImpl.class); - protected AuthoritySolrServiceImpl() - { + protected AuthoritySolrServiceImpl() { } @@ -62,21 +60,21 @@ public class AuthoritySolrServiceImpl implements AuthorityIndexingService, Autho } @Override - public void indexContent(AuthorityValue value, boolean force) { + public void indexContent(AuthorityValue value) { SolrInputDocument doc = value.getSolrInputDocument(); - try{ + try { writeDocument(doc); - }catch (Exception e){ + } catch (Exception e) { log.error("Error while writing authority value to the index: " + value.toString(), e); } } @Override public void cleanIndex() throws Exception { - try{ + try { getSolr().deleteByQuery("*:*"); - } catch (Exception e){ + } catch (Exception e) { log.error("Error while cleaning authority solr server index", e); throw new Exception(e); } @@ -97,15 +95,19 @@ public class AuthoritySolrServiceImpl implements AuthorityIndexingService, Autho public boolean isConfiguredProperly() { boolean solrReturn = false; try { - solrReturn = (getSolr()!=null); + solrReturn = (getSolr() != null); } catch (Exception e) { - log.error("Authority solr is not correctly configured, check \"solr.authority.server\" property in the dspace.cfg", e); + log.error( + "Authority solr is not correctly configured, check \"solr.authority.server\" property in the dspace" + + ".cfg", + e); } return solrReturn; } /** * Write the document to the solr index + * * @param doc the solr document * @throws IOException if IO error */ @@ -115,7 +117,10 @@ public class AuthoritySolrServiceImpl implements AuthorityIndexingService, Autho getSolr().add(doc); } catch (Exception e) { try { - log.error("An error occurred for document: " + doc.getField("id").getFirstValue() + ", source: " + doc.getField("source").getFirstValue() + ", field: " + doc.getField("field").getFirstValue() + ", full-text: " + doc.getField("full-text").getFirstValue(), e); + log.error("An error occurred for document: " + doc.getField("id").getFirstValue() + ", source: " + doc + .getField("source").getFirstValue() + ", field: " + doc.getField("field") + .getFirstValue() + ", full-text: " + doc + .getField("full-text").getFirstValue(), e); } catch (Exception e1) { //shouldn't happen } @@ -130,6 +135,7 @@ public class AuthoritySolrServiceImpl implements AuthorityIndexingService, Autho /** * Retrieves all the metadata fields which are indexed in the authority control + * * @return a list of metadata fields * @throws Exception if error */ @@ -144,9 +150,9 @@ public class AuthoritySolrServiceImpl implements AuthorityIndexingService, Autho List results = new ArrayList(); FacetField facetField = response.getFacetField("field"); - if(facetField != null){ + if (facetField != null) { List values = facetField.getValues(); - if(values != null){ + if (values != null) { for (FacetField.Count facetValue : values) { if (facetValue != null && facetValue.getName() != null) { results.add(facetValue.getName()); diff --git a/dspace-api/src/main/java/org/dspace/authority/AuthorityTypes.java b/dspace-api/src/main/java/org/dspace/authority/AuthorityTypes.java index 9b808a21ea..22f2f495cf 100644 --- a/dspace-api/src/main/java/org/dspace/authority/AuthorityTypes.java +++ b/dspace-api/src/main/java/org/dspace/authority/AuthorityTypes.java @@ -7,13 +7,13 @@ */ package org.dspace.authority; -import org.apache.log4j.Logger; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.log4j.Logger; + /** * This class contains a list of active authority types. * It can be used to created a new instance of a specific type. @@ -39,7 +39,6 @@ public class AuthorityTypes { protected Map fieldDefaults = new HashMap(); - public List getTypes() { return types; } diff --git a/dspace-api/src/main/java/org/dspace/authority/AuthorityValue.java b/dspace-api/src/main/java/org/dspace/authority/AuthorityValue.java index 883c0edf1d..80d9e16289 100644 --- a/dspace-api/src/main/java/org/dspace/authority/AuthorityValue.java +++ b/dspace-api/src/main/java/org/dspace/authority/AuthorityValue.java @@ -7,6 +7,13 @@ */ package org.dspace.authority; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.solr.common.SolrDocument; @@ -15,17 +22,12 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.MetadataValueService; import org.dspace.core.Context; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; -import java.sql.SQLException; -import java.util.*; - /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -142,6 +144,7 @@ public class AuthorityValue { /** * Generate a solr record from this instance + * * @return SolrInputDocument */ public SolrInputDocument getSolrInputDocument() { @@ -159,6 +162,7 @@ public class AuthorityValue { /** * Initialize this instance based on a solr record + * * @param document SolrDocument */ public void setValues(SolrDocument document) { @@ -172,13 +176,15 @@ public class AuthorityValue { /** * Replace an item's DCValue with this authority - * @param context context - * @param value metadata value + * + * @param context context + * @param value metadata value * @param currentItem item - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public void updateItem(Context context, Item currentItem, MetadataValue value) throws SQLException, AuthorizeException { + public void updateItem(Context context, Item currentItem, MetadataValue value) + throws SQLException, AuthorizeException { value.setValue(getValue()); value.setAuthority(getId()); ContentServiceFactory.getInstance().getMetadataValueService().update(context, value, true); @@ -186,6 +192,7 @@ public class AuthorityValue { /** * Information that can be used the choice ui + * * @return map */ public Map choiceSelectMap() { @@ -206,7 +213,7 @@ public class AuthorityValue { List dateFormatters = getDateFormatters(); boolean converted = false; int formatter = 0; - while(!converted) { + while (!converted) { try { DateTimeFormatter dateTimeFormatter = dateFormatters.get(formatter); DateTime dateTime = dateTimeFormatter.parseDateTime(date); @@ -217,7 +224,7 @@ public class AuthorityValue { if (formatter > dateFormatters.size()) { converted = true; } - log.error("Could not find a valid date format for: \""+date+"\"", e); + log.error("Could not find a valid date format for: \"" + date + "\"", e); } } } @@ -232,19 +239,22 @@ public class AuthorityValue { @Override public String toString() { return "AuthorityValue{" + - "id='" + id + '\'' + - ", field='" + field + '\'' + - ", value='" + value + '\'' + - ", creationDate=" + creationDate + - ", deleted=" + deleted + - ", lastModified=" + lastModified + - '}'; + "id='" + id + '\'' + + ", field='" + field + '\'' + + ", value='" + value + '\'' + + ", creationDate=" + creationDate + + ", deleted=" + deleted + + ", lastModified=" + lastModified + + '}'; } /** * Provides a string that will allow this AuthorityType to be recognized and * provides information to create a new instance to be created using {@link #newInstance(String)}. - * See the implementation of {@link org.dspace.authority.AuthorityValueServiceImpl#generateRaw(java.lang.String, java.lang.String, java.lang.String)} for more details. + * See the implementation of + * {@link org.dspace.authority.AuthorityValueServiceImpl#generateRaw(java.lang.String, java.lang.String, + * java.lang.String)} for more details. + * * @return see {@link org.dspace.authority.service.AuthorityValueService#GENERATE AuthorityValueService.GENERATE} */ public String generateString() { @@ -253,6 +263,7 @@ public class AuthorityValue { /** * Makes an instance of the AuthorityValue with the given information. + * * @param info string info * @return AuthorityValue */ @@ -268,6 +279,7 @@ public class AuthorityValue { * The regular equals() only checks if both AuthorityValues describe the same authority. * This method checks if the AuthorityValues have different information * E.g. it is used to decide when lastModified should be updated. + * * @param o object * @return true or false */ diff --git a/dspace-api/src/main/java/org/dspace/authority/AuthorityValueServiceImpl.java b/dspace-api/src/main/java/org/dspace/authority/AuthorityValueServiceImpl.java index 875c3da4b8..7780c79232 100644 --- a/dspace-api/src/main/java/org/dspace/authority/AuthorityValueServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authority/AuthorityValueServiceImpl.java @@ -7,6 +7,12 @@ */ package org.dspace.authority; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.solr.client.solrj.SolrQuery; @@ -18,8 +24,6 @@ import org.dspace.core.Context; import org.dspace.core.LogManager; import org.springframework.beans.factory.annotation.Autowired; -import java.util.*; - /** * This service contains all methods for using authority values * @@ -28,15 +32,14 @@ import java.util.*; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class AuthorityValueServiceImpl implements AuthorityValueService{ +public class AuthorityValueServiceImpl implements AuthorityValueService { private final Logger log = Logger.getLogger(AuthorityValueServiceImpl.class); @Autowired(required = true) protected AuthorityTypes authorityTypes; - protected AuthorityValueServiceImpl() - { + protected AuthorityValueServiceImpl() { } @@ -75,7 +78,8 @@ public class AuthorityValueServiceImpl implements AuthorityValueService{ AuthorityValue nextValue; if (authorityKey != null && authorityKey.startsWith(GENERATE)) { String[] split = StringUtils.split(authorityKey, SPLIT); - String type = null, info = null; + String type = null; + String info = null; if (split.length > 0) { type = split[1]; if (split.length > 1) { @@ -104,7 +108,7 @@ public class AuthorityValueServiceImpl implements AuthorityValueService{ updated.setField(value.getField()); if (updated.hasTheSameInformationAs(value)) { updated.setLastModified(value.getLastModified()); - }else { + } else { updated.updateLastModifiedDate(); } } @@ -113,7 +117,8 @@ public class AuthorityValueServiceImpl implements AuthorityValueService{ /** * Item.ANY does not work here. - * @param context Context + * + * @param context Context * @param authorityID authority id * @return AuthorityValue */ @@ -145,20 +150,24 @@ public class AuthorityValueServiceImpl implements AuthorityValueService{ } @Override - public List findByValue(Context context, String schema, String element, String qualifier, String value) { + public List findByValue(Context context, String schema, String element, String qualifier, + String value) { String field = fieldParameter(schema, element, qualifier); return findByValue(context, field, qualifier); } @Override - public List findByName(Context context, String schema, String element, String qualifier, String name) { + public List findByName(Context context, String schema, String element, String qualifier, + String name) { String field = fieldParameter(schema, element, qualifier); - String queryString = "first_name:" + name + " OR last_name:" + name + " OR name_variant:" + name + " AND field:" + field; + String queryString = "first_name:" + name + " OR last_name:" + name + " OR name_variant:" + name + " AND " + + "field:" + field; return find(context, queryString); } @Override - public List findByAuthorityMetadata(Context context, String schema, String element, String qualifier, String value) { + public List findByAuthorityMetadata(Context context, String schema, String element, + String qualifier, String value) { String field = fieldParameter(schema, element, qualifier); String queryString = "all_Labels:" + value + " AND field:" + field; return find(context, queryString); @@ -188,7 +197,7 @@ public class AuthorityValueServiceImpl implements AuthorityValueService{ public AuthorityValue getAuthorityValueType(String metadataString) { AuthorityValue fromAuthority = null; for (AuthorityValue type : authorityTypes.getTypes()) { - if (StringUtils.startsWithIgnoreCase(metadataString,type.getAuthorityType())) { + if (StringUtils.startsWithIgnoreCase(metadataString, type.getAuthorityType())) { fromAuthority = type; } } @@ -202,7 +211,8 @@ public class AuthorityValueServiceImpl implements AuthorityValueService{ solrQuery.setQuery(filtered(queryString)); log.debug("AuthorityValueFinder makes the query: " + queryString); QueryResponse queryResponse = SolrAuthority.getSearchService().search(solrQuery); - if (queryResponse != null && queryResponse.getResults() != null && 0 < queryResponse.getResults().getNumFound()) { + if (queryResponse != null && queryResponse.getResults() != null && 0 < queryResponse.getResults() + .getNumFound()) { for (SolrDocument document : queryResponse.getResults()) { AuthorityValue authorityValue = fromSolr(document); findings.add(authorityValue); @@ -210,7 +220,8 @@ public class AuthorityValueServiceImpl implements AuthorityValueService{ } } } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while retrieving AuthorityValue from solr", "query: " + queryString),e); + log.error(LogManager.getHeader(context, "Error while retrieving AuthorityValue from solr", + "query: " + queryString), e); } return findings; diff --git a/dspace-api/src/main/java/org/dspace/authority/PersonAuthorityValue.java b/dspace-api/src/main/java/org/dspace/authority/PersonAuthorityValue.java index 2949cb6c6d..179e06fc79 100644 --- a/dspace-api/src/main/java/org/dspace/authority/PersonAuthorityValue.java +++ b/dspace-api/src/main/java/org/dspace/authority/PersonAuthorityValue.java @@ -7,18 +7,17 @@ */ package org.dspace.authority; -import org.apache.commons.lang.ObjectUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.solr.common.SolrDocument; -import org.apache.solr.common.SolrInputDocument; - import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrInputDocument; + /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -184,7 +183,7 @@ public class PersonAuthorityValue extends AuthorityValue { boolean added = false; for (String email : getEmails()) { if (!added && StringUtils.isNotBlank(email)) { - map.put("email",email); + map.put("email", email); added = true; } } @@ -204,7 +203,8 @@ public class PersonAuthorityValue extends AuthorityValue { @Override public String generateString() { return AuthorityValueServiceImpl.GENERATE + getAuthorityType() + AuthorityValueServiceImpl.SPLIT + getName(); - // the part after "AuthorityValueGenerator.GENERATE + getAuthorityType() + AuthorityValueGenerator.SPLIT" is the value of the "info" parameter in public AuthorityValue newInstance(String info) + // the part after "AuthorityValueGenerator.GENERATE + getAuthorityType() + AuthorityValueGenerator.SPLIT" is + // the value of the "info" parameter in public AuthorityValue newInstance(String info) } @Override @@ -217,12 +217,12 @@ public class PersonAuthorityValue extends AuthorityValue { @Override public String toString() { return "PersonAuthorityValue{" + - "firstName='" + firstName + '\'' + - ", lastName='" + lastName + '\'' + - ", nameVariants=" + nameVariants + - ", institution='" + institution + '\'' + - ", emails=" + emails + - "} " + super.toString(); + "firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", nameVariants=" + nameVariants + + ", institution='" + institution + '\'' + + ", emails=" + emails + + "} " + super.toString(); } @Override @@ -233,7 +233,7 @@ public class PersonAuthorityValue extends AuthorityValue { if (o == null || getClass() != o.getClass()) { return false; } - if(!super.hasTheSameInformationAs(o)){ + if (!super.hasTheSameInformationAs(o)) { return false; } diff --git a/dspace-api/src/main/java/org/dspace/authority/SolrAuthorityInterface.java b/dspace-api/src/main/java/org/dspace/authority/SolrAuthorityInterface.java new file mode 100644 index 0000000000..63ad909218 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/authority/SolrAuthorityInterface.java @@ -0,0 +1,20 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.authority; + +import java.util.List; + +/** + * @author Jonas Van Goolen (jonas at atmire dot com) + */ +public interface SolrAuthorityInterface { + + List queryAuthorities(String text, int max); + + AuthorityValue queryAuthorityID(String id); +} diff --git a/dspace-api/src/main/java/org/dspace/authority/UpdateAuthorities.java b/dspace-api/src/main/java/org/dspace/authority/UpdateAuthorities.java index 9c5f71aa1d..44fd0a9241 100644 --- a/dspace-api/src/main/java/org/dspace/authority/UpdateAuthorities.java +++ b/dspace-api/src/main/java/org/dspace/authority/UpdateAuthorities.java @@ -7,7 +7,18 @@ */ package org.dspace.authority; -import org.apache.commons.cli.*; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +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.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.dspace.authority.factory.AuthorityServiceFactory; import org.dspace.authority.service.AuthorityValueService; @@ -18,14 +29,7 @@ import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -108,7 +112,8 @@ public class UpdateAuthorities { protected static Options createCommandLineOptions() { Options options = new Options(); options.addOption("h", "help", false, "help"); - options.addOption("i", "id", true, "Import and/or update specific solr records with the given ids (comma-separated)"); + options.addOption("i", "id", true, + "Import and/or update specific solr records with the given ids (comma-separated)"); return options; } @@ -152,12 +157,14 @@ public class UpdateAuthorities { protected void updateItems(AuthorityValue authority) { try { - Iterator itemIterator = itemService.findByMetadataFieldAuthority(context, authority.getField(), authority.getId()); + Iterator itemIterator = itemService + .findByMetadataFieldAuthority(context, authority.getField(), authority.getId()); while (itemIterator.hasNext()) { Item next = itemIterator.next(); List metadata = itemService.getMetadata(next, authority.getField(), authority.getId()); authority.updateItem(context, next, metadata.get(0)); //should be only one - List metadataAfter = itemService.getMetadata(next, authority.getField(), authority.getId()); + List metadataAfter = itemService + .getMetadata(next, authority.getField(), authority.getId()); if (!metadata.get(0).getValue().equals(metadataAfter.get(0).getValue())) { print.println("Updated item with handle " + next.getHandle()); } diff --git a/dspace-api/src/main/java/org/dspace/authority/factory/AuthorityServiceFactory.java b/dspace-api/src/main/java/org/dspace/authority/factory/AuthorityServiceFactory.java index 1f63a4a1be..cde2e0c681 100644 --- a/dspace-api/src/main/java/org/dspace/authority/factory/AuthorityServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/authority/factory/AuthorityServiceFactory.java @@ -7,6 +7,8 @@ */ package org.dspace.authority.factory; +import java.util.List; + import org.dspace.authority.AuthoritySearchService; import org.dspace.authority.AuthorityTypes; import org.dspace.authority.indexer.AuthorityIndexerInterface; @@ -15,10 +17,9 @@ import org.dspace.authority.service.AuthorityService; import org.dspace.authority.service.AuthorityValueService; import org.dspace.services.factory.DSpaceServicesFactory; -import java.util.List; - /** - * Abstract factory to get services for the authority package, use AuthorityServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the authority package, use AuthorityServiceFactory.getInstance() to retrieve + * an implementation * * @author kevinvandevelde at atmire.com */ @@ -36,8 +37,8 @@ public abstract class AuthorityServiceFactory { public abstract List getAuthorityIndexers(); - public static AuthorityServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("authorityServiceFactory", AuthorityServiceFactory.class); + public static AuthorityServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("authorityServiceFactory", AuthorityServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/authority/factory/AuthorityServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/authority/factory/AuthorityServiceFactoryImpl.java index efd268335d..5d81877aaa 100644 --- a/dspace-api/src/main/java/org/dspace/authority/factory/AuthorityServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/authority/factory/AuthorityServiceFactoryImpl.java @@ -7,6 +7,8 @@ */ package org.dspace.authority.factory; +import java.util.List; + import org.dspace.authority.AuthoritySearchService; import org.dspace.authority.AuthorityTypes; import org.dspace.authority.indexer.AuthorityIndexerInterface; @@ -15,10 +17,9 @@ import org.dspace.authority.service.AuthorityService; import org.dspace.authority.service.AuthorityValueService; import org.springframework.beans.factory.annotation.Autowired; -import java.util.List; - /** - * Factory implementation to get services for the authority package, use AuthorityServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the authority package, use AuthorityServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityConsumer.java b/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityConsumer.java index 353e59585a..c5029db53a 100644 --- a/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityConsumer.java +++ b/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityConsumer.java @@ -8,6 +8,10 @@ package org.dspace.authority.indexer; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + import org.apache.log4j.Logger; import org.dspace.authority.factory.AuthorityServiceFactory; import org.dspace.authority.service.AuthorityService; @@ -19,10 +23,6 @@ import org.dspace.core.Context; import org.dspace.event.Consumer; import org.dspace.event.Event; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - /** * Consumer that takes care of the indexing of authority controlled metadata fields for installed/updated items * @@ -35,10 +35,14 @@ public class AuthorityConsumer implements Consumer { private final Logger log = Logger.getLogger(AuthorityConsumer.class); - /** A set of all item IDs installed which need their authority updated **/ + /** + * A set of all item IDs installed which need their authority updated + **/ protected Set itemsToUpdateAuthority = null; - /** A set of item IDs who's metadata needs to be reindexed **/ + /** + * A set of item IDs who's metadata needs to be reindexed + **/ protected Set itemsToReindex = null; protected ItemService itemService; @@ -54,20 +58,21 @@ public class AuthorityConsumer implements Consumer { @Override public void consume(Context ctx, Event event) throws Exception { - if(itemsToUpdateAuthority == null){ + if (itemsToUpdateAuthority == null) { itemsToUpdateAuthority = new HashSet<>(); itemsToReindex = new HashSet<>(); } DSpaceObject dso = event.getSubject(ctx); - if(dso instanceof Item){ + if (dso instanceof Item) { Item item = (Item) dso; - if(item.isArchived()){ - if(!itemsToReindex.contains(item.getID())) + if (item.isArchived()) { + if (!itemsToReindex.contains(item.getID())) { itemsToReindex.add(item.getID()); + } } - if(("ARCHIVED: " + true).equals(event.getDetail())){ + if (("ARCHIVED: " + true).equals(event.getDetail())) { itemsToUpdateAuthority.add(item.getID()); } @@ -76,10 +81,11 @@ public class AuthorityConsumer implements Consumer { @Override public void end(Context ctx) throws Exception { - if(itemsToUpdateAuthority == null) + if (itemsToUpdateAuthority == null) { return; + } - try{ + try { ctx.turnOffAuthorisationSystem(); for (UUID id : itemsToUpdateAuthority) { Item item = itemService.find(ctx, id); @@ -91,7 +97,7 @@ public class AuthorityConsumer implements Consumer { authorityService.indexItem(ctx, item); } - } catch (Exception e){ + } catch (Exception e) { log.error("Error while consuming the authority consumer", e); } finally { diff --git a/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexClient.java b/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexClient.java index c812259e0f..2b933a3bff 100644 --- a/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexClient.java +++ b/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexClient.java @@ -7,18 +7,21 @@ */ package org.dspace.authority.indexer; -import org.dspace.authority.AuthorityValue; -import org.apache.log4j.Logger; -import org.dspace.authority.factory.AuthorityServiceFactory; -import org.dspace.authority.service.AuthorityService; -import org.dspace.core.Context; - import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import org.apache.log4j.Logger; +import org.dspace.authority.AuthorityValue; +import org.dspace.authority.factory.AuthorityServiceFactory; +import org.dspace.authority.service.AuthorityService; +import org.dspace.content.Item; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; + /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -28,9 +31,19 @@ public class AuthorityIndexClient { private static Logger log = Logger.getLogger(AuthorityIndexClient.class); - protected static final AuthorityService authorityService = AuthorityServiceFactory.getInstance().getAuthorityService(); - protected static final AuthorityIndexingService indexingService = AuthorityServiceFactory.getInstance().getAuthorityIndexingService(); - protected static final List indexers = AuthorityServiceFactory.getInstance().getAuthorityIndexers(); + protected static final AuthorityService authorityService = + AuthorityServiceFactory.getInstance().getAuthorityService(); + protected static final AuthorityIndexingService indexingService = + AuthorityServiceFactory.getInstance().getAuthorityIndexingService(); + protected static final List indexers = + AuthorityServiceFactory.getInstance().getAuthorityIndexers(); + protected static final ItemService itemService = + ContentServiceFactory.getInstance().getItemService(); + + /** + * Default constructor + */ + private AuthorityIndexClient() { } public static void main(String[] args) throws Exception { @@ -40,14 +53,15 @@ public class AuthorityIndexClient { context.turnOffAuthorisationSystem(); - - if(!authorityService.isConfigurationValid()){ - //Cannot index, configuration not valid - System.out.println("Cannot index authority values since the configuration isn't valid. Check dspace logs for more information."); + if (!authorityService.isConfigurationValid()) { + //Cannot index, configuration not valid + System.out.println( + "Cannot index authority values since the configuration isn't valid. Check dspace logs for more " + + "information."); return; } - + System.out.println("Retrieving all data"); log.info("Retrieving all data"); @@ -56,15 +70,17 @@ public class AuthorityIndexClient { for (AuthorityIndexerInterface indexerInterface : indexers) { log.info("Initialize " + indexerInterface.getClass().getName()); System.out.println("Initialize " + indexerInterface.getClass().getName()); - indexerInterface.init(context, true); - while (indexerInterface.hasMore()) { - AuthorityValue authorityValue = indexerInterface.nextValue(); - if(authorityValue != null){ + Iterator allItems = itemService.findAll(context); + Map authorityCache = new HashMap<>(); + while (allItems.hasNext()) { + Item item = allItems.next(); + List authorityValues = indexerInterface.getAuthorityValues( + context, item, authorityCache); + for (AuthorityValue authorityValue : authorityValues) { toIndexValues.put(authorityValue.getId(), authorityValue); } + context.uncacheEntity(item); } - //Close up - indexerInterface.close(); } @@ -73,8 +89,8 @@ public class AuthorityIndexClient { indexingService.cleanIndex(); log.info("Writing new data"); System.out.println("Writing new data"); - for(String id : toIndexValues.keySet()){ - indexingService.indexContent(toIndexValues.get(id), true); + for (String id : toIndexValues.keySet()) { + indexingService.indexContent(toIndexValues.get(id)); indexingService.commit(); } diff --git a/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexerInterface.java b/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexerInterface.java index f085b2465d..3d3af104dc 100644 --- a/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexerInterface.java +++ b/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexerInterface.java @@ -8,15 +8,16 @@ package org.dspace.authority.indexer; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + import org.dspace.authority.AuthorityValue; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; import org.dspace.core.Context; -import java.sql.SQLException; - /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -24,17 +25,10 @@ import java.sql.SQLException; */ public interface AuthorityIndexerInterface { - public void init(Context context, Item item); - - public void init(Context context, boolean useCache); - - public void init(Context context); - - public AuthorityValue nextValue(); - - public boolean hasMore() throws SQLException, AuthorizeException; - - public void close(); + public List getAuthorityValues(Context context, Item item) + throws SQLException, AuthorizeException; + public List getAuthorityValues(Context context, Item item, Map cache) + throws SQLException, AuthorizeException; public boolean isConfiguredProperly(); } diff --git a/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexingService.java b/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexingService.java index f69dfe72d1..730ac1a011 100644 --- a/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexingService.java +++ b/dspace-api/src/main/java/org/dspace/authority/indexer/AuthorityIndexingService.java @@ -11,7 +11,6 @@ package org.dspace.authority.indexer; import org.dspace.authority.AuthorityValue; /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -20,7 +19,7 @@ import org.dspace.authority.AuthorityValue; public interface AuthorityIndexingService { - public void indexContent(AuthorityValue value, boolean force); + public void indexContent(AuthorityValue value); public void cleanIndex() throws Exception; diff --git a/dspace-api/src/main/java/org/dspace/authority/indexer/DSpaceAuthorityIndexer.java b/dspace-api/src/main/java/org/dspace/authority/indexer/DSpaceAuthorityIndexer.java index aa92189deb..3b8cc1daf8 100644 --- a/dspace-api/src/main/java/org/dspace/authority/indexer/DSpaceAuthorityIndexer.java +++ b/dspace-api/src/main/java/org/dspace/authority/indexer/DSpaceAuthorityIndexer.java @@ -7,32 +7,35 @@ */ package org.dspace.authority.indexer; -import org.apache.commons.collections.CollectionUtils; -import org.dspace.authority.AuthorityValue; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.dspace.authority.AuthorityValue; import org.dspace.authority.service.AuthorityValueService; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.MetadataValue; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.*; - /** * DSpaceAuthorityIndexer is used in IndexClient, which is called by the AuthorityConsumer and the indexing-script. *

    - * An instance of DSpaceAuthorityIndexer is bound to a list of items. - * This can be one item or all items too depending on the init() method. + * The DSpaceAuthorityIndexer will return a list of all authority values for a + * given item. It will return an authority value for all metadata fields defined + * in dspace.conf with 'authority.author.indexer.field'. *

    - * DSpaceAuthorityIndexer lets you iterate over each metadata value - * for each metadata field defined in dspace.cfg with 'authority.author.indexer.field' - * for each item in the list. + * You have to call getAuthorityValues for every Item you want to index. But you + * can supply an optional cache, to save the mapping from the metadata value to + * the new authority values for metadata fields without an authority key. *

    * * @author Antoine Snyers (antoine at atmire.com) @@ -44,23 +47,14 @@ public class DSpaceAuthorityIndexer implements AuthorityIndexerInterface, Initia private static final Logger log = Logger.getLogger(DSpaceAuthorityIndexer.class); - protected Iterator itemIterator; - protected Item currentItem; /** * The list of metadata fields which are to be indexed * */ protected List metadataFields; - protected int currentFieldIndex; - protected int currentMetadataIndex; - protected AuthorityValue nextValue; - protected Context context; @Autowired(required = true) protected AuthorityValueService authorityValueService; @Autowired(required = true) protected ItemService itemService; - protected boolean useCache; - protected Map cache; - @Autowired(required = true) protected ConfigurationService configurationService; @@ -76,151 +70,92 @@ public class DSpaceAuthorityIndexer implements AuthorityIndexerInterface, Initia } } - @Override - public void init(Context context, Item item) { - ArrayList itemList = new ArrayList<>(); - itemList.add(item); - this.itemIterator = itemList.iterator(); - currentItem = this.itemIterator.next(); - initialize(context); + public List getAuthorityValues(Context context, Item item) + throws SQLException, AuthorizeException { + return getAuthorityValues(context, item, null); } - @Override - public void init(Context context) { - init(context, false); - } - - @Override - public void init(Context context, boolean useCache) { - try { - this.itemIterator = itemService.findAll(context); - currentItem = this.itemIterator.next(); - } catch (SQLException e) { - log.error("Error while retrieving all items in the metadata indexer"); - } - initialize(context); - this.useCache = useCache; - } - - protected void initialize(Context context) { - this.context = context; - - currentFieldIndex = 0; - currentMetadataIndex = 0; - useCache = false; - cache = new HashMap<>(); - } - - @Override - public AuthorityValue nextValue() { - return nextValue; - } - - - @Override - public boolean hasMore() throws SQLException, AuthorizeException { - if (currentItem == null) { - return false; - } - - // 1. iterate over the metadata values - - String metadataField = metadataFields.get(currentFieldIndex); - List values = itemService.getMetadataByMetadataString(currentItem, metadataField); - if (currentMetadataIndex < values.size()) { - prepareNextValue(metadataField, values.get(currentMetadataIndex)); - - currentMetadataIndex++; - return true; - } else { - - // 2. iterate over the metadata fields - - if ((currentFieldIndex + 1) < metadataFields.size()) { - currentFieldIndex++; - //Reset our current metadata index since we are moving to another field - currentMetadataIndex = 0; - return hasMore(); - } else { - - // 3. iterate over the items - context.uncacheEntity(currentItem); - - if (itemIterator.hasNext()) { - currentItem = itemIterator.next(); - //Reset our current field index - currentFieldIndex = 0; - //Reset our current metadata index - currentMetadataIndex = 0; - } else { - currentItem = null; + public List getAuthorityValues(Context context, Item item, Map cache) + throws SQLException, AuthorizeException { + List values = new ArrayList<>(); + for (String metadataField : metadataFields) { + List metadataValues = itemService.getMetadataByMetadataString(item, metadataField); + for (MetadataValue metadataValue : metadataValues) { + String content = metadataValue.getValue(); + String authorityKey = metadataValue.getAuthority(); + // We only want to update our item IF our UUID is not present + // or if we need to generate one. + boolean requiresItemUpdate = StringUtils.isBlank(authorityKey) || + StringUtils.startsWith(authorityKey, AuthorityValueService.GENERATE); + AuthorityValue value = null; + if (StringUtils.isBlank(authorityKey) && cache != null) { + // This is a value currently without an authority. So query + // the cache, if an authority is found for the exact value. + value = cache.get(content); + } + if (value == null) { + value = getAuthorityValue(context, metadataField, content,authorityKey); + } + if (value != null) { + if (requiresItemUpdate) { + value.updateItem(context, item, metadataValue); + try { + itemService.update(context, item); + } catch (Exception e) { + log.error("Error creating a metadatavalue's authority", e); + } + } + if (cache != null) { + cache.put(content, value); + } + values.add(value); + } else { + log.error("Error getting an authority value for " + + "the metadata value \"" + content + "\" " + + "in the field \"" + metadataField + "\" " + + "of the item " + item.getHandle()); } - return hasMore(); } } + return values; } - /** - * This method looks at the authority of a metadata. + * This method looks at the authority of a metadata value. * If the authority can be found in solr, that value is reused. * Otherwise a new authority value will be generated that will be indexed in solr. - * If the authority starts with AuthorityValueGenerator.GENERATE, a specific type of AuthorityValue will be generated. + * + * If the authority starts with AuthorityValueGenerator.GENERATE, a specific type of AuthorityValue will be + * generated. * Depending on the type this may involve querying an external REST service * + * @param context Current DSpace context * @param metadataField Is one of the fields defined in dspace.cfg to be indexed. - * @param value Is one of the values of the given metadataField in one of the items being indexed. - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @param metadataContent Content of the current metadata value. + * @param metadataAuthorityKey Existing authority of the metadata value. */ - protected void prepareNextValue(String metadataField, MetadataValue value) throws SQLException, AuthorizeException { - - nextValue = null; - - String content = value.getValue(); - String authorityKey = value.getAuthority(); - //We only want to update our item IF our UUID is not present or if we need to generate one. - boolean requiresItemUpdate = StringUtils.isBlank(authorityKey) || StringUtils.startsWith(authorityKey, AuthorityValueService.GENERATE); - - if (StringUtils.isNotBlank(authorityKey) && !authorityKey.startsWith(AuthorityValueService.GENERATE)) { - // !uid.startsWith(AuthorityValueGenerator.GENERATE) is not strictly necessary here but it prevents exceptions in solr - nextValue = authorityValueService.findByUID(context, authorityKey); - } - if (nextValue == null && StringUtils.isBlank(authorityKey) && useCache) { - // A metadata without authority is being indexed - // If there is an exact match in the cache, reuse it rather than adding a new one. - AuthorityValue cachedAuthorityValue = cache.get(content); - if (cachedAuthorityValue != null) { - nextValue = cachedAuthorityValue; + private AuthorityValue getAuthorityValue(Context context, String metadataField, + String metadataContent, String metadataAuthorityKey) { + if (StringUtils.isNotBlank(metadataAuthorityKey) && + !metadataAuthorityKey.startsWith(AuthorityValueService.GENERATE)) { + // !uid.startsWith(AuthorityValueGenerator.GENERATE) is not strictly + // necessary here but it prevents exceptions in solr + AuthorityValue value = authorityValueService.findByUID(context, metadataAuthorityKey); + if (value != null) { + return value; } } - if (nextValue == null) { - nextValue = authorityValueService.generate(context, authorityKey, content, metadataField.replaceAll("\\.", "_")); - } - if (nextValue != null && requiresItemUpdate) { - nextValue.updateItem(context, currentItem, value); - try { - itemService.update(context, currentItem); - } catch (Exception e) { - log.error("Error creating a metadatavalue's authority", e); - } - } - if (useCache) { - cache.put(content, nextValue); - } - } - - @Override - public void close() { - itemIterator = null; - cache.clear(); + return authorityValueService.generate(context, metadataAuthorityKey, + metadataContent, metadataField.replaceAll("\\.", "_")); } @Override public boolean isConfiguredProperly() { boolean isConfiguredProperly = true; - if(CollectionUtils.isEmpty(metadataFields)){ - log.warn("Authority indexer not properly configured, no metadata fields configured for indexing. Check the \"authority.author.indexer.field\" properties."); + if (CollectionUtils.isEmpty(metadataFields)) { + log.warn( + "Authority indexer not properly configured, no metadata fields configured for indexing. Check the " + + "\"authority.author.indexer.field\" properties."); isConfiguredProperly = false; } return isConfiguredProperly; diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/Orcid.java b/dspace-api/src/main/java/org/dspace/authority/orcid/Orcid.java deleted file mode 100644 index 4cd89e0626..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/Orcid.java +++ /dev/null @@ -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.authority.orcid; - -import org.dspace.authority.AuthorityValue; -import org.dspace.authority.orcid.model.Bio; -import org.dspace.authority.orcid.model.Work; -import org.dspace.authority.orcid.xml.XMLtoBio; -import org.dspace.authority.orcid.xml.XMLtoWork; -import org.dspace.authority.rest.RestSource; -import org.apache.log4j.Logger; -import org.dspace.services.factory.DSpaceServicesFactory; -import org.w3c.dom.Document; - -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class Orcid extends RestSource { - - /** - * log4j logger - */ - private static Logger log = Logger.getLogger(Orcid.class); - - private static Orcid orcid; - - public static Orcid getOrcid() { - if (orcid == null) { - orcid = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("OrcidSource", Orcid.class); - } - return orcid; - } - - private Orcid(String url) { - super(url); - } - - public Bio getBio(String id) { - Document bioDocument = restConnector.get(id + "/orcid-bio"); - XMLtoBio converter = new XMLtoBio(); - Bio bio = converter.convert(bioDocument).get(0); - bio.setOrcid(id); - return bio; - } - - public List getWorks(String id) { - Document document = restConnector.get(id + "/orcid-works"); - XMLtoWork converter = new XMLtoWork(); - return converter.convert(document); - } - - public List queryBio(String name, int start, int rows) { - Document bioDocument = restConnector.get("search/orcid-bio?q=" + URLEncoder.encode("\"" + name + "\"") + "&start=" + start + "&rows=" + rows); - XMLtoBio converter = new XMLtoBio(); - return converter.convert(bioDocument); - } - - @Override - public List queryAuthorities(String text, int max) { - List bios = queryBio(text, 0, max); - List authorities = new ArrayList(); - for (Bio bio : bios) { - authorities.add(OrcidAuthorityValue.create(bio)); - } - return authorities; - } - - @Override - public AuthorityValue queryAuthorityID(String id) { - Bio bio = getBio(id); - return OrcidAuthorityValue.create(bio); - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/OrcidAuthorityValue.java b/dspace-api/src/main/java/org/dspace/authority/orcid/OrcidAuthorityValue.java deleted file mode 100644 index a36f4f5152..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/OrcidAuthorityValue.java +++ /dev/null @@ -1,320 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid; - -import org.dspace.authority.AuthorityValue; -import org.dspace.authority.AuthorityValueServiceImpl; -import org.dspace.authority.PersonAuthorityValue; -import org.dspace.authority.orcid.model.Bio; -import org.dspace.authority.orcid.model.BioExternalIdentifier; -import org.dspace.authority.orcid.model.BioName; -import org.dspace.authority.orcid.model.BioResearcherUrl; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.apache.solr.common.SolrDocument; -import org.apache.solr.common.SolrInputDocument; - -import java.util.*; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class OrcidAuthorityValue extends PersonAuthorityValue { - - /** - * log4j logger - */ - private static Logger log = Logger.getLogger(OrcidAuthorityValue.class); - - private String orcid_id; - private Map> otherMetadata = new HashMap>(); - private boolean update; // used in setValues(Bio bio) - - - /** - * Creates an instance of OrcidAuthorityValue with only uninitialized fields. - * This is meant to be filled in with values from an existing record. - * To create a brand new OrcidAuthorityValue, use create() - */ - public OrcidAuthorityValue() { - } - - public OrcidAuthorityValue(SolrDocument document) { - super(document); - } - - public String getOrcid_id() { - return orcid_id; - } - - public void setOrcid_id(String orcid_id) { - this.orcid_id = orcid_id; - } - - public Map> getOtherMetadata() { - return otherMetadata; - } - - public void addOtherMetadata(String label, String data) { - List strings = otherMetadata.get(label); - if (strings == null) { - strings = new ArrayList(); - } - strings.add(data); - otherMetadata.put(label, strings); - } - - @Override - public SolrInputDocument getSolrInputDocument() { - SolrInputDocument doc = super.getSolrInputDocument(); - if (StringUtils.isNotBlank(getOrcid_id())) { - doc.addField("orcid_id", getOrcid_id()); - } - - for (String t : otherMetadata.keySet()) { - List data = otherMetadata.get(t); - for (String data_entry : data) { - doc.addField("label_" + t, data_entry); - } - } - return doc; - } - - @Override - public void setValues(SolrDocument document) { - super.setValues(document); - this.orcid_id = String.valueOf(document.getFieldValue("orcid_id")); - - otherMetadata = new HashMap>(); - for (String fieldName : document.getFieldNames()) { - String labelPrefix = "label_"; - if (fieldName.startsWith(labelPrefix)) { - String label = fieldName.substring(labelPrefix.length()); - List list = new ArrayList(); - Collection fieldValues = document.getFieldValues(fieldName); - for (Object o : fieldValues) { - list.add(String.valueOf(o)); - } - otherMetadata.put(label, list); - } - } - } - - public static OrcidAuthorityValue create() { - OrcidAuthorityValue orcidAuthorityValue = new OrcidAuthorityValue(); - orcidAuthorityValue.setId(UUID.randomUUID().toString()); - orcidAuthorityValue.updateLastModifiedDate(); - orcidAuthorityValue.setCreationDate(new Date()); - return orcidAuthorityValue; - } - - /** - * Create an authority based on a given orcid bio - * @param bio Bio - * @return OrcidAuthorityValue - */ - public static OrcidAuthorityValue create(Bio bio) { - OrcidAuthorityValue authority = OrcidAuthorityValue.create(); - - authority.setValues(bio); - - return authority; - } - - public boolean setValues(Bio bio) { - BioName name = bio.getName(); - - if (updateValue(bio.getOrcid(), getOrcid_id())) { - setOrcid_id(bio.getOrcid()); - } - - if (updateValue(name.getFamilyName(), getLastName())) { - setLastName(name.getFamilyName()); - } - - if (updateValue(name.getGivenNames(), getFirstName())) { - setFirstName(name.getGivenNames()); - } - - if (StringUtils.isNotBlank(name.getCreditName())) { - if (!getNameVariants().contains(name.getCreditName())) { - addNameVariant(name.getCreditName()); - update = true; - } - } - for (String otherName : name.getOtherNames()) { - if (!getNameVariants().contains(otherName)) { - addNameVariant(otherName); - update = true; - } - } - - if (updateOtherMetadata("country", bio.getCountry())) { - addOtherMetadata("country", bio.getCountry()); - } - - for (String keyword : bio.getKeywords()) { - if (updateOtherMetadata("keyword", keyword)) { - addOtherMetadata("keyword", keyword); - } - } - - for (BioExternalIdentifier externalIdentifier : bio.getBioExternalIdentifiers()) { - if (updateOtherMetadata("external_identifier", externalIdentifier.toString())) { - addOtherMetadata("external_identifier", externalIdentifier.toString()); - } - } - - for (BioResearcherUrl researcherUrl : bio.getResearcherUrls()) { - if (updateOtherMetadata("researcher_url", researcherUrl.toString())) { - addOtherMetadata("researcher_url", researcherUrl.toString()); - } - } - - if (updateOtherMetadata("biography", bio.getBiography())) { - addOtherMetadata("biography", bio.getBiography()); - } - - setValue(getName()); - - if (update) { - update(); - } - boolean result = update; - update = false; - return result; - } - - private boolean updateOtherMetadata(String label, String data) { - List strings = getOtherMetadata().get(label); - boolean update; - if (strings == null) { - update = StringUtils.isNotBlank(data); - } else { - update = !strings.contains(data); - } - if (update) { - this.update = true; - } - return update; - } - - private boolean updateValue(String incoming, String resident) { - boolean update = StringUtils.isNotBlank(incoming) && !incoming.equals(resident); - if (update) { - this.update = true; - } - return update; - } - - @Override - public Map choiceSelectMap() { - - Map map = super.choiceSelectMap(); - - map.put("orcid", getOrcid_id()); - - return map; - } - - @Override - public String getAuthorityType() { - return "orcid"; - } - - @Override - public String generateString() { - String generateString = AuthorityValueServiceImpl.GENERATE + getAuthorityType() + AuthorityValueServiceImpl.SPLIT; - if (StringUtils.isNotBlank(getOrcid_id())) { - generateString += getOrcid_id(); - } - return generateString; - } - - - @Override - public AuthorityValue newInstance(String info) { - AuthorityValue authorityValue = null; - if (StringUtils.isNotBlank(info)) { - Orcid orcid = Orcid.getOrcid(); - authorityValue = orcid.queryAuthorityID(info); - } else { - authorityValue = OrcidAuthorityValue.create(); - } - return authorityValue; - } - - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - OrcidAuthorityValue that = (OrcidAuthorityValue) o; - - if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return orcid_id != null ? orcid_id.hashCode() : 0; - } - - @Override - public boolean hasTheSameInformationAs(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - if (!super.hasTheSameInformationAs(o)) { - return false; - } - - OrcidAuthorityValue that = (OrcidAuthorityValue) o; - - if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) { - return false; - } - - for (String key : otherMetadata.keySet()) { - if(otherMetadata.get(key) != null){ - List metadata = otherMetadata.get(key); - List otherMetadata = that.otherMetadata.get(key); - if (otherMetadata == null) { - return false; - } else { - HashSet metadataSet = new HashSet(metadata); - HashSet otherMetadataSet = new HashSet(otherMetadata); - if (!metadataSet.equals(otherMetadataSet)) { - return false; - } - } - }else{ - if(that.otherMetadata.get(key) != null){ - return false; - } - } - } - - return true; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/Orcidv2.java b/dspace-api/src/main/java/org/dspace/authority/orcid/Orcidv2.java new file mode 100644 index 0000000000..cf97bbe442 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/authority/orcid/Orcidv2.java @@ -0,0 +1,188 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.authority.orcid; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.log4j.Logger; +import org.dspace.authority.AuthorityValue; +import org.dspace.authority.SolrAuthorityInterface; +import org.dspace.authority.orcid.xml.XMLtoBio; +import org.dspace.authority.rest.RESTConnector; +import org.json.JSONObject; +import org.orcid.jaxb.model.record_v2.Person; + +/** + * @author Jonas Van Goolen (jonas at atmire dot com) + * This class contains all methods for retrieving "Person" objects calling the ORCID (version 2) endpoints. + * Additionally, this can also create AuthorityValues based on these returned Person objects + */ +public class Orcidv2 implements SolrAuthorityInterface { + + private static Logger log = Logger.getLogger(Orcidv2.class); + + public RESTConnector restConnector; + private String OAUTHUrl; + private String clientId; + + private String clientSecret; + + private String accessToken; + + /** + * Initialize the accessToken that is required for all subsequent calls to ORCID + */ + public void init() throws IOException { + if (StringUtils.isNotBlank(accessToken) && StringUtils.isNotBlank(clientSecret)) { + String authenticationParameters = "?client_id=" + clientId + + "&client_secret=" + clientSecret + + "&scope=/read-public&grant_type=client_credentials"; + HttpPost httpPost = new HttpPost(OAUTHUrl + authenticationParameters); + httpPost.addHeader("Accept", "application/json"); + httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded"); + + HttpClient httpClient = HttpClientBuilder.create().build(); + HttpResponse getResponse = httpClient.execute(httpPost); + + InputStream is = getResponse.getEntity().getContent(); + BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8")); + + JSONObject responseObject = null; + String inputStr; + while ((inputStr = streamReader.readLine()) != null && responseObject == null) { + if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) { + try { + responseObject = new JSONObject(inputStr); + } catch (Exception e) { + //Not as valid as I'd hoped, move along + responseObject = null; + } + } + } + + if (responseObject != null && responseObject.has("access_token")) { + accessToken = (String) responseObject.get("access_token"); + } + } + } + + /** + * Makes an instance of the Orcidv2 class based on the provided parameters. + * This constructor is called through the spring bean initialization + */ + private Orcidv2(String url, String OAUTHUrl, String clientId, String clientSecret) { + this.restConnector = new RESTConnector(url); + this.OAUTHUrl = OAUTHUrl; + this.clientId = clientId; + this.clientSecret = clientSecret; + } + + /** + * Makes an instance of the Orcidv2 class based on the provided parameters. + * This constructor is called through the spring bean initialization + */ + private Orcidv2(String url) { + this.restConnector = new RESTConnector(url); + } + + /** + * Makes an instance of the AuthorityValue with the given information. + * @param text search string + * @return List + */ + @Override + public List queryAuthorities(String text, int max) { + List bios = queryBio(text, max); + List result = new ArrayList<>(); + for (Person person : bios) { + AuthorityValue orcidAuthorityValue = Orcidv2AuthorityValue.create(person); + if (orcidAuthorityValue != null) { + result.add(orcidAuthorityValue); + } + } + return result; + } + + /** + * Create an AuthorityValue from a Person retrieved using the given orcid identifier. + * @param id orcid identifier + * @return AuthorityValue + */ + public AuthorityValue queryAuthorityID(String id) { + Person person = getBio(id); + AuthorityValue valueFromPerson = Orcidv2AuthorityValue.create(person); + return valueFromPerson; + } + + /** + * Retrieve a Person object based on a given orcid identifier + * @param id orcid identifier + * @return Person + */ + public Person getBio(String id) { + log.debug("getBio called with ID=" + id); + if (!isValid(id)) { + return null; + } + InputStream bioDocument = restConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken); + XMLtoBio converter = new XMLtoBio(); + Person person = converter.convertSinglePerson(bioDocument); + return person; + } + + + /** + * Retrieve a list of Person objects. + * @param text search string + * @param start offset to use + * @param rows how many rows to return + * @return List + */ + public List queryBio(String text, int start, int rows) { + if (rows > 100) { + throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100."); + } + + String searchPath = "search?q=" + URLEncoder.encode(text) + "&start=" + start + "&rows=" + rows; + log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken); + InputStream bioDocument = restConnector.get(searchPath, accessToken); + XMLtoBio converter = new XMLtoBio(); + List bios = converter.convert(bioDocument); + return bios; + } + + /** + * Retrieve a list of Person objects. + * @param text search string + * @param max how many rows to return + * @return List + */ + public List queryBio(String text, int max) { + return queryBio(text, 0, max); + } + + /** + * Check to see if the provided text has the correct ORCID syntax. + * Since only searching on ORCID id is allowed, this way, we filter out any queries that would return a + * blank result anyway + */ + private boolean isValid(String text) { + return StringUtils.isNotBlank(text) && text.matches(Orcidv2AuthorityValue.ORCID_ID_SYNTAX); + } +} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/Orcidv2AuthorityValue.java b/dspace-api/src/main/java/org/dspace/authority/orcid/Orcidv2AuthorityValue.java new file mode 100644 index 0000000000..0aa0d292e7 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/authority/orcid/Orcidv2AuthorityValue.java @@ -0,0 +1,342 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.authority.orcid; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrInputDocument; +import org.dspace.authority.AuthorityValue; +import org.dspace.authority.AuthorityValueServiceImpl; +import org.dspace.authority.PersonAuthorityValue; +import org.dspace.utils.DSpace; +import org.orcid.jaxb.model.common_v2.ExternalId; +import org.orcid.jaxb.model.record_v2.ExternalIdentifiers; +import org.orcid.jaxb.model.record_v2.KeywordType; +import org.orcid.jaxb.model.record_v2.NameType; +import org.orcid.jaxb.model.record_v2.Person; +import org.orcid.jaxb.model.record_v2.ResearcherUrlType; + +/** + * @author Jonas Van Goolen (jonas at atmire dot com) + */ +public class Orcidv2AuthorityValue extends PersonAuthorityValue { + + /* + * The ORCID identifier + */ + private String orcid_id; + + /* + * Map containing key-value pairs filled in by "setValues(Person person)". + * This represents all dynamic information of the object. + */ + private Map> otherMetadata = new HashMap>(); + + /** + * The syntax that the ORCID id needs to conform to + */ + public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})"; + + + /** + * Creates an instance of Orcidv2AuthorityValue with only uninitialized fields. + * This is meant to be filled in with values from an existing record. + * To create a brand new Orcidv2AuthorityValue, use create() + */ + public Orcidv2AuthorityValue() { + } + + public Orcidv2AuthorityValue(SolrDocument document) { + super(document); + } + + + public String getOrcid_id() { + return orcid_id; + } + + public void setOrcid_id(String orcid_id) { + this.orcid_id = orcid_id; + } + + /** + * Create an empty authority. + * @return OrcidAuthorityValue + */ + public static Orcidv2AuthorityValue create() { + Orcidv2AuthorityValue orcidAuthorityValue = new Orcidv2AuthorityValue(); + orcidAuthorityValue.setId(UUID.randomUUID().toString()); + orcidAuthorityValue.updateLastModifiedDate(); + orcidAuthorityValue.setCreationDate(new Date()); + return orcidAuthorityValue; + } + + /** + * Create an authority based on a given orcid bio + * @return OrcidAuthorityValue + */ + public static Orcidv2AuthorityValue create(Person person) { + if (person == null) { + return null; + } + Orcidv2AuthorityValue authority = Orcidv2AuthorityValue.create(); + + authority.setValues(person); + + return authority; + } + + /** + * Initialize this instance based on a Person object + * @param person Person + */ + protected void setValues(Person person) { + NameType name = person.getName(); + + if (!StringUtils.equals(name.getPath(), this.getOrcid_id())) { + this.setOrcid_id(name.getPath()); + } + + if (!StringUtils.equals(name.getFamilyName().getValue(), this.getLastName())) { + this.setLastName(name.getFamilyName().getValue()); + } + + if (!StringUtils.equals(name.getGivenNames().getValue(), this.getFirstName())) { + this.setFirstName(name.getGivenNames().getValue()); + } + + if (name.getCreditName() != null && StringUtils.isNotBlank(name.getCreditName().getValue())) { + if (!this.getNameVariants().contains(name.getCreditName().getValue())) { + this.addNameVariant(name.getCreditName().getValue()); + } + } + + if (person.getKeywords() != null) { + for (KeywordType keyword : person.getKeywords().getKeyword()) { + if (this.isNewMetadata("keyword", keyword.getContent())) { + this.addOtherMetadata("keyword", keyword.getContent()); + } + } + } + + ExternalIdentifiers externalIdentifiers = person.getExternalIdentifiers(); + if (externalIdentifiers != null) { + for (ExternalId externalIdentifier : externalIdentifiers.getExternalIdentifier()) { + if (this.isNewMetadata("external_identifier", externalIdentifier.getExternalIdValue())) { + this.addOtherMetadata("external_identifier", externalIdentifier.getExternalIdValue()); + + } + } + } + if (person.getResearcherUrls() != null) { + for (ResearcherUrlType researcherUrl : person.getResearcherUrls().getResearcherUrl()) { + if (this.isNewMetadata("researcher_url", researcherUrl.getUrl().getValue())) { + this.addOtherMetadata("researcher_url", researcherUrl.getUrl().getValue()); + } + } + + } + if (person.getBiography() != null) { + if (this.isNewMetadata("biography", person.getBiography().getContent())) { + this.addOtherMetadata("biography", person.getBiography().getContent()); + } + } + + this.setValue(this.getName()); + + } + + /** + * Makes an instance of the AuthorityValue with the given information. + * @param info string info + * @return AuthorityValue + */ + @Override + public AuthorityValue newInstance(String info) { + AuthorityValue authorityValue = null; + if (StringUtils.isNotBlank(info)) { + Orcidv2 orcid = new DSpace().getServiceManager().getServiceByName("AuthoritySource", Orcidv2.class); + authorityValue = orcid.queryAuthorityID(info); + } else { + authorityValue = this.create(); + } + return authorityValue; + } + + @Override + public void setValue(String value) { + super.setValue(value); + } + + /** + * Check to see if the provided label / data pair is already present in the "otherMetadata" or not + * */ + public boolean isNewMetadata(String label, String data) { + List strings = getOtherMetadata().get(label); + boolean update; + if (strings == null) { + update = StringUtils.isNotBlank(data); + } else { + update = !strings.contains(data); + } + return update; + } + + /** + * Add additional metadata to the otherMetadata map*/ + public void addOtherMetadata(String label, String data) { + List strings = otherMetadata.get(label); + if (strings == null) { + strings = new ArrayList<>(); + } + strings.add(data); + otherMetadata.put(label, strings); + } + + public Map> getOtherMetadata() { + return otherMetadata; + } + + + /** + * Generate a solr record from this instance + * @return SolrInputDocument + */ + @Override + public SolrInputDocument getSolrInputDocument() { + SolrInputDocument doc = super.getSolrInputDocument(); + if (StringUtils.isNotBlank(getOrcid_id())) { + doc.addField("orcid_id", getOrcid_id()); + } + + for (String t : otherMetadata.keySet()) { + List data = otherMetadata.get(t); + for (String data_entry : data) { + doc.addField("label_" + t, data_entry); + } + } + return doc; + } + + /** + * Information that can be used the choice ui + * @return map + */ + @Override + public Map choiceSelectMap() { + + Map map = super.choiceSelectMap(); + + String orcid_id = getOrcid_id(); + if (StringUtils.isNotBlank(orcid_id)) { + map.put("orcid", orcid_id); + } + + return map; + } + + @Override + public String getAuthorityType() { + return "orcid"; + } + + /** + * Provides a string that will allow this AuthorityType to be recognized and provides information to create a new + * instance to be created using public Orcidv2AuthorityValue newInstance(String info). + * @return see {@link org.dspace.authority.service.AuthorityValueService#GENERATE AuthorityValueService.GENERATE} + */ + @Override + public String generateString() { + String generateString = AuthorityValueServiceImpl.GENERATE + getAuthorityType() + + AuthorityValueServiceImpl.SPLIT; + if (StringUtils.isNotBlank(getOrcid_id())) { + generateString += getOrcid_id(); + } + return generateString; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Orcidv2AuthorityValue that = (Orcidv2AuthorityValue) o; + + if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return orcid_id != null ? orcid_id.hashCode() : 0; + } + + /** + * The regular equals() only checks if both AuthorityValues describe the same authority. + * This method checks if the AuthorityValues have different information + * E.g. it is used to decide when lastModified should be updated. + * @param o object + * @return true or false + */ + @Override + public boolean hasTheSameInformationAs(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.hasTheSameInformationAs(o)) { + return false; + } + + Orcidv2AuthorityValue that = (Orcidv2AuthorityValue) o; + + if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) { + return false; + } + + for (String key : otherMetadata.keySet()) { + if (otherMetadata.get(key) != null) { + List metadata = otherMetadata.get(key); + List otherMetadata = that.otherMetadata.get(key); + if (otherMetadata == null) { + return false; + } else { + HashSet metadataSet = new HashSet(metadata); + HashSet otherMetadataSet = new HashSet(otherMetadata); + if (!metadataSet.equals(otherMetadataSet)) { + return false; + } + } + } else { + if (that.otherMetadata.get(key) != null) { + return false; + } + } + } + + return true; + } +} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/Bio.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/Bio.java deleted file mode 100644 index b3ede32f36..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/Bio.java +++ /dev/null @@ -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.authority.orcid.model; - -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class Bio { - - protected String orcid; - - protected BioName name; - - protected String country; - - protected Set keywords; - - protected Set bioExternalIdentifiers; - - protected Set researcherUrls; - - protected String biography; - - public Bio() { - this.name = new BioName(); - keywords = new LinkedHashSet(); - bioExternalIdentifiers = new LinkedHashSet(); - researcherUrls = new LinkedHashSet(); - } - - public String getOrcid() { - return orcid; - } - - public void setOrcid(String orcid) { - this.orcid = orcid; - } - - public BioName getName() { - return name; - } - - public void setName(BioName name) { - this.name = name; - } - - public String getCountry() { - return country; - } - - public void setCountry(String country) { - this.country = country; - } - - public Set getKeywords() { - return keywords; - } - - public void addKeyword(String keyword) { - this.keywords.add(keyword); - } - - public Set getBioExternalIdentifiers() { - return bioExternalIdentifiers; - } - - public void addExternalIdentifier(BioExternalIdentifier externalReference) { - bioExternalIdentifiers.add(externalReference); - } - - public Set getResearcherUrls() { - return researcherUrls; - } - - public void addResearcherUrl(BioResearcherUrl researcherUrl) { - researcherUrls.add(researcherUrl); - } - - public String getBiography() { - return biography; - } - - public void setBiography(String biography) { - this.biography = biography; - } - - @Override - public String toString() { - return "Bio{" + - "orcid='" + orcid + '\'' + - ", name=" + name + - ", country='" + country + '\'' + - ", keywords=" + keywords + - ", bioExternalIdentifiers=" + bioExternalIdentifiers + - ", researcherUrls=" + researcherUrls + - ", biography='" + biography + '\'' + - '}'; - } -} - diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioExternalIdentifier.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioExternalIdentifier.java deleted file mode 100644 index 65f4161b04..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioExternalIdentifier.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid.model; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class BioExternalIdentifier { - - - protected String id_orcid; - protected String id_common_name; - protected String id_reference; - protected String id_url; - - public BioExternalIdentifier(String id_orcid, String id_common_name, String id_reference, String id_url) { - this.id_orcid = id_orcid; - this.id_common_name = id_common_name; - this.id_reference = id_reference; - this.id_url = id_url; - } - - public String getId_orcid() { - return id_orcid; - } - - public void setId_orcid(String id_orcid) { - this.id_orcid = id_orcid; - } - - public String getId_common_name() { - return id_common_name; - } - - public void setId_common_name(String id_common_name) { - this.id_common_name = id_common_name; - } - - public String getId_reference() { - return id_reference; - } - - public void setId_reference(String id_reference) { - this.id_reference = id_reference; - } - - public String getId_url() { - return id_url; - } - - public void setId_url(String id_url) { - this.id_url = id_url; - } - - @Override - public String toString() { - return "BioExternalIdentifier{" + - "id_orcid='" + id_orcid + '\'' + - ", id_common_name='" + id_common_name + '\'' + - ", id_reference='" + id_reference + '\'' + - ", id_url='" + id_url + '\'' + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - BioExternalIdentifier that = (BioExternalIdentifier) o; - - if (id_common_name != null ? !id_common_name.equals(that.id_common_name) : that.id_common_name != null) { - return false; - } - if (id_orcid != null ? !id_orcid.equals(that.id_orcid) : that.id_orcid != null) { - return false; - } - if (id_reference != null ? !id_reference.equals(that.id_reference) : that.id_reference != null) { - return false; - } - if (id_url != null ? !id_url.equals(that.id_url) : that.id_url != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = id_orcid != null ? id_orcid.hashCode() : 0; - result = 31 * result + (id_common_name != null ? id_common_name.hashCode() : 0); - result = 31 * result + (id_reference != null ? id_reference.hashCode() : 0); - result = 31 * result + (id_url != null ? id_url.hashCode() : 0); - return result; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioName.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioName.java deleted file mode 100644 index faae5dacf8..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioName.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid.model; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class BioName { - - protected String givenNames; - protected String familyName; - protected String creditName; - protected List otherNames; - - BioName() { - otherNames = new ArrayList(); - } - - BioName(String givenNames, String familyName, String creditName, List otherNames) { - this.givenNames = givenNames; - this.familyName = familyName; - this.creditName = creditName; - this.otherNames = otherNames; - } - - public String getGivenNames() { - return givenNames; - } - - public void setGivenNames(String givenNames) { - this.givenNames = givenNames; - } - - public String getFamilyName() { - return familyName; - } - - public void setFamilyName(String familyName) { - this.familyName = familyName; - } - - public String getCreditName() { - return creditName; - } - - public void setCreditName(String creditName) { - this.creditName = creditName; - } - - public List getOtherNames() { - return otherNames; - } - - public void setOtherNames(List otherNames) { - this.otherNames = otherNames; - } - - @Override - public String toString() { - return "BioName{" + - "givenNames='" + givenNames + '\'' + - ", familyName='" + familyName + '\'' + - ", creditName='" + creditName + '\'' + - ", otherNames=" + otherNames + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - BioName bioName = (BioName) o; - - if (creditName != null ? !creditName.equals(bioName.creditName) : bioName.creditName != null) { - return false; - } - if (familyName != null ? !familyName.equals(bioName.familyName) : bioName.familyName != null) { - return false; - } - if (givenNames != null ? !givenNames.equals(bioName.givenNames) : bioName.givenNames != null) { - return false; - } - if (otherNames != null ? !otherNames.equals(bioName.otherNames) : bioName.otherNames != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = givenNames != null ? givenNames.hashCode() : 0; - result = 31 * result + (familyName != null ? familyName.hashCode() : 0); - result = 31 * result + (creditName != null ? creditName.hashCode() : 0); - result = 31 * result + (otherNames != null ? otherNames.hashCode() : 0); - return result; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioResearcherUrl.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioResearcherUrl.java deleted file mode 100644 index 6f3965b2ee..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/BioResearcherUrl.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid.model; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class BioResearcherUrl { - - protected String name; - protected String url; - - public BioResearcherUrl(String name, String url) { - this.name = name; - this.url = url; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - @Override - public String toString() { - return "BioResearcherUrl{" + - "name='" + name + '\'' + - ", url='" + url + '\'' + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - BioResearcherUrl that = (BioResearcherUrl) o; - - if (name != null ? !name.equals(that.name) : that.name != null) { - return false; - } - if (url != null ? !url.equals(that.url) : that.url != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = name != null ? name.hashCode() : 0; - result = 31 * result + (url != null ? url.hashCode() : 0); - return result; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/Citation.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/Citation.java deleted file mode 100644 index 04ae3071e9..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/Citation.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid.model; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class Citation { - - private CitationType type; - private String citation; - - public Citation(CitationType type, String citation) { - this.type = type; - this.citation = citation; - } - - public CitationType getType() { - return type; - } - - public void setType(CitationType type) { - this.type = type; - } - - public String getCitation() { - return citation; - } - - public void setCitation(String citation) { - this.citation = citation; - } - - @Override - public String toString() { - return "Citation{" + - "type=" + type + - ", citation='" + citation + '\'' + - '}'; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/CitationType.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/CitationType.java deleted file mode 100644 index 687b3f667d..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/CitationType.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ - -package org.dspace.authority.orcid.model; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public enum CitationType { - - FORMATTED_UNSPECIFIED, - BIBTEX, - FORMATTED_APA, - FORMATTED_HARVARD, - FORMATTED_IEEE, - FORMATTED_MLA, - FORMATTED_VANCOUVER, - FORMATTED_CHICAGO - -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/Contributor.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/Contributor.java deleted file mode 100644 index b5fc118ad5..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/Contributor.java +++ /dev/null @@ -1,111 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ - -package org.dspace.authority.orcid.model; - -import java.util.Set; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class Contributor { - - private String orcid; - private String creditName; - private String email; - private Set contributorAttributes; - - public Contributor(String orcid, String creditName, String email, Set contributorAttributes) { - this.orcid = orcid; - this.creditName = creditName; - this.email = email; - this.contributorAttributes = contributorAttributes; - } - - public String getOrcid() { - return orcid; - } - - public void setOrcid(String orcid) { - this.orcid = orcid; - } - - public String getCreditName() { - return creditName; - } - - public void setCreditName(String creditName) { - this.creditName = creditName; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Set getContributorAttributes() { - return contributorAttributes; - } - - public void setContributorAttributes(Set contributorAttributes) { - this.contributorAttributes = contributorAttributes; - } - - @Override - public String toString() { - return "Contributor{" + - "orcid='" + orcid + '\'' + - ", creditName='" + creditName + '\'' + - ", email='" + email + '\'' + - ", contributorAttributes=" + contributorAttributes + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Contributor that = (Contributor) o; - - if (contributorAttributes != null ? !contributorAttributes.equals(that.contributorAttributes) : that.contributorAttributes != null) { - return false; - } - if (creditName != null ? !creditName.equals(that.creditName) : that.creditName != null) { - return false; - } - if (email != null ? !email.equals(that.email) : that.email != null) { - return false; - } - if (orcid != null ? !orcid.equals(that.orcid) : that.orcid != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = orcid != null ? orcid.hashCode() : 0; - result = 31 * result + (creditName != null ? creditName.hashCode() : 0); - result = 31 * result + (email != null ? email.hashCode() : 0); - result = 31 * result + (contributorAttributes != null ? contributorAttributes.hashCode() : 0); - return result; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttribute.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttribute.java deleted file mode 100644 index ec9f843409..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttribute.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ - -package org.dspace.authority.orcid.model; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class ContributorAttribute { - - private ContributorAttributeRole role; - private ContributorAttributeSequence sequence; - - public ContributorAttribute(ContributorAttributeRole role, ContributorAttributeSequence sequence) { - this.role = role; - this.sequence = sequence; - } - - public ContributorAttributeRole getRole() { - return role; - } - - public void setRole(ContributorAttributeRole role) { - this.role = role; - } - - public ContributorAttributeSequence getSequence() { - return sequence; - } - - public void setSequence(ContributorAttributeSequence sequence) { - this.sequence = sequence; - } - - @Override - public String toString() { - return "ContributorAttribute{" + - "role=" + role + - ", sequence=" + sequence + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - ContributorAttribute that = (ContributorAttribute) o; - - if (role != that.role) { - return false; - } - if (sequence != that.sequence) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = role != null ? role.hashCode() : 0; - result = 31 * result + (sequence != null ? sequence.hashCode() : 0); - return result; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttributeRole.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttributeRole.java deleted file mode 100644 index a22546b56d..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttributeRole.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid.model; - -/** - * http://support.orcid.org/knowledgebase/articles/118843-anatomy-of-a-contributor - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public enum ContributorAttributeRole { - - AUTHOR, - ASSIGNEE, - EDITOR, - CHAIR_OR_TRANSLATOR, - CO_INVESTIGATOR, - CO_INVENTOR, - GRADUATE_STUDENT, - OTHER_INVENTOR, - PRINCIPAL_INVESTIGATOR, - POSTDOCTORAL_RESEARCHER, - SUPPORT_STAFF - -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttributeSequence.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttributeSequence.java deleted file mode 100644 index 8407fe28dc..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/ContributorAttributeSequence.java +++ /dev/null @@ -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.authority.orcid.model; - -/** - * http://support.orcid.org/knowledgebase/articles/118843-anatomy-of-a-contributor - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public enum ContributorAttributeSequence { - - FIRST, - ADDITIONAL - -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/Work.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/Work.java deleted file mode 100644 index 0b7552d1e6..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/Work.java +++ /dev/null @@ -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.authority.orcid.model; - -import java.util.Set; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class Work { - - private WorkTitle workTitle; - private String description; - private Citation citation; - private WorkType workType; - private String publicationDate; - private WorkExternalIdentifier workExternalIdentifier; - private String url; - private Set contributors; - private String workSource; - - public WorkTitle getWorkTitle() { - return workTitle; - } - - public void setWorkTitle(WorkTitle workTitle) { - this.workTitle = workTitle; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Citation getCitation() { - return citation; - } - - public void setCitation(Citation citation) { - this.citation = citation; - } - - public WorkType getWorkType() { - return workType; - } - - public void setWorkType(WorkType workType) { - this.workType = workType; - } - - public String getPublicationDate() { - return publicationDate; - } - - public void setPublicationDate(String publicationDate) { - this.publicationDate = publicationDate; - } - - public WorkExternalIdentifier getWorkExternalIdentifier() { - return workExternalIdentifier; - } - - public void setWorkExternalIdentifier(WorkExternalIdentifier workExternalIdentifier) { - this.workExternalIdentifier = workExternalIdentifier; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public Set getContributors() { - return contributors; - } - - public void setContributors(Set contributors) { - this.contributors = contributors; - } - - public String getWorkSource() { - return workSource; - } - - public void setWorkSource(String workSource) { - this.workSource = workSource; - } - - @Override - public String toString() { - return "Work{" + - "workTitle=" + workTitle + - ", description='" + description + '\'' + - ", citation=" + citation + - ", workType=" + workType + - ", publicationDate='" + publicationDate + '\'' + - ", workExternalIdentifier=" + workExternalIdentifier + - ", url='" + url + '\'' + - ", contributors=" + contributors + - ", workSource='" + workSource + '\'' + - '}'; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkExternalIdentifier.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkExternalIdentifier.java deleted file mode 100644 index b0fca03037..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkExternalIdentifier.java +++ /dev/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.authority.orcid.model; - -/** - * http://support.orcid.org/knowledgebase/articles/118807 - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class WorkExternalIdentifier { - - private WorkExternalIdentifierType workExternalIdentifierType; - private String workExternalIdenfitierID; - - public WorkExternalIdentifier(WorkExternalIdentifierType workExternalIdentifierType, String workExternalIdenfitierID) { - this.workExternalIdentifierType = workExternalIdentifierType; - this.workExternalIdenfitierID = workExternalIdenfitierID; - } - - public WorkExternalIdentifierType getWorkExternalIdentifierType() { - return workExternalIdentifierType; - } - - public void setWorkExternalIdentifierType(WorkExternalIdentifierType workExternalIdentifierType) { - this.workExternalIdentifierType = workExternalIdentifierType; - } - - @Override - public String toString() { - return "WorkExternalIdentifier{" + - "workExternalIdentifierType=" + workExternalIdentifierType + - ", workExternalIdenfitierID='" + workExternalIdenfitierID + '\'' + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - WorkExternalIdentifier that = (WorkExternalIdentifier) o; - - if (workExternalIdenfitierID != null ? !workExternalIdenfitierID.equals(that.workExternalIdenfitierID) : that.workExternalIdenfitierID != null) { - return false; - } - if (workExternalIdentifierType != that.workExternalIdentifierType) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = workExternalIdentifierType != null ? workExternalIdentifierType.hashCode() : 0; - result = 31 * result + (workExternalIdenfitierID != null ? workExternalIdenfitierID.hashCode() : 0); - return result; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkExternalIdentifierType.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkExternalIdentifierType.java deleted file mode 100644 index 17d74371f9..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkExternalIdentifierType.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid.model; - -/** - * http://support.orcid.org/knowledgebase/articles/118807 - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public enum WorkExternalIdentifierType { - -// OTHER_ID, - ARXIV, - ASIN, - ASIN_TLD, - BIBCODE, - DOI, - EID, - ISBN, - ISSN, - JFM, - JSTOR, - LCCN, - MR, - OCLC, - OL, - OSTI, - PMC, - PMID, - RFC, - SSRN, - ZBL - -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkTitle.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkTitle.java deleted file mode 100644 index e9961c9d2b..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkTitle.java +++ /dev/null @@ -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.authority.orcid.model; - -import java.util.Map; - -/** - * http://support.orcid.org/knowledgebase/articles/118807 - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class WorkTitle { - - private String title; - private String subtitle; - private Map translatedTitles; - - public WorkTitle(String title, String subtitle, Map translatedTitles) { - this.title = title; - this.subtitle = subtitle; - this.translatedTitles = translatedTitles; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getSubtitle() { - return subtitle; - } - - public void setSubtitle(String subtitle) { - this.subtitle = subtitle; - } - - public String getTranslatedTitles(String languageCode) { - return translatedTitles.get(languageCode); - } - - public void setTranslatedTitle(String languageCode, String translatedTitle) { - translatedTitles.put(languageCode, translatedTitle); - } - - @Override - public String toString() { - return "WorkTitle{" + - "title='" + title + '\'' + - ", subtitle='" + subtitle + '\'' + - ", translatedTitles=" + translatedTitles + - '}'; - } -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkType.java b/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkType.java deleted file mode 100644 index 5c4ca354cc..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/model/WorkType.java +++ /dev/null @@ -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.authority.orcid.model; - -/** - * http://support.orcid.org/knowledgebase/articles/118795 - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public enum WorkType { - - BOOK, - BOOK_CHAPTER, - BOOK_REVIEW, - DICTIONARY_ENTRY, - DISSERTATION, - ENCYCLOPEDIA_ARTICLE, - EDITED_BOOK, - JOURNAL_ARTICLE, - JOURNAL_ISSUE, - MAGAZINE_ARTICLE, - MANUAL, - ONLINE_RESOURCE, - NEWSLETTER_ARTICLE, - NEWSPAPER_ARTICLE, - REPORT, - RESEARCH_TOOL, - SUPERVISED_STUDENT_PUBLICATION, - TEST, - TRANSLATION, - WEBSITE, - CONFERENCE_ABSTRACT, - CONFERENCE_PAPER, - CONFERENCE_POSTER, - DISCLOSURE, - LICENSE, - PATENT, - REGISTERED_COPYRIGHT, - ARTISTIC_PERFORMANCE, - DATA_SET, - INVENTION, - LECTURE_SPEECH, - RESEARCH_TECHNIQUE, - SPIN_OFF_COMPANY, - STANDARDS_AND_POLICY, - TECHNICAL_STANDARD, - OTHER - -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/xml/Converter.java b/dspace-api/src/main/java/org/dspace/authority/orcid/xml/Converter.java index 248720d95f..784a3fdf24 100644 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/xml/Converter.java +++ b/dspace-api/src/main/java/org/dspace/authority/orcid/xml/Converter.java @@ -7,16 +7,23 @@ */ package org.dspace.authority.orcid.xml; +import java.io.InputStream; +import java.net.URISyntaxException; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + import org.apache.log4j.Logger; -import org.w3c.dom.Document; +import org.xml.sax.SAXException; + /** - * + * @param type * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) - * @param type */ public abstract class Converter { @@ -25,11 +32,15 @@ public abstract class Converter { */ private static Logger log = Logger.getLogger(Converter.class); + public abstract T convert(InputStream document); - protected void processError(Document xml) { - String errorMessage = XMLErrors.getErrorMessage(xml); - log.error("The orcid-message reports an error: " + errorMessage); + protected Object unmarshall(InputStream input, Class type) throws SAXException, URISyntaxException { + try { + JAXBContext context = JAXBContext.newInstance(type); + Unmarshaller unmarshaller = context.createUnmarshaller(); + return unmarshaller.unmarshal(input); + } catch (JAXBException e) { + throw new RuntimeException("Unable to unmarshall orcid message" + e); + } } - - public abstract T convert(Document document); } diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLErrors.java b/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLErrors.java deleted file mode 100644 index ddf10ee2a1..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLErrors.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid.xml; - -import org.dspace.authority.util.XMLUtils; -import org.apache.log4j.Logger; -import org.w3c.dom.Document; - -import javax.xml.xpath.XPathExpressionException; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class XMLErrors { - - /** - * log4j logger - */ - private static Logger log = Logger.getLogger(XMLErrors.class); - - private static final String ERROR_DESC = "/orcid-message/error-desc"; - - /** - * Evaluates whether a given xml document contains errors or not. - * - * @param xml The given xml document - * @return true if the given xml document is null - * or if it contains errors - */ - public static boolean check(Document xml) { - - if (xml == null) { - return true; - } - - String textContent = null; - - try { - textContent = XMLUtils.getTextContent(xml, ERROR_DESC); - } catch (XPathExpressionException e) { - log.error("Error while checking for errors in orcid message", e); - } - - return textContent == null; - } - - public static String getErrorMessage(Document xml) { - - if (xml == null) { - return "Did not receive an XML document."; - } - - String textContent = null; - - try { - textContent = XMLUtils.getTextContent(xml, ERROR_DESC); - } catch (XPathExpressionException e) { - log.error("Error while checking for errors in orcid message", e); - } - - return textContent; - } - -} diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLtoBio.java b/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLtoBio.java index affeb18aea..9fb4a50d5f 100644 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLtoBio.java +++ b/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLtoBio.java @@ -7,23 +7,23 @@ */ package org.dspace.authority.orcid.xml; -import org.dspace.authority.orcid.model.Bio; -import org.dspace.authority.orcid.model.BioExternalIdentifier; -import org.dspace.authority.orcid.model.BioName; -import org.dspace.authority.orcid.model.BioResearcherUrl; -import org.dspace.authority.util.XMLUtils; -import org.apache.log4j.Logger; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import javax.xml.xpath.XPathExpressionException; +import java.io.InputStream; +import java.net.URISyntaxException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; +import org.apache.log4j.Logger; +import org.dspace.authority.orcid.Orcidv2; +import org.dspace.utils.DSpace; +import org.orcid.jaxb.model.common_v2.OrcidId; +import org.orcid.jaxb.model.record_v2.Person; +import org.orcid.jaxb.model.search_v2.Result; +import org.orcid.jaxb.model.search_v2.Search; +import org.xml.sax.SAXException; + + + /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -36,218 +36,38 @@ public class XMLtoBio extends Converter { */ private static Logger log = Logger.getLogger(XMLtoBio.class); - /** - * orcid-message XPATHs - */ - - protected String ORCID_BIO = "//orcid-bio"; - -// protected String ORCID = "parent::*/orcid"; - protected String ORCID = "parent::*/orcid-identifier/path"; - - protected String PERSONAL_DETAILS = "personal-details"; - protected String GIVEN_NAMES = PERSONAL_DETAILS + "/given-names"; - protected String FAMILY_NAME = PERSONAL_DETAILS + "/family-name"; - protected String CREDIT_NAME = PERSONAL_DETAILS + "/credit-name"; - protected String OTHER_NAMES = PERSONAL_DETAILS + "/other-names"; - protected String OTHER_NAME = OTHER_NAMES + "/other-name"; - - protected String CONTACT_DETAILS = "contact-details"; - protected String COUNTRY = CONTACT_DETAILS + "/address/country"; - - protected String KEYWORDS = "keywords"; - protected String KEYWORD = KEYWORDS + "/keyword"; - - protected String EXTERNAL_IDENTIFIERS = "external-identifiers"; - protected String EXTERNAL_IDENTIFIER = EXTERNAL_IDENTIFIERS + "/external-identifier"; - protected String EXTERNAL_ID_ORCID = "external-id-orcid"; - protected String EXTERNAL_ID_COMMNON_NAME = "external-id-common-name"; - protected String EXTERNAL_ID_REFERENCE = "external-id-reference"; - protected String EXTERNAL_ID_URL = "external-id-url"; - - protected String RESEARCHER_URLS = "researcher-urls"; - protected String RESEARCHER_URL = "researcher-urls/researcher-url"; - protected String URL_NAME = "url-name"; - protected String URL = "url"; - - protected String BIOGRAPHY = ORCID_BIO + "/biography"; - - protected String AFFILIATIONS = ORCID_BIO + "/affiliation"; - - /** - * Regex - */ - - protected String ORCID_NOT_FOUND = "ORCID [\\d-]* not found"; - - @Override - public List convert(Document xml) { - List result = new ArrayList(); - - if (XMLErrors.check(xml)) { - - try { - Iterator iterator = XMLUtils.getNodeListIterator(xml, ORCID_BIO); - while (iterator.hasNext()) { - Bio bio = convertBio(iterator.next()); - result.add(bio); - } - } catch (XPathExpressionException e) { - log.error("Error in xpath syntax", e); - } - } else { - processError(xml); - } - - return result; - } - - private Bio convertBio(Node node) { - Bio bio = new Bio(); - - setOrcid(node,bio); - setPersonalDetails(node, bio); - setContactDetails(node, bio); - setKeywords(node, bio); - setExternalIdentifiers(node, bio); - setResearcherUrls(node, bio); - setBiography(node, bio); - - return bio; - } - - @Override - protected void processError(Document xml) { - String errorMessage = XMLErrors.getErrorMessage(xml); - - if(errorMessage.matches(ORCID_NOT_FOUND)) - { - // do something? - } - - log.error("The orcid-message reports an error: " + errorMessage); - } - - - private void setOrcid(Node node, Bio bio) { + public List convert(InputStream xml) { + List bios = new ArrayList<>(); try { - String orcid = XMLUtils.getTextContent(node, ORCID); - bio.setOrcid(orcid); - } catch (XPathExpressionException e) { - log.debug("Error in finding the biography in bio xml.", e); - } - } + Orcidv2 connector = new DSpace().getServiceManager().getServiceByName("AuthoritySource", Orcidv2.class); - protected void setBiography(Node xml, Bio bio) { - try { - String biography = XMLUtils.getTextContent(xml, BIOGRAPHY); - bio.setBiography(biography); - } catch (XPathExpressionException e) { - log.error("Error in finding the biography in bio xml.", e); - } - } - - protected void setResearcherUrls(Node xml, Bio bio) { - try { - NodeList researcher_urls = XMLUtils.getNodeList(xml, RESEARCHER_URL); - if (researcher_urls != null) { - for (int i = 0; i < researcher_urls.getLength(); i++) { - Node researcher_url = researcher_urls.item(i); - if (researcher_url.getNodeType() != Node.TEXT_NODE) { - String url_name = XMLUtils.getTextContent(researcher_url, URL_NAME); - String url = XMLUtils.getTextContent(researcher_url, URL); - BioResearcherUrl researcherUrl = new BioResearcherUrl(url_name, url); - bio.addResearcherUrl(researcherUrl); + Search search = (Search) unmarshall(xml, Search.class); + for (Result result : search.getResult()) { + OrcidId orcidIdentifier = result.getOrcidIdentifier(); + if (orcidIdentifier != null) { + log.debug("Found OrcidId=" + orcidIdentifier.toString()); + String orcid = orcidIdentifier.getUriPath(); + Person bio = connector.getBio(orcid); + if (bio != null) { + bios.add(bio); } } } - } catch (XPathExpressionException e) { - log.error("Error in finding the researcher url in bio xml.", e); + } catch (SAXException | URISyntaxException e) { + log.error(e); } + return bios; } - protected void setExternalIdentifiers(Node xml, Bio bio) { + public Person convertSinglePerson(InputStream xml) { + Person person = null; try { - - Iterator iterator = XMLUtils.getNodeListIterator(xml, EXTERNAL_IDENTIFIER); - while (iterator.hasNext()) { - Node external_identifier = iterator.next(); - String id_orcid = XMLUtils.getTextContent(external_identifier, EXTERNAL_ID_ORCID); - String id_common_name = XMLUtils.getTextContent(external_identifier, EXTERNAL_ID_COMMNON_NAME); - String id_reference = XMLUtils.getTextContent(external_identifier, EXTERNAL_ID_REFERENCE); - String id_url = XMLUtils.getTextContent(external_identifier, EXTERNAL_ID_URL); - BioExternalIdentifier externalIdentifier = new BioExternalIdentifier(id_orcid, id_common_name, id_reference, id_url); - bio.addExternalIdentifier(externalIdentifier); - } - - } catch (XPathExpressionException e) { - log.error("Error in finding the external identifier in bio xml.", e); + person = (Person) unmarshall(xml, Person.class); + return person; + } catch (SAXException | URISyntaxException e) { + log.error(e); } + return null; } - - protected void setKeywords(Node xml, Bio bio) { - try { - NodeList keywords = XMLUtils.getNodeList(xml, KEYWORD); - if (keywords != null) { - for (int i = 0; i < keywords.getLength(); i++) { - String keyword = keywords.item(i).getTextContent(); - String[] split = keyword.split(","); - for (String k : split) { - bio.addKeyword(k.trim()); - } - } - } - } catch (XPathExpressionException e) { - log.error("Error in finding the keywords in bio xml.", e); - } - } - - protected void setContactDetails(Node xml, Bio bio) { - try { - String country = XMLUtils.getTextContent(xml, COUNTRY); - bio.setCountry(country); - } catch (XPathExpressionException e) { - log.error("Error in finding the country in bio xml.", e); - } - } - - protected void setPersonalDetails(Node xml, Bio bio) { - BioName name = bio.getName(); - - try { - String givenNames = XMLUtils.getTextContent(xml, GIVEN_NAMES); - name.setGivenNames(givenNames); - } catch (XPathExpressionException e) { - log.error("Error in finding the given names in bio xml.", e); - } - - try { - String familyName = XMLUtils.getTextContent(xml, FAMILY_NAME); - name.setFamilyName(familyName); - } catch (XPathExpressionException e) { - log.error("Error in finding the family name in bio xml.", e); - } - - try { - String creditName = XMLUtils.getTextContent(xml, CREDIT_NAME); - name.setCreditName(creditName); - } catch (XPathExpressionException e) { - log.error("Error in finding the credit name in bio xml.", e); - } - - try { - - Iterator iterator = XMLUtils.getNodeListIterator(xml, OTHER_NAME); - while (iterator.hasNext()) { - Node otherName = iterator.next(); - String textContent = otherName.getTextContent(); - name.getOtherNames().add(textContent.trim()); - } - - } catch (XPathExpressionException e) { - log.error("Error in finding the other names in bio xml.", e); - } - } - } diff --git a/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLtoWork.java b/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLtoWork.java deleted file mode 100644 index 3ca599130f..0000000000 --- a/dspace-api/src/main/java/org/dspace/authority/orcid/xml/XMLtoWork.java +++ /dev/null @@ -1,240 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.authority.orcid.xml; - -import org.dspace.authority.orcid.model.*; -import org.dspace.authority.util.*; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import javax.xml.xpath.XPathExpressionException; -import java.util.*; - -/** - * - * @author Antoine Snyers (antoine at atmire.com) - * @author Kevin Van de Velde (kevin at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - */ -public class XMLtoWork extends Converter { - - /** - * log4j logger - */ - private static Logger log = Logger.getLogger(XMLtoWork.class); - - /** - * orcid-message XPATHs - */ - - protected String ORCID_WORKS = "//orcid-works"; - protected String ORCID_WORK = ORCID_WORKS + "/orcid-work"; - - protected String WORK_TITLE = "work-title"; - protected String TITLE = WORK_TITLE + "/title"; - protected String SUBTITLE = WORK_TITLE + "/subtitle"; - protected String TRANSLATED_TITLES = WORK_TITLE + "/translated-title"; - protected String TRANSLATED_TITLES_LANGUAGE = "@language-code"; - - protected String SHORT_DESCRIPTION = "short-description"; - - protected String WORK_CITATION = "work-citation"; - protected String CITATION_TYPE = WORK_CITATION + "/work-citation-type"; - protected String CITATION = WORK_CITATION + "/citation"; - - protected String WORK_TYPE = "work-type"; - - protected String PUBLICATION_DATE = "publication-date"; - protected String YEAR = PUBLICATION_DATE + "/year"; - protected String MONTH = PUBLICATION_DATE + "/month"; - protected String DAY = PUBLICATION_DATE + "/day"; - - protected String WORK_EXTERNAL_IDENTIFIERS = "work-external-identifiers"; - protected String WORK_EXTERNAL_IDENTIFIER = WORK_EXTERNAL_IDENTIFIERS + "/work-external-identifier"; - protected String WORK_EXTERNAL_IDENTIFIER_TYPE = "work-external-identifier-type"; - protected String WORK_EXTERNAL_IDENTIFIER_ID = "work-external-identifier-id"; - - protected String URL = "url"; - - protected String WORK_CONTRIBUTOR = "work-contributors"; - protected String CONTRIBUTOR = WORK_CONTRIBUTOR+"/contributor"; - protected String CONTRIBUTOR_ORCID = "contributor-orcid"; - protected String CREDIT_NAME = "credit-name"; - protected String CONTRIBUTOR_EMAIL = "contributor-email"; - protected String CONTRIBUTOR_ATTRIBUTES = "contributor-attributes"; - protected String CONTRIBUTOR_SEQUENCE = "contributor-sequence"; - protected String CONTRIBUTOR_ROLE = "contributor-role"; - - protected String WORK_SOURCE = "work-source"; - - - @Override - public List convert(Document document) { - List result = new ArrayList(); - - if (XMLErrors.check(document)) { - - try { - Iterator iterator = XMLUtils.getNodeListIterator(document, ORCID_WORK); - while (iterator.hasNext()) { - Work work = convertWork(iterator.next()); - result.add(work); - } - } catch (XPathExpressionException e) { - log.error("Error in xpath syntax", e); - } - } else { - processError(document); - } - - return result; - } - - protected Work convertWork(Node node) throws XPathExpressionException { - Work work = new Work(); - setTitle(node, work); - setDescription(node, work); - setCitation(node, work); - setWorkType(node, work); - setPublicationDate(node, work); - setExternalIdentifiers(node, work); - setUrl(node, work); - setContributors(node, work); - setWorkSource(node, work); - - return work; - } - - protected void setWorkSource(Node node, Work work) throws XPathExpressionException { - String workSource = XMLUtils.getTextContent(node, WORK_SOURCE); - work.setWorkSource(workSource); - } - - protected void setContributors(Node node, Work work) throws XPathExpressionException { - - Set contributors = new HashSet(); - - Iterator iterator = XMLUtils.getNodeListIterator(node, CONTRIBUTOR); - while (iterator.hasNext()) { - Node nextContributorNode = iterator.next(); - String orcid = XMLUtils.getTextContent(nextContributorNode, CONTRIBUTOR_ORCID); - String creditName = XMLUtils.getTextContent(nextContributorNode, CREDIT_NAME); - String email = XMLUtils.getTextContent(nextContributorNode, CONTRIBUTOR_EMAIL); - - Set contributorAttributes = new HashSet(); - NodeList attributeNodes = XMLUtils.getNodeList(nextContributorNode, CONTRIBUTOR_ATTRIBUTES); - Iterator attributesIterator = XMLUtils.getNodeListIterator(attributeNodes); - while (attributesIterator.hasNext()) { - Node nextAttribute = attributesIterator.next(); - - String roleText = XMLUtils.getTextContent(nextAttribute, CONTRIBUTOR_ROLE); - ContributorAttributeRole role = EnumUtils.lookup(ContributorAttributeRole.class, roleText); - - String sequenceText = XMLUtils.getTextContent(nextAttribute, CONTRIBUTOR_SEQUENCE); - ContributorAttributeSequence sequence = EnumUtils.lookup(ContributorAttributeSequence.class, sequenceText); - - ContributorAttribute attribute = new ContributorAttribute(role, sequence); - contributorAttributes.add(attribute); - } - - Contributor contributor = new Contributor(orcid, creditName, email, contributorAttributes); - contributors.add(contributor); - } - - work.setContributors(contributors); - } - - protected void setUrl(Node node, Work work) throws XPathExpressionException { - String url = XMLUtils.getTextContent(node, URL); - work.setUrl(url); - } - - protected void setExternalIdentifiers(Node node, Work work) throws XPathExpressionException { - - Iterator iterator = XMLUtils.getNodeListIterator(node, WORK_EXTERNAL_IDENTIFIER); - while (iterator.hasNext()) { - Node work_external_identifier = iterator.next(); - String typeText = XMLUtils.getTextContent(work_external_identifier, WORK_EXTERNAL_IDENTIFIER_TYPE); - - WorkExternalIdentifierType type = EnumUtils.lookup(WorkExternalIdentifierType.class, typeText); - - String id = XMLUtils.getTextContent(work_external_identifier, WORK_EXTERNAL_IDENTIFIER_ID); - - WorkExternalIdentifier externalID = new WorkExternalIdentifier(type, id); - work.setWorkExternalIdentifier(externalID); - } - } - - protected void setPublicationDate(Node node, Work work) throws XPathExpressionException { - - String year = XMLUtils.getTextContent(node, YEAR); - String month = XMLUtils.getTextContent(node, MONTH); - String day = XMLUtils.getTextContent(node, DAY); - - String publicationDate = year; - if (StringUtils.isNotBlank(month)) { - publicationDate += "-" + month; - if (StringUtils.isNotBlank(day)) { - publicationDate += "-" + day; - } - } - - work.setPublicationDate(publicationDate); - } - - protected void setWorkType(Node node, Work work) throws XPathExpressionException { - - String workTypeText = XMLUtils.getTextContent(node, WORK_TYPE); - WorkType workType = EnumUtils.lookup(WorkType.class, workTypeText); - - work.setWorkType(workType); - } - - protected void setCitation(Node node, Work work) throws XPathExpressionException { - - String typeText = XMLUtils.getTextContent(node, CITATION_TYPE); - CitationType type = EnumUtils.lookup(CitationType.class, typeText); - - String citationtext = XMLUtils.getTextContent(node, CITATION); - - Citation citation = new Citation(type, citationtext); - work.setCitation(citation); - } - - protected void setDescription(Node node, Work work) throws XPathExpressionException { - - String description = null; - description = XMLUtils.getTextContent(node, SHORT_DESCRIPTION); - work.setDescription(description); - } - - protected void setTitle(Node node, Work work) throws XPathExpressionException { - - String title = XMLUtils.getTextContent(node, TITLE); - - String subtitle = XMLUtils.getTextContent(node, SUBTITLE); - - Map translatedTitles = new HashMap(); - NodeList nodeList = XMLUtils.getNodeList(node, TRANSLATED_TITLES); - Iterator iterator = XMLUtils.getNodeListIterator(nodeList); - while (iterator.hasNext()) { - Node languageNode = iterator.next(); - String language = XMLUtils.getTextContent(languageNode, TRANSLATED_TITLES_LANGUAGE); - String translated_title = XMLUtils.getTextContent(languageNode, "."); - translatedTitles.put(language, translated_title); - } - - WorkTitle workTitle = new WorkTitle(title, subtitle, translatedTitles); - work.setWorkTitle(workTitle); - } - -} diff --git a/dspace-api/src/main/java/org/dspace/authority/rest/RESTConnector.java b/dspace-api/src/main/java/org/dspace/authority/rest/RESTConnector.java index 7a5adf157e..cfa21a66cb 100644 --- a/dspace-api/src/main/java/org/dspace/authority/rest/RESTConnector.java +++ b/dspace-api/src/main/java/org/dspace/authority/rest/RESTConnector.java @@ -7,19 +7,17 @@ */ package org.dspace.authority.rest; -import org.apache.http.impl.client.HttpClientBuilder; -import org.dspace.authority.util.XMLUtils; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.log4j.Logger; -import org.w3c.dom.Document; - import java.io.InputStream; import java.util.Scanner; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.log4j.Logger; + /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -38,30 +36,30 @@ public class RESTConnector { this.url = url; } - public Document get(String path) { - Document document = null; - + public InputStream get(String path, String accessToken) { InputStream result = null; path = trimSlashes(path); String fullPath = url + '/' + path; HttpGet httpGet = new HttpGet(fullPath); + if (StringUtils.isNotBlank(accessToken)) { + httpGet.addHeader("Content-Type", "application/vnd.orcid+xml"); + httpGet.addHeader("Authorization","Bearer " + accessToken); + } try { HttpClient httpClient = HttpClientBuilder.create().build(); HttpResponse getResponse = httpClient.execute(httpGet); //do not close this httpClient result = getResponse.getEntity().getContent(); - document = XMLUtils.convertStreamToXML(result); - } catch (Exception e) { getGotError(e, fullPath); } - return document; + return result; } protected void getGotError(Exception e, String fullPath) { - log.error("Error in rest connector for path: "+fullPath, e); + log.error("Error in rest connector for path: " + fullPath, e); } public static String trimSlashes(String path) { diff --git a/dspace-api/src/main/java/org/dspace/authority/rest/RestSource.java b/dspace-api/src/main/java/org/dspace/authority/rest/RestSource.java index 2278ac24b4..ce38cc99dc 100644 --- a/dspace-api/src/main/java/org/dspace/authority/rest/RestSource.java +++ b/dspace-api/src/main/java/org/dspace/authority/rest/RestSource.java @@ -7,26 +7,19 @@ */ package org.dspace.authority.rest; -import org.dspace.authority.AuthorityValue; - -import java.util.List; +import org.dspace.authority.SolrAuthorityInterface; /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public abstract class RestSource { +public abstract class RestSource implements SolrAuthorityInterface { protected RESTConnector restConnector; public RestSource(String url) { this.restConnector = new RESTConnector(url); } - - public abstract List queryAuthorities(String text, int max); - - public abstract AuthorityValue queryAuthorityID(String id); } diff --git a/dspace-api/src/main/java/org/dspace/authority/service/AuthorityService.java b/dspace-api/src/main/java/org/dspace/authority/service/AuthorityService.java index a2031308f9..42cbe2d686 100644 --- a/dspace-api/src/main/java/org/dspace/authority/service/AuthorityService.java +++ b/dspace-api/src/main/java/org/dspace/authority/service/AuthorityService.java @@ -7,15 +7,16 @@ */ package org.dspace.authority.service; +import java.sql.SQLException; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; import org.dspace.core.Context; -import java.sql.SQLException; - /** * Service interface class for the Metadata Authority - * The implementation of this class is responsible for all business logic calls for the Metadata Authority and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Metadata Authority and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/authority/service/AuthorityValueService.java b/dspace-api/src/main/java/org/dspace/authority/service/AuthorityValueService.java index c61ba819fd..fd00f51109 100644 --- a/dspace-api/src/main/java/org/dspace/authority/service/AuthorityValueService.java +++ b/dspace-api/src/main/java/org/dspace/authority/service/AuthorityValueService.java @@ -7,12 +7,12 @@ */ package org.dspace.authority.service; +import java.util.List; + import org.apache.solr.common.SolrDocument; import org.dspace.authority.AuthorityValue; import org.dspace.core.Context; -import java.util.List; - /** * This service contains all methods for using authority values * @@ -21,8 +21,7 @@ import java.util.List; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public interface AuthorityValueService -{ +public interface AuthorityValueService { public static final String SPLIT = "::"; public static final String GENERATE = "will be generated" + SPLIT; @@ -36,13 +35,16 @@ public interface AuthorityValueService public AuthorityValue findByOrcidID(Context context, String orcid_id); - public List findByName(Context context, String schema, String element, String qualifier, String name); + public List findByName(Context context, String schema, String element, String qualifier, + String name); - public List findByAuthorityMetadata(Context context, String schema, String element, String qualifier, String value); + public List findByAuthorityMetadata(Context context, String schema, String element, + String qualifier, String value); public List findByExactValue(Context context, String field, String value); - public List findByValue(Context context, String schema, String element, String qualifier, String value); + public List findByValue(Context context, String schema, String element, String qualifier, + String value); public List findOrcidHolders(Context context); diff --git a/dspace-api/src/main/java/org/dspace/authority/util/EnumUtils.java b/dspace-api/src/main/java/org/dspace/authority/util/EnumUtils.java index ad58f749ab..72dc41d6b9 100644 --- a/dspace-api/src/main/java/org/dspace/authority/util/EnumUtils.java +++ b/dspace-api/src/main/java/org/dspace/authority/util/EnumUtils.java @@ -11,7 +11,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -24,17 +23,22 @@ public class EnumUtils { */ private static Logger log = Logger.getLogger(EnumUtils.class); + /** + * Default constructor + */ + private EnumUtils() { } + private static String getEnumName(String value) { return StringUtils.isNotBlank(value) ? - value.toUpperCase().trim().replaceAll("[^a-zA-Z]", "_") - : null; + value.toUpperCase().trim().replaceAll("[^a-zA-Z]", "_") + : null; } public static > E lookup(Class enumClass, String enumName) { try { return Enum.valueOf(enumClass, getEnumName(enumName)); } catch (Exception ex) { - log.warn("Did not find an "+enumClass.getSimpleName()+" for value '"+enumName+"'"); + log.warn("Did not find an " + enumClass.getSimpleName() + " for value '" + enumName + "'"); return null; } } diff --git a/dspace-api/src/main/java/org/dspace/authority/util/XMLUtils.java b/dspace-api/src/main/java/org/dspace/authority/util/XMLUtils.java index 9a2861293d..5249f599e3 100644 --- a/dspace-api/src/main/java/org/dspace/authority/util/XMLUtils.java +++ b/dspace-api/src/main/java/org/dspace/authority/util/XMLUtils.java @@ -7,6 +7,16 @@ */ package org.dspace.authority.util; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathExpressionException; + import org.apache.log4j.Logger; import org.apache.xpath.XPathAPI; import org.w3c.dom.Document; @@ -15,18 +25,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.xpath.XPathExpressionException; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Iterator; - /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -40,7 +39,12 @@ public class XMLUtils { private static Logger log = Logger.getLogger(XMLUtils.class); /** - * @param xml The starting context (a Node or a Document, for example). + * Default constructor + */ + private XMLUtils() { } + + /** + * @param xml The starting context (a Node or a Document, for example). * @param singleNodeXPath xpath * @return node.getTextContent() on the node that matches singleNodeXPath * null if nothing matches the NodeListXPath @@ -57,7 +61,7 @@ public class XMLUtils { } /** - * @param xml The starting context (a Node or a Document, for example). + * @param xml The starting context (a Node or a Document, for example). * @param NodeListXPath xpath * @return A Node matches the NodeListXPath * null if nothing matches the NodeListXPath @@ -74,7 +78,7 @@ public class XMLUtils { } /** - * @param xml The starting context (a Node or a Document, for example). + * @param xml The starting context (a Node or a Document, for example). * @param NodeListXPath xpath * @return A NodeList containing the nodes that match the NodeListXPath * null if nothing matches the NodeListXPath @@ -99,6 +103,7 @@ public class XMLUtils { * that are element nodes: * node.getNodeType() == Node.ELEMENT_NODE * node instanceof Element + * * @param nodeList NodeList * @return iterator over nodes */ diff --git a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeConfiguration.java b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeConfiguration.java index 6282a97c9d..231008d267 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeConfiguration.java @@ -12,481 +12,484 @@ import org.dspace.core.ConfigurationManager; /** * This class is responsible to provide access to the configuration of the * Authorization System - * + * * @author bollini - * */ -public class AuthorizeConfiguration -{ +public class AuthorizeConfiguration { private static boolean can_communityAdmin_group = ConfigurationManager - .getBooleanProperty("core.authorization.community-admin.group", - true); + .getBooleanProperty("core.authorization.community-admin.group", + true); // subcommunities and collections private static boolean can_communityAdmin_createSubelement = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.create-subelement", - true); + .getBooleanProperty( + "core.authorization.community-admin.create-subelement", + true); private static boolean can_communityAdmin_deleteSubelement = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.delete-subelement", - true); + .getBooleanProperty( + "core.authorization.community-admin.delete-subelement", + true); private static boolean can_communityAdmin_policies = ConfigurationManager - .getBooleanProperty("core.authorization.community-admin.policies", - true); + .getBooleanProperty("core.authorization.community-admin.policies", + true); private static boolean can_communityAdmin_adminGroup = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.admin-group", true); + .getBooleanProperty( + "core.authorization.community-admin.admin-group", true); private static boolean can_communityAdmin_collectionPolicies = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.collection.policies", - true); + .getBooleanProperty( + "core.authorization.community-admin.collection.policies", + true); private static boolean can_communityAdmin_collectionTemplateItem = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.collection.template-item", - true); + .getBooleanProperty( + "core.authorization.community-admin.collection.template-item", + true); private static boolean can_communityAdmin_collectionSubmitters = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.collection.submitters", - true); + .getBooleanProperty( + "core.authorization.community-admin.collection.submitters", + true); private static boolean can_communityAdmin_collectionWorkflows = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.collection.workflows", - true); + .getBooleanProperty( + "core.authorization.community-admin.collection.workflows", + true); private static boolean can_communityAdmin_collectionAdminGroup = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.collection.admin-group", - true); + .getBooleanProperty( + "core.authorization.community-admin.collection.admin-group", + true); private static boolean can_communityAdmin_itemDelete = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.item.delete", true); + .getBooleanProperty( + "core.authorization.community-admin.item.delete", true); private static boolean can_communityAdmin_itemWithdraw = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.item.withdraw", true); + .getBooleanProperty( + "core.authorization.community-admin.item.withdraw", true); private static boolean can_communityAdmin_itemReinstatiate = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.item.reinstatiate", - true); + .getBooleanProperty( + "core.authorization.community-admin.item.reinstatiate", + true); private static boolean can_communityAdmin_itemPolicies = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.item.policies", true); + .getBooleanProperty( + "core.authorization.community-admin.item.policies", true); // # also bundle private static boolean can_communityAdmin_itemCreateBitstream = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.item.create-bitstream", - true); + .getBooleanProperty( + "core.authorization.community-admin.item.create-bitstream", + true); private static boolean can_communityAdmin_itemDeleteBitstream = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.item.delete-bitstream", - true); + .getBooleanProperty( + "core.authorization.community-admin.item.delete-bitstream", + true); private static boolean can_communityAdmin_itemAdminccLicense = ConfigurationManager - .getBooleanProperty( - "core.authorization.community-admin.item-admin.cc-license", - true); + .getBooleanProperty( + "core.authorization.community-admin.item-admin.cc-license", + true); // # COLLECTION ADMIN private static boolean can_collectionAdmin_policies = ConfigurationManager - .getBooleanProperty("core.authorization.collection-admin.policies", - true); + .getBooleanProperty("core.authorization.collection-admin.policies", + true); private static boolean can_collectionAdmin_templateItem = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.template-item", true); + .getBooleanProperty( + "core.authorization.collection-admin.template-item", true); private static boolean can_collectionAdmin_submitters = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.submitters", true); + .getBooleanProperty( + "core.authorization.collection-admin.submitters", true); private static boolean can_collectionAdmin_workflows = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.workflows", true); + .getBooleanProperty( + "core.authorization.collection-admin.workflows", true); private static boolean can_collectionAdmin_adminGroup = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.admin-group", true); + .getBooleanProperty( + "core.authorization.collection-admin.admin-group", true); private static boolean can_collectionAdmin_itemDelete = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.item.delete", true); + .getBooleanProperty( + "core.authorization.collection-admin.item.delete", true); private static boolean can_collectionAdmin_itemWithdraw = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.item.withdraw", true); + .getBooleanProperty( + "core.authorization.collection-admin.item.withdraw", true); private static boolean can_collectionAdmin_itemReinstatiate = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.item.reinstatiate", - true); + .getBooleanProperty( + "core.authorization.collection-admin.item.reinstatiate", + true); private static boolean can_collectionAdmin_itemPolicies = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.item.policies", true); + .getBooleanProperty( + "core.authorization.collection-admin.item.policies", true); // # also bundle private static boolean can_collectionAdmin_itemCreateBitstream = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.item.create-bitstream", - true); + .getBooleanProperty( + "core.authorization.collection-admin.item.create-bitstream", + true); private static boolean can_collectionAdmin_itemDeleteBitstream = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.item.delete-bitstream", - true); + .getBooleanProperty( + "core.authorization.collection-admin.item.delete-bitstream", + true); private static boolean can_collectionAdmin_itemAdminccLicense = ConfigurationManager - .getBooleanProperty( - "core.authorization.collection-admin.item-admin.cc-license", - true); + .getBooleanProperty( + "core.authorization.collection-admin.item-admin.cc-license", + true); // # ITEM ADMIN private static boolean can_itemAdmin_policies = ConfigurationManager - .getBooleanProperty("core.authorization.item-admin.policies", true); + .getBooleanProperty("core.authorization.item-admin.policies", true); // # also bundle private static boolean can_itemAdmin_createBitstream = ConfigurationManager - .getBooleanProperty( - "core.authorization.item-admin.create-bitstream", true); + .getBooleanProperty( + "core.authorization.item-admin.create-bitstream", true); private static boolean can_itemAdmin_deleteBitstream = ConfigurationManager - .getBooleanProperty( - "core.authorization.item-admin.delete-bitstream", true); + .getBooleanProperty( + "core.authorization.item-admin.delete-bitstream", true); private static boolean can_itemAdmin_ccLicense = ConfigurationManager - .getBooleanProperty("core.authorization.item-admin.cc-license", - true); + .getBooleanProperty("core.authorization.item-admin.cc-license", + true); + + /** + * Default constructor + */ + private AuthorizeConfiguration() { } /** * Are community admins allowed to create new, not strictly community * related, group? + * * @return true/false */ - public static boolean canCommunityAdminPerformGroupCreation() - { + public static boolean canCommunityAdminPerformGroupCreation() { return can_communityAdmin_group; } /** * Are community admins allowed to create collections or subcommunities? + * * @return true/false */ - public static boolean canCommunityAdminPerformSubelementCreation() - { + public static boolean canCommunityAdminPerformSubelementCreation() { return can_communityAdmin_createSubelement; } /** * Are community admins allowed to remove collections or subcommunities? + * * @return true/false */ - public static boolean canCommunityAdminPerformSubelementDeletion() - { + public static boolean canCommunityAdminPerformSubelementDeletion() { return can_communityAdmin_deleteSubelement; } /** * Are community admins allowed to manage the community's and * subcommunities' policies? + * * @return true/false */ - public static boolean canCommunityAdminManagePolicies() - { + public static boolean canCommunityAdminManagePolicies() { return can_communityAdmin_policies; } /** * Are community admins allowed to create/edit them community's and * subcommunities' admin groups? + * * @return true/false */ - public static boolean canCommunityAdminManageAdminGroup() - { + public static boolean canCommunityAdminManageAdminGroup() { return can_communityAdmin_adminGroup; } /** * Are community admins allowed to create/edit the community's and * subcommunities' admin group? + * * @return true/false */ - public static boolean canCommunityAdminManageCollectionPolicies() - { + public static boolean canCommunityAdminManageCollectionPolicies() { return can_communityAdmin_collectionPolicies; } /** * Are community admins allowed to manage the item template of them * collections? + * * @return true/false */ - public static boolean canCommunityAdminManageCollectionTemplateItem() - { + public static boolean canCommunityAdminManageCollectionTemplateItem() { return can_communityAdmin_collectionTemplateItem; } /** * Are community admins allowed to manage (create/edit/remove) the * submitters group of them collections? + * * @return true/false */ - public static boolean canCommunityAdminManageCollectionSubmitters() - { + public static boolean canCommunityAdminManageCollectionSubmitters() { return can_communityAdmin_collectionSubmitters; } /** * Are community admins allowed to manage (create/edit/remove) the workflows * group of them collections? + * * @return true/false */ - public static boolean canCommunityAdminManageCollectionWorkflows() - { + public static boolean canCommunityAdminManageCollectionWorkflows() { return can_communityAdmin_collectionWorkflows; } /** * Are community admins allowed to manage (create/edit/remove) the admin * group of them collections? + * * @return true/false */ - public static boolean canCommunityAdminManageCollectionAdminGroup() - { + public static boolean canCommunityAdminManageCollectionAdminGroup() { return can_communityAdmin_collectionAdminGroup; } /** * Are community admins allowed to remove an item from them collections? + * * @return true/false */ - public static boolean canCommunityAdminPerformItemDeletion() - { + public static boolean canCommunityAdminPerformItemDeletion() { return can_communityAdmin_itemDelete; } /** * Are community admins allowed to withdrawn an item from them collections? + * * @return true/false */ - public static boolean canCommunityAdminPerformItemWithdrawn() - { + public static boolean canCommunityAdminPerformItemWithdrawn() { return can_communityAdmin_itemWithdraw; } /** * Are community admins allowed to reinstate an item from them * collections? + * * @return true/false */ - public static boolean canCommunityAdminPerformItemReinstatiate() - { + public static boolean canCommunityAdminPerformItemReinstatiate() { return can_communityAdmin_itemReinstatiate; } /** * Are community admins allowed to manage the policies of an item owned by * one of them collections? + * * @return true/false */ - public static boolean canCommunityAdminManageItemPolicies() - { + public static boolean canCommunityAdminManageItemPolicies() { return can_communityAdmin_itemPolicies; } /** * Are community admins allowed to add a bitstream to an item owned by one * of them collections? + * * @return true/false */ - public static boolean canCommunityAdminPerformBitstreamCreation() - { + public static boolean canCommunityAdminPerformBitstreamCreation() { return can_communityAdmin_itemCreateBitstream; } /** * Are community admins allowed to remove a bitstream from an item owned by * one of them collections? + * * @return true/false */ - public static boolean canCommunityAdminPerformBitstreamDeletion() - { + public static boolean canCommunityAdminPerformBitstreamDeletion() { return can_communityAdmin_itemDeleteBitstream; } /** * Are community admins allowed to perform CC License replace or addition to * an item owned by one of them collections? + * * @return true/false */ - public static boolean canCommunityAdminManageCCLicense() - { + public static boolean canCommunityAdminManageCCLicense() { return can_communityAdmin_itemAdminccLicense; } /** * Are collection admins allowed to manage the collection's policies? + * * @return true/false */ - public static boolean canCollectionAdminManagePolicies() - { + public static boolean canCollectionAdminManagePolicies() { return can_collectionAdmin_policies; } /** * Are collection admins allowed to manage (create/edit/delete) the * collection's item template? + * * @return true/false */ - public static boolean canCollectionAdminManageTemplateItem() - { + public static boolean canCollectionAdminManageTemplateItem() { return can_collectionAdmin_templateItem; } /** * Are collection admins allowed to manage (create/edit/delete) the * collection's submitters group? + * * @return true/false */ - public static boolean canCollectionAdminManageSubmitters() - { + public static boolean canCollectionAdminManageSubmitters() { return can_collectionAdmin_submitters; } /** * Are collection admins allowed to manage (create/edit/delete) the * collection's workflows group? + * * @return true/false */ - public static boolean canCollectionAdminManageWorkflows() - { + public static boolean canCollectionAdminManageWorkflows() { return can_collectionAdmin_workflows; } /** * Are collection admins allowed to manage (create/edit) the collection's * admins group? + * * @return true/false */ - public static boolean canCollectionAdminManageAdminGroup() - { + public static boolean canCollectionAdminManageAdminGroup() { return can_collectionAdmin_adminGroup; } /** * Are collection admins allowed to remove an item from the collection? + * * @return true/false */ - public static boolean canCollectionAdminPerformItemDeletion() - { + public static boolean canCollectionAdminPerformItemDeletion() { return can_collectionAdmin_itemDelete; } /** * Are collection admins allowed to withdrawn an item from the collection? + * * @return true/false */ - public static boolean canCollectionAdminPerformItemWithdrawn() - { + public static boolean canCollectionAdminPerformItemWithdrawn() { return can_collectionAdmin_itemWithdraw; } /** * Are collection admins allowed to reinstate an item from the * collection? + * * @return true/false */ - public static boolean canCollectionAdminPerformItemReinstatiate() - { + public static boolean canCollectionAdminPerformItemReinstatiate() { return can_collectionAdmin_itemReinstatiate; } /** * Are collection admins allowed to manage the policies of item owned by the * collection? + * * @return true/false */ - public static boolean canCollectionAdminManageItemPolicies() - { + public static boolean canCollectionAdminManageItemPolicies() { return can_collectionAdmin_itemPolicies; } /** * Are collection admins allowed to add a bitstream to an item owned by the * collections? + * * @return true/false */ - public static boolean canCollectionAdminPerformBitstreamCreation() - { + public static boolean canCollectionAdminPerformBitstreamCreation() { return can_collectionAdmin_itemCreateBitstream; } /** * Are collection admins allowed to remove a bitstream from an item owned by * the collections? + * * @return true/false */ - public static boolean canCollectionAdminPerformBitstreamDeletion() - { + public static boolean canCollectionAdminPerformBitstreamDeletion() { return can_collectionAdmin_itemDeleteBitstream; } /** * Are collection admins allowed to replace or adding a CC License to an * item owned by the collections? + * * @return true/false */ - public static boolean canCollectionAdminManageCCLicense() - { + public static boolean canCollectionAdminManageCCLicense() { return can_collectionAdmin_itemAdminccLicense; } /** * Are item admins allowed to manage the item's policies? + * * @return true/false */ - public static boolean canItemAdminManagePolicies() - { + public static boolean canItemAdminManagePolicies() { return can_itemAdmin_policies; } /** * Are item admins allowed to add bitstreams to the item? + * * @return true/false */ - public static boolean canItemAdminPerformBitstreamCreation() - { + public static boolean canItemAdminPerformBitstreamCreation() { return can_itemAdmin_createBitstream; } /** * Are item admins allowed to remove bitstreams from the item? + * * @return true/false */ - public static boolean canItemAdminPerformBitstreamDeletion() - { + public static boolean canItemAdminPerformBitstreamDeletion() { return can_itemAdmin_deleteBitstream; } /** * Are item admins allowed to replace or adding CC License to the item? + * * @return true/false */ - public static boolean canItemAdminManageCCLicense() - { + public static boolean canItemAdminManageCCLicense() { return can_itemAdmin_ccLicense; } diff --git a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeException.java b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeException.java index 66e439688c..6063f6a78d 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeException.java +++ b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeException.java @@ -12,12 +12,11 @@ import org.dspace.content.DSpaceObject; /** * Exception indicating the current user of the context does not have permission * to perform a particular action. - * + * * @author David Stuve * @version $Revision$ */ -public class AuthorizeException extends Exception -{ +public class AuthorizeException extends Exception { private int myaction; // action attempted, or -1 private DSpaceObject myobject; // object action attempted on or null @@ -25,8 +24,7 @@ public class AuthorizeException extends Exception /** * Create an empty authorize exception */ - public AuthorizeException() - { + public AuthorizeException() { super(); myaction = -1; @@ -35,20 +33,17 @@ public class AuthorizeException extends Exception /** * create an exception with only a message - * - * @param message - * Exception message + * + * @param message Exception message */ - public AuthorizeException(String message) - { + public AuthorizeException(String message) { super(message); myaction = -1; myobject = null; } - public AuthorizeException(Throwable throwable) - { + public AuthorizeException(Throwable throwable) { super(throwable); myaction = -1; @@ -57,27 +52,23 @@ public class AuthorizeException extends Exception /** * Create an authorize exception with a message - * - * @param message - * the message - * @param o object - * @param a actionID + * + * @param message the message + * @param o object + * @param a actionID */ - public AuthorizeException(String message, DSpaceObject o, int a) - { + public AuthorizeException(String message, DSpaceObject o, int a) { super(message); myobject = o; myaction = a; } - public int getAction() - { + public int getAction() { return myaction; } - public DSpaceObject getObject() - { + public DSpaceObject getObject() { return myobject; } } diff --git a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java index d551b23795..8eca4ccf52 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java @@ -7,12 +7,24 @@ */ package org.dspace.authorize; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.ResourcePolicyService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; 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.BitstreamService; import org.dspace.content.service.WorkspaceItemService; @@ -24,9 +36,6 @@ import org.dspace.eperson.service.GroupService; import org.dspace.workflow.WorkflowItemService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.*; - /** * AuthorizeManager handles all authorization checks for DSpace. For better * security, DSpace assumes that you do not have the right to do something @@ -42,8 +51,7 @@ import java.util.*; * are automatically given permission for all requests another special group is * group 0, which is anonymous - all EPeople are members of group 0. */ -public class AuthorizeServiceImpl implements AuthorizeService -{ +public class AuthorizeServiceImpl implements AuthorizeService { @Autowired(required = true) protected BitstreamService bitstreamService; @Autowired(required = true) @@ -57,14 +65,12 @@ public class AuthorizeServiceImpl implements AuthorizeService @Autowired(required = true) protected WorkflowItemService workflowItemService; - protected AuthorizeServiceImpl() - { + protected AuthorizeServiceImpl() { } @Override - public void authorizeAnyOf(Context c, DSpaceObject o, int[] actions)throws AuthorizeException, SQLException - { + public void authorizeAnyOf(Context c, DSpaceObject o, int[] actions) throws AuthorizeException, SQLException { AuthorizeException ex = null; for (int action : actions) { @@ -84,60 +90,51 @@ public class AuthorizeServiceImpl implements AuthorizeService @Override public void authorizeAction(Context c, DSpaceObject o, int action) - throws AuthorizeException, SQLException - { + throws AuthorizeException, SQLException { authorizeAction(c, o, action, true); } @Override - public void authorizeAction(Context c, DSpaceObject o, int action, boolean useInheritance) throws AuthorizeException, SQLException - { + public void authorizeAction(Context c, DSpaceObject o, int action, boolean useInheritance) + throws AuthorizeException, SQLException { authorizeAction(c, c.getCurrentUser(), o, action, useInheritance); } - + @Override - public void authorizeAction(Context c, EPerson e, DSpaceObject o, int action, boolean useInheritance) throws AuthorizeException, SQLException - { - if (o == null) - { + public void authorizeAction(Context c, EPerson e, DSpaceObject o, int action, boolean useInheritance) + throws AuthorizeException, SQLException { + if (o == null) { // action can be -1 due to a null entry String actionText; - if (action == -1) - { + if (action == -1) { actionText = "null"; - } else - { + } else { actionText = Constants.actionText[action]; } UUID userid; - if (e == null) - { + if (e == null) { userid = null; - } else - { + } else { userid = e.getID(); } throw new AuthorizeException( - "Authorization attempted on null DSpace object " - + actionText + " by user " + userid); + "Authorization attempted on null DSpace object " + + actionText + " by user " + userid); } - if (!authorize(c, o, action, e, useInheritance)) - { + if (!authorize(c, o, action, e, useInheritance)) { // denied, assemble and throw exception int otype = o.getType(); UUID oid = o.getID(); UUID userid; - if (e == null) - { + if (e == null) { userid = null; - } else - { + } else { userid = e.getID(); } @@ -146,41 +143,35 @@ public class AuthorizeServiceImpl implements AuthorizeService // action can be -1 due to a null entry String actionText; - if (action == -1) - { + if (action == -1) { actionText = "null"; - } else - { + } else { actionText = Constants.actionText[action]; } throw new AuthorizeException("Authorization denied for action " - + actionText + " on " + Constants.typeText[otype] + ":" - + oid + " by user " + userid, o, action); + + actionText + " on " + Constants.typeText[otype] + ":" + + oid + " by user " + userid, o, action); } } @Override - public boolean authorizeActionBoolean(Context c, DSpaceObject o, int a) throws SQLException - { + public boolean authorizeActionBoolean(Context c, DSpaceObject o, int a) throws SQLException { return authorizeActionBoolean(c, o, a, true); } @Override - public boolean authorizeActionBoolean(Context c, DSpaceObject o, int a, boolean useInheritance) throws SQLException - { + public boolean authorizeActionBoolean(Context c, DSpaceObject o, int a, boolean useInheritance) + throws SQLException { boolean isAuthorized = true; - if (o == null) - { + if (o == null) { return false; } - try - { + try { authorizeAction(c, o, a, useInheritance); - } catch (AuthorizeException e) - { + } catch (AuthorizeException e) { isAuthorized = false; } @@ -188,59 +179,49 @@ public class AuthorizeServiceImpl implements AuthorizeService } @Override - public boolean authorizeActionBoolean(Context c, EPerson e, DSpaceObject o, int a, boolean useInheritance) throws SQLException - { + public boolean authorizeActionBoolean(Context c, EPerson e, DSpaceObject o, int a, boolean useInheritance) + throws SQLException { boolean isAuthorized = true; - if (o == null) - { + if (o == null) { return false; } - try - { + try { authorizeAction(c, e, o, a, useInheritance); - } catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { isAuthorized = false; } return isAuthorized; } - + /** * Check to see if the given user can perform the given action on the given * object. Always returns true if the ignore authorization flat is set in * the current context. * - * @param c - * current context. User is irrelevant; "ignore authorization" - * flag is relevant - * @param o - * object action is being attempted on - * @param action - * ID of action being attempted, from - * org.dspace.core.Constants - * @param e - * user attempting action - * @param useInheritance - * flag to say if ADMIN action on the current object or parent - * object can be used + * @param c current context. User is irrelevant; "ignore authorization" + * flag is relevant + * @param o object action is being attempted on + * @param action ID of action being attempted, from + * org.dspace.core.Constants + * @param e user attempting action + * @param useInheritance flag to say if ADMIN action on the current object or parent + * object can be used * @return true if user is authorized to perform the given - * action, false otherwise + * action, false otherwise * @throws SQLException if database error */ - protected boolean authorize(Context c, DSpaceObject o, int action, EPerson e, boolean useInheritance) throws SQLException - { + protected boolean authorize(Context c, DSpaceObject o, int action, EPerson e, boolean useInheritance) + throws SQLException { // return FALSE if there is no DSpaceObject - if (o == null) - { + if (o == null) { return false; } // is authorization disabled for this context? - if (c.ignoreAuthorization()) - { + if (c.ignoreAuthorization()) { return true; } @@ -252,16 +233,15 @@ public class AuthorizeServiceImpl implements AuthorizeService // is eperson set? if not, userToCheck = null (anonymous) EPerson userToCheck = null; - if (e != null) - { + if (e != null) { userToCheck = e; // perform isAdmin check to see // if user is an Admin on this object - DSpaceObject adminObject = useInheritance ? serviceFactory.getDSpaceObjectService(o).getAdminObject(c, o, action) : null; + DSpaceObject adminObject = useInheritance ? serviceFactory.getDSpaceObjectService(o) + .getAdminObject(c, o, action) : null; - if (isAdmin(c, e, adminObject)) - { + if (isAdmin(c, e, adminObject)) { c.cacheAuthorizedAction(o, action, e, true, null); return true; } @@ -273,38 +253,31 @@ public class AuthorizeServiceImpl implements AuthorizeService // In case the dso is an item and a corresponding workspace or workflow // item exist, we have to ignore custom policies (see DS-2614). boolean ignoreCustomPolicies = false; - if (o instanceof Bitstream) - { + if (o instanceof Bitstream) { Bitstream b = (Bitstream) o; // Ensure that this is not a collection or community logo DSpaceObject parent = bitstreamService.getParentObject(c, b); - if (!(parent instanceof Collection) && !(parent instanceof Community)) - { + if (!(parent instanceof Collection) && !(parent instanceof Community)) { ignoreCustomPolicies = !isAnyItemInstalled(c, b.getBundles()); } } - if (o instanceof Bundle) - { + if (o instanceof Bundle) { ignoreCustomPolicies = !isAnyItemInstalled(c, Arrays.asList(((Bundle) o))); } - if (o instanceof Item) - { + if (o instanceof Item) { if (workspaceItemService.findByItem(c, (Item) o) != null || - workflowItemService.findByItem(c, (Item) o) != null) - { + workflowItemService.findByItem(c, (Item) o) != null) { ignoreCustomPolicies = true; } } - for (ResourcePolicy rp : getPoliciesActionFilter(c, o, action)) - { + for (ResourcePolicy rp : getPoliciesActionFilter(c, o, action)) { if (ignoreCustomPolicies - && ResourcePolicy.TYPE_CUSTOM.equals(rp.getRpType())) - { - if(c.isReadOnly()) { + && ResourcePolicy.TYPE_CUSTOM.equals(rp.getRpType())) { + if (c.isReadOnly()) { //When we are in read-only mode, we will cache authorized actions in a different way //So we remove this resource policy from the cache. c.uncacheEntity(rp); @@ -313,17 +286,14 @@ public class AuthorizeServiceImpl implements AuthorizeService } // check policies for date validity - if (resourcePolicyService.isDateValid(rp)) - { - if (rp.getEPerson() != null && rp.getEPerson().equals(userToCheck)) - { + if (resourcePolicyService.isDateValid(rp)) { + if (rp.getEPerson() != null && rp.getEPerson().equals(userToCheck)) { c.cacheAuthorizedAction(o, action, e, true, rp); return true; // match } if ((rp.getGroup() != null) - && (groupService.isMember(c, e, rp.getGroup()))) - { + && (groupService.isMember(c, e, rp.getGroup()))) { // group was set, and eperson is a member // of that group c.cacheAuthorizedAction(o, action, e, true, rp); @@ -331,7 +301,7 @@ public class AuthorizeServiceImpl implements AuthorizeService } } - if(c.isReadOnly()) { + if (c.isReadOnly()) { //When we are in read-only mode, we will cache authorized actions in a different way //So we remove this resource policy from the cache. c.uncacheEntity(rp); @@ -346,15 +316,11 @@ public class AuthorizeServiceImpl implements AuthorizeService // check whether any bundle belongs to any item that passed submission // and workflow process protected boolean isAnyItemInstalled(Context ctx, List bundles) - throws SQLException - { - for (Bundle bundle : bundles) - { - for (Item item : bundle.getItems()) - { + throws SQLException { + for (Bundle bundle : bundles) { + for (Item item : bundle.getItems()) { if (workspaceItemService.findByItem(ctx, item) == null - && workflowItemService.findByItem(ctx, item) == null) - { + && workflowItemService.findByItem(ctx, item) == null) { return true; } } @@ -368,22 +334,18 @@ public class AuthorizeServiceImpl implements AuthorizeService /////////////////////////////////////////////// @Override - public boolean isAdmin(Context c, DSpaceObject o) throws SQLException - { + public boolean isAdmin(Context c, DSpaceObject o) throws SQLException { return this.isAdmin(c, c.getCurrentUser(), o); } @Override - public boolean isAdmin(Context c, EPerson e, DSpaceObject o) throws SQLException - { + public boolean isAdmin(Context c, EPerson e, DSpaceObject o) throws SQLException { // return true if user is an Administrator - if (isAdmin(c, e)) - { + if (isAdmin(c, e)) { return true; } - if (o == null) - { + if (o == null) { return false; } @@ -397,20 +359,16 @@ public class AuthorizeServiceImpl implements AuthorizeService // List policies = getPoliciesActionFilter(c, o, Constants.ADMIN); - for (ResourcePolicy rp : policies) - { + for (ResourcePolicy rp : policies) { // check policies for date validity - if (resourcePolicyService.isDateValid(rp)) - { - if (rp.getEPerson() != null && rp.getEPerson().equals(e)) - { + if (resourcePolicyService.isDateValid(rp)) { + if (rp.getEPerson() != null && rp.getEPerson().equals(e)) { c.cacheAuthorizedAction(o, Constants.ADMIN, e, true, rp); return true; // match } if ((rp.getGroup() != null) - && (groupService.isMember(c, e, rp.getGroup()))) - { + && (groupService.isMember(c, e, rp.getGroup()))) { // group was set, and eperson is a member // of that group c.cacheAuthorizedAction(o, Constants.ADMIN, e, true, rp); @@ -418,7 +376,7 @@ public class AuthorizeServiceImpl implements AuthorizeService } } - if(c.isReadOnly()) { + if (c.isReadOnly()) { //When we are in read-only mode, we will cache authorized actions in a different way //So we remove this resource policy from the cache. c.uncacheEntity(rp); @@ -430,8 +388,7 @@ public class AuthorizeServiceImpl implements AuthorizeService // permissions to be inherited automatically (e.g. Admin on Community // is also an Admin of all Collections/Items in that Community) DSpaceObject parent = serviceFactory.getDSpaceObjectService(o).getParentObject(c, o); - if (parent != null) - { + if (parent != null) { boolean admin = isAdmin(c, e, parent); c.cacheAuthorizedAction(o, Constants.ADMIN, e, admin, null); return admin; @@ -442,76 +399,64 @@ public class AuthorizeServiceImpl implements AuthorizeService } @Override - public boolean isAdmin(Context c) throws SQLException - { + public boolean isAdmin(Context c) throws SQLException { // if we're ignoring authorization, user is member of admin - if (c.ignoreAuthorization()) - { + if (c.ignoreAuthorization()) { return true; } EPerson e = c.getCurrentUser(); - if (e == null) - { + if (e == null) { return false; // anonymous users can't be admins.... - } else - { + } else { return groupService.isMember(c, Group.ADMIN); } } + @Override - public boolean isAdmin(Context c, EPerson e) throws SQLException - { + public boolean isAdmin(Context c, EPerson e) throws SQLException { // if we're ignoring authorization, user is member of admin - if (c.ignoreAuthorization()) - { + if (c.ignoreAuthorization()) { return true; } - if (e == null) - { + if (e == null) { return false; // anonymous users can't be admins.... - } else - { + } else { return groupService.isMember(c, e, Group.ADMIN); } } - public boolean isCommunityAdmin(Context c) throws SQLException - { - EPerson e = c.getCurrentUser(); - - if (e != null) - { - List policies = resourcePolicyService.find(c, e, - groupService.allMemberGroups(c, e), - Constants.ADMIN, Constants.COMMUNITY); - if (CollectionUtils.isNotEmpty(policies)) - { + public boolean isCommunityAdmin(Context c) throws SQLException { + EPerson e = c.getCurrentUser(); + + if (e != null) { + List policies = resourcePolicyService.find(c, e, + groupService.allMemberGroups(c, e), + Constants.ADMIN, Constants.COMMUNITY); + + if (CollectionUtils.isNotEmpty(policies)) { return true; } } - + return false; } - - public boolean isCollectionAdmin(Context c) throws SQLException - { - EPerson e = c.getCurrentUser(); - - if (e != null) - { - List policies = resourcePolicyService.find(c, e, - groupService.allMemberGroups(c, e), - Constants.ADMIN, Constants.COLLECTION); - if (CollectionUtils.isNotEmpty(policies)) - { + public boolean isCollectionAdmin(Context c) throws SQLException { + EPerson e = c.getCurrentUser(); + + if (e != null) { + List policies = resourcePolicyService.find(c, e, + groupService.allMemberGroups(c, e), + Constants.ADMIN, Constants.COLLECTION); + + if (CollectionUtils.isNotEmpty(policies)) { return true; } } - + return false; } @@ -521,81 +466,71 @@ public class AuthorizeServiceImpl implements AuthorizeService @Override public void addPolicy(Context c, DSpaceObject o, int actionID, - EPerson e) throws SQLException, AuthorizeException - { + EPerson e) throws SQLException, AuthorizeException { addPolicy(c, o, actionID, e, null); } @Override public void addPolicy(Context context, DSpaceObject o, int actionID, - EPerson e, String type) throws SQLException, AuthorizeException - { + EPerson e, String type) throws SQLException, AuthorizeException { createResourcePolicy(context, o, null, e, actionID, type); } @Override public void addPolicy(Context c, DSpaceObject o, int actionID, - Group g) throws SQLException, AuthorizeException - { + Group g) throws SQLException, AuthorizeException { createResourcePolicy(c, o, g, null, actionID, null); } @Override public void addPolicy(Context c, DSpaceObject o, int actionID, - Group g, String type) throws SQLException, AuthorizeException - { + Group g, String type) throws SQLException, AuthorizeException { createResourcePolicy(c, o, g, null, actionID, type); } @Override public List getPolicies(Context c, DSpaceObject o) - throws SQLException - { + throws SQLException { return resourcePolicyService.find(c, o); } @Override public List findPoliciesByDSOAndType(Context c, DSpaceObject o, String type) - throws SQLException - { + throws SQLException { return resourcePolicyService.find(c, o, type); } @Override public List getPoliciesForGroup(Context c, Group g) - throws SQLException - { + throws SQLException { return resourcePolicyService.find(c, g); } @Override public List getPoliciesActionFilter(Context c, DSpaceObject o, - int actionID) throws SQLException - { + int actionID) throws SQLException { return resourcePolicyService.find(c, o, actionID); } @Override public void inheritPolicies(Context c, DSpaceObject src, - DSpaceObject dest) throws SQLException, AuthorizeException - { + DSpaceObject dest) throws SQLException, AuthorizeException { // find all policies for the source object List policies = getPolicies(c, src); //Only inherit non-ADMIN policies (since ADMIN policies are automatically inherited) List nonAdminPolicies = new ArrayList(); - for (ResourcePolicy rp : policies) - { - if (rp.getAction() != Constants.ADMIN) - { + for (ResourcePolicy rp : policies) { + if (rp.getAction() != Constants.ADMIN) { nonAdminPolicies.add(rp); } } addPolicies(c, nonAdminPolicies, dest); } - + @Override - public void switchPoliciesAction(Context context, DSpaceObject dso, int fromAction, int toAction) throws SQLException, AuthorizeException { + public void switchPoliciesAction(Context context, DSpaceObject dso, int fromAction, int toAction) + throws SQLException, AuthorizeException { List rps = getPoliciesActionFilter(context, dso, fromAction); for (ResourcePolicy rp : rps) { rp.setAction(toAction); @@ -605,13 +540,11 @@ public class AuthorizeServiceImpl implements AuthorizeService @Override public void addPolicies(Context c, List policies, DSpaceObject dest) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { // now add them to the destination object List newPolicies = new LinkedList<>(); - for (ResourcePolicy srp : policies) - { + for (ResourcePolicy srp : policies) { ResourcePolicy rp = resourcePolicyService.create(c); // copy over values @@ -639,51 +572,48 @@ public class AuthorizeServiceImpl implements AuthorizeService @Override public void removeAllPoliciesByDSOAndTypeNotEqualsTo(Context c, DSpaceObject o, String type) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { resourcePolicyService.removeDsoAndTypeNotEqualsToPolicies(c, o, type); } @Override public void removeAllPoliciesByDSOAndType(Context c, DSpaceObject o, String type) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { resourcePolicyService.removePolicies(c, o, type); } @Override public void removePoliciesActionFilter(Context context, DSpaceObject dso, int actionID) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { resourcePolicyService.removePolicies(context, dso, actionID); } @Override public void removeGroupPolicies(Context c, Group group) - throws SQLException - { + throws SQLException { resourcePolicyService.removeGroupPolicies(c, group); } @Override public void removeGroupPolicies(Context c, DSpaceObject o, Group g) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { resourcePolicyService.removeDsoGroupPolicies(c, o, g); } @Override public void removeEPersonPolicies(Context c, DSpaceObject o, EPerson e) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { resourcePolicyService.removeDsoEPersonPolicies(c, o, e); } @Override public List getAuthorizedGroups(Context c, DSpaceObject o, - int actionID) throws java.sql.SQLException - { + int actionID) throws java.sql.SQLException { List policies = getPoliciesActionFilter(c, o, actionID); List groups = new ArrayList(); for (ResourcePolicy resourcePolicy : policies) { - if (resourcePolicy.getGroup() != null && resourcePolicyService.isDateValid(resourcePolicy)) - { + if (resourcePolicy.getGroup() != null && resourcePolicyService.isDateValid(resourcePolicy)) { groups.add(resourcePolicy.getGroup()); } } @@ -692,25 +622,22 @@ public class AuthorizeServiceImpl implements AuthorizeService @Override - public boolean isAnIdenticalPolicyAlreadyInPlace(Context c, DSpaceObject o, ResourcePolicy rp) throws SQLException - { + public boolean isAnIdenticalPolicyAlreadyInPlace(Context c, DSpaceObject o, ResourcePolicy rp) throws SQLException { return isAnIdenticalPolicyAlreadyInPlace(c, o, rp.getGroup(), rp.getAction(), rp.getID()); } @Override - public boolean isAnIdenticalPolicyAlreadyInPlace(Context c, DSpaceObject dso, Group group, int action, int policyID) throws SQLException - { + public boolean isAnIdenticalPolicyAlreadyInPlace(Context c, DSpaceObject dso, Group group, int action, int policyID) + throws SQLException { return !resourcePolicyService.findByTypeGroupActionExceptId(c, dso, group, action, policyID).isEmpty(); } @Override public ResourcePolicy findByTypeGroupAction(Context c, DSpaceObject dso, Group group, int action) - throws SQLException - { + throws SQLException { List policies = resourcePolicyService.find(c, dso, group, action); - if (CollectionUtils.isNotEmpty(policies)) - { + if (CollectionUtils.isNotEmpty(policies)) { return policies.iterator().next(); } else { return null; @@ -718,30 +645,25 @@ public class AuthorizeServiceImpl implements AuthorizeService } /** - * Generate Policies policies READ for the date in input adding reason. New policies are assigned automatically at the groups that - * have right on the collection. E.g., if the anonymous can access the collection policies are assigned to anonymous. + * Generate Policies policies READ for the date in input adding reason. New policies are assigned automatically + * at the groups that + * have right on the collection. E.g., if the anonymous can access the collection policies are assigned to + * anonymous. * - * @param context - * The relevant DSpace Context. - * @param embargoDate - * embargo end date - * @param reason - * embargo reason - * @param dso - * DSpace object - * @param owningCollection - * collection to get group policies from - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param embargoDate embargo end date + * @param reason embargo reason + * @param dso DSpace object + * @param owningCollection collection to get group policies from + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void generateAutomaticPolicies(Context context, Date embargoDate, - String reason, DSpaceObject dso, Collection owningCollection) - throws SQLException, AuthorizeException - { + String reason, DSpaceObject dso, Collection owningCollection) + throws SQLException, AuthorizeException { - if (embargoDate != null || (embargoDate == null && dso instanceof Bitstream)) - { + if (embargoDate != null || (embargoDate == null && dso instanceof Bitstream)) { List authorizedGroups = getAuthorizedGroups(context, owningCollection, Constants.DEFAULT_ITEM_READ); @@ -749,38 +671,46 @@ public class AuthorizeServiceImpl implements AuthorizeService // look for anonymous boolean isAnonymousInPlace = false; - for (Group g : authorizedGroups) - { - if (StringUtils.equals(g.getName(), Group.ANONYMOUS)) - { + for (Group g : authorizedGroups) { + if (StringUtils.equals(g.getName(), Group.ANONYMOUS)) { isAnonymousInPlace = true; } } - if (!isAnonymousInPlace) - { + if (!isAnonymousInPlace) { // add policies for all the groups - for (Group g : authorizedGroups) - { - ResourcePolicy rp = createOrModifyPolicy(null, context, null, g, null, embargoDate, Constants.READ, reason, dso); - if (rp != null) + for (Group g : authorizedGroups) { + ResourcePolicy rp = createOrModifyPolicy(null, context, null, g, null, embargoDate, Constants.READ, + reason, dso); + if (rp != null) { resourcePolicyService.update(context, rp); + } } - } else - { + } else { // add policy just for anonymous - ResourcePolicy rp = createOrModifyPolicy(null, context, null, groupService.findByName(context, Group.ANONYMOUS), null, embargoDate, Constants.READ, reason, dso); - if (rp != null) + ResourcePolicy rp = createOrModifyPolicy(null, context, null, + groupService.findByName(context, Group.ANONYMOUS), null, + embargoDate, Constants.READ, reason, dso); + if (rp != null) { resourcePolicyService.update(context, rp); + } } } } @Override - public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Group group, EPerson eperson, int type, String rpType) throws SQLException, AuthorizeException { - if (group == null && eperson == null) - { - throw new IllegalArgumentException("We need at least an eperson or a group in order to create a resource policy."); + public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Group group, EPerson eperson, + int type, String rpType) throws SQLException, AuthorizeException { + return createResourcePolicy(context, dso, group, eperson, type, rpType, null, null, null, null); + } + + @Override + public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Group group, EPerson eperson, + int type, String rpType, String rpName, String rpDescription, + Date startDate, Date endDate) throws SQLException, AuthorizeException { + if (group == null && eperson == null) { + throw new IllegalArgumentException( + "We need at least an eperson or a group in order to create a resource policy."); } ResourcePolicy myPolicy = resourcePolicyService.create(context); @@ -789,21 +719,25 @@ public class AuthorizeServiceImpl implements AuthorizeService myPolicy.setGroup(group); myPolicy.setEPerson(eperson); myPolicy.setRpType(rpType); + myPolicy.setRpName(rpName); + myPolicy.setRpDescription(rpDescription); + myPolicy.setEndDate(endDate); + myPolicy.setStartDate(startDate); resourcePolicyService.update(context, myPolicy); return myPolicy; } @Override - public ResourcePolicy createOrModifyPolicy(ResourcePolicy policy, Context context, String name, Group group, EPerson ePerson, - Date embargoDate, int action, String reason, DSpaceObject dso) throws AuthorizeException, SQLException - { + public ResourcePolicy createOrModifyPolicy(ResourcePolicy policy, Context context, String name, Group group, + EPerson ePerson, + Date embargoDate, int action, String reason, DSpaceObject dso) + throws AuthorizeException, SQLException { ResourcePolicy policyTemp = null; - if (policy != null) - { - List duplicates = resourcePolicyService.findByTypeGroupActionExceptId(context, dso, group, action, policy.getID()); - if (!duplicates.isEmpty()) - { + if (policy != null) { + List duplicates = resourcePolicyService + .findByTypeGroupActionExceptId(context, dso, group, action, policy.getID()); + if (!duplicates.isEmpty()) { policy = duplicates.get(0); } } else { @@ -811,24 +745,20 @@ public class AuthorizeServiceImpl implements AuthorizeService policyTemp = findByTypeGroupAction(context, dso, group, action); } - if (policyTemp != null) - { + if (policyTemp != null) { policy = policyTemp; policy.setRpType(ResourcePolicy.TYPE_CUSTOM); } - if (policy == null) - { + if (policy == null) { policy = createResourcePolicy(context, dso, group, ePerson, action, ResourcePolicy.TYPE_CUSTOM); } policy.setGroup(group); policy.setEPerson(ePerson); - if (embargoDate != null) - { + if (embargoDate != null) { policy.setStartDate(embargoDate); - } else - { + } else { policy.setStartDate(null); policy.setEndDate(null); } diff --git a/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java b/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java index 9323423435..61e783920a 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java +++ b/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java @@ -8,6 +8,7 @@ package org.dspace.authorize; //import org.dspace.browse.Browse; + import java.sql.SQLException; import java.util.List; @@ -26,20 +27,24 @@ import org.dspace.eperson.factory.EPersonServiceFactory; * Command line tool to locate collections without default item and bitstream * read policies, and assign them some. (They must be there for submitted items * to inherit.) - * + * * @author dstuve * @version $Revision$ */ -public class FixDefaultPolicies -{ +public class FixDefaultPolicies { + + /** + * Default constructor + */ + private FixDefaultPolicies() { } + /** * Command line interface to setPolicies - run to see arguments * * @param argv the command line arguments given * @throws Exception if error */ - public static void main(String[] argv) throws Exception - { + public static void main(String[] argv) throws Exception { Context c = new Context(); // turn off authorization @@ -66,7 +71,7 @@ public class FixDefaultPolicies System.out.println("\tFound DEFAULT_ITEM_READ policies!"); } else { System.out - .println("\tNo DEFAULT_ITEM_READ policy found, adding anonymous."); + .println("\tNo DEFAULT_ITEM_READ policy found, adding anonymous."); addAnonymousPolicy(c, t, Constants.DEFAULT_ITEM_READ); } @@ -74,7 +79,7 @@ public class FixDefaultPolicies System.out.println("\tFound DEFAULT_BITSTREAM_READ policies!"); } else { System.out - .println("\tNo DEFAULT_BITSTREAM_READ policy found, adding anonymous."); + .println("\tNo DEFAULT_BITSTREAM_READ policy found, adding anonymous."); addAnonymousPolicy(c, t, Constants.DEFAULT_BITSTREAM_READ); } } @@ -102,10 +107,10 @@ public class FixDefaultPolicies * check to see if a collection has any policies for a given action */ private static boolean checkForPolicy(Context c, DSpaceObject t, - int myaction) throws SQLException - { + int myaction) throws SQLException { // check to see if any policies exist for this action - List policies = AuthorizeServiceFactory.getInstance().getAuthorizeService().getPoliciesActionFilter(c, t, myaction); + List policies = AuthorizeServiceFactory.getInstance().getAuthorizeService() + .getPoliciesActionFilter(c, t, myaction); return policies.size() > 0; } @@ -115,8 +120,7 @@ public class FixDefaultPolicies * action */ private static void addAnonymousPolicy(Context c, DSpaceObject t, - int myaction) throws SQLException, AuthorizeException - { + int myaction) throws SQLException, AuthorizeException { // group 0 is the anonymous group! Group anonymousGroup = EPersonServiceFactory.getInstance().getGroupService().findByName(c, Group.ANONYMOUS); diff --git a/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java b/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java index 32c12dd474..72998b9fd1 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java +++ b/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java @@ -16,7 +16,10 @@ import java.util.UUID; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.ResourcePolicyService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +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; @@ -33,26 +36,31 @@ import org.dspace.eperson.service.GroupService; * @author dstuve * @version $Revision$ */ -public class PolicySet -{ - private static final AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); - private static final ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); +public class PolicySet { + private static final AuthorizeService authorizeService = + AuthorizeServiceFactory.getInstance().getAuthorizeService(); + private static final ResourcePolicyService resourcePolicyService = + AuthorizeServiceFactory.getInstance().getResourcePolicyService(); private static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final CollectionService collectionService = + ContentServiceFactory.getInstance().getCollectionService(); private static final GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); + /** + * Default constructor + */ + private PolicySet() { } + /** * Command line interface to setPolicies - run to see arguments * * @param argv the command line arguments given * @throws Exception if error */ - public static void main(String[] argv) throws Exception - { - if (argv.length < 6) - { + public static void main(String[] argv) throws Exception { + if (argv.length < 6) { System.out - .println("Args: containerType containerID contentType actionID groupID command [filter]"); + .println("Args: containerType containerID contentType actionID groupID command [filter]"); System.out.println("container=COLLECTION command = ADD|REPLACE"); return; @@ -67,13 +75,11 @@ public class PolicySet boolean isReplace = false; String command = argv[5]; String filter = null; - if ( argv.length == 7 ) - { + if (argv.length == 7) { filter = argv[6]; } - if (command.equals("REPLACE")) - { + if (command.equals("REPLACE")) { isReplace = true; } @@ -86,7 +92,7 @@ public class PolicySet // carnage begins here ////////////////////// setPoliciesFilter(c, containertype, containerID, contenttype, actionID, - groupID, isReplace, false, filter); + groupID, isReplace, false, filter); c.complete(); System.exit(0); @@ -96,176 +102,129 @@ public class PolicySet * Useful policy wildcard tool. Can set entire collections' contents' * policies * - * @param c - * current context - * @param containerType - * type, Constants.ITEM or Constants.COLLECTION - * @param containerID - * ID of container (DB primary key) - * @param contentType - * type (BUNDLE, ITEM, or BITSTREAM) - * @param actionID - * action ID - * @param groupID - * group ID (database key) - * @param isReplace - * if true, existing policies are removed first, - * otherwise add to existing policies - * @param clearOnly - * if true, just delete policies for matching - * objects - * @throws SQLException if database error - * if database problem + * @param c current context + * @param containerType type, Constants.ITEM or Constants.COLLECTION + * @param containerID ID of container (DB primary key) + * @param contentType type (BUNDLE, ITEM, or BITSTREAM) + * @param actionID action ID + * @param groupID group ID (database key) + * @param isReplace if true, existing policies are removed first, + * otherwise add to existing policies + * @param clearOnly if true, just delete policies for matching + * objects + * @throws SQLException if database error + * if database problem * @throws AuthorizeException if authorization error - * if current user is not authorized to change these policies + * if current user is not authorized to change these policies */ public static void setPolicies(Context c, int containerType, UUID containerID, int contentType, int actionID, UUID groupID, boolean isReplace, boolean clearOnly) throws SQLException, - AuthorizeException - { - setPoliciesFilter(c, containerType,containerID, contentType, actionID, groupID, isReplace, clearOnly, null, null, null, null, null); + AuthorizeException { + setPoliciesFilter(c, containerType, containerID, contentType, actionID, groupID, isReplace, clearOnly, null, + null, null, null, null); } /** - * - * @param c - * current context - * @param containerType - * type, Constants.ITEM or Constants.COLLECTION - * @param containerID - * ID of container (DB primary key) - * @param contentType - * ID of container (DB primary key) - * @param actionID - * action ID (e.g. Constants.READ) - * @param groupID - * group ID (database key) - * @param isReplace - * if true, existing policies are removed first, - * otherwise add to existing policies - * @param clearOnly - * if non-null, only process bitstreams whose names contain filter - * @param name - * policy name - * @param description - * policy descrption - * @param startDate - * policy start date - * @param endDate - * policy end date - * @throws SQLException if database error + * @param c current context + * @param containerType type, Constants.ITEM or Constants.COLLECTION + * @param containerID ID of container (DB primary key) + * @param contentType ID of container (DB primary key) + * @param actionID action ID (e.g. Constants.READ) + * @param groupID group ID (database key) + * @param isReplace if true, existing policies are removed first, + * otherwise add to existing policies + * @param clearOnly if non-null, only process bitstreams whose names contain filter + * @param name policy name + * @param description policy descrption + * @param startDate policy start date + * @param endDate policy end date + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public static void setPolicies(Context c, int containerType, UUID containerID, int contentType, int actionID, UUID groupID, boolean isReplace, boolean clearOnly, - String name, String description, Date startDate, Date endDate) throws SQLException, AuthorizeException - { + String name, String description, Date startDate, Date endDate) + throws SQLException, AuthorizeException { setPoliciesFilter(c, containerType, containerID, contentType, - actionID, groupID, isReplace, clearOnly, null, name, description, startDate, endDate); + actionID, groupID, isReplace, clearOnly, null, name, description, startDate, endDate); } /** * Useful policy wildcard tool. Can set entire collections' contents' * policies * - * @param c - * current context - * @param containerType - * type, Constants.ITEM or Constants.COLLECTION - * @param containerID - * ID of container (DB primary key) - * @param contentType - * type (BUNDLE, ITEM, or BITSTREAM) - * @param actionID - * action ID (e.g. Constants.READ) - * @param groupID - * group ID (database key) - * @param isReplace - * if true, existing policies are removed first, - * otherwise add to existing policies - * @param clearOnly - * if true, just delete policies for matching - * objects - * @param filter - * if non-null, only process bitstreams whose names contain filter - * @throws SQLException if database error - * if database problem + * @param c current context + * @param containerType type, Constants.ITEM or Constants.COLLECTION + * @param containerID ID of container (DB primary key) + * @param contentType type (BUNDLE, ITEM, or BITSTREAM) + * @param actionID action ID (e.g. Constants.READ) + * @param groupID group ID (database key) + * @param isReplace if true, existing policies are removed first, + * otherwise add to existing policies + * @param clearOnly if true, just delete policies for matching + * objects + * @param filter if non-null, only process bitstreams whose names contain filter + * @throws SQLException if database error + * if database problem * @throws AuthorizeException if authorization error - * if current user is not authorized to change these policies + * if current user is not authorized to change these policies */ public static void setPoliciesFilter(Context c, int containerType, UUID containerID, int contentType, int actionID, UUID groupID, - boolean isReplace, boolean clearOnly, String filter) throws SQLException,AuthorizeException - { - setPoliciesFilter(c, containerType,containerID, contentType, actionID, groupID, isReplace, clearOnly, filter, null, null, null, null); + boolean isReplace, boolean clearOnly, String filter) + throws SQLException, AuthorizeException { + setPoliciesFilter(c, containerType, containerID, contentType, actionID, groupID, isReplace, clearOnly, filter, + null, null, null, null); } /** * Useful policy wildcard tool. Can set entire collections' contents' * policies * - * @param c - * current context - * @param containerType - * type, Constants.ITEM or Constants.COLLECTION - * @param containerID - * ID of container (DB primary key) - * @param contentType - * type (BUNDLE, ITEM, or BITSTREAM) - * @param actionID - * action ID - * @param groupID - * group ID (database key) - * @param isReplace - * if true, existing policies are removed first, - * otherwise add to existing policies - * @param clearOnly - * if true, just delete policies for matching - * objects - * @param filter - * if non-null, only process bitstreams whose names contain filter - * @param name - * policy name - * @param description - * policy description - * @param startDate - * policy start date - * @param endDate - * policy end date - * @throws SQLException if database error - * if database problem + * @param c current context + * @param containerType type, Constants.ITEM or Constants.COLLECTION + * @param containerID ID of container (DB primary key) + * @param contentType type (BUNDLE, ITEM, or BITSTREAM) + * @param actionID action ID + * @param groupID group ID (database key) + * @param isReplace if true, existing policies are removed first, + * otherwise add to existing policies + * @param clearOnly if true, just delete policies for matching + * objects + * @param filter if non-null, only process bitstreams whose names contain filter + * @param name policy name + * @param description policy description + * @param startDate policy start date + * @param endDate policy end date + * @throws SQLException if database error + * if database problem * @throws AuthorizeException if authorization error - * if current user is not authorized to change these policies + * if current user is not authorized to change these policies */ public static void setPoliciesFilter(Context c, int containerType, UUID containerID, int contentType, int actionID, UUID groupID, boolean isReplace, boolean clearOnly, String filter, - String name, String description, Date startDate, Date endDate) throws SQLException, AuthorizeException - { - if (containerType == Constants.COLLECTION) - { + String name, String description, Date startDate, Date endDate) + throws SQLException, AuthorizeException { + if (containerType == Constants.COLLECTION) { Collection collection = collectionService.find(c, containerID); Group group = groupService.find(c, groupID); Iterator i = itemService.findAllByCollection(c, collection); - if (contentType == Constants.ITEM) - { + if (contentType == Constants.ITEM) { // build list of all items in a collection - while (i.hasNext()) - { + while (i.hasNext()) { Item myitem = i.next(); // is this a replace? delete policies first - if (isReplace || clearOnly) - { + if (isReplace || clearOnly) { authorizeService.removeAllPolicies(c, myitem); } - if (!clearOnly) - { + if (!clearOnly) { // before create a new policy check if an identical policy is already in place if (!authorizeService.isAnIdenticalPolicyAlreadyInPlace(c, myitem, group, actionID, -1)) { @@ -285,13 +244,10 @@ public class PolicySet } } } - } - else if (contentType == Constants.BUNDLE) - { + } else if (contentType == Constants.BUNDLE) { // build list of all items in a collection // build list of all bundles in those items - while (i.hasNext()) - { + while (i.hasNext()) { Item myitem = i.next(); List bundles = myitem.getBundles(); @@ -322,13 +278,10 @@ public class PolicySet } } } - } - else if (contentType == Constants.BITSTREAM) - { + } else if (contentType == Constants.BITSTREAM) { // build list of all bitstreams in a collection // iterate over items, bundles, get bitstreams - while (i.hasNext()) - { + while (i.hasNext()) { Item myitem = i.next(); System.out.println("Item " + myitem.getID()); @@ -341,7 +294,7 @@ public class PolicySet for (Bitstream bitstream : bitstreams) { if (filter == null || - bitstream.getName().indexOf(filter) != -1) { + bitstream.getName().indexOf(filter) != -1) { // is this a replace? delete policies first if (isReplace || clearOnly) { authorizeService.removeAllPolicies(c, bitstream); @@ -349,7 +302,8 @@ public class PolicySet if (!clearOnly) { // before create a new policy check if an identical policy is already in place - if (!authorizeService.isAnIdenticalPolicyAlreadyInPlace(c, bitstream, group, actionID, -1)) { + if (!authorizeService + .isAnIdenticalPolicyAlreadyInPlace(c, bitstream, group, actionID, -1)) { // now add the policy ResourcePolicy rp = resourcePolicyService.create(c); diff --git a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicy.java b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicy.java index d6e24584ca..68d7ecd4f5 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicy.java +++ b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicy.java @@ -7,6 +7,22 @@ */ package org.dspace.authorize; +import java.util.Date; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + import org.apache.commons.lang.ObjectUtils; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; @@ -16,29 +32,26 @@ import org.dspace.eperson.Group; import org.hibernate.annotations.Type; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.util.Date; - /** * Database entity representation of the ResourcePolicy table * * @author kevinvandevelde at atmire.com */ @Entity -@Table(name="resourcepolicy") +@Table(name = "resourcepolicy") public class ResourcePolicy implements ReloadableEntity { public static String TYPE_SUBMISSION = "TYPE_SUBMISSION"; public static String TYPE_WORKFLOW = "TYPE_WORKFLOW"; - public static String TYPE_CUSTOM= "TYPE_CUSTOM"; - public static String TYPE_INHERITED= "TYPE_INHERITED"; + public static String TYPE_CUSTOM = "TYPE_CUSTOM"; + public static String TYPE_INHERITED = "TYPE_INHERITED"; @Id - @Column(name="policy_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="resourcepolicy_seq") - @SequenceGenerator(name="resourcepolicy_seq", sequenceName="resourcepolicy_seq", allocationSize = 1) + @Column(name = "policy_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "resourcepolicy_seq") + @SequenceGenerator(name = "resourcepolicy_seq", sequenceName = "resourcepolicy_seq", allocationSize = 1) private Integer id; - @ManyToOne(fetch = FetchType.EAGER, cascade={CascadeType.PERSIST}) + @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST}) @JoinColumn(name = "dspace_object") private DSpaceObject dSpaceObject; @@ -51,7 +64,7 @@ public class ResourcePolicy implements ReloadableEntity { /* * {@see org.dspace.core.Constants#Constants Constants} */ - @Column(name="action_id") + @Column(name = "action_id") private int actionId; @@ -60,76 +73,66 @@ public class ResourcePolicy implements ReloadableEntity { private EPerson eperson; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name="epersongroup_id") + @JoinColumn(name = "epersongroup_id") private Group epersonGroup; - @Column(name="start_date") + @Column(name = "start_date") @Temporal(TemporalType.DATE) private Date startDate; - @Column(name="end_date") + @Column(name = "end_date") @Temporal(TemporalType.DATE) private Date endDate; - @Column(name="rpname", length = 30) + @Column(name = "rpname", length = 30) private String rpname; - @Column(name="rptype", length = 30) + @Column(name = "rptype", length = 30) private String rptype; @Lob - @Type(type="org.hibernate.type.MaterializedClobType") - @Column(name="rpdescription") + @Type(type = "org.hibernate.type.MaterializedClobType") + @Column(name = "rpdescription") private String rpdescription; /** * Protected constructor, create object using: * {@link org.dspace.authorize.service.ResourcePolicyService#create(Context)} */ - protected ResourcePolicy() - { + protected ResourcePolicy() { } /** * Return true if this object equals obj, false otherwise. * - * @param obj - * object to compare (eperson, group, start date, end date, ...) + * @param obj object to compare (eperson, group, start date, end date, ...) * @return true if ResourcePolicy objects are equal */ @Override - public boolean equals(Object obj) - { - if (obj == null) - { + public boolean equals(Object obj) { + if (obj == null) { return false; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } final ResourcePolicy other = (ResourcePolicy) obj; - if (getAction() != other.getAction()) - { + if (getAction() != other.getAction()) { return false; } - if (!ObjectUtils.equals(getEPerson(), other.getEPerson())) - { + if (!ObjectUtils.equals(getEPerson(), other.getEPerson())) { return false; } - if (!ObjectUtils.equals(getGroup(), other.getGroup())) - { + if (!ObjectUtils.equals(getGroup(), other.getGroup())) { return false; } - if (!ObjectUtils.equals(getStartDate(), other.getStartDate())) - { + if (!ObjectUtils.equals(getStartDate(), other.getStartDate())) { return false; } - if (!ObjectUtils.equals(getEndDate(), other.getEndDate())) - { + if (!ObjectUtils.equals(getEndDate(), other.getEndDate())) { return false; } return true; @@ -141,19 +144,16 @@ public class ResourcePolicy implements ReloadableEntity { * @return int hash of object */ @Override - public int hashCode() - { + public int hashCode() { int hash = 7; hash = 19 * hash + this.getAction(); - if (this.getGroup() != null) - { + if (this.getGroup() != null) { hash = 19 * hash + this.getGroup().hashCode(); } else { hash = 19 * hash + -1; } - if (this.getEPerson() != null) - { + if (this.getEPerson() != null) { hash = 19 * hash + this.getEPerson().hashCode(); } else { hash = 19 * hash + -1; @@ -185,35 +185,32 @@ public class ResourcePolicy implements ReloadableEntity { /** * set the action this policy authorizes * - * @param myid action ID from {@link org.dspace.core.Constants#Constants Constants} + * @param myid action ID from {@link org.dspace.core.Constants#Constants Constants} */ - public void setAction(int myid) - { + public void setAction(int myid) { this.actionId = myid; } /** * @return get the action this policy authorizes */ - public int getAction() - { + public int getAction() { return actionId; } /** * @return eperson, null if EPerson not set */ - public EPerson getEPerson() - { + public EPerson getEPerson() { return eperson; } /** * assign an EPerson to this policy + * * @param eperson Eperson */ - public void setEPerson(EPerson eperson) - { + public void setEPerson(EPerson eperson) { this.eperson = eperson; } @@ -222,17 +219,16 @@ public class ResourcePolicy implements ReloadableEntity { * * @return group, or null if no group set */ - public Group getGroup() - { + public Group getGroup() { return epersonGroup; } /** * sets the Group referred to by this policy + * * @param epersonGroup Group */ - public void setGroup(Group epersonGroup) - { + public void setGroup(Group epersonGroup) { this.epersonGroup = epersonGroup; } @@ -240,21 +236,18 @@ public class ResourcePolicy implements ReloadableEntity { * Get the start date of the policy * * @return start date, or null if there is no start date set (probably most - * common case) + * common case) */ - public java.util.Date getStartDate() - { + public java.util.Date getStartDate() { return startDate; } /** * Set the start date for the policy * - * @param d - * date, or null for no start date + * @param d date, or null for no start date */ - public void setStartDate(java.util.Date d) - { + public void setStartDate(java.util.Date d) { startDate = d; } @@ -263,25 +256,23 @@ public class ResourcePolicy implements ReloadableEntity { * * @return end date or null for no end date */ - public java.util.Date getEndDate() - { + public java.util.Date getEndDate() { return endDate; } /** * Set end date for the policy * - * @param d - * end date, or null + * @param d end date, or null */ - public void setEndDate(java.util.Date d) - { + public void setEndDate(java.util.Date d) { this.endDate = d; } public String getRpName() { return rpname; } + public void setRpName(String name) { this.rpname = name; } @@ -289,6 +280,7 @@ public class ResourcePolicy implements ReloadableEntity { public String getRpType() { return rptype; } + public void setRpType(String type) { this.rptype = type; } @@ -296,6 +288,7 @@ public class ResourcePolicy implements ReloadableEntity { public String getRpDescription() { return rpdescription; } + public void setRpDescription(String description) { this.rpdescription = description; } diff --git a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java index 615a237b72..2609c6d165 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java @@ -7,7 +7,14 @@ */ package org.dspace.authorize; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.ObjectUtils; import org.apache.log4j.Logger; import org.dspace.authorize.dao.ResourcePolicyDAO; @@ -20,9 +27,6 @@ import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.*; - /** * Service implementation for the ResourcePolicy object. * This class is responsible for all business logic calls for the ResourcePolicy object and is autowired by spring. @@ -30,9 +34,10 @@ import java.util.*; * * @author kevinvandevelde at atmire.com */ -public class ResourcePolicyServiceImpl implements ResourcePolicyService -{ - /** log4j logger */ +public class ResourcePolicyServiceImpl implements ResourcePolicyService { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(ResourcePolicyServiceImpl.class); @Autowired(required = true) @@ -41,38 +46,31 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService @Autowired(required = true) protected ResourcePolicyDAO resourcePolicyDAO; - protected ResourcePolicyServiceImpl() - { + protected ResourcePolicyServiceImpl() { } /** * Get an ResourcePolicy from the database. * - * @param context - * DSpace context object - * @param id - * ID of the ResourcePolicy - * + * @param context DSpace context object + * @param id ID of the ResourcePolicy * @return the ResourcePolicy format, or null if the ID is invalid. * @throws SQLException if database error */ @Override - public ResourcePolicy find(Context context, int id) throws SQLException - { + public ResourcePolicy find(Context context, int id) throws SQLException { return resourcePolicyDAO.findByID(context, ResourcePolicy.class, id); } /** * Create a new ResourcePolicy * - * @param context - * DSpace context object + * @param context DSpace context object * @return ResourcePolicy * @throws SQLException if database error */ @Override - public ResourcePolicy create(Context context) throws SQLException - { + public ResourcePolicy create(Context context) throws SQLException { // FIXME: Check authorisation // Create a table row ResourcePolicy resourcePolicy = resourcePolicyDAO.create(context, new ResourcePolicy()); @@ -80,15 +78,13 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService } @Override - public List find(Context c, DSpaceObject o) throws SQLException - { + public List find(Context c, DSpaceObject o) throws SQLException { return resourcePolicyDAO.findByDso(c, o); } @Override - public List find(Context c, DSpaceObject o, String type) throws SQLException - { + public List find(Context c, DSpaceObject o, String type) throws SQLException { return resourcePolicyDAO.findByDsoAndType(c, o, type); } @@ -98,8 +94,7 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService } @Override - public List find(Context c, DSpaceObject o, int actionId) throws SQLException - { + public List find(Context c, DSpaceObject o, int actionId) throws SQLException { return resourcePolicyDAO.findByDSoAndAction(c, o, actionId); } @@ -107,26 +102,27 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService public List find(Context c, DSpaceObject dso, Group group, int action) throws SQLException { return resourcePolicyDAO.findByTypeGroupAction(c, dso, group, action); } - + @Override - public List find(Context c, EPerson e, List groups, int action, int type_id) throws SQLException{ + public List find(Context c, EPerson e, List groups, int action, int type_id) + throws SQLException { return resourcePolicyDAO.findByEPersonGroupTypeIdAction(c, e, groups, action, type_id); } - + @Override - public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, int action, int notPolicyID) - throws SQLException - { + public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, + int action, int notPolicyID) + throws SQLException { return resourcePolicyDAO.findByTypeGroupActionExceptId(context, dso, group, action, notPolicyID); } - + /** * Delete an ResourcePolicy * - * @param context context + * @param context context * @param resourcePolicy resource policy - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override @@ -134,12 +130,12 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService // FIXME: authorizations // Remove ourself resourcePolicyDAO.delete(context, resourcePolicy); - + context.turnOffAuthorisationSystem(); - if(resourcePolicy.getdSpaceObject() != null) - { + if (resourcePolicy.getdSpaceObject() != null) { //A policy for a DSpace Object has been modified, fire a modify event on the DSpace object - contentServiceFactory.getDSpaceObjectService(resourcePolicy.getdSpaceObject()).updateLastModified(context, resourcePolicy.getdSpaceObject()); + contentServiceFactory.getDSpaceObjectService(resourcePolicy.getdSpaceObject()) + .updateLastModified(context, resourcePolicy.getdSpaceObject()); } context.restoreAuthSystemState(); } @@ -150,35 +146,30 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService * @return action text or 'null' if action row empty */ @Override - public String getActionText(ResourcePolicy resourcePolicy) - { + public String getActionText(ResourcePolicy resourcePolicy) { int myAction = resourcePolicy.getAction(); - if (myAction == -1) - { + if (myAction == -1) { return "..."; - } - else - { + } else { return Constants.actionText[myAction]; } } + /** * figures out if the date is valid for the policy * * @param resourcePolicy resource policy * @return true if policy has begun and hasn't expired yet (or no dates are - * set) + * set) */ @Override - public boolean isDateValid(ResourcePolicy resourcePolicy) - { + public boolean isDateValid(ResourcePolicy resourcePolicy) { Date sd = resourcePolicy.getStartDate(); Date ed = resourcePolicy.getEndDate(); // if no dates set, return true (most common case) - if ((sd == null) && (ed == null)) - { + if ((sd == null) && (ed == null)) { return true; } @@ -186,15 +177,13 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService Date now = new Date(); // check start date first - if (sd != null && now.before(sd)) - { + if (sd != null && now.before(sd)) { // start date is set, return false if we're before it return false; } // now expiration date - if (ed != null && now.after(ed)) - { + if (ed != null && now.after(ed)) { // end date is set, return false if we're after it return false; } @@ -204,7 +193,8 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService } @Override - public ResourcePolicy clone(Context context, ResourcePolicy resourcePolicy) throws SQLException, AuthorizeException { + public ResourcePolicy clone(Context context, ResourcePolicy resourcePolicy) + throws SQLException, AuthorizeException { ResourcePolicy clone = create(context); clone.setGroup(resourcePolicy.getGroup()); clone.setEPerson(resourcePolicy.getEPerson()); @@ -233,7 +223,8 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService } @Override - public void removeDsoGroupPolicies(Context context, DSpaceObject dso, Group group) throws SQLException, AuthorizeException { + public void removeDsoGroupPolicies(Context context, DSpaceObject dso, Group group) + throws SQLException, AuthorizeException { resourcePolicyDAO.deleteByDsoGroupPolicies(context, dso, group); context.turnOffAuthorisationSystem(); contentServiceFactory.getDSpaceObjectService(dso).updateLastModified(context, dso); @@ -241,7 +232,8 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService } @Override - public void removeDsoEPersonPolicies(Context context, DSpaceObject dso, EPerson ePerson) throws SQLException, AuthorizeException { + public void removeDsoEPersonPolicies(Context context, DSpaceObject dso, EPerson ePerson) + throws SQLException, AuthorizeException { resourcePolicyDAO.deleteByDsoEPersonPolicies(context, dso, ePerson); context.turnOffAuthorisationSystem(); contentServiceFactory.getDSpaceObjectService(dso).updateLastModified(context, dso); @@ -256,10 +248,9 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService @Override public void removePolicies(Context c, DSpaceObject o, int actionId) throws SQLException, AuthorizeException { - if (actionId == -1) - { + if (actionId == -1) { removeAllPolicies(c, o); - }else{ + } else { resourcePolicyDAO.deleteByDsoAndAction(c, o, actionId); c.turnOffAuthorisationSystem(); contentServiceFactory.getDSpaceObjectService(o).updateLastModified(c, o); @@ -268,7 +259,8 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService } @Override - public void removeDsoAndTypeNotEqualsToPolicies(Context c, DSpaceObject o, String type) throws SQLException, AuthorizeException { + public void removeDsoAndTypeNotEqualsToPolicies(Context c, DSpaceObject o, String type) + throws SQLException, AuthorizeException { resourcePolicyDAO.deleteByDsoAndTypeNotEqualsTo(c, o, type); c.turnOffAuthorisationSystem(); contentServiceFactory.getDSpaceObjectService(o).updateLastModified(c, o); @@ -278,9 +270,10 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService /** * Update the ResourcePolicy - * @param context context + * + * @param context context * @param resourcePolicy resource policy - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override @@ -293,7 +286,7 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService */ @Override public void update(Context context, List resourcePolicies) throws SQLException, AuthorizeException { - if(CollectionUtils.isNotEmpty(resourcePolicies)) { + if (CollectionUtils.isNotEmpty(resourcePolicies)) { Set relatedDSpaceObjects = new HashSet<>(); for (ResourcePolicy resourcePolicy : resourcePolicies) { @@ -309,7 +302,7 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService context.turnOffAuthorisationSystem(); for (DSpaceObject dSpaceObject : relatedDSpaceObjects) { //A policy for a DSpace Object has been modified, fire a modify event on the DSpace object - contentServiceFactory.getDSpaceObjectService(dSpaceObject).updateLastModified(context, dSpaceObject); + contentServiceFactory.getDSpaceObjectService(dSpaceObject).updateLastModified(context, dSpaceObject); } context.restoreAuthSystemState(); } diff --git a/dspace-api/src/main/java/org/dspace/authorize/dao/ResourcePolicyDAO.java b/dspace-api/src/main/java/org/dspace/authorize/dao/ResourcePolicyDAO.java index 05b13c8ba8..ecaeef18e7 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/dao/ResourcePolicyDAO.java +++ b/dspace-api/src/main/java/org/dspace/authorize/dao/ResourcePolicyDAO.java @@ -7,6 +7,9 @@ */ package org.dspace.authorize.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.ResourcePolicy; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; @@ -14,12 +17,10 @@ import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the ResourcePolicy object. - * The implementation of this class is responsible for all database calls for the ResourcePolicy object and is autowired by spring + * The implementation of this class is responsible for all database calls for the ResourcePolicy object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -28,24 +29,29 @@ public interface ResourcePolicyDAO extends GenericDAO { public List findByDso(Context context, DSpaceObject dso) throws SQLException; - public List findByDsoAndType(Context context, DSpaceObject dSpaceObject, String type) throws SQLException; + public List findByDsoAndType(Context context, DSpaceObject dSpaceObject, String type) + throws SQLException; public List findByGroup(Context context, Group group) throws SQLException; public List findByDSoAndAction(Context context, DSpaceObject dso, int actionId) throws SQLException; - public List findByTypeGroupAction(Context context, DSpaceObject dso, Group group, int action) throws SQLException; - + public List findByTypeGroupAction(Context context, DSpaceObject dso, Group group, int action) + throws SQLException; + /** * Look for ResourcePolicies by DSpaceObject, Group, and action, ignoring IDs with a specific PolicyID. * This method can be used to detect duplicate ResourcePolicies. + * * @param notPolicyID ResourcePolicies with this ID will be ignored while looking out for equal ResourcePolicies. * @return List of resource policies for the same DSpaceObject, group and action but other policyID. - * @throws SQLException + * @throws SQLException */ - public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, int action, int notPolicyID) throws SQLException; - - public List findByEPersonGroupTypeIdAction(Context context, EPerson e, List groups, int action, int type_id) throws SQLException; + public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, + int action, int notPolicyID) throws SQLException; + + public List findByEPersonGroupTypeIdAction(Context context, EPerson e, List groups, + int action, int type_id) throws SQLException; public void deleteByDso(Context context, DSpaceObject dso) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java b/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java index a876c77819..a0f69dc526 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java @@ -7,19 +7,21 @@ */ package org.dspace.authorize.dao.impl; -import org.dspace.authorize.ResourcePolicy; -import org.dspace.authorize.dao.ResourcePolicyDAO; -import org.dspace.content.DSpaceObject; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.eperson.EPerson; -import org.dspace.eperson.Group; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.authorize.ResourcePolicy; +import org.dspace.authorize.ResourcePolicy_; +import org.dspace.authorize.dao.ResourcePolicyDAO; +import org.dspace.content.DSpaceObject; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; /** * Hibernate implementation of the Database Access Object interface class for the ResourcePolicy object. @@ -28,93 +30,116 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class ResourcePolicyDAOImpl extends AbstractHibernateDAO implements ResourcePolicyDAO -{ +public class ResourcePolicyDAOImpl extends AbstractHibernateDAO implements ResourcePolicyDAO { - protected ResourcePolicyDAOImpl() - { + protected ResourcePolicyDAOImpl() { super(); } @Override public List findByDso(Context context, DSpaceObject dso) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso) - )); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery.where(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso)); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override - public List findByDsoAndType(Context context, DSpaceObject dso, String type) throws SQLException - { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - Restrictions.eq("rptype", type) - )); - return list(criteria); + public List findByDsoAndType(Context context, DSpaceObject dso, String type) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.rptype), type) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override public List findByGroup(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.eq("epersonGroup", group)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery.where(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.epersonGroup), group)); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override - public List findByDSoAndAction(Context context, DSpaceObject dso, int actionId) throws SQLException - { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - Restrictions.eq("actionId", actionId) - )); - return list(criteria); + public List findByDSoAndAction(Context context, DSpaceObject dso, int actionId) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), actionId) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override - public List findByTypeGroupAction(Context context, DSpaceObject dso, Group group, int action) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - Restrictions.eq("epersonGroup", group), - Restrictions.eq("actionId", action) - )); - criteria.setMaxResults(1); - return list(criteria); + public List findByTypeGroupAction(Context context, DSpaceObject dso, Group group, int action) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso), + criteriaBuilder + .equal(resourcePolicyRoot.get(ResourcePolicy_.epersonGroup), group), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), action) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); } - - @Override - public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, int action, int notPolicyID) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - Restrictions.eq("epersonGroup", group), - Restrictions.eq("actionId", action) - )); - criteria.add(Restrictions.and(Restrictions.not(Restrictions.eq("id", notPolicyID)))); - return list(criteria); - } - - public List findByEPersonGroupTypeIdAction(Context context, EPerson e, List groups, int action, int type_id) throws SQLException - { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("resourceTypeId", type_id), - Restrictions.eq("actionId", action), - (Restrictions.or( - Restrictions.eq("eperson", e), - Restrictions.in("epersonGroup", groups) - )) - )); - return list(criteria); - } @Override - public void deleteByDso(Context context, DSpaceObject dso) throws SQLException - { + public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, + int action, int notPolicyID) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso), + criteriaBuilder + .equal(resourcePolicyRoot.get(ResourcePolicy_.epersonGroup), group), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), action), + criteriaBuilder.notEqual(resourcePolicyRoot.get(ResourcePolicy_.id), notPolicyID) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); + } + + public List findByEPersonGroupTypeIdAction(Context context, EPerson e, List groups, + int action, int type_id) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.resourceTypeId), type_id), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), action), + criteriaBuilder + .or(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.eperson), e), + criteriaBuilder + .in(resourcePolicyRoot.get(ResourcePolicy_.epersonGroup).in(groups))) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); + } + + @Override + public void deleteByDso(Context context, DSpaceObject dso) throws SQLException { String queryString = "delete from ResourcePolicy where dSpaceObject= :dSpaceObject"; Query query = createQuery(context, queryString); query.setParameter("dSpaceObject", dso); @@ -126,7 +151,7 @@ public class ResourcePolicyDAOImpl extends AbstractHibernateDAO String queryString = "delete from ResourcePolicy where dSpaceObject= :dSpaceObject AND actionId= :actionId"; Query query = createQuery(context, queryString); query.setParameter("dSpaceObject", dso); - query.setInteger("actionId", actionId); + query.setParameter("actionId", actionId); query.executeUpdate(); } @@ -135,7 +160,7 @@ public class ResourcePolicyDAOImpl extends AbstractHibernateDAO String queryString = "delete from ResourcePolicy where dSpaceObject.id = :dsoId AND rptype = :rptype"; Query query = createQuery(context, queryString); query.setParameter("dsoId", dso.getID()); - query.setString("rptype", type); + query.setParameter("rptype", type); query.executeUpdate(); } diff --git a/dspace-api/src/main/java/org/dspace/authorize/factory/AuthorizeServiceFactory.java b/dspace-api/src/main/java/org/dspace/authorize/factory/AuthorizeServiceFactory.java index bf48b1593c..028ceb1462 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/factory/AuthorizeServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/authorize/factory/AuthorizeServiceFactory.java @@ -12,7 +12,8 @@ import org.dspace.authorize.service.ResourcePolicyService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the authorize package, use AuthorizeServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the authorize package, use AuthorizeServiceFactory.getInstance() to retrieve + * an implementation * * @author kevinvandevelde at atmire.com */ @@ -22,8 +23,8 @@ public abstract class AuthorizeServiceFactory { public abstract ResourcePolicyService getResourcePolicyService(); - public static AuthorizeServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("authorizeServiceFactory", AuthorizeServiceFactory.class); + public static AuthorizeServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("authorizeServiceFactory", AuthorizeServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/authorize/factory/AuthorizeServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/authorize/factory/AuthorizeServiceFactoryImpl.java index 9649df8a6e..dfa7b3b4a1 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/factory/AuthorizeServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/factory/AuthorizeServiceFactoryImpl.java @@ -12,7 +12,8 @@ import org.dspace.authorize.service.ResourcePolicyService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the authorize package, use AuthorizeServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the authorize package, use AuthorizeServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java b/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java index 9b5d30ebe1..092460f10f 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java +++ b/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java @@ -7,6 +7,10 @@ */ package org.dspace.authorize.service; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.content.Collection; @@ -15,10 +19,6 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; - /** * AuthorizeManager handles all authorization checks for DSpace. For better * security, DSpace assumes that you do not have the right to do something @@ -41,14 +41,13 @@ public interface AuthorizeService { * perform all of the specified actions on the given object. An * AuthorizeException if all the authorizations fail. * - * @param c context with the current user - * @param o DSpace object user is attempting to perform action on + * @param c context with the current user + * @param o DSpace object user is attempting to perform action on * @param actions array of action IDs from - * org.dspace.core.Constants - * @throws AuthorizeException if any one of the specified actions cannot be - * performed by the current user on the given object. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * org.dspace.core.Constants + * @throws AuthorizeException if any one of the specified actions cannot be + * performed by the current user on the given object. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void authorizeAnyOf(Context c, DSpaceObject o, int[] actions) throws AuthorizeException, SQLException; @@ -57,14 +56,12 @@ public interface AuthorizeService { * the given object. Throws an exception if the user is not authorized, * otherwise the method call does nothing. * - * @param c context - * @param o a DSpaceObject + * @param c context + * @param o a DSpaceObject * @param action action to perform from org.dspace.core.Constants - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void authorizeAction(Context c, DSpaceObject o, int action) throws AuthorizeException, SQLException; @@ -73,42 +70,36 @@ public interface AuthorizeService { * the given object. Throws an exception if the user is not authorized, * otherwise the method call does nothing. * - * @param c context - * @param o a DSpaceObject - * @param useInheritance - * flag to say if ADMIN action on the current object or parent - * object can be used - * @param action action to perform from org.dspace.core.Constants - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param c context + * @param o a DSpaceObject + * @param useInheritance flag to say if ADMIN action on the current object or parent + * object can be used + * @param action action to perform from org.dspace.core.Constants + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void authorizeAction(Context c, DSpaceObject o, int action, boolean useInheritance) - throws AuthorizeException, SQLException; + throws AuthorizeException, SQLException; /** * Checks that the specified eperson can perform the given action on * the given object. Throws an exception if the user is not authorized, * otherwise the method call does nothing. * - * @param c context - * @param e the eperson to use for the authorization check - * @param o a DSpaceObject - * @param useInheritance - * flag to say if ADMIN action on the current object or parent - * object can be used - * @param action action to perform from org.dspace.core.Constants - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param c context + * @param e the eperson to use for the authorization check + * @param o a DSpaceObject + * @param useInheritance flag to say if ADMIN action on the current object or parent + * object can be used + * @param action action to perform from org.dspace.core.Constants + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void authorizeAction(Context c, EPerson e, DSpaceObject o, int action, boolean useInheritance) - throws AuthorizeException, SQLException; - + throws AuthorizeException, SQLException; + /** * same authorize, returns boolean for those who don't want to deal with * catching exceptions. @@ -116,11 +107,10 @@ public interface AuthorizeService { * @param c DSpace context, containing current user * @param o DSpaceObject * @param a action being attempted, from - * org.dspace.core.Constants + * org.dspace.core.Constants * @return {@code true} if the current user in the context is - * authorized to perform the given action on the given object - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * authorized to perform the given action on the given object + * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean authorizeActionBoolean(Context c, DSpaceObject o, int a) throws SQLException; @@ -128,38 +118,36 @@ public interface AuthorizeService { * same authorize, returns boolean for those who don't want to deal with * catching exceptions. * - * @param c DSpace context, containing current user - * @param o DSpaceObject - * @param a action being attempted, from - * org.dspace.core.Constants - * @param useInheritance - * flag to say if ADMIN action on the current object or parent - * object can be used + * @param c DSpace context, containing current user + * @param o DSpaceObject + * @param a action being attempted, from + * org.dspace.core.Constants + * @param useInheritance flag to say if ADMIN action on the current object or parent + * object can be used * @return {@code true} if the current user in the context is - * authorized to perform the given action on the given object - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * authorized to perform the given action on the given object + * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean authorizeActionBoolean(Context c, DSpaceObject o, int a, boolean useInheritance) throws SQLException; - + /** - * same authorize with a specif eperson (not the current user), returns boolean for those who don't want to deal with + * same authorize with a specif eperson (not the current user), returns boolean for those who don't want to deal + * with * catching exceptions. * - * @param c DSpace context - * @param e EPerson to use in the check - * @param o DSpaceObject - * @param a action being attempted, from - * org.dspace.core.Constants - * @param useInheritance - * flag to say if ADMIN action on the current object or parent - * object can be used + * @param c DSpace context + * @param e EPerson to use in the check + * @param o DSpaceObject + * @param a action being attempted, from + * org.dspace.core.Constants + * @param useInheritance flag to say if ADMIN action on the current object or parent + * object can be used * @return {@code true} if the requested user is - * authorized to perform the given action on the given object - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * authorized to perform the given action on the given object + * @throws SQLException An exception that provides information on a database access error or other errors. */ - public boolean authorizeActionBoolean(Context c, EPerson e, DSpaceObject o, int a, boolean useInheritance) throws SQLException; + public boolean authorizeActionBoolean(Context c, EPerson e, DSpaceObject o, int a, boolean useInheritance) + throws SQLException; /////////////////////////////////////////////// // admin check methods @@ -172,12 +160,11 @@ public interface AuthorizeService { * * @param c current context * @param o current DSpace Object, if null the call will be - * equivalent to a call to the isAdmin(Context c) - * method + * equivalent to a call to the isAdmin(Context c) + * method * @return {@code true} if user has administrative privileges on the - * given DSpace object - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * given DSpace object + * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean isAdmin(Context c, DSpaceObject o) throws SQLException; @@ -189,10 +176,10 @@ public interface AuthorizeService { * @param c current context * @param e the user to check * @param o current DSpace Object, if null the call will be - * equivalent to a call to the isAdmin(Context c) - * method + * equivalent to a call to the isAdmin(Context c) + * method * @return {@code true} if the user has administrative privileges on the - * given DSpace object + * given DSpace object * @throws SQLException if database error */ public boolean isAdmin(Context c, EPerson e, DSpaceObject o) throws SQLException; @@ -206,9 +193,8 @@ public interface AuthorizeService { * * @param c current context * @return {@code true} if user is an admin or ignore authorization - * flag set - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * flag set + * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean isAdmin(Context c) throws SQLException; @@ -218,14 +204,14 @@ public interface AuthorizeService { * * @param c current context * @return {@code true} if user is an admin or ignore authorization - * flag set + * flag set * @throws SQLException if database error */ public boolean isAdmin(Context c, EPerson e) throws SQLException; - + public boolean isCommunityAdmin(Context c) throws SQLException; - - public boolean isCollectionAdmin(Context c) throws SQLException; + + public boolean isCollectionAdmin(Context c) throws SQLException; /////////////////////////////////////////////// // policy manipulation methods @@ -234,11 +220,11 @@ public interface AuthorizeService { /** * Add a policy for an individual eperson * - * @param c context. Current user irrelevant - * @param o DSpaceObject to add policy to + * @param c context. Current user irrelevant + * @param o DSpaceObject to add policy to * @param actionID ID of action from org.dspace.core.Constants - * @param e eperson who can perform the action - * @throws SQLException if database error + * @param e eperson who can perform the action + * @throws SQLException if database error * @throws AuthorizeException if current user in context is not authorized to add policies */ public void addPolicy(Context c, DSpaceObject o, int actionID, EPerson e) throws SQLException, AuthorizeException; @@ -247,24 +233,25 @@ public interface AuthorizeService { /** * Add a policy for an individual eperson * - * @param c context. Current user irrelevant - * @param o DSpaceObject to add policy to + * @param c context. Current user irrelevant + * @param o DSpaceObject to add policy to * @param actionID ID of action from org.dspace.core.Constants - * @param e eperson who can perform the action - * @param type policy type, deafult types are declared in the ResourcePolicy class - * @throws SQLException if database error + * @param e eperson who can perform the action + * @param type policy type, deafult types are declared in the ResourcePolicy class + * @throws SQLException if database error * @throws AuthorizeException if current user in context is not authorized to add policies */ - public void addPolicy(Context c, DSpaceObject o, int actionID, EPerson e, String type) throws SQLException, AuthorizeException; + public void addPolicy(Context c, DSpaceObject o, int actionID, EPerson e, String type) + throws SQLException, AuthorizeException; /** * Add a policy for a group * - * @param c current context - * @param o object to add policy for + * @param c current context + * @param o object to add policy for * @param actionID ID of action from org.dspace.core.Constants - * @param g group to add policy for - * @throws SQLException if there's a database problem + * @param g group to add policy for + * @throws SQLException if there's a database problem * @throws AuthorizeException if the current user is not authorized to add this policy */ public void addPolicy(Context c, DSpaceObject o, int actionID, Group g) throws SQLException, AuthorizeException; @@ -272,15 +259,16 @@ public interface AuthorizeService { /** * Add a policy for a group * - * @param c current context - * @param o object to add policy for + * @param c current context + * @param o object to add policy for * @param actionID ID of action from org.dspace.core.Constants - * @param g group to add policy for - * @param type policy type, deafult types are declared in the ResourcePolicy class - * @throws SQLException if there's a database problem + * @param g group to add policy for + * @param type policy type, deafult types are declared in the ResourcePolicy class + * @throws SQLException if there's a database problem * @throws AuthorizeException if the current user is not authorized to add this policy */ - public void addPolicy(Context c, DSpaceObject o, int actionID, Group g, String type) throws SQLException, AuthorizeException; + public void addPolicy(Context c, DSpaceObject o, int actionID, Group g, String type) + throws SQLException, AuthorizeException; /** * Return a List of the policies for an object @@ -295,8 +283,8 @@ public interface AuthorizeService { /** * Return a List of the policies for an object * - * @param c current context - * @param o object to retrieve policies for + * @param c current context + * @param o object to retrieve policies for * @param type type * @return List of {@code ResourcePolicy} objects * @throws SQLException if database error @@ -316,8 +304,8 @@ public interface AuthorizeService { /** * Return a list of policies for an object that match the action * - * @param c context - * @param o DSpaceObject policies relate to + * @param c context + * @param o DSpaceObject policies relate to * @param actionID action (defined in class Constants) * @return list of resource policies * @throws SQLException if there's a database problem @@ -327,10 +315,10 @@ public interface AuthorizeService { /** * Add policies to an object to match those from a previous object * - * @param c context - * @param src source of policies + * @param c context + * @param src source of policies * @param dest destination of inherited policies - * @throws SQLException if there's a database problem + * @throws SQLException if there's a database problem * @throws AuthorizeException if the current user is not authorized to add these policies */ public void inheritPolicies(Context c, DSpaceObject src, DSpaceObject dest) throws SQLException, AuthorizeException; @@ -338,20 +326,21 @@ public interface AuthorizeService { /** * Copies policies from a list of resource policies to a given DSpaceObject * - * @param c DSpace context + * @param c DSpace context * @param policies List of ResourcePolicy objects - * @param dest object to have policies added - * @throws SQLException if there's a database problem + * @param dest object to have policies added + * @throws SQLException if there's a database problem * @throws AuthorizeException if the current user is not authorized to add these policies */ - public void addPolicies(Context c, List policies, DSpaceObject dest) throws SQLException, AuthorizeException; + public void addPolicies(Context c, List policies, DSpaceObject dest) + throws SQLException, AuthorizeException; /** * removes ALL policies for an object. FIXME doesn't check authorization * * @param c DSpace context * @param o object to remove policies for - * @throws SQLException if there's a database problem + * @throws SQLException if there's a database problem * @throws AuthorizeException if authorization error */ public void removeAllPolicies(Context c, DSpaceObject o) throws SQLException, AuthorizeException; @@ -359,43 +348,46 @@ public interface AuthorizeService { /** * removes ALL policies for an object that are not of the input type. * - * @param c DSpace context - * @param o object to remove policies for + * @param c DSpace context + * @param o object to remove policies for * @param type type - * @throws SQLException if there's a database problem + * @throws SQLException if there's a database problem * @throws AuthorizeException if authorization error */ - public void removeAllPoliciesByDSOAndTypeNotEqualsTo(Context c, DSpaceObject o, String type) throws SQLException, AuthorizeException; + public void removeAllPoliciesByDSOAndTypeNotEqualsTo(Context c, DSpaceObject o, String type) + throws SQLException, AuthorizeException; /** * removes policies * - * @param c DSpace context - * @param o object to remove policies for + * @param c DSpace context + * @param o object to remove policies for * @param type policy type - * @throws SQLException if there's a database problem + * @throws SQLException if there's a database problem * @throws AuthorizeException if authorization error */ - public void removeAllPoliciesByDSOAndType(Context c, DSpaceObject o, String type) throws SQLException, AuthorizeException; + public void removeAllPoliciesByDSOAndType(Context c, DSpaceObject o, String type) + throws SQLException, AuthorizeException; /** * Remove all policies from an object that match a given action. FIXME * doesn't check authorization * - * @param context current context - * @param dso object to remove policies from + * @param context current context + * @param dso object to remove policies from * @param actionID ID of action to match from - * {@link org.dspace.core.Constants#Constants Constants}, or -1=all - * @throws SQLException if there's a database problem + * {@link org.dspace.core.Constants#Constants Constants}, or -1=all + * @throws SQLException if there's a database problem * @throws AuthorizeException if authorization error */ - public void removePoliciesActionFilter(Context context, DSpaceObject dso, int actionID) throws SQLException, AuthorizeException; + public void removePoliciesActionFilter(Context context, DSpaceObject dso, int actionID) + throws SQLException, AuthorizeException; /** * Removes all policies relating to a particular group. FIXME doesn't check * authorization * - * @param c current context + * @param c current context * @param group the group * @throws SQLException if there's a database problem */ @@ -408,7 +400,7 @@ public interface AuthorizeService { * @param c current context * @param o the object * @param g the group - * @throws SQLException if there's a database problem + * @throws SQLException if there's a database problem * @throws AuthorizeException if authorization error */ public void removeGroupPolicies(Context c, DSpaceObject o, Group g) throws SQLException, AuthorizeException; @@ -420,7 +412,7 @@ public interface AuthorizeService { * @param c current context * @param o the object * @param e the eperson - * @throws SQLException if there's a database problem + * @throws SQLException if there's a database problem * @throws AuthorizeException if authorization error */ public void removeEPersonPolicies(Context c, DSpaceObject o, EPerson e) throws SQLException, AuthorizeException; @@ -429,11 +421,11 @@ public interface AuthorizeService { * Returns all groups authorized to perform an action on an object. Returns * empty array if no matches. * - * @param c current context - * @param o object + * @param c current context + * @param o object * @param actionID ID of action from {@link org.dspace.core.Constants#Constants Constants} * @return array of {@link org.dspace.eperson.Group#Group Groups} that can perform the specified - * action on the specified object + * action on the specified object * @throws SQLException if there's a database problem */ public List getAuthorizedGroups(Context c, DSpaceObject o, int actionID) throws java.sql.SQLException; @@ -444,56 +436,62 @@ public interface AuthorizeService { /** * Is a policy with the specified parameters already in place? * - * @param c current context - * @param o object - * @param group group + * @param c current context + * @param o object + * @param group group * @param actionID ID of action from {@link org.dspace.core.Constants#Constants Constants} * @param policyID ID of an existing policy. If -1 is specified, this parameter will be ignored * @return true if such a policy exists, false otherwise * @throws SQLException if there's a database problem */ - public boolean isAnIdenticalPolicyAlreadyInPlace(Context c, DSpaceObject o, Group group, int actionID, int policyID) throws SQLException; - - public ResourcePolicy findByTypeGroupAction(Context c, DSpaceObject dso, Group group, int action) throws SQLException; + public boolean isAnIdenticalPolicyAlreadyInPlace(Context c, DSpaceObject o, Group group, int actionID, int policyID) + throws SQLException; + + public ResourcePolicy findByTypeGroupAction(Context c, DSpaceObject dso, Group group, int action) + throws SQLException; /** - * Generate Policies policies READ for the date in input adding reason. New policies are assigned automatically at the groups that - * have right on the collection. E.g., if the anonymous can access the collection policies are assigned to anonymous. + * Generate Policies policies READ for the date in input adding reason. New policies are assigned automatically + * at the groups that + * have right on the collection. E.g., if the anonymous can access the collection policies are assigned to + * anonymous. * - * @param context current context - * @param embargoDate date - * @param reason reason - * @param dso DSpaceObject + * @param context current context + * @param embargoDate date + * @param reason reason + * @param dso DSpaceObject * @param owningCollection collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public void generateAutomaticPolicies(Context context, Date embargoDate, String reason, DSpaceObject dso, Collection owningCollection) throws SQLException, AuthorizeException; + public void generateAutomaticPolicies(Context context, Date embargoDate, String reason, DSpaceObject dso, + Collection owningCollection) throws SQLException, AuthorizeException; - public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Group group, EPerson eperson, int type, String rpType) throws SQLException, AuthorizeException; + public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Group group, EPerson eperson, + int type, String rpType) throws SQLException, AuthorizeException; - public ResourcePolicy createOrModifyPolicy(ResourcePolicy policy, Context context, String name, Group group, EPerson ePerson, Date embargoDate, int action, String reason, DSpaceObject dso) throws AuthorizeException, SQLException; + public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Group group, EPerson eperson, + int type, String rpType, String rpName, String rpDescription, + Date startDate, Date endDate) throws SQLException, AuthorizeException; + + public ResourcePolicy createOrModifyPolicy(ResourcePolicy policy, Context context, String name, Group group, + EPerson ePerson, Date embargoDate, int action, String reason, + DSpaceObject dso) throws AuthorizeException, SQLException; /** * Change all the policies related to the action (fromPolicy) of the * specified object to the new action (toPolicy) - * - * @param context - * The relevant DSpace Context. - * @param dso - * the dspace object - * @param fromAction - * the action to change - * @param toAction - * the new action to set - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * + * @param context The relevant DSpace Context. + * @param dso the dspace object + * @param fromAction the action to change + * @param toAction the new action to set + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ void switchPoliciesAction(Context context, DSpaceObject dso, int fromAction, int toAction) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; } diff --git a/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java b/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java index 8dc934d69e..689898daa2 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java +++ b/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java @@ -7,6 +7,9 @@ */ package org.dspace.authorize.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.content.DSpaceObject; @@ -15,12 +18,10 @@ import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.service.DSpaceCRUDService; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the ResourcePolicy object. - * The implementation of this class is responsible for all business logic calls for the ResourcePolicy object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the ResourcePolicy object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -36,18 +37,21 @@ public interface ResourcePolicyService extends DSpaceCRUDService public List find(Context c, DSpaceObject dso, Group group, int action) throws SQLException; public List find(Context context, Group group) throws SQLException; - - public List find(Context c, EPerson e, List groups, int action, int type_id) throws SQLException; - + + public List find(Context c, EPerson e, List groups, int action, int type_id) + throws SQLException; + /** * Look for ResourcePolicies by DSpaceObject, Group, and action, ignoring IDs with a specific PolicyID. * This method can be used to detect duplicate ResourcePolicies. + * * @param notPolicyID ResourcePolicies with this ID will be ignored while looking out for equal ResourcePolicies. * @return List of resource policies for the same DSpaceObject, group and action but other policyID. - * @throws SQLException + * @throws SQLException */ - public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, int action, int notPolicyID) - throws SQLException; + public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, + int action, int notPolicyID) + throws SQLException; public String getActionText(ResourcePolicy resourcePolicy); @@ -61,12 +65,15 @@ public interface ResourcePolicyService extends DSpaceCRUDService public void removePolicies(Context c, DSpaceObject o, String type) throws SQLException, AuthorizeException; - public void removeDsoGroupPolicies(Context context, DSpaceObject dso, Group group) throws SQLException, AuthorizeException; + public void removeDsoGroupPolicies(Context context, DSpaceObject dso, Group group) + throws SQLException, AuthorizeException; - public void removeDsoEPersonPolicies(Context context, DSpaceObject dso, EPerson ePerson) throws SQLException, AuthorizeException; + public void removeDsoEPersonPolicies(Context context, DSpaceObject dso, EPerson ePerson) + throws SQLException, AuthorizeException; public void removeGroupPolicies(Context c, Group group) throws SQLException; - public void removeDsoAndTypeNotEqualsToPolicies(Context c, DSpaceObject o, String type) throws SQLException, AuthorizeException; + public void removeDsoAndTypeNotEqualsToPolicies(Context c, DSpaceObject o, String type) + throws SQLException, AuthorizeException; } diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowseDAO.java b/dspace-api/src/main/java/org/dspace/browse/BrowseDAO.java index c9eabc130a..22cf02fe13 100644 --- a/dspace-api/src/main/java/org/dspace/browse/BrowseDAO.java +++ b/dspace-api/src/main/java/org/dspace/browse/BrowseDAO.java @@ -7,11 +7,11 @@ */ package org.dspace.browse; -import org.dspace.content.Item; - import java.util.List; import java.util.UUID; +import org.dspace.content.Item; + /** * Interface for any class wishing to interact with the Browse storage layer for * Read Only operations. If you wish to modify the contents of the browse indices @@ -30,10 +30,8 @@ import java.util.UUID; * is the relevant target. * * @author Richard Jones - * */ -public interface BrowseDAO -{ +public interface BrowseDAO { // Objects implementing this interface should also include // a constructor which takes the DSpace Context as an argument // @@ -43,7 +41,7 @@ public interface BrowseDAO * This executes a query which will count the number of results for the * parameters you set. * - * @return the integer value of the number of results found + * @return the integer value of the number of results found * @throws BrowseException if browse error */ public int doCountQuery() throws BrowseException; @@ -54,7 +52,7 @@ public interface BrowseDAO * example, the list of all subject headings). This is most * commonly used with a Distinct browse type. * - * @return List of Strings representing the single value query results + * @return List of Strings representing the single value query results * @throws BrowseException if browse error */ public List doValueQuery() throws BrowseException; @@ -63,7 +61,7 @@ public interface BrowseDAO * This executes a query which returns a List object containing BrowseItem objects * representing the results of a full item browse. * - * @return List of BrowseItem objects + * @return List of BrowseItem objects * @throws BrowseException if browse error */ public List doQuery() throws BrowseException; @@ -72,10 +70,10 @@ public interface BrowseDAO * This executes a query which returns the value of the "highest" (max) value * in the given table's column for the given item id. * - * @param column the column to interrogate - * @param table the table to query - * @param itemID the item id - * @return String representing the max value in the given column + * @param column the column to interrogate + * @param table the table to query + * @param itemID the item id + * @return String representing the max value in the given column * @throws BrowseException if browse error */ public String doMaxQuery(String column, String table, int itemID) throws BrowseException; @@ -84,10 +82,10 @@ public interface BrowseDAO * This executes a query which returns the offset where the value (or nearest greater * equivalent) can be found in the specified table ordered by the column. * - * @param column the column to interrogate - * @param value the item id + * @param column the column to interrogate + * @param value the item id * @param isAscending browsing in ascending or descending order - * @return the offset into the table + * @return the offset into the table * @throws BrowseException if browse error */ public int doOffsetQuery(String column, String value, boolean isAscending) throws BrowseException; @@ -96,10 +94,10 @@ public interface BrowseDAO * This executes a query which returns the offset where the value (or nearest greater * equivalent) can be found in the specified table ordered by the column. * - * @param column the column to interrogate - * @param value the item id + * @param column the column to interrogate + * @param value the item id * @param isAscending browsing in ascending or descending order - * @return the offset into the table + * @return the offset into the table * @throws BrowseException if browse error */ public int doDistinctOffsetQuery(String column, String value, boolean isAscending) throws BrowseException; @@ -110,7 +108,7 @@ public interface BrowseDAO * * Default value is true * - * @return true if using it, false if not + * @return true if using it, false if not */ public boolean useEqualsComparator(); @@ -120,7 +118,7 @@ public interface BrowseDAO * using the equivalent of {@code <=} and {@code >=}, while if false it will use the * equivalent of {@code <} and {@code >} * - * @param equalsComparator true to use, false to not. + * @param equalsComparator true to use, false to not. */ public void setEqualsComparator(boolean equalsComparator); @@ -129,7 +127,7 @@ public interface BrowseDAO * * Default value is true * - * @return true for ascending, false for descending + * @return true for ascending, false for descending */ public boolean isAscending(); @@ -137,7 +135,7 @@ public interface BrowseDAO * Set whether the results should be sorted in ascending order (on the given sort column) * or descending order. * - * @param ascending true to ascend, false to descend + * @param ascending true to ascend, false to descend */ public void setAscending(boolean ascending); @@ -145,7 +143,7 @@ public interface BrowseDAO * Get the database ID of the container object. The container object will be a * Community or a Collection. * - * @return the database id of the container, or -1 if none is set + * @return the database id of the container, or -1 if none is set */ public UUID getContainerID(); @@ -154,8 +152,7 @@ public interface BrowseDAO * Community or Collection. This will constrain the results of the browse * to only items or values within items that appear in the given container. * - * @param containerID - * community/collection internal ID (UUID) + * @param containerID community/collection internal ID (UUID) */ public void setContainerID(UUID containerID); @@ -163,16 +160,16 @@ public interface BrowseDAO * get the name of the field in which to look for the container id. This is * principally for use internal to the DAO. * - * @return the name of the container id field. For example "collection_id" or - * "community_id" + * @return the name of the container id field. For example "collection_id" or + * "community_id" */ public String getContainerIDField(); /** * set the name of the field in which to look for the container id. * - * @param containerIDField the name of the container id field. - * For example "collection_id" or "community_id" + * @param containerIDField the name of the container id field. + * For example "collection_id" or "community_id" */ public void setContainerIDField(String containerIDField); @@ -181,7 +178,7 @@ public interface BrowseDAO * the browse. This will either be the "sort_value" field or one of the * additional sort fields defined by configuration * - * @return the name of the focus field + * @return the name of the focus field */ public String getJumpToField(); @@ -190,7 +187,7 @@ public interface BrowseDAO * the browse. This will either be the "sort_value" field or one of the * additional sort fields defined by configuration * - * @param focusField the name of the focus field + * @param focusField the name of the focus field */ public void setJumpToField(String focusField); @@ -198,7 +195,7 @@ public interface BrowseDAO * Get the value at which the browse will start. The value supplied here will * be the top result on the page of results. * - * @return the value to start browsing on + * @return the value to start browsing on */ public String getJumpToValue(); @@ -206,7 +203,7 @@ public interface BrowseDAO * Set the value upon which to start the browse from. The value supplied here * will be the top result on the page of results * - * @param focusValue the value in the focus field on which to start browsing + * @param focusValue the value in the focus field on which to start browsing */ public void setJumpToValue(String focusValue); @@ -214,7 +211,7 @@ public interface BrowseDAO * get the integer number which is the limit of the results that will be returned * by any query. The default is -1, which means unlimited results. * - * @return the maximum possible number of results allowed to be returned + * @return the maximum possible number of results allowed to be returned */ public int getLimit(); @@ -225,7 +222,7 @@ public interface BrowseDAO * query is less than this number, the size of the result set will be smaller * than this limit. * - * @param limit the maximum number of results to return. + * @param limit the maximum number of results to return. */ public void setLimit(int limit); @@ -235,7 +232,7 @@ public interface BrowseDAO * normal browse operations can be completed without it. The default is -1, which * means do not offset. * - * @return paging offset + * @return paging offset */ public int getOffset(); @@ -245,22 +242,21 @@ public interface BrowseDAO * normal browse operations can be completed without it. The default is -1, which * means do not offset. * - * @param offset - * paging offset + * @param offset paging offset */ public void setOffset(int offset); /** * Get the database field which will be used to do the sorting of result sets on. * - * @return the field by which results will be sorted + * @return the field by which results will be sorted */ public String getOrderField(); /** * Set the database field which will be used to sort result sets on * - * @param orderField the field by which results will be sorted + * @param orderField the field by which results will be sorted */ public void setOrderField(String orderField); @@ -268,7 +264,7 @@ public interface BrowseDAO * Get the array of values that we will be selecting on. The default is * to select all of the values from a given table * - * @return an array of values to select on + * @return an array of values to select on */ public String[] getSelectValues(); @@ -277,14 +273,14 @@ public interface BrowseDAO * available in the target table, or the SQL wildcards. The default is * single element array with the standard wildcard (*) * - * @param selectValues the values to select on + * @param selectValues the values to select on */ public void setSelectValues(String[] selectValues); /** * Get the array of fields that we will be counting on. * - * @return an array of fields to be counted over + * @return an array of fields to be counted over */ public String[] getCountValues(); @@ -292,35 +288,36 @@ public interface BrowseDAO * Set the array of columns that we will be counting over. In general, the * wildcard (*) will suffice * - * @param fields an array of fields to be counted over + * @param fields an array of fields to be counted over */ public void setCountValues(String[] fields); /** * get the name of the table that we are querying * - * @return the name of the table + * @return the name of the table */ public String getTable(); /** * Set the name of the table to query * - * @param table the name of the table + * @param table the name of the table */ public void setTable(String table); /** * Set the name of the mapping tables to use for filtering - * @param tableDis the name of the table holding the distinct values - * @param tableMap the name of the table holding the mappings + * + * @param tableDis the name of the table holding the distinct values + * @param tableMap the name of the table holding the mappings */ public void setFilterMappingTables(String tableDis, String tableMap); /** * Get the value which we are constraining all our browse results to contain. * - * @return the value to which to constrain results + * @return the value to which to constrain results */ public String getFilterValue(); @@ -344,7 +341,7 @@ public interface BrowseDAO * Get the name of the field in which the value to constrain results is * contained * - * @return the name of the field + * @return the name of the field */ public String getFilterValueField(); @@ -352,21 +349,21 @@ public interface BrowseDAO * Set he name of the field in which the value to constrain results is * contained * - * @param valueField the name of the field + * @param valueField the name of the field */ public void setFilterValueField(String valueField); /** * Set whether this is a distinct value browse or not * - * @param bool true if distinct value, false if not + * @param bool true if distinct value, false if not */ public void setDistinct(boolean bool); /** * Is this a distinct value browse? * - * @return true if distinct, false if not + * @return true if distinct, false if not */ public boolean isDistinct(); @@ -376,7 +373,7 @@ public interface BrowseDAO * the distinct value. Since we are in a container, this value will actually be * the view which allows us to select only items which are within a given container * - * @param containerTable the name of the container table mapping + * @param containerTable the name of the container table mapping */ public void setContainerTable(String containerTable); @@ -384,15 +381,19 @@ public interface BrowseDAO * Get the name of the container table that is being used to map items to distinct * values when in a container constrained browse * - * @return the name of the table + * @return the name of the table */ public String getContainerTable(); public void setAuthorityValue(String value); public String getAuthorityValue(); - + public boolean isEnableBrowseFrequencies(); - public void setEnableBrowseFrequencies(boolean enableBrowseFrequencies); + public void setEnableBrowseFrequencies(boolean enableBrowseFrequencies); + + public void setStartsWith(String startsWith); + + public String getStartsWith(); } diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowseDAOFactory.java b/dspace-api/src/main/java/org/dspace/browse/BrowseDAOFactory.java index 994404e55a..b8b3bbff94 100644 --- a/dspace-api/src/main/java/org/dspace/browse/BrowseDAOFactory.java +++ b/dspace-api/src/main/java/org/dspace/browse/BrowseDAOFactory.java @@ -12,38 +12,38 @@ import org.dspace.core.Context; /** * Factory class to generate DAOs based on the configuration - * - * @author Richard Jones * + * @author Richard Jones */ -public class BrowseDAOFactory -{ - /** - * Get an instance of the relevant Read Only DAO class, which will - * conform to the BrowseDAO interface - * - * @param context the DSpace context - * @return the relevant DAO - * @throws BrowseException if browse error - */ - public static BrowseDAO getInstance(Context context) - throws BrowseException - { - String className = ConfigurationManager.getProperty("browseDAO.class"); - if (className == null) - { - // SOLR implementation is the default since DSpace 4.0 +public class BrowseDAOFactory { + + /** + * Default constructor + */ + private BrowseDAOFactory() { } + + + /** + * Get an instance of the relevant Read Only DAO class, which will + * conform to the BrowseDAO interface + * + * @param context the DSpace context + * @return the relevant DAO + * @throws BrowseException if browse error + */ + public static BrowseDAO getInstance(Context context) + throws BrowseException { + String className = ConfigurationManager.getProperty("browseDAO.class"); + if (className == null) { + // SOLR implementation is the default since DSpace 4.0 return new SolrBrowseDAO(context); } - try - { + try { return (BrowseDAO) Class - .forName(ConfigurationManager.getProperty("browseDAO.class")) - .getConstructor(Context.class).newInstance(context); + .forName(ConfigurationManager.getProperty("browseDAO.class")) + .getConstructor(Context.class).newInstance(context); + } catch (Exception e) { + throw new BrowseException("The configuration for browseDAO is invalid: " + className, e); } - catch (Exception e) - { - throw new BrowseException("The configuration for browseDAO is invalid: "+className, e); - } - } + } } diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowseEngine.java b/dspace-api/src/main/java/org/dspace/browse/BrowseEngine.java index 6eb3096678..f7fb0b21ee 100644 --- a/dspace-api/src/main/java/org/dspace/browse/BrowseEngine.java +++ b/dspace-api/src/main/java/org/dspace/browse/BrowseEngine.java @@ -8,17 +8,18 @@ package org.dspace.browse; import java.sql.SQLException; -import java.util.List; import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.core.LogManager; -import org.dspace.sort.SortOption; import org.dspace.sort.OrderFormat; +import org.dspace.sort.SortOption; /** * This class does most of the actual grunt work of preparing a browse @@ -28,23 +29,31 @@ import org.dspace.sort.OrderFormat; * the results of the requested browse * * @author Richard Jones - * */ -public class BrowseEngine -{ - /** the logger for this class */ +public class BrowseEngine { + /** + * the logger for this class + */ private static final Logger log = Logger.getLogger(BrowseEngine.class); - /** the browse scope which is the basis for our browse */ + /** + * the browse scope which is the basis for our browse + */ private BrowserScope scope; - /** the DSpace context */ + /** + * the DSpace context + */ private final Context context; - /** The Data Access Object for the browse tables */ + /** + * The Data Access Object for the browse tables + */ private final BrowseDAO dao; - /** The Browse Index associated with the Browse Scope */ + /** + * The Browse Index associated with the Browse Scope + */ private BrowseIndex browseIndex; /** @@ -52,12 +61,11 @@ public class BrowseEngine * Context object. This will automatically assign a Data Access Object * for the Browse Engine, based on the brand of the provided DBMS. * - * @param context the DSpace context + * @param context the DSpace context * @throws BrowseException if browse error */ public BrowseEngine(Context context) - throws BrowseException - { + throws BrowseException { // set the context this.context = context; @@ -71,13 +79,12 @@ public class BrowseEngine * total number of results, the range, and information to construct * previous and next links on any web page * - * @param bs the scope of the browse - * @return the results of the browse + * @param bs the scope of the browse + * @return the results of the browse * @throws BrowseException if browse error */ public BrowseInfo browse(BrowserScope bs) - throws BrowseException - { + throws BrowseException { log.debug(LogManager.getHeader(context, "browse", "")); // first, load the browse scope into the object @@ -88,14 +95,11 @@ public class BrowseEngine browseIndex = scope.getBrowseIndex(); // now make the decision as to how to browse - if (browseIndex.isMetadataIndex() && !scope.isSecondLevel()) - { + if (browseIndex.isMetadataIndex() && !scope.isSecondLevel()) { // this is a single value browse type that has not gone to // the second level (i.e. authors, not items by a given author) return browseByValue(scope); - } - else - { + } else { // this is the full browse type or a browse that has gone to // the second level return browseByItem(scope); @@ -109,13 +113,12 @@ public class BrowseEngine * not currently support focus or values. This method is used, for example, * to generate the Recently Submitted Items results. * - * @param bs the scope of the browse - * @return the results of the browse + * @param bs the scope of the browse + * @return the results of the browse * @throws BrowseException if browse error */ public BrowseInfo browseMini(BrowserScope bs) - throws BrowseException - { + throws BrowseException { log.info(LogManager.getHeader(context, "browse_mini", "")); // load the scope into the object @@ -133,17 +136,13 @@ public class BrowseEngine // define a clause for the WHERE clause which will allow us to constrain // our browse to a specified community or collection - if (scope.inCollection() || scope.inCommunity()) - { - if (scope.inCollection()) - { + if (scope.inCollection() || scope.inCommunity()) { + if (scope.inCollection()) { Collection col = (Collection) scope.getBrowseContainer(); dao.setContainerTable("collection2item"); dao.setContainerIDField("collection_id"); dao.setContainerID(col.getID()); - } - else if (scope.inCommunity()) - { + } else if (scope.inCommunity()) { Community com = (Community) scope.getBrowseContainer(); dao.setContainerTable("communities2item"); dao.setContainerIDField("community_id"); @@ -156,8 +155,7 @@ public class BrowseEngine // assemble the ORDER BY clause String orderBy = browseIndex.getSortField(scope.isSecondLevel()); - if (scope.getSortBy() > 0) - { + if (scope.getSortBy() > 0) { orderBy = "sort_" + Integer.toString(scope.getSortBy()); } dao.setOrderField(orderBy); @@ -178,8 +176,7 @@ public class BrowseEngine browseInfo.setAscending(scope.isAscending()); // tell the browse info what the container for the browse was - if (scope.inCollection() || scope.inCommunity()) - { + if (scope.inCollection() || scope.inCommunity()) { browseInfo.setBrowseContainer(scope.getBrowseContainer()); } @@ -195,16 +192,14 @@ public class BrowseEngine * BrowseInfo object which contains full BrowseItem objects as its result * set. * - * @param bs the scope of the browse - * @return the results of the browse + * @param bs the scope of the browse + * @return the results of the browse * @throws BrowseException if browse error */ private BrowseInfo browseByItem(BrowserScope bs) - throws BrowseException - { + throws BrowseException { log.info(LogManager.getHeader(context, "browse_by_item", "")); - try - { + try { // get the table name that we are going to be getting our data from dao.setTable(browseIndex.getTableName()); @@ -213,27 +208,23 @@ public class BrowseEngine // assemble the value clause String rawValue = null; - if (scope.hasFilterValue() && scope.isSecondLevel()) - { + if (scope.hasFilterValue() && scope.isSecondLevel()) { String value = scope.getFilterValue(); rawValue = value; // make sure the incoming value is normalised value = OrderFormat.makeSortString(value, scope.getFilterValueLang(), - scope.getBrowseIndex().getDataType()); + scope.getBrowseIndex().getDataType()); dao.setAuthorityValue(scope.getAuthorityValue()); // set the values in the Browse Query - if (scope.isSecondLevel()) - { + if (scope.isSecondLevel()) { dao.setFilterValueField("value"); - dao.setFilterValue(rawValue); - } - else - { - dao.setFilterValueField("sort_value"); - dao.setFilterValue(value); + dao.setFilterValue(rawValue); + } else { + dao.setFilterValueField("sort_value"); + dao.setFilterValue(value); } dao.setFilterValuePartial(scope.getFilterValuePartial()); @@ -244,17 +235,13 @@ public class BrowseEngine // define a clause for the WHERE clause which will allow us to constrain // our browse to a specified community or collection - if (scope.inCollection() || scope.inCommunity()) - { - if (scope.inCollection()) - { + if (scope.inCollection() || scope.inCommunity()) { + if (scope.inCollection()) { Collection col = (Collection) scope.getBrowseContainer(); dao.setContainerTable("collection2item"); dao.setContainerIDField("collection_id"); dao.setContainerID(col.getID()); - } - else if (scope.inCommunity()) - { + } else if (scope.inCommunity()) { Community com = (Community) scope.getBrowseContainer(); dao.setContainerTable("communities2item"); dao.setContainerIDField("community_id"); @@ -267,16 +254,14 @@ public class BrowseEngine // assemble the ORDER BY clause String orderBy = browseIndex.getSortField(scope.isSecondLevel()); - if (scope.getSortBy() > 0) - { + if (scope.getSortBy() > 0) { orderBy = "sort_" + Integer.toString(scope.getSortBy()); } dao.setOrderField(orderBy); int offset = scope.getOffset(); String rawFocusValue = null; - if (offset < 1 && (scope.hasJumpToItem() || scope.hasJumpToValue() || scope.hasStartsWith())) - { + if (offset < 1 && (scope.hasJumpToItem() || scope.hasJumpToValue() || scope.hasStartsWith())) { // We need to convert these to an offset for the actual browse query. // First, get a value that we can look up in the ordering field rawFocusValue = getJumpToValue(); @@ -299,20 +284,17 @@ public class BrowseEngine List results = null; // Does this browse have any contents? - if (total > 0) - { + if (total > 0) { // now run the query results = dao.doQuery(); // now, if we don't have any results, we are at the end of the browse. This will // be because a starts_with value has been supplied for which we don't have // any items. - if (results.size() == 0) - { + if (results.size() == 0) { // In this case, we will calculate a new offset for the last page of results offset = total - scope.getResultsPerPage(); - if (offset < 0) - { + if (offset < 0) { offset = 0; } @@ -320,9 +302,7 @@ public class BrowseEngine dao.setOffset(offset); results = dao.doQuery(); } - } - else - { + } else { // No records, so make an empty list results = new ArrayList<>(); } @@ -331,13 +311,11 @@ public class BrowseEngine // BrowseInfo browseInfo = new BrowseInfo(results, position, total, offset); BrowseInfo browseInfo = new BrowseInfo(results, offset, total, offset); - if (offset + scope.getResultsPerPage() < total) - { + if (offset + scope.getResultsPerPage() < total) { browseInfo.setNextOffset(offset + scope.getResultsPerPage()); } - if (offset - scope.getResultsPerPage() > -1) - { + if (offset - scope.getResultsPerPage() > -1) { browseInfo.setPrevOffset(offset - scope.getResultsPerPage()); } @@ -362,8 +340,7 @@ public class BrowseEngine // set the focus value if there is one browseInfo.setFocus(rawFocusValue); - if (scope.hasJumpToItem()) - { + if (scope.hasJumpToItem()) { browseInfo.setFocusItem(scope.getJumpToItem()); } @@ -371,8 +348,7 @@ public class BrowseEngine browseInfo.setStartsWith(scope.hasStartsWith()); // tell the browse info what the container for the browse was - if (scope.inCollection() || scope.inCommunity()) - { + if (scope.inCollection() || scope.inCommunity()) { browseInfo.setBrowseContainer(scope.getBrowseContainer()); } @@ -381,9 +357,7 @@ public class BrowseEngine browseInfo.setEtAl(scope.getEtAl()); return browseInfo; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("caught exception: ", e); throw new BrowseException(e); } @@ -394,21 +368,20 @@ public class BrowseEngine * produces a BrowseInfo object that contains Strings as the results of * the browse * - * @param bs the scope of the browse - * @return the results of the browse + * @param bs the scope of the browse + * @return the results of the browse * @throws BrowseException if browse error */ private BrowseInfo browseByValue(BrowserScope bs) - throws BrowseException - { + throws BrowseException { log.info(LogManager.getHeader(context, "browse_by_value", "focus=" + bs.getJumpToValue())); - try - { + try { // get the table name that we are going to be getting our data from // this is the distinct table constrained to either community or collection dao.setTable(browseIndex.getDistinctTableName()); + dao.setStartsWith(StringUtils.lowerCase(scope.getStartsWith())); // remind the DAO that this is a distinct value browse, so it knows what sort // of query to build dao.setDistinct(true); @@ -418,29 +391,26 @@ public class BrowseEngine // inform dao about the display frequencies flag dao.setEnableBrowseFrequencies(browseIndex.isDisplayFrequencies()); - + // if we want to display frequencies, we need to pass the map table - if (browseIndex.isDisplayFrequencies()){ - dao.setFilterMappingTables(null, browseIndex.getMapTableName()); + if (browseIndex.isDisplayFrequencies()) { + dao.setFilterMappingTables(null, browseIndex.getMapTableName()); } - + // set our constraints on community or collection - if (scope.inCollection() || scope.inCommunity()) - { - // Scoped browsing of distinct metadata requires the mapping + if (scope.inCollection() || scope.inCommunity()) { + // Scoped browsing of distinct metadata requires the mapping // table to be specified. - if (!browseIndex.isDisplayFrequencies()) - dao.setFilterMappingTables(null, browseIndex.getMapTableName()); - - if (scope.inCollection()) - { + if (!browseIndex.isDisplayFrequencies()) { + dao.setFilterMappingTables(null, browseIndex.getMapTableName()); + } + + if (scope.inCollection()) { Collection col = (Collection) scope.getBrowseContainer(); dao.setContainerTable("collection2item"); dao.setContainerIDField("collection_id"); dao.setContainerID(col.getID()); - } - else if (scope.inCommunity()) - { + } else if (scope.inCommunity()) { Community com = (Community) scope.getBrowseContainer(); dao.setContainerTable("communities2item"); dao.setContainerIDField("community_id"); @@ -461,17 +431,8 @@ public class BrowseEngine dao.setJumpToField("sort_value"); int offset = scope.getOffset(); String rawFocusValue = null; - if (offset < 1 && scope.hasJumpToValue() || scope.hasStartsWith()) - { - String focusValue = getJumpToValue(); - - // store the value to tell the Browse Info object which value we are browsing on - rawFocusValue = focusValue; - - // make sure the incoming value is normalised - focusValue = normalizeJumpToValue(focusValue); - - offset = getOffsetForDistinctValue(focusValue); + if (offset < 1 && scope.hasJumpToValue() || scope.hasStartsWith()) { + rawFocusValue = getJumpToValue(); } @@ -483,20 +444,17 @@ public class BrowseEngine List results = null; // Does this browse have any contents? - if (total > 0) - { + if (total > 0) { // now run the query results = dao.doValueQuery(); // now, if we don't have any results, we are at the end of the browse. This will // be because a starts_with value has been supplied for which we don't have // any items. - if (results.size() == 0) - { + if (results.size() == 0) { // In this case, we will calculate a new offset for the last page of results offset = total - scope.getResultsPerPage(); - if (offset < 0) - { + if (offset < 0) { offset = 0; } @@ -504,9 +462,7 @@ public class BrowseEngine dao.setOffset(offset); results = dao.doValueQuery(); } - } - else - { + } else { // No records, so make an empty list results = new ArrayList(); } @@ -514,13 +470,11 @@ public class BrowseEngine // construct the BrowseInfo object to pass back BrowseInfo browseInfo = new BrowseInfo(results, offset, total, offset); - if (offset + scope.getResultsPerPage() < total) - { + if (offset + scope.getResultsPerPage() < total) { browseInfo.setNextOffset(offset + scope.getResultsPerPage()); } - if (offset - scope.getResultsPerPage() > -1) - { + if (offset - scope.getResultsPerPage() > -1) { browseInfo.setPrevOffset(offset - scope.getResultsPerPage()); } @@ -543,17 +497,14 @@ public class BrowseEngine browseInfo.setStartsWith(scope.hasStartsWith()); // tell the browse info what the container for the browse was - if (scope.inCollection() || scope.inCommunity()) - { + if (scope.inCollection() || scope.inCommunity()) { browseInfo.setBrowseContainer(scope.getBrowseContainer()); } browseInfo.setResultsPerPage(scope.getResultsPerPage()); return browseInfo; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("caught exception: ", e); throw new BrowseException(e); } @@ -562,24 +513,21 @@ public class BrowseEngine /** * Return the focus value. * - * @return the focus value to use + * @return the focus value to use * @throws BrowseException if browse error */ private String getJumpToValue() - throws BrowseException - { + throws BrowseException { log.debug(LogManager.getHeader(context, "get_focus_value", "")); // if the focus is by value, just return it - if (scope.hasJumpToValue()) - { + if (scope.hasJumpToValue()) { log.debug(LogManager.getHeader(context, "get_focus_value_return", "return=" + scope.getJumpToValue())); return scope.getJumpToValue(); } // if the focus is to start with, then we need to return the value of the starts with - if (scope.hasStartsWith()) - { + if (scope.hasStartsWith()) { log.debug(LogManager.getHeader(context, "get_focus_value_return", "return=" + scope.getStartsWith())); return scope.getStartsWith(); } @@ -600,17 +548,14 @@ public class BrowseEngine // to do comparisons in other columns. The use of the focus value needs to be consistent // across the browse SortOption so = scope.getSortOption(); - if (so == null || so.getNumber() == 0) - { - if (browseIndex.getSortOption() != null) - { + if (so == null || so.getNumber() == 0) { + if (browseIndex.getSortOption() != null) { so = browseIndex.getSortOption(); } } String col = "sort_1"; - if (so.getNumber() > 0) - { + if (so.getNumber() > 0) { col = "sort_" + Integer.toString(so.getNumber()); } @@ -629,29 +574,25 @@ public class BrowseEngine * Convert the value into an offset into the table for this browse * * @param value value - * @return the focus value to use + * @return the focus value to use * @throws BrowseException if browse error */ private int getOffsetForValue(String value) - throws BrowseException - { + throws BrowseException { // we need to make sure that we select from the correct column. If the sort option // is the 0th option then we use sort_value, but if it is one of the others we have // to select from that column instead. Otherwise, we end up missing the focus value // to do comparisons in other columns. The use of the focus value needs to be consistent // across the browse SortOption so = scope.getSortOption(); - if (so == null || so.getNumber() == 0) - { - if (browseIndex.getSortOption() != null) - { + if (so == null || so.getNumber() == 0) { + if (browseIndex.getSortOption() != null) { so = browseIndex.getSortOption(); } } String col = "sort_1"; - if (so.getNumber() > 0) - { + if (so.getNumber() > 0) { col = "sort_" + Integer.toString(so.getNumber()); } @@ -665,14 +606,12 @@ public class BrowseEngine * Convert the value into an offset into the table for this browse * * @param value value - * @return the focus value to use + * @return the focus value to use * @throws BrowseException if browse error */ private int getOffsetForDistinctValue(String value) - throws BrowseException - { - if (!browseIndex.isMetadataIndex()) - { + throws BrowseException { + if (!browseIndex.isMetadataIndex()) { throw new IllegalArgumentException("getOffsetForDistinctValue called when not a metadata index"); } @@ -687,20 +626,17 @@ public class BrowseEngine * return the focus value that is passed in. * * @param value a focus value to normalize - * @return the normalized focus value + * @return the normalized focus value * @throws BrowseException if browse error */ private String normalizeJumpToValue(String value) - throws BrowseException - { + throws BrowseException { // If the scope has a focus value (focus by value) - if (scope.hasJumpToValue()) - { + if (scope.hasJumpToValue()) { // Normalize it based on the specified language as appropriate for this index - return OrderFormat.makeSortString(scope.getJumpToValue(), scope.getJumpToValueLang(), scope.getBrowseIndex().getDataType()); - } - else if (scope.hasStartsWith()) - { + return OrderFormat.makeSortString(scope.getJumpToValue(), scope.getJumpToValueLang(), + scope.getBrowseIndex().getDataType()); + } else if (scope.hasStartsWith()) { // Scope has a starts with, so normalize that instead return OrderFormat.makeSortString(scope.getStartsWith(), null, scope.getBrowseIndex().getDataType()); } @@ -716,12 +652,11 @@ public class BrowseEngine * calling getTotalResults(false) * * @return total - * @throws SQLException if database error + * @throws SQLException if database error * @throws BrowseException if browse error */ private int getTotalResults() - throws SQLException, BrowseException - { + throws SQLException, BrowseException { return getTotalResults(false); } @@ -729,21 +664,20 @@ public class BrowseEngine * Get the total number of results. The argument determines whether this is a distinct * browse or not as this has an impact on how results are counted * - * @param distinct is this a distinct browse or not - * @return the total number of results available in this type of browse - * @throws SQLException if database error + * @param distinct is this a distinct browse or not + * @return the total number of results available in this type of browse + * @throws SQLException if database error * @throws BrowseException if browse error */ private int getTotalResults(boolean distinct) - throws SQLException, BrowseException - { + throws SQLException, BrowseException { log.debug(LogManager.getHeader(context, "get_total_results", "distinct=" + distinct)); // tell the browse query whether we are distinct dao.setDistinct(distinct); // ensure that the select is set to "*" - String[] select = { "*" }; + String[] select = {"*"}; dao.setCountValues(select); // FIXME: it would be nice to have a good way of doing this in the DAO @@ -760,7 +694,7 @@ public class BrowseEngine dao.setOrderField(null); dao.setLimit(-1); dao.setOffset(-1); - + // perform the query and get the result int count = dao.doCountQuery(); diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowseException.java b/dspace-api/src/main/java/org/dspace/browse/BrowseException.java index cb1f5ac0a5..0ccd61dec4 100644 --- a/dspace-api/src/main/java/org/dspace/browse/BrowseException.java +++ b/dspace-api/src/main/java/org/dspace/browse/BrowseException.java @@ -9,30 +9,25 @@ package org.dspace.browse; /** * Just a quick BrowseException class to give us the relevant data type - * + * * @author Richard Jones */ -public class BrowseException extends Exception -{ +public class BrowseException extends Exception { - public BrowseException() - { + public BrowseException() { super(); } - - public BrowseException(String message) - { + + public BrowseException(String message) { super(message); } - public BrowseException(String message, Throwable cause) - { - super(message, cause); - } + public BrowseException(String message, Throwable cause) { + super(message, cause); + } - public BrowseException(Throwable cause) - { - super(cause); - } + public BrowseException(Throwable cause) { + super(cause); + } } diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowseIndex.java b/dspace-api/src/main/java/org/dspace/browse/BrowseIndex.java index 0a39b9b748..334e651e1c 100644 --- a/dspace-api/src/main/java/org/dspace/browse/BrowseIndex.java +++ b/dspace-api/src/main/java/org/dspace/browse/BrowseIndex.java @@ -14,55 +14,78 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.dspace.core.ConfigurationManager; -import org.dspace.sort.SortOption; import org.dspace.sort.SortException; +import org.dspace.sort.SortOption; /** - * This class holds all the information about a specifically configured + * This class holds all the information about a specifically configured * BrowseIndex. It is responsible for parsing the configuration, understanding * about what sort options are available, and what the names of the database * tables that hold all the information are actually called. - * + * * @author Richard Jones */ -public final class BrowseIndex -{ - /** the configuration number, as specified in the config */ - /** used for single metadata browse tables for generating the table name */ +public final class BrowseIndex { + /** the configuration number, as specified in the config */ + /** + * used for single metadata browse tables for generating the table name + */ private int number; - - /** the name of the browse index, as specified in the config */ + + /** + * the name of the browse index, as specified in the config + */ private String name; - /** the SortOption for this index (only valid for item indexes) */ + /** + * the SortOption for this index (only valid for item indexes) + */ private SortOption sortOption; - /** the value of the metadata, as specified in the config */ + /** + * the value of the metadata, as specified in the config + */ private String metadataAll; - /** the metadata fields, as an array */ + /** + * the metadata fields, as an array + */ private String[] metadata; - /** the datatype of the index, as specified in the config */ + /** + * the datatype of the index, as specified in the config + */ private String datatype; - - /** the display type of the metadata, as specified in the config */ + + /** + * the display type of the metadata, as specified in the config + */ private String displayType; - - /** base name for tables, sequences */ + + /** + * base name for tables, sequences + */ private String tableBaseName; - - /** a three part array of the metadata bits (e.g. dc.contributor.author) */ + + /** + * a three part array of the metadata bits (e.g. dc.contributor.author) + */ private String[][] mdBits; - /** default order (asc / desc) for this index */ + /** + * default order (asc / desc) for this index + */ private String defaultOrder = SortOption.ASCENDING; - - /** whether to display frequencies or not, in case of a "metadata" browse index*/ + + /** + * whether to display frequencies or not, in case of a "metadata" browse index + */ private boolean displayFrequencies = true; - /** additional 'internal' tables that are always defined */ - private static BrowseIndex itemIndex = new BrowseIndex("bi_item"); + /** + * additional 'internal' tables that are always defined + */ + private static BrowseIndex itemIndex = new BrowseIndex("bi_item"); private static BrowseIndex withdrawnIndex = new BrowseIndex("bi_withdrawn"); private static BrowseIndex privateIndex = new BrowseIndex("bi_private"); @@ -70,65 +93,59 @@ public final class BrowseIndex /** * Ensure no one else can create these */ - private BrowseIndex() - { + private BrowseIndex() { } - + /** * Constructor for creating generic / internal index objects + * * @param baseName The base of the table name */ - private BrowseIndex(String baseName) - { - try - { + private BrowseIndex(String baseName) { + try { number = -1; tableBaseName = baseName; displayType = "item"; sortOption = SortOption.getDefaultSortOption(); - } - catch (SortException se) - { + } catch (SortException se) { // FIXME Exception handling } } - + /** * Create a new BrowseIndex object using the definition from the configuration, * and the number of the configuration option. The definition should follow * one of the following forms: - * + * * * [name]:item:[sort option]:[order] * - * + * * or - * + * * * [name]:metadata:[metadata]:[data type]:[order]:[sort option] * - * + * * [name] is a freetext name for the field * item or metadata defines the display type * [metadata] is the usual format of the metadata such as dc.contributor.author * [sort option] is the name of a separately defined sort option * [order] must be either asc or desc * [data type] must be either "title", "date" or "text" - * + * * If you use the first form (to define an index of type item), the order * is facultative. If you use the second form (for type metadata), the order - * and sort option are facultative, but you must configure the order if you + * and sort option are facultative, but you must configure the order if you * want to configure the sort option. - * - * @param definition the configuration definition of this index - * @param number the configuration number of this index + * + * @param definition the configuration definition of this index + * @param number the configuration number of this index * @throws BrowseException if browse error */ private BrowseIndex(String definition, int number) - throws BrowseException - { - try - { + throws BrowseException { + try { boolean valid = true; this.defaultOrder = SortOption.ASCENDING; this.number = number; @@ -137,51 +154,40 @@ public final class BrowseIndex Pattern pattern = Pattern.compile(rx); Matcher matcher = pattern.matcher(definition); - if (matcher.matches()) - { + if (matcher.matches()) { name = matcher.group(1); displayType = matcher.group(2); - if (isMetadataIndex()) - { + if (isMetadataIndex()) { metadataAll = matcher.group(3); datatype = matcher.group(4); - if (metadataAll != null) - { + if (metadataAll != null) { metadata = metadataAll.split(","); } - if (metadata == null || metadata.length == 0) - { + if (metadata == null || metadata.length == 0) { valid = false; } - if (datatype == null || datatype.equals("")) - { + if (datatype == null || datatype.equals("")) { valid = false; } // If an optional ordering configuration is supplied, // set the defaultOrder appropriately (asc or desc) - if (matcher.groupCount() > 4) - { + if (matcher.groupCount() > 4) { String order = matcher.group(5); - if (SortOption.DESCENDING.equalsIgnoreCase(order)) - { + if (SortOption.DESCENDING.equalsIgnoreCase(order)) { this.defaultOrder = SortOption.DESCENDING; } } - - if (matcher.groupCount() > 5) - { + + if (matcher.groupCount() > 5) { String sortName = matcher.group(6).trim(); - if (sortName.length() > 0) - { - for (SortOption so : SortOption.getSortOptions()) - { - if (so.getName().equals(sortName)) - { + if (sortName.length() > 0) { + for (SortOption so : SortOption.getSortOptions()) { + if (so.getName().equals(sortName)) { sortOption = so; } } @@ -189,64 +195,49 @@ public final class BrowseIndex // for backward compatability we ignore the keywords // single and full here if (!sortName.equalsIgnoreCase("single") - && !sortName.equalsIgnoreCase("full") - && sortOption == null) - { + && !sortName.equalsIgnoreCase("full") + && sortOption == null) { valid = false; } } } tableBaseName = getItemBrowseIndex().tableBaseName; - } - else if (isItemIndex()) - { + } else if (isItemIndex()) { String sortName = matcher.group(3); - for (SortOption so : SortOption.getSortOptions()) - { - if (so.getName().equals(sortName)) - { + for (SortOption so : SortOption.getSortOptions()) { + if (so.getName().equals(sortName)) { sortOption = so; } } - if (sortOption == null) - { + if (sortOption == null) { valid = false; } // If an optional ordering configuration is supplied, // set the defaultOrder appropriately (asc or desc) - if (matcher.groupCount() > 3) - { + if (matcher.groupCount() > 3) { String order = matcher.group(4); - if (SortOption.DESCENDING.equalsIgnoreCase(order)) - { + if (SortOption.DESCENDING.equalsIgnoreCase(order)) { this.defaultOrder = SortOption.DESCENDING; } } tableBaseName = getItemBrowseIndex().tableBaseName; - } - else - { + } else { valid = false; } - } - else - { + } else { valid = false; } - if (!valid) - { + if (!valid) { throw new BrowseException("Browse Index configuration is not valid: webui.browse.index." + - number + " = " + definition); + number + " = " + definition); } - } - catch (SortException se) - { + } catch (SortException se) { throw new BrowseException("Error in SortOptions", se); } } @@ -254,39 +245,33 @@ public final class BrowseIndex /** * @return Default order for this index, null if not specified */ - public String getDefaultOrder() - { + public String getDefaultOrder() { return defaultOrder; } /** - * @return Returns the datatype. - */ - public String getDataType() - { - if (sortOption != null) - { + * @return Returns the datatype. + */ + public String getDataType() { + if (sortOption != null) { return sortOption.getType(); } - return datatype; - } + return datatype; + } - /** - * @return Returns the displayType. - */ - public String getDisplayType() - { + /** + * @return Returns the displayType. + */ + public String getDisplayType() { return displayType; - } + } /** * @return Returns the number of metadata fields for this index */ - public int getMetadataCount() - { - if (isMetadataIndex()) - { + public int getMetadataCount() { + if (isMetadataIndex()) { return metadata.length; } @@ -295,450 +280,403 @@ public final class BrowseIndex /** * @param idx index - * @return Returns the mdBits. - */ - public String[] getMdBits(int idx) - { - if (isMetadataIndex()) - { + * @return Returns the mdBits. + */ + public String[] getMdBits(int idx) { + if (isMetadataIndex()) { return mdBits[idx]; } - - return null; - } - /** - * @return Returns the metadata. - */ - public String getMetadata() - { - return metadataAll; - } + return null; + } + + /** + * @return Returns the metadata. + */ + public String getMetadata() { + return metadataAll; + } /** - * * @param idx index * @return metadata */ - public String getMetadata(int idx) - { + public String getMetadata(int idx) { return metadata[idx]; } - /** - * @return Returns the name. - */ - public String getName() - { - return name; - } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } - /** - * @param name The name to set. - */ -// public void setName(String name) -// { -// this.name = name; -// } - - /** - * Get the SortOption associated with this index. - * @return SortOption - */ - public SortOption getSortOption() - { - return sortOption; - } - - /** - * - * @return true or false - */ - public boolean isDisplayFrequencies() { - return displayFrequencies; - } + /** + * @param name The name to set. + */ +// public void setName(String name) +// { +// this.name = name; +// } - /** - * Populate the internal array containing the bits of metadata, for - * ease of use later - */ - public void generateMdBits() - { - try - { - if (isMetadataIndex()) - { + /** + * Get the SortOption associated with this index. + * + * @return SortOption + */ + public SortOption getSortOption() { + return sortOption; + } + + /** + * @return true or false + */ + public boolean isDisplayFrequencies() { + return displayFrequencies; + } + + /** + * Populate the internal array containing the bits of metadata, for + * ease of use later + */ + public void generateMdBits() { + try { + if (isMetadataIndex()) { mdBits = new String[metadata.length][]; - for (int i = 0; i < metadata.length; i++) - { + for (int i = 0; i < metadata.length; i++) { mdBits[i] = interpretField(metadata[i], null); } } + } catch (IOException e) { + // it's not obvious what we really ought to do here + //log.error("caught exception: ", e); } - catch(IOException e) - { - // it's not obvious what we really ought to do here - //log.error("caught exception: ", e); - } } - - /** - * Get the name of the sequence that will be used in the given circumstances - * - * @param isDistinct is a distinct table - * @param isMap is a map table - * @return the name of the sequence - */ - public String getSequenceName(boolean isDistinct, boolean isMap) - { - if (isDistinct || isMap) - { - return BrowseIndex.getSequenceName(number, isDistinct, isMap); - } - - return BrowseIndex.getSequenceName(tableBaseName, isDistinct, isMap); - } - + /** * Get the name of the sequence that will be used in the given circumstances - * - * @param number the index configuration number - * @param isDistinct is a distinct table - * @param isMap is a map table - * @return the name of the sequence + * + * @param isDistinct is a distinct table + * @param isMap is a map table + * @return the name of the sequence */ - public static String getSequenceName(int number, boolean isDistinct, boolean isMap) - { + public String getSequenceName(boolean isDistinct, boolean isMap) { + if (isDistinct || isMap) { + return BrowseIndex.getSequenceName(number, isDistinct, isMap); + } + + return BrowseIndex.getSequenceName(tableBaseName, isDistinct, isMap); + } + + /** + * Get the name of the sequence that will be used in the given circumstances + * + * @param number the index configuration number + * @param isDistinct is a distinct table + * @param isMap is a map table + * @return the name of the sequence + */ + public static String getSequenceName(int number, boolean isDistinct, boolean isMap) { return BrowseIndex.getSequenceName(makeTableBaseName(number), isDistinct, isMap); } - + /** * Generate a sequence name from the given base + * * @param baseName * @param isDistinct * @param isMap * @return */ - private static String getSequenceName(String baseName, boolean isDistinct, boolean isMap) - { - if (isDistinct) - { + private static String getSequenceName(String baseName, boolean isDistinct, boolean isMap) { + if (isDistinct) { baseName = baseName + "_dis"; - } - else if (isMap) - { + } else if (isMap) { baseName = baseName + "_dmap"; } - + baseName = baseName + "_seq"; - + return baseName; } - + /** * Get the name of the table for the given set of circumstances * This is provided solely for cleaning the database, where you are * trying to create table names that may not be reflected in the current index - * - * @param number the index configuration number - * @param isCommunity whether this is a community constrained index (view) - * @param isCollection whether this is a collection constrained index (view) - * @param isDistinct whether this is a distinct table - * @param isMap whether this is a distinct map table - * @return the name of the table + * + * @param number the index configuration number + * @param isCommunity whether this is a community constrained index (view) + * @param isCollection whether this is a collection constrained index (view) + * @param isDistinct whether this is a distinct table + * @param isMap whether this is a distinct map table + * @return the name of the table * @deprecated 1.5 */ - public static String getTableName(int number, boolean isCommunity, boolean isCollection, boolean isDistinct, boolean isMap) - { + public static String getTableName(int number, boolean isCommunity, boolean isCollection, boolean isDistinct, + boolean isMap) { return BrowseIndex.getTableName(makeTableBaseName(number), isCommunity, isCollection, isDistinct, isMap); } - + /** * Generate a table name from the given base - * @param baseName base name - * @param isCommunity whether this is a community constrained index (view) - * @param isCollection whether this is a collection constrained index (view) - * @param isDistinct whether this is a distinct table - * @param isMap whether this is a distinct map table + * + * @param baseName base name + * @param isCommunity whether this is a community constrained index (view) + * @param isCollection whether this is a collection constrained index (view) + * @param isDistinct whether this is a distinct table + * @param isMap whether this is a distinct map table * @return table name */ - private static String getTableName(String baseName, boolean isCommunity, boolean isCollection, boolean isDistinct, boolean isMap) - { - // isDistinct is meaningless in relation to isCommunity and isCollection - // so we bounce that back first, ignoring other arguments - if (isDistinct) - { - return baseName + "_dis"; - } - - // isCommunity and isCollection are mutually exclusive - if (isCommunity) - { - baseName = baseName + "_com"; - } - else if (isCollection) - { - baseName = baseName + "_col"; - } - - // isMap is additive to isCommunity and isCollection - if (isMap) - { - baseName = baseName + "_dmap"; - } - - return baseName; + private static String getTableName(String baseName, boolean isCommunity, boolean isCollection, boolean isDistinct, + boolean isMap) { + // isDistinct is meaningless in relation to isCommunity and isCollection + // so we bounce that back first, ignoring other arguments + if (isDistinct) { + return baseName + "_dis"; + } + + // isCommunity and isCollection are mutually exclusive + if (isCommunity) { + baseName = baseName + "_com"; + } else if (isCollection) { + baseName = baseName + "_col"; + } + + // isMap is additive to isCommunity and isCollection + if (isMap) { + baseName = baseName + "_dmap"; + } + + return baseName; } - + /** * Get the name of the table in the given circumstances - * - * @param isCommunity whether this is a community constrained index (view) - * @param isCollection whether this is a collection constrained index (view) - * @param isDistinct whether this is a distinct table - * @param isMap whether this is a distinct map table - * @return the name of the table + * + * @param isCommunity whether this is a community constrained index (view) + * @param isCollection whether this is a collection constrained index (view) + * @param isDistinct whether this is a distinct table + * @param isMap whether this is a distinct map table + * @return the name of the table * @deprecated 1.5 */ - public String getTableName(boolean isCommunity, boolean isCollection, boolean isDistinct, boolean isMap) - { - if (isDistinct || isMap) - { + public String getTableName(boolean isCommunity, boolean isCollection, boolean isDistinct, boolean isMap) { + if (isDistinct || isMap) { return BrowseIndex.getTableName(number, isCommunity, isCollection, isDistinct, isMap); } - + return BrowseIndex.getTableName(tableBaseName, isCommunity, isCollection, isDistinct, isMap); } - + /** * Get the name of the table in the given circumstances. This is the same as calling - * + * * * getTableName(isCommunity, isCollection, false, false); * - * - * @param isCommunity whether this is a community constrained index (view) - * @param isCollection whether this is a collection constrained index (view) - * @return the name of the table + * + * @param isCommunity whether this is a community constrained index (view) + * @param isCollection whether this is a collection constrained index (view) + * @return the name of the table * @deprecated 1.5 */ - public String getTableName(boolean isCommunity, boolean isCollection) - { + public String getTableName(boolean isCommunity, boolean isCollection) { return getTableName(isCommunity, isCollection, false, false); } - + /** * Get the default index table name. This is the same as calling - * + * * * getTableName(false, false, false, false); * - * + * * @return table name */ - public String getTableName() - { + public String getTableName() { return getTableName(false, false, false, false); } - + /** * Get the table name for the given set of circumstances. - * + * * This is the same as calling: - * + * * * getTableName(isCommunity, isCollection, isDistinct, false); * - * - * @param isCommunity whether this is a community constrained index (view) - * @param isCollection whether this is a collection constrained index (view) - * @param isDistinct whether this is a distinct table - * @deprecated 1.5 + * + * @param isCommunity whether this is a community constrained index (view) + * @param isCollection whether this is a collection constrained index (view) + * @param isDistinct whether this is a distinct table * @return table name + * @deprecated 1.5 */ - public String getTableName(boolean isDistinct, boolean isCommunity, boolean isCollection) - { - return getTableName(isCommunity, isCollection, isDistinct, false); + public String getTableName(boolean isDistinct, boolean isCommunity, boolean isCollection) { + return getTableName(isCommunity, isCollection, isDistinct, false); } - + /** * Get the default name of the distinct map table. This is the same as calling - * + * * * getTableName(false, false, false, true); * + * * @return table name */ - public String getMapTableName() - { - return getTableName(false, false, false, true); + public String getMapTableName() { + return getTableName(false, false, false, true); } - + /** * Get the default name of the distinct table. This is the same as calling * * * getTableName(false, false, true, false); * + * * @return table name */ - public String getDistinctTableName() - { - return getTableName(false, false, true, false); + public String getDistinctTableName() { + return getTableName(false, false, true, false); } /** * Get the name of the column that is used to store the default value column - * - * @return the name of the value column + * + * @return the name of the value column */ - public String getValueColumn() - { - if (!isDate()) - { + public String getValueColumn() { + if (!isDate()) { return "sort_text_value"; - } - else - { + } else { return "text_value"; } } - + /** * Get the name of the primary key index column - * - * @return the name of the primary key index column + * + * @return the name of the primary key index column */ - public String getIndexColumn() - { + public String getIndexColumn() { return "id"; } - + /** * Is this browse index type for a title? - * - * @return true if title type, false if not + * + * @return true if title type, false if not */ // public boolean isTitle() // { // return "title".equals(getDataType()); // } - + /** * Is the browse index type for a date? - * - * @return true if date type, false if not + * + * @return true if date type, false if not */ - public boolean isDate() - { + public boolean isDate() { return "date".equals(getDataType()); } - + /** * Is the browse index type for a plain text type? - * - * @return true if plain text type, false if not + * + * @return true if plain text type, false if not */ // public boolean isText() // { // return "text".equals(getDataType()); // } - + /** * Is the browse index of display type single? - * + * * @return true if singe, false if not */ - public boolean isMetadataIndex() - { - return displayType != null && displayType.startsWith("metadata"); + public boolean isMetadataIndex() { + return displayType != null && displayType.startsWith("metadata"); } - + /** * Is the browse index authority value? * * @return true if authority, false if not */ - public boolean isAuthorityIndex() - { + public boolean isAuthorityIndex() { return "metadataAuthority".equals(displayType); } - + /** * Is the browse index of display type full? - * - * @return true if full, false if not + * + * @return true if full, false if not */ - public boolean isItemIndex() - { + public boolean isItemIndex() { return "item".equals(displayType); } - + /** * Get the field for sorting associated with this index. + * * @param isSecondLevel whether second level browse * @return sort field * @throws BrowseException if browse error */ - public String getSortField(boolean isSecondLevel) throws BrowseException - { + public String getSortField(boolean isSecondLevel) throws BrowseException { String focusField; - if (isMetadataIndex() && !isSecondLevel) - { + if (isMetadataIndex() && !isSecondLevel) { focusField = "sort_value"; - } - else - { - if (sortOption != null) - { + } else { + if (sortOption != null) { focusField = "sort_" + sortOption.getNumber(); - } - else - { + } else { focusField = "sort_1"; // Use the first sort column } } - + return focusField; } - + /** * @return array of tables - * @deprecated * @throws BrowseException if browse error + * @deprecated */ public static String[] tables() - throws BrowseException - { + throws BrowseException { BrowseIndex[] bis = getBrowseIndices(); String[] returnTables = new String[bis.length]; - for (int i = 0; i < bis.length; i++) - { + for (int i = 0; i < bis.length; i++) { returnTables[i] = bis[i].getTableName(); } return returnTables; } - + /** * Get an array of all the browse indices for the current configuration - * - * @return an array of all the current browse indices + * + * @return an array of all the current browse indices * @throws BrowseException if browse error */ public static BrowseIndex[] getBrowseIndices() - throws BrowseException - { + throws BrowseException { int idx = 1; String definition; ArrayList browseIndices = new ArrayList(); - while ( ((definition = ConfigurationManager.getProperty("webui.browse.index." + idx))) != null) - { + while (((definition = ConfigurationManager.getProperty("webui.browse.index." + idx))) != null) { BrowseIndex bi = new BrowseIndex(definition, idx); - bi.displayFrequencies = Boolean.valueOf(ConfigurationManager - .getBooleanProperty("webui.browse.metadata.show-freq." - + idx, true)); + bi.displayFrequencies = Boolean.valueOf(ConfigurationManager + .getBooleanProperty("webui.browse.metadata.show-freq." + + idx, true)); browseIndices.add(bi); idx++; @@ -754,129 +692,120 @@ public final class BrowseIndex * Get the browse index from configuration with the specified name. * The name is the first part of the browse configuration * - * @param name the name to retrieve - * @return the specified browse index + * @param name the name to retrieve + * @return the specified browse index * @throws BrowseException if browse error */ public static BrowseIndex getBrowseIndex(String name) - throws BrowseException - { - for (BrowseIndex bix : BrowseIndex.getBrowseIndices()) - { - if (bix.getName().equals(name)) - { + throws BrowseException { + for (BrowseIndex bix : BrowseIndex.getBrowseIndices()) { + if (bix.getName().equals(name)) { return bix; } } - + return null; } - + /** * Get the configured browse index that is defined to use this sort option. - * + * * @param so sort option * @return browse index * @throws BrowseException if browse error */ - public static BrowseIndex getBrowseIndex(SortOption so) throws BrowseException - { - for (BrowseIndex bix : BrowseIndex.getBrowseIndices()) - { - if (bix.getSortOption() == so) - { + public static BrowseIndex getBrowseIndex(SortOption so) throws BrowseException { + for (BrowseIndex bix : BrowseIndex.getBrowseIndices()) { + if (bix.getSortOption() == so) { return bix; } } - + return null; } - + /** * Get the internally defined browse index for archived items. + * * @return browse index */ - public static BrowseIndex getItemBrowseIndex() - { + public static BrowseIndex getItemBrowseIndex() { return BrowseIndex.itemIndex; } - + /** * Get the internally defined browse index for withdrawn items. + * * @return browse index */ - public static BrowseIndex getWithdrawnBrowseIndex() - { + public static BrowseIndex getWithdrawnBrowseIndex() { return BrowseIndex.withdrawnIndex; } /** * @return browse index */ - public static BrowseIndex getPrivateBrowseIndex() - { + public static BrowseIndex getPrivateBrowseIndex() { return BrowseIndex.privateIndex; } - + /** * Take a string representation of a metadata field, and return it as an array. - * This is just a convenient utility method to basically break the metadata + * This is just a convenient utility method to basically break the metadata * representation up by its delimiter (.), and stick it in an array, inserting * the value of the init parameter when there is no metadata field part. - * - * @param mfield the string representation of the metadata - * @param init the default value of the array elements - * @return a three element array with schema, element and qualifier respectively + * + * @param mfield the string representation of the metadata + * @param init the default value of the array elements + * @return a three element array with schema, element and qualifier respectively * @throws IOException if IO error */ public String[] interpretField(String mfield, String init) - throws IOException - { - StringTokenizer sta = new StringTokenizer(mfield, "."); - String[] field = {init, init, init}; - - int i = 0; - while (sta.hasMoreTokens()) - { - field[i++] = sta.nextToken(); - } - - // error checks to make sure we have at least a schema and qualifier for both - if (field[0] == null || field[1] == null) - { - throw new IOException("at least a schema and element be " + - "specified in configuration. You supplied: " + mfield); - } - - return field; + throws IOException { + StringTokenizer sta = new StringTokenizer(mfield, "."); + String[] field = {init, init, init}; + + int i = 0; + while (sta.hasMoreTokens()) { + field[i++] = sta.nextToken(); + } + + // error checks to make sure we have at least a schema and qualifier for both + if (field[0] == null || field[1] == null) { + throw new IOException("at least a schema and element be " + + "specified in configuration. You supplied: " + mfield); + } + + return field; } /** * Does this browse index represent one of the internal item indexes? + * * @return true or false */ - public boolean isInternalIndex() - { + public boolean isInternalIndex() { return (this == itemIndex || this == withdrawnIndex || this == privateIndex); } /** * Generate a base table name. + * * @param number index number * @return table name */ - private static String makeTableBaseName(int number) - { + private static String makeTableBaseName(int number) { return "bi_" + Integer.toString(number); } /** * Is tag cloud enabled + * * @return true or false */ - public boolean isTagCloudEnabled() { - - return ConfigurationManager.getBooleanProperty("webui.browse.index.tagcloud." + number); - - } + public boolean isTagCloudEnabled() { + + return ConfigurationManager.getBooleanProperty("webui.browse.index.tagcloud." + number); + + } } diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowseInfo.java b/dspace-api/src/main/java/org/dspace/browse/BrowseInfo.java index 42b1b5d725..5c71ae730b 100644 --- a/dspace-api/src/main/java/org/dspace/browse/BrowseInfo.java +++ b/dspace-api/src/main/java/org/dspace/browse/BrowseInfo.java @@ -12,7 +12,11 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.sort.SortOption; @@ -24,8 +28,7 @@ import org.dspace.sort.SortOption; * * @author Richard Jones */ -public class BrowseInfo -{ +public class BrowseInfo { /** * The results of the browse. * FIXME: Unable to generify due to mixed usage @@ -54,49 +57,79 @@ public class BrowseInfo */ private boolean cached; - /** the browse index to which this pertains */ + /** + * the browse index to which this pertains + */ private BrowseIndex browseIndex; - /** the sort option being used */ + /** + * the sort option being used + */ private SortOption sortOption; - /** is the browse ascending or descending */ + /** + * is the browse ascending or descending + */ private boolean ascending; - /** what level of browse are we in? full and single front pages are 0, single value browse is 1 */ + /** + * what level of browse are we in? full and single front pages are 0, single value browse is 1 + */ private int level = 0; - /** the value browsed upon */ + /** + * the value browsed upon + */ private String value; - /** the authority key browsed upon */ + /** + * the authority key browsed upon + */ private String authority; - /** is this a "starts_with" browse? */ + /** + * is this a "starts_with" browse? + */ private boolean startsWith = false; - /** Collection we are constrained to */ + /** + * Collection we are constrained to + */ private Collection collection; - /** Community we are constrained to */ + /** + * Community we are constrained to + */ private Community community; - /** offset of the item at the top of the next page */ + /** + * offset of the item at the top of the next page + */ private int nextOffset = -1; - /** offset of the item at the top of the previous page */ + /** + * offset of the item at the top of the previous page + */ private int prevOffset = -1; - /** the value upon which we are focusing */ + /** + * the value upon which we are focusing + */ private String focus; - /** number of results to display per page */ + /** + * number of results to display per page + */ private int resultsPerPage = -1; - /** database id of the item upon which we are focusing */ + /** + * database id of the item upon which we are focusing + */ private int focusItem = -1; - /** number of metadata elements to display before truncating using "et al" */ + /** + * number of metadata elements to display before truncating using "et al" + */ private int etAl = -1; protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); @@ -105,19 +138,13 @@ public class BrowseInfo * Constructor * FIXME: Unable to generify due to mixed usage * - * @param results - * A List of Browse results - * @param overallPosition - * The position of the first returned item in the overall index - * @param total - * The total number of items in the index - * @param offset - * The position of the requested item in the set of results + * @param results A List of Browse results + * @param overallPosition The position of the first returned item in the overall index + * @param total The total number of items in the index + * @param offset The position of the requested item in the set of results */ - public BrowseInfo(List results, int overallPosition, int total, int offset) - { - if (results == null) - { + public BrowseInfo(List results, int overallPosition, int total, int offset) { + if (results == null) { throw new IllegalArgumentException("Null result list not allowed"); } @@ -128,37 +155,32 @@ public class BrowseInfo } /** - * @return the number of metadata fields at which to truncate with "et al" + * @return the number of metadata fields at which to truncate with "et al" */ - public int getEtAl() - { + public int getEtAl() { return etAl; } /** * set the number of metadata fields at which to truncate with "et al" * - * @param etAl - * the number of metadata fields at which to truncate with "et al" + * @param etAl the number of metadata fields at which to truncate with "et al" */ - public void setEtAl(int etAl) - { + public void setEtAl(int etAl) { this.etAl = etAl; } /** * @return Returns the focusItem. */ - public int getFocusItem() - { + public int getFocusItem() { return focusItem; } /** * @param focusItem The focusItem to set. */ - public void setFocusItem(int focusItem) - { + public void setFocusItem(int focusItem) { this.focusItem = focusItem; } @@ -166,12 +188,10 @@ public class BrowseInfo * Does this browse have an item focus (as opposed to one of: no focus, * a value focus) * - * @return true if item focus, false if not + * @return true if item focus, false if not */ - public boolean hasItemFocus() - { - if (focusItem == -1) - { + public boolean hasItemFocus() { + if (focusItem == -1) { return false; } return true; @@ -180,28 +200,24 @@ public class BrowseInfo /** * @return Returns the resultsPerPage. */ - public int getResultsPerPage() - { + public int getResultsPerPage() { return resultsPerPage; } /** * @param resultsPerPage The resultsPerPage to set. */ - public void setResultsPerPage(int resultsPerPage) - { + public void setResultsPerPage(int resultsPerPage) { this.resultsPerPage = resultsPerPage; } /** * Is there a value associated with this browse * - * @return true if a value, false if not + * @return true if a value, false if not */ - public boolean hasValue() - { - if (this.value != null) - { + public boolean hasValue() { + if (this.value != null) { return true; } return false; @@ -210,12 +226,10 @@ public class BrowseInfo /** * Is there an authority key associated with this browse * - * @return true if an authority key, false if not + * @return true if an authority key, false if not */ - public boolean hasAuthority() - { - if (this.authority != null) - { + public boolean hasAuthority() { + if (this.authority != null) { return true; } return false; @@ -224,30 +238,26 @@ public class BrowseInfo /** * Are there results for this browse, or was the result set empty? * - * @return true if results, false if not + * @return true if results, false if not */ - public boolean hasResults() - { - if (results.size() > 0) - { + public boolean hasResults() { + if (results.size() > 0) { return true; } return false; } /** - * @param focus the value to focus the browse around + * @param focus the value to focus the browse around */ - public void setFocus(String focus) - { + public void setFocus(String focus) { this.focus = focus; } /** - * @return the value to focus the browse around + * @return the value to focus the browse around */ - public String getFocus() - { + public String getFocus() { return this.focus; } @@ -256,22 +266,16 @@ public class BrowseInfo * is not of type Collection or Community, this method will throw an * exception * - * @param dso the container object; a Community or Collection + * @param dso the container object; a Community or Collection * @throws BrowseException if browse error */ public void setBrowseContainer(DSpaceObject dso) - throws BrowseException - { - if (dso instanceof Collection) - { + throws BrowseException { + if (dso instanceof Collection) { this.collection = (Collection) dso; - } - else if (dso instanceof Community) - { + } else if (dso instanceof Community) { this.community = (Community) dso; - } - else - { + } else { throw new BrowseException("The container must be a community or a collection"); } } @@ -280,162 +284,141 @@ public class BrowseInfo * Obtain a DSpaceObject that represents the container object. This will be * a Community or a Collection * - * @return A DSpaceObject representing a Community or a Collection + * @return A DSpaceObject representing a Community or a Collection */ - public DSpaceObject getBrowseContainer() - { - if (this.collection != null) - { + public DSpaceObject getBrowseContainer() { + if (this.collection != null) { return this.collection; } - if (this.community != null) - { + if (this.community != null) { return this.community; } return null; } /** - * @param level the browse level + * @param level the browse level */ - public void setBrowseLevel(int level) - { + public void setBrowseLevel(int level) { this.level = level; } /** - * @return the browse level + * @return the browse level */ - public int getBrowseLevel() - { + public int getBrowseLevel() { return this.level; } /** - * @param offset the database id of the item at the top of the next page + * @param offset the database id of the item at the top of the next page */ - public void setNextOffset(int offset) - { + public void setNextOffset(int offset) { this.nextOffset = offset; } /** - * @return the database id of the item at the top of the next page + * @return the database id of the item at the top of the next page */ - public int getNextOffset() - { + public int getNextOffset() { return this.nextOffset; } - /** + /** * @return Returns the ascending. */ - public boolean isAscending() - { + public boolean isAscending() { return ascending; } /** * @param ascending The ascending to set. */ - public void setAscending(boolean ascending) - { + public void setAscending(boolean ascending) { this.ascending = ascending; } /** * @return Returns the browseIndex. */ - public BrowseIndex getBrowseIndex() - { + public BrowseIndex getBrowseIndex() { return browseIndex; } /** * @param browseIndex The browseIndex to set. */ - public void setBrowseIndex(BrowseIndex browseIndex) - { + public void setBrowseIndex(BrowseIndex browseIndex) { this.browseIndex = browseIndex; } /** * @return Returns the prevItem. */ - public int getPrevOffset() - { + public int getPrevOffset() { return prevOffset > -1 ? prevOffset : 0; } /** * @param prevOffset The prevOffset to set. */ - public void setPrevOffset(int prevOffset) - { + public void setPrevOffset(int prevOffset) { this.prevOffset = prevOffset; } /** * @return Returns the sortOption. */ - public SortOption getSortOption() - { + public SortOption getSortOption() { return sortOption; } /** * @param sortOption The sortOption to set. */ - public void setSortOption(SortOption sortOption) - { + public void setSortOption(SortOption sortOption) { this.sortOption = sortOption; } /** * @return Returns the startsWith. */ - public boolean isStartsWith() - { + public boolean isStartsWith() { return startsWith; } /** * @param startsWith The startsWith to set. */ - public void setStartsWith(boolean startsWith) - { + public void setStartsWith(boolean startsWith) { this.startsWith = startsWith; } /** * @return Returns the value. */ - public String getValue() - { + public String getValue() { return value; } /** * @param value The value to set. */ - public void setValue(String value) - { + public void setValue(String value) { this.value = value; } /** * @return Returns the authority key. */ - public String getAuthority() - { + public String getAuthority() { return authority; } /** * @param authority The authority key to set. */ - public void setAuthority(String authority) - { + public void setAuthority(String authority) { this.authority = authority; } @@ -444,12 +427,10 @@ public class BrowseInfo * browse or a single browse. Other browse types are considered * second level (1) * - * @return true if top level, false if not + * @return true if top level, false if not */ - public boolean isTopLevel() - { - if (this.level == 0) - { + public boolean isTopLevel() { + if (this.level == 0) { return true; } return false; @@ -459,12 +440,10 @@ public class BrowseInfo * Is this a second level (1) browse? Examples of this are a single * value browse (e.g. all items by a given author) * - * @return true if second level, false if not + * @return true if second level, false if not */ - public boolean isSecondLevel() - { - if (this.level == 1) - { + public boolean isSecondLevel() { + if (this.level == 1) { return true; } return false; @@ -478,8 +457,7 @@ public class BrowseInfo * * @return Result list. This list cannot be modified. */ - public List getResults() - { + public List getResults() { return results; } @@ -489,27 +467,24 @@ public class BrowseInfo * * @return The results of the Browse as a String array. */ - public String[][] getStringResults() - { + public String[][] getStringResults() { return (String[][]) results.toArray(new String[results.size()][2]); } /** - * @deprecated * @return an empty array of Item. + * @deprecated */ - public Item[] getItemResults() - { + public Item[] getItemResults() { return new Item[0]; } /** * Return the results of the Browse as a BrowseItem array * - * @return the results of the browse as a BrowseItem array + * @return the results of the browse as a BrowseItem array */ - public List getBrowseItemResults() - { + public List getBrowseItemResults() { return results; } @@ -518,8 +493,7 @@ public class BrowseInfo * * @return The number of results. */ - public int getResultCount() - { + public int getResultCount() { return results.size(); } @@ -529,8 +503,7 @@ public class BrowseInfo * * @return The position of the results in index being browsed. */ - public int getOverallPosition() - { + public int getOverallPosition() { return overallPosition; } @@ -539,8 +512,7 @@ public class BrowseInfo * * @return The total number of items in the index. */ - public int getTotal() - { + public int getTotal() { return total; } @@ -549,8 +521,7 @@ public class BrowseInfo * * @return The position of the requested item or value in the set of results */ - public int getOffset() - { + public int getOffset() { return offset; } @@ -559,8 +530,7 @@ public class BrowseInfo * * @return True if there are no previous results from the browse */ - public boolean isFirst() - { + public boolean isFirst() { return overallPosition == 0; } @@ -569,37 +539,33 @@ public class BrowseInfo * * @return True if these are the last results from the browse */ - public boolean isLast() - { + public boolean isLast() { return (overallPosition + getResultCount()) == total; } /** * True if this browse was cached. + * * @return true/false */ - public boolean wasCached() - { + public boolean wasCached() { return cached; } /** * Set whether this browse was cached. */ - void setCached(boolean cached) - { + void setCached(boolean cached) { this.cached = cached; } /** * are we browsing within a Community container? * - * @return true if in community, false if not + * @return true if in community, false if not */ - public boolean inCommunity() - { - if (this.community != null) - { + public boolean inCommunity() { + if (this.community != null) { return true; } return false; @@ -608,12 +574,10 @@ public class BrowseInfo /** * are we browsing within a Collection container * - * @return true if in collection, false if not + * @return true if in collection, false if not */ - public boolean inCollection() - { - if (this.collection != null) - { + public boolean inCollection() { + if (this.collection != null) { return true; } return false; @@ -622,12 +586,10 @@ public class BrowseInfo /** * Are there further results for the browse that haven't been returned yet? * - * @return true if next page, false if not + * @return true if next page, false if not */ - public boolean hasNextPage() - { - if (nextOffset > -1) - { + public boolean hasNextPage() { + if (nextOffset > -1) { return true; } return false; @@ -636,12 +598,10 @@ public class BrowseInfo /** * Are there results prior to these that haven't been returned here? * - * @return true if previous page, false if not + * @return true if previous page, false if not */ - public boolean hasPrevPage() - { - if (offset > 0) - { + public boolean hasPrevPage() { + if (offset > 0) { return true; } return false; @@ -650,12 +610,10 @@ public class BrowseInfo /** * Does this browse have a focus? * - * @return true if focus, false if not + * @return true if focus, false if not */ - public boolean hasFocus() - { - if ("".equals(focus) || focus == null) - { + public boolean hasFocus() { + if ("".equals(focus) || focus == null) { return false; } return true; @@ -665,10 +623,9 @@ public class BrowseInfo * Get an integer representing the number within the total set of results which * marks the position of the first result in the current sub-set * - * @return the start point of the browse page + * @return the start point of the browse page */ - public int getStart() - { + public int getStart() { return overallPosition + 1; } @@ -676,22 +633,20 @@ public class BrowseInfo * Get an integer representing the number within the total set of results which * marks the position of the last result in the current sub-set * - * @return the end point of the browse page + * @return the end point of the browse page */ - public int getFinish() - { + public int getFinish() { return overallPosition + results.size(); } /** * Utility method for obtaining a string representation of the browse. This is * useful only for debug - * @return String representation + * + * @return String representation */ - public String toString() - { - try - { + public String toString() { + try { StringBuffer sb = new StringBuffer(); // calculate the range for display @@ -705,28 +660,24 @@ public class BrowseInfo // insert the information about which index sb.append("in index: " + browseIndex.getName() + - " (data type: " + browseIndex.getDataType() + - ", display type: " + browseIndex.getDisplayType() + ") "); + " (data type: " + browseIndex.getDataType() + + ", display type: " + browseIndex.getDisplayType() + ") "); sb.append("||"); // report on the browse scope container String container = "all of DSpace"; DSpaceObject theContainer = null; - if (inCollection()) - { + if (inCollection()) { container = "collection"; theContainer = this.collection; - } - else if (inCommunity()) - { + } else if (inCommunity()) { container = "community"; theContainer = this.community; } String containerID = "no id available/necessary"; - if (theContainer != null) - { + if (theContainer != null) { containerID = theContainer.getID().toString() + " (" + theContainer.getHandle() + ")"; } @@ -737,42 +688,30 @@ public class BrowseInfo ItemListConfig config = new ItemListConfig(); // some information about the columns to be displayed - if (browseIndex.isItemIndex()) - { + if (browseIndex.isItemIndex()) { sb.append("Listing over " + Integer.toString(config.numCols()) + " columns: "); - for (int k = 1; k <= config.numCols(); k++) - { - if (k > 1) - { + for (int k = 1; k <= config.numCols(); k++) { + if (k > 1) { sb.append(","); } String[] meta = config.getMetadata(k); sb.append(meta[0] + "." + meta[1] + "." + meta[2]); } - if (value != null) - { + if (value != null) { sb.append(" on value: ").append(value); } - if (isStartsWith()) - { + if (isStartsWith()) { sb.append(" sort column starting with: ").append(focus); - } - else if (hasFocus()) - { + } else if (hasFocus()) { sb.append(" sort column focus: ").append(focus); } - } - else if (browseIndex.isMetadataIndex()) - { + } else if (browseIndex.isMetadataIndex()) { sb.append("Listing single column: ").append(browseIndex.getMetadata()); - if (isStartsWith()) - { + if (isStartsWith()) { sb.append(" sort column starting with: ").append(focus); - } - else if (hasFocus()) - { + } else if (hasFocus()) { sb.append(" sort column focus: ").append(focus); } } @@ -782,16 +721,13 @@ public class BrowseInfo // some information about how the data is sorted String direction = (ascending ? "ASC" : "DESC"); sb.append("Sorting by: " + sortOption.getMetadata() + " " + direction + - " (option " + Integer.toString(sortOption.getNumber()) + ")"); + " (option " + Integer.toString(sortOption.getNumber()) + ")"); sb.append("||"); // output the results - if (browseIndex.isMetadataIndex() && !isSecondLevel()) - { + if (browseIndex.isMetadataIndex() && !isSecondLevel()) { sb.append(valueListingString()); - } - else if (browseIndex.isItemIndex() || isSecondLevel()) - { + } else if (browseIndex.isItemIndex() || isSecondLevel()) { sb.append(fullListingString(config)); } @@ -799,36 +735,26 @@ public class BrowseInfo // tell us what the next and previous values are going to be sb.append("Top of next page: "); - if (hasNextPage()) - { + if (hasNextPage()) { sb.append("offset: ").append(Integer.toString(this.nextOffset)); - } - else - { + } else { sb.append("n/a"); } sb.append(";"); sb.append("Top of previous page: "); - if (hasPrevPage()) - { + if (hasPrevPage()) { sb.append("offset: ").append(Integer.toString(this.prevOffset)); - } - else - { + } else { sb.append("n/a"); } sb.append("||"); return sb.toString(); - } - catch (SQLException e) - { + } catch (SQLException e) { return e.getMessage(); - } - catch (BrowseException e) - { + } catch (BrowseException e) { return e.getMessage(); } } @@ -842,45 +768,35 @@ public class BrowseInfo * @throws SQLException if database error */ private String fullListingString(ItemListConfig config) - throws SQLException - { + throws SQLException { // report on all the results contained herein StringBuffer sb = new StringBuffer(); Iterator itr = results.iterator(); - while (itr.hasNext()) - { + while (itr.hasNext()) { Item bi = (Item) itr.next(); - if (bi == null) - { + if (bi == null) { sb.append("{{ NULL ITEM }}"); break; } sb.append("{{Item ID: " + bi.getID().toString() + " :: "); - for (int j = 1; j <= config.numCols(); j++) - { + for (int j = 1; j <= config.numCols(); j++) { String[] md = config.getMetadata(j); - if (md == null) - { + if (md == null) { sb.append("{{ NULL METADATA }}"); break; } List values = itemService.getMetadata(bi, md[0], md[1], md[2], Item.ANY); StringBuffer value = new StringBuffer(); - if (values != null) - { - for (int i = 0; i < values.size(); i++) - { - if (i > 0) - { + if (values != null) { + for (int i = 0; i < values.size(); i++) { + if (i > 0) { value.append(","); } value.append(values.get(i).getValue()); } - } - else - { + } else { value.append("-"); } String metadata = "[" + md[0] + "." + md[1] + "." + md[2] + ":" + value.toString() + "]"; @@ -898,17 +814,14 @@ public class BrowseInfo * * @return */ - private String valueListingString() - { + private String valueListingString() { // report on all the results contained herein StringBuffer sb = new StringBuffer(); Iterator itr = results.iterator(); - while (itr.hasNext()) - { + while (itr.hasNext()) { String theValue = (String) itr.next(); - if (theValue == null) - { + if (theValue == null) { sb.append("{{ NULL VALUE }}"); break; } diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowseOutput.java b/dspace-api/src/main/java/org/dspace/browse/BrowseOutput.java index 4a1bebd525..20afc68c51 100644 --- a/dspace-api/src/main/java/org/dspace/browse/BrowseOutput.java +++ b/dspace-api/src/main/java/org/dspace/browse/BrowseOutput.java @@ -15,175 +15,158 @@ import java.io.IOException; * Utility class to provide a wrapper for the various output possibilities from * the IndexBrowse class. It can output to the screen and to file, and it can be * verbose or not verbose. - * - * @author Richard Jones * + * @author Richard Jones */ -public class BrowseOutput -{ +public class BrowseOutput { - /** be verbose? */ - private boolean verbose = false; + /** + * be verbose? + */ + private boolean verbose = false; - /** print to the screen? */ - private boolean print = false; + /** + * print to the screen? + */ + private boolean print = false; - /** write to file? */ - private boolean file = false; + /** + * write to file? + */ + private boolean file = false; - /** append to file, or overwrite? */ - private boolean append = true; - - /** name of file to write to */ - private String fileName; + /** + * append to file, or overwrite? + */ + private boolean append = true; - /** - * Constructor. - */ - public BrowseOutput() - { - - } + /** + * name of file to write to + */ + private String fileName; - /** - * @return Returns the append. - */ - public boolean isAppend() - { - return append; - } + /** + * Constructor. + */ + public BrowseOutput() { - /** - * @param append - * The append to set. - */ - public void setAppend(boolean append) - { - this.append = append; - } + } - /** - * @return Returns the fileName. - */ - public String getFileName() - { - return fileName; - } + /** + * @return Returns the append. + */ + public boolean isAppend() { + return append; + } - /** - * @param fileName - * The fileName to set. - */ - public void setFileName(String fileName) - { - this.fileName = fileName; - setAppend(false); - } + /** + * @param append The append to set. + */ + public void setAppend(boolean append) { + this.append = append; + } - /** - * @return Returns the file. - */ - public boolean isFile() - { - return file; - } + /** + * @return Returns the fileName. + */ + public String getFileName() { + return fileName; + } - /** - * @param file - * The file to set. - */ - public void setFile(boolean file) - { - this.file = file; - } + /** + * @param fileName The fileName to set. + */ + public void setFileName(String fileName) { + this.fileName = fileName; + setAppend(false); + } - /** - * @return Returns the print. - */ - public boolean isPrint() - { - return print; - } + /** + * @return Returns the file. + */ + public boolean isFile() { + return file; + } - /** - * @param print - * The print to set. - */ - public void setPrint(boolean print) - { - this.print = print; - } + /** + * @param file The file to set. + */ + public void setFile(boolean file) { + this.file = file; + } - /** - * @return Returns the verbose. - */ - public boolean isVerbose() - { - return verbose; - } + /** + * @return Returns the print. + */ + public boolean isPrint() { + return print; + } - /** - * @param verbose - * The verbose to set. - */ - public void setVerbose(boolean verbose) - { - this.verbose = verbose; - } + /** + * @param print The print to set. + */ + public void setPrint(boolean print) { + this.print = print; + } - /** - * Pass in a message to be processed. If the setting is verbose - * then this will be output to System.out - * - * @param message the message to set - */ - public void message(String message) - { - if (isVerbose()) - { - System.out.println(message); - } - } + /** + * @return Returns the verbose. + */ + public boolean isVerbose() { + return verbose; + } - /** - * Pass in a message that must be displayed to the user, irrespective - * of the verbosity. Will be displayed to System.out - * - * @param message the urgent message - */ - public void urgent(String message) - { - System.out.println(message); - } + /** + * @param verbose The verbose to set. + */ + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } - /** - * Pass in some SQL. If print is set to true this will output to the - * screen. If file is set to true, this will write to the file specified. - * - * @param sql SQL string - * @throws BrowseException if browse error - */ - public void sql(String sql) throws BrowseException - { - if (isPrint()) - { - System.out.println(sql); - } + /** + * Pass in a message to be processed. If the setting is verbose + * then this will be output to System.out + * + * @param message the message to set + */ + public void message(String message) { + if (isVerbose()) { + System.out.println(message); + } + } - if (isFile()) - { - try - { - BufferedWriter out = new BufferedWriter(new FileWriter(fileName, isAppend())); - out.write(sql + "\n"); - out.close(); - setAppend(true); - } - catch (IOException e) - { - throw new BrowseException(e); - } - } - } + /** + * Pass in a message that must be displayed to the user, irrespective + * of the verbosity. Will be displayed to System.out + * + * @param message the urgent message + */ + public void urgent(String message) { + System.out.println(message); + } + + /** + * Pass in some SQL. If print is set to true this will output to the + * screen. If file is set to true, this will write to the file specified. + * + * @param sql SQL string + * @throws BrowseException if browse error + */ + public void sql(String sql) throws BrowseException { + if (isPrint()) { + System.out.println(sql); + } + + if (isFile()) { + try { + BufferedWriter out = new BufferedWriter(new FileWriter(fileName, isAppend())); + out.write(sql + "\n"); + out.close(); + setAppend(true); + } catch (IOException e) { + throw new BrowseException(e); + } + } + } } diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowserScope.java b/dspace-api/src/main/java/org/dspace/browse/BrowserScope.java index 3f7606cfde..aecfacd594 100644 --- a/dspace-api/src/main/java/org/dspace/browse/BrowserScope.java +++ b/dspace-api/src/main/java/org/dspace/browse/BrowserScope.java @@ -11,8 +11,8 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; -import org.dspace.sort.SortOption; import org.dspace.sort.SortException; +import org.dspace.sort.SortOption; /** * A class which represents the initial request to the browse system. @@ -20,62 +20,96 @@ import org.dspace.sort.SortException; * of a BrowseInfo object * * @author Richard Jones - * */ -public class BrowserScope -{ - /** the DSpace context */ +public class BrowserScope { + /** + * the DSpace context + */ private Context context; - /** the current browse index */ + /** + * the current browse index + */ private BrowseIndex browseIndex; - /** the order in which to display results */ + /** + * the order in which to display results + */ private String order; - /** the field upon which to sort */ + /** + * the field upon which to sort + */ private int sortBy; - /** the value to restrict the browse to */ + /** + * the value to restrict the browse to + */ private String filterValue; - /** exact or partial matching of the value */ + /** + * exact or partial matching of the value + */ private boolean filterValuePartial = false; - /** the language of the value to restrict the browse to */ + /** + * the language of the value to restrict the browse to + */ private String filterValueLang; - /** the item id focus of the browse */ + /** + * the item id focus of the browse + */ private int jumpItemId = -1; - /** the string value to start with */ + /** + * the string value to start with + */ private String startsWith; - /** the number of results per page to display */ + /** + * the number of results per page to display + */ private int resultsPerPage = 20; - /** the Collection to which to restrict */ + /** + * the Collection to which to restrict + */ private Collection collection; - /** the Community to which to restrict */ + /** + * the Community to which to restrict + */ private Community community; - /** the sort option being used */ + /** + * the sort option being used + */ private SortOption sortOption; - /** the value upon which to focus */ + /** + * the value upon which to focus + */ private String jumpValue; - /** the language of the value upon which to focus */ + /** + * the language of the value upon which to focus + */ private String jumpValueLang; - /** the browse level */ + /** + * the browse level + */ private int level = 0; - /** the number of authors to display in the results */ + /** + * the number of authors to display in the results + */ private int etAl = 0; - /** the number of items to offset into the result ie. 0 = 1st record */ + /** + * the number of items to offset into the result ie. 0 = 1st record + */ private int offset = 0; private String authority = null; @@ -83,10 +117,9 @@ public class BrowserScope /** * Construct a new BrowserScope using the given Context * - * @param context the DSpace Context + * @param context the DSpace Context */ - public BrowserScope(Context context) - { + public BrowserScope(Context context) { this.context = context; } @@ -95,22 +128,16 @@ public class BrowserScope * is not of type Collection or Community, this method will throw an * exception * - * @param dso the container object; a Community or Collection + * @param dso the container object; a Community or Collection * @throws BrowseException if browse error */ public void setBrowseContainer(DSpaceObject dso) - throws BrowseException - { - if (dso instanceof Collection) - { + throws BrowseException { + if (dso instanceof Collection) { this.collection = (Collection) dso; - } - else if (dso instanceof Community) - { + } else if (dso instanceof Community) { this.community = (Community) dso; - } - else - { + } else { throw new BrowseException("The container must be a community or a collection"); } } @@ -119,56 +146,47 @@ public class BrowserScope * Obtain a DSpaceObject that represents the container object. This will be * a Community or a Collection * - * @return A DSpaceObject representing a Community or a Collection + * @return A DSpaceObject representing a Community or a Collection */ - public DSpaceObject getBrowseContainer() - { - if (this.collection != null) - { + public DSpaceObject getBrowseContainer() { + if (this.collection != null) { return this.collection; } - if (this.community != null) - { + if (this.community != null) { return this.community; } return null; } /** - * @param level the browse level + * @param level the browse level */ - public void setBrowseLevel(int level) - { + public void setBrowseLevel(int level) { this.level = level; } /** - * @return the browse level + * @return the browse level */ - public int getBrowseLevel() - { + public int getBrowseLevel() { return this.level; } /** * @return true if top level browse, false if not */ - public boolean isTopLevel() - { - if (this.level == 0) - { + public boolean isTopLevel() { + if (this.level == 0) { return true; } return false; } /** - * @return true if second level browse, false if not + * @return true if second level browse, false if not */ - public boolean isSecondLevel() - { - if (this.level == 1) - { + public boolean isSecondLevel() { + if (this.level == 1) { return true; } return false; @@ -177,8 +195,7 @@ public class BrowserScope /** * @return Returns the browseIndex. */ - public BrowseIndex getBrowseIndex() - { + public BrowseIndex getBrowseIndex() { return browseIndex; } @@ -187,136 +204,118 @@ public class BrowserScope * @throws BrowseException if error */ public void setBrowseIndex(BrowseIndex browseIndex) - throws BrowseException - { + throws BrowseException { this.browseIndex = browseIndex; } /** * @return Returns the author limit. */ - public int getEtAl() - { + public int getEtAl() { return etAl; } /** * @param etAl the author limit */ - public void setEtAl(int etAl) - { + public void setEtAl(int etAl) { this.etAl = etAl; } /** * @return Returns the collection. */ - public Collection getCollection() - { + public Collection getCollection() { return collection; } /** * @param collection The collection to set. */ - public void setCollection(Collection collection) - { + public void setCollection(Collection collection) { this.collection = collection; } /** * @return Returns the community. */ - public Community getCommunity() - { + public Community getCommunity() { return community; } /** * @param community The community to set. */ - public void setCommunity(Community community) - { + public void setCommunity(Community community) { this.community = community; } /** * @return Returns the context. */ - public Context getContext() - { + public Context getContext() { return context; } /** * @param context The context to set. */ - public void setContext(Context context) - { + public void setContext(Context context) { this.context = context; } /** * @return Returns the focus. */ - public int getJumpToItem() - { + public int getJumpToItem() { return jumpItemId; } /** * @param itemId The focus to set. */ - public void setJumpToItem(int itemId) - { + public void setJumpToItem(int itemId) { this.jumpItemId = itemId; } /** - * @return the value to focus on + * @return the value to focus on */ - public String getJumpToValue() - { + public String getJumpToValue() { return jumpValue; } /** - * @param value the value to focus on + * @param value the value to focus on */ - public void setJumpToValue(String value) - { + public void setJumpToValue(String value) { this.jumpValue = value; } /** - * @return the language of the value to focus on + * @return the language of the value to focus on */ - public String getJumpToValueLang() - { + public String getJumpToValueLang() { return jumpValueLang; } /** - * @param valueLang the language of the value to focus on + * @param valueLang the language of the value to focus on */ - public void setJumpToValueLang(String valueLang) - { + public void setJumpToValueLang(String valueLang) { this.jumpValueLang = valueLang; } /** * @return Returns the order. */ - public String getOrder() - { - if (order != null) - { + public String getOrder() { + if (order != null) { return order; } BrowseIndex bi = getBrowseIndex(); - if (bi != null) - { + if (bi != null) { return bi.getDefaultOrder(); } @@ -326,18 +325,12 @@ public class BrowserScope /** * @param order The order to set. */ - public void setOrder(String order) - { - if (order == null) - { + public void setOrder(String order) { + if (order == null) { this.order = null; - } - else if (SortOption.ASCENDING.equalsIgnoreCase(order)) - { + } else if (SortOption.ASCENDING.equalsIgnoreCase(order)) { this.order = SortOption.ASCENDING; - } - else if (SortOption.DESCENDING.equalsIgnoreCase(order)) - { + } else if (SortOption.DESCENDING.equalsIgnoreCase(order)) { this.order = SortOption.DESCENDING; } } @@ -345,18 +338,15 @@ public class BrowserScope /** * @return Returns the resultsPerPage. */ - public int getResultsPerPage() - { + public int getResultsPerPage() { return resultsPerPage; } /** * @param resultsPerPage The resultsPerPage to set. */ - public void setResultsPerPage(int resultsPerPage) - { - if (resultsPerPage > -1 || (browseIndex != null && browseIndex.isTagCloudEnabled())) - { + public void setResultsPerPage(int resultsPerPage) { + if (resultsPerPage > -1 || (browseIndex != null && browseIndex.isTagCloudEnabled())) { this.resultsPerPage = resultsPerPage; } } @@ -364,8 +354,7 @@ public class BrowserScope /** * @return Returns the sortBy. */ - public int getSortBy() - { + public int getSortBy() { return sortBy; } @@ -374,74 +363,58 @@ public class BrowserScope * @throws BrowseException if error */ public void setSortBy(int sortBy) - throws BrowseException - { + throws BrowseException { this.sortBy = sortBy; } /** * @return returns the offset for the browse */ - public int getOffset() - { + public int getOffset() { return offset; } /** - * @param offset the offset to use for this scope + * @param offset the offset to use for this scope */ - public void setOffset(int offset) - { + public void setOffset(int offset) { this.offset = offset; } /** * Obtain the sort option * - * @return the sort option + * @return the sort option * @throws BrowseException if browse error */ public SortOption getSortOption() - throws BrowseException - { - try - { + throws BrowseException { + try { // If a sortOption hasn't been set, work out the default, providing we have an index - if (sortOption == null && browseIndex != null) - { + if (sortOption == null && browseIndex != null) { // If a sorting hasn't been specified, and it's a metadata browse - if (sortBy <= 0 && browseIndex.isMetadataIndex()) - { + if (sortBy <= 0 && browseIndex.isMetadataIndex()) { // Create a dummy sortOption for the metadata sort String dataType = browseIndex.getDataType(); String type = ("date".equals(dataType) ? "date" : "text"); sortOption = new SortOption(0, browseIndex.getName(), browseIndex.getMetadata(0), type); - } - else - { + } else { // If a sorting hasn't been specified - if (sortBy <= 0) - { + if (sortBy <= 0) { // Get the sort option from the index sortOption = browseIndex.getSortOption(); - if (sortOption == null) - { + if (sortOption == null) { // No sort option, so default to the first one defined in the config - for (SortOption so : SortOption.getSortOptions()) - { + for (SortOption so : SortOption.getSortOptions()) { sortOption = so; break; } } - } - else - { + } else { // A sorting has been specified, so get it from the configured sort columns - for (SortOption so : SortOption.getSortOptions()) - { - if (so.getNumber() == sortBy) - { + for (SortOption so : SortOption.getSortOptions()) { + if (so.getNumber() == sortBy) { sortOption = so; } } @@ -450,9 +423,7 @@ public class BrowserScope } return sortOption; - } - catch (SortException se) - { + } catch (SortException se) { throw new BrowseException("Error in SortOptions", se); } } @@ -460,116 +431,104 @@ public class BrowserScope /** * @return Returns the startsWith. */ - public String getStartsWith() - { + public String getStartsWith() { return startsWith; } /** * @param startsWith The startsWith to set. */ - public void setStartsWith(String startsWith) - { + public void setStartsWith(String startsWith) { this.startsWith = startsWith; } /** * Used for second-level item browses, * to only display items that match the value + * * @return Returns the value. */ - public String getFilterValue() - { + public String getFilterValue() { return filterValue; } /** * Used for second-level item browses, * to only display items that match the value + * * @param value The value to set. */ - public void setFilterValue(String value) - { + public void setFilterValue(String value) { this.filterValue = value; } /** * Should the filter value be treated as partial, or exact + * * @return true if partial, false if exact */ - public boolean getFilterValuePartial() - { + public boolean getFilterValuePartial() { return filterValuePartial; } /** * Should the filter value be treated as partial, or exact + * * @param filterValuePartial true if partial, false if exact */ - public void setFilterValuePartial(boolean filterValuePartial) - { + public void setFilterValuePartial(boolean filterValuePartial) { this.filterValuePartial = filterValuePartial; } /** * @return Returns the language. */ - public String getFilterValueLang() - { + public String getFilterValueLang() { return filterValueLang; } /** * @param lang The language to set. */ - public void setFilterValueLang(String lang) - { + public void setFilterValueLang(String lang) { this.filterValueLang = lang; } /** - * @return true if in community, false if not + * @return true if in community, false if not */ - public boolean inCommunity() - { - if (this.community != null) - { + public boolean inCommunity() { + if (this.community != null) { return true; } return false; } /** - * @return true if in collection, false if not + * @return true if in collection, false if not */ - public boolean inCollection() - { - if (this.collection != null) - { + public boolean inCollection() { + if (this.collection != null) { return true; } return false; } /** - * @return true if ascending, false if not - or not set + * @return true if ascending, false if not - or not set */ - public boolean isAscending() - { - if (SortOption.ASCENDING.equalsIgnoreCase(order)) - { + public boolean isAscending() { + if (SortOption.ASCENDING.equalsIgnoreCase(order)) { return true; } - if (SortOption.DESCENDING.equalsIgnoreCase(order)) - { + if (SortOption.DESCENDING.equalsIgnoreCase(order)) { return false; } BrowseIndex bi = getBrowseIndex(); - if (bi != null && SortOption.DESCENDING.equalsIgnoreCase(bi.getDefaultOrder())) - { + if (bi != null && SortOption.DESCENDING.equalsIgnoreCase(bi.getDefaultOrder())) { return false; } @@ -577,48 +536,40 @@ public class BrowserScope } /** - * @return true if has value, false if not + * @return true if has value, false if not */ - public boolean hasFilterValue() - { - if (filterValue == null || "".equals(filterValue)) - { + public boolean hasFilterValue() { + if (filterValue == null || "".equals(filterValue)) { return false; } return true; } /** - * @return true if has item focus, false if not + * @return true if has item focus, false if not */ - public boolean hasJumpToItem() - { - if (jumpItemId == -1) - { + public boolean hasJumpToItem() { + if (jumpItemId == -1) { return false; } return true; } /** - * @return true if has value focus, false if not + * @return true if has value focus, false if not */ - public boolean hasJumpToValue() - { - if (this.jumpValue != null) - { + public boolean hasJumpToValue() { + if (this.jumpValue != null) { return true; } return false; } /** - * @return true if has starts with value, false if not + * @return true if has starts with value, false if not */ - public boolean hasStartsWith() - { - if (this.startsWith != null) - { + public boolean hasStartsWith() { + if (this.startsWith != null) { return true; } return false; diff --git a/dspace-api/src/main/java/org/dspace/browse/CrossLinks.java b/dspace-api/src/main/java/org/dspace/browse/CrossLinks.java index 1694d0324c..a2447b812b 100644 --- a/dspace-api/src/main/java/org/dspace/browse/CrossLinks.java +++ b/dspace-api/src/main/java/org/dspace/browse/CrossLinks.java @@ -16,62 +16,56 @@ import org.dspace.core.ConfigurationManager; * Class to represent the configuration of the cross-linking between browse * pages (for example, between the author name in one full listing to the * author's list of publications). - * - * @author Richard Jones * + * @author Richard Jones */ -public class CrossLinks -{ - /** a map of the desired links */ - private Map links = new HashMap(); - - /** - * Construct a new object which will obtain the configuration for itself. - * - * @throws BrowseException if browse error - */ - public CrossLinks() - throws BrowseException - { - int i = 1; - while (true) - { - String field = "webui.browse.link." + i; - String config = ConfigurationManager.getProperty(field); - if (config == null) - { - break; - } - - String[] parts = config.split(":"); - if (parts.length != 2) - { - throw new BrowseException("Invalid configuration for " + field + ": " + config); - } - links.put(parts[1], parts[0]); - i++; - } - } +public class CrossLinks { + /** + * a map of the desired links + */ + private Map links = new HashMap(); - /** - * Is there a link for the given canonical form of metadata (i.e. schema.element.qualifier)? - * - * @param metadata the metadata to check for a link on - * @return true/false - */ - public boolean hasLink(String metadata) - { - return links.containsKey(metadata); - } - - /** - * Get the type of link that the bit of metadata has. - * - * @param metadata the metadata to get the link type for - * @return type - */ - public String getLinkType(String metadata) - { - return links.get(metadata); - } + /** + * Construct a new object which will obtain the configuration for itself. + * + * @throws BrowseException if browse error + */ + public CrossLinks() + throws BrowseException { + int i = 1; + while (true) { + String field = "webui.browse.link." + i; + String config = ConfigurationManager.getProperty(field); + if (config == null) { + break; + } + + String[] parts = config.split(":"); + if (parts.length != 2) { + throw new BrowseException("Invalid configuration for " + field + ": " + config); + } + links.put(parts[1], parts[0]); + i++; + } + } + + /** + * Is there a link for the given canonical form of metadata (i.e. schema.element.qualifier)? + * + * @param metadata the metadata to check for a link on + * @return true/false + */ + public boolean hasLink(String metadata) { + return links.containsKey(metadata); + } + + /** + * Get the type of link that the bit of metadata has. + * + * @param metadata the metadata to get the link type for + * @return type + */ + public String getLinkType(String metadata) { + return links.get(metadata); + } } diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAO.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAO.java index ef3b329540..ab16f68d35 100644 --- a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAO.java +++ b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAO.java @@ -7,34 +7,32 @@ */ package org.dspace.browse; -import org.dspace.core.Context; import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; /** * Interface for data access of cached community and collection item count * information - * - * @author Richard Jones * + * @author Richard Jones */ -public interface ItemCountDAO -{ - /** - * Set the DSpace Context to use during data access - * - * @param context DSpace Context - * @throws ItemCountException if count error - */ - public void setContext(Context context) throws ItemCountException; - - /** - * Get the number of items in the given DSpaceObject container. This method will - * only succeed if the DSpaceObject is an instance of either a Community or a - * Collection. Otherwise it will throw an exception. - * - * @param dso Dspace Object - * @return count - * @throws ItemCountException if count error - */ - public int getCount(DSpaceObject dso) throws ItemCountException; +public interface ItemCountDAO { + /** + * Set the DSpace Context to use during data access + * + * @param context DSpace Context + * @throws ItemCountException if count error + */ + public void setContext(Context context) throws ItemCountException; + + /** + * Get the number of items in the given DSpaceObject container. This method will + * only succeed if the DSpaceObject is an instance of either a Community or a + * Collection. Otherwise it will throw an exception. + * + * @param dso Dspace Object + * @return count + * @throws ItemCountException if count error + */ + public int getCount(DSpaceObject dso) throws ItemCountException; } diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOFactory.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOFactory.java index 5da1649802..697dc5bb22 100644 --- a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOFactory.java +++ b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOFactory.java @@ -7,54 +7,51 @@ */ package org.dspace.browse; -import org.dspace.core.Context; import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; /** * Factory class to allow us to load the correct DAO for registering * item count information - * + * * @author Richard Jones * @author Ivan Masár - * */ -public class ItemCountDAOFactory -{ +public class ItemCountDAOFactory { + + /** + * Default constructor + */ + private ItemCountDAOFactory() { } + /** * Get an instance of ItemCountDAO which supports the correct storage backend * for the specific DSpace instance. - * + * * @param context DSpace Context * @return DAO * @throws ItemCountException if count error */ public static ItemCountDAO getInstance(Context context) - throws ItemCountException - { - + throws ItemCountException { + /** Log4j logger */ ItemCountDAO dao = null; - + String className = ConfigurationManager.getProperty("ItemCountDAO.class"); - + // SOLR implementation is the default since DSpace 4.0 - if (className == null) - { + if (className == null) { dao = new ItemCountDAOSolr(); - } - else - { - try - { + } else { + try { dao = (ItemCountDAO) Class - .forName(className.trim()).newInstance(); - } - catch (Exception e) - { + .forName(className.trim()).newInstance(); + } catch (Exception e) { throw new ItemCountException("The configuration for ItemCountDAO is invalid: " + className, e); } } - + dao.setContext(context); return dao; } diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java index e71e7e779a..e39a584684 100644 --- a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java +++ b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java @@ -29,18 +29,20 @@ import org.dspace.services.factory.DSpaceServicesFactory; * Discovery (Solr) driver implementing ItemCountDAO interface to look up item * count information in communities and collections. Caching operations are * intentionally not implemented because Solr already is our cache. - * + * * @author Ivan Masár, Andrea Bollini - * */ -public class ItemCountDAOSolr implements ItemCountDAO -{ - /** Log4j logger */ +public class ItemCountDAOSolr implements ItemCountDAO { + /** + * Log4j logger + */ private static Logger log = Logger.getLogger(ItemCountDAOSolr.class); - - /** DSpace context */ + + /** + * DSpace context + */ private Context context; - + /** * Hold the communities item count obtained from SOLR after the first query. This only works * well if the ItemCountDAO lifecycle is bound to the request lifecycle as @@ -49,105 +51,93 @@ public class ItemCountDAOSolr implements ItemCountDAO **/ private Map communitiesCount = null; - /** Hold the collection item count obtained from SOLR after the first query **/ + /** + * Hold the collection item count obtained from SOLR after the first query + **/ private Map collectionsCount = null; - - /** Solr search service */ - SearchService searcher = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(SearchService.class.getName(), SearchService.class); - + + /** + * Solr search service + */ + SearchService searcher = DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(SearchService.class.getName(), SearchService.class); + /** * Set the dspace context to use - * + * * @param context DSpace Context * @throws ItemCountException if count error */ @Override - public void setContext(Context context) throws ItemCountException - { + public void setContext(Context context) throws ItemCountException { this.context = context; } /** * Get the count of the items in the given container. - * + * * @param dso Dspace Context * @return count * @throws ItemCountException if count error */ @Override - public int getCount(DSpaceObject dso) throws ItemCountException - { - loadCount(); - Integer val; - if (dso instanceof Collection) - { + public int getCount(DSpaceObject dso) throws ItemCountException { + loadCount(); + Integer val; + if (dso instanceof Collection) { val = collectionsCount.get(String.valueOf(((Collection) dso).getID())); - } - else if (dso instanceof Community) - { + } else if (dso instanceof Community) { val = communitiesCount.get(String.valueOf(((Community) dso).getID())); - } - else - { + } else { throw new ItemCountException("We can only count items in Communities or Collections"); } - - if (val != null) - { + + if (val != null) { return val.intValue(); - } - else - { + } else { return 0; - } + } } - + /** * make sure that the counts are actually fetched from Solr (if haven't been * cached in a Map yet) - * + * * @throws ItemCountException if count error */ - private void loadCount() throws ItemCountException - { - if (communitiesCount != null || collectionsCount != null) - { + private void loadCount() throws ItemCountException { + if (communitiesCount != null || collectionsCount != null) { return; - } - - communitiesCount = new HashMap(); + } + + communitiesCount = new HashMap(); collectionsCount = new HashMap(); - + DiscoverQuery query = new DiscoverQuery(); query.setFacetMinCount(1); query.addFacetField(new DiscoverFacetField("location.comm", - DiscoveryConfigurationParameters.TYPE_STANDARD, -1, - DiscoveryConfigurationParameters.SORT.COUNT)); + DiscoveryConfigurationParameters.TYPE_STANDARD, -1, + DiscoveryConfigurationParameters.SORT.COUNT)); query.addFacetField(new DiscoverFacetField("location.coll", - DiscoveryConfigurationParameters.TYPE_STANDARD, -1, - DiscoveryConfigurationParameters.SORT.COUNT)); + DiscoveryConfigurationParameters.TYPE_STANDARD, -1, + DiscoveryConfigurationParameters.SORT.COUNT)); query.addFilterQueries("search.resourcetype:2"); // count only items query.addFilterQueries("NOT(discoverable:false)"); // only discoverable query.setMaxResults(0); - + DiscoverResult sResponse = null; - try - { + try { sResponse = searcher.search(context, query, false); List commCount = sResponse.getFacetResult("location.comm"); List collCount = sResponse.getFacetResult("location.coll"); - for (FacetResult c : commCount) - { - communitiesCount.put(c.getAsFilterQuery(),(int) c.getCount()); + for (FacetResult c : commCount) { + communitiesCount.put(c.getAsFilterQuery(), (int) c.getCount()); } - for (FacetResult c : collCount) - { - collectionsCount.put(c.getAsFilterQuery(),(int) c.getCount()); + for (FacetResult c : collCount) { + collectionsCount.put(c.getAsFilterQuery(), (int) c.getCount()); } - } - catch (SearchServiceException e) - { + } catch (SearchServiceException e) { log.error("caught exception: ", e); throw new ItemCountException(e); } diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountException.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountException.java index e7fb31099e..533e6ecceb 100644 --- a/dspace-api/src/main/java/org/dspace/browse/ItemCountException.java +++ b/dspace-api/src/main/java/org/dspace/browse/ItemCountException.java @@ -9,30 +9,24 @@ package org.dspace.browse; /** * Exception type to handle item count specific problems - * - * @author Richard Jones * + * @author Richard Jones */ -public class ItemCountException extends Exception -{ +public class ItemCountException extends Exception { - public ItemCountException() - { - } + public ItemCountException() { + } - public ItemCountException(String message) - { - super(message); - } + public ItemCountException(String message) { + super(message); + } - public ItemCountException(Throwable cause) - { - super(cause); - } + public ItemCountException(Throwable cause) { + super(cause); + } - public ItemCountException(String message, Throwable cause) - { - super(message, cause); - } + public ItemCountException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java b/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java index 3fcaf56de0..9b91f7afb9 100644 --- a/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java +++ b/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java @@ -7,15 +7,15 @@ */ package org.dspace.browse; +import java.sql.SQLException; + import org.apache.log4j.Logger; -import org.dspace.content.Community; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.Context; -import org.dspace.content.DSpaceObject; - -import java.sql.SQLException; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; @@ -24,40 +24,41 @@ import org.dspace.services.factory.DSpaceServicesFactory; * operations for communities and collections. It can be run from the * command line to prepare the cached data if desired, simply by * running: - * + * * java org.dspace.browse.ItemCounter - * + * * It can also be invoked via its standard API. In the event that * the data cache is not being used, this class will return direct * real time counts of content. - * - * @author Richard Jones * + * @author Richard Jones */ -public class ItemCounter -{ - /** Log4j logger */ +public class ItemCounter { + /** + * Log4j logger + */ private static Logger log = Logger.getLogger(ItemCounter.class); - /** DAO to use to store and retrieve data */ + /** + * DAO to use to store and retrieve data + */ private ItemCountDAO dao; - /** DSpace Context */ + /** + * DSpace Context + */ private Context context; protected ItemService itemService; protected ConfigurationService configurationService; - + /** * Construct a new item counter which will use the given DSpace Context - * + * * @param context current context * @throws ItemCountException if count error */ - public ItemCounter(Context context) - throws ItemCountException - - { + public ItemCounter(Context context) throws ItemCountException { this.context = context; this.dao = ItemCountDAOFactory.getInstance(this.context); this.itemService = ContentServiceFactory.getInstance().getItemService(); @@ -69,25 +70,21 @@ public class ItemCounter * value webui.strengths.cache is equal to 'true' this will return the * cached value if it exists. If it is equal to 'false' it will count * the number of items in the container in real time. - * + * * @param dso DSpaceObject * @return count * @throws ItemCountException when error occurs */ - public int getCount(DSpaceObject dso) - throws ItemCountException - { + public int getCount(DSpaceObject dso) throws ItemCountException { boolean useCache = configurationService.getBooleanProperty( - "webui.strengths.cache", true); + "webui.strengths.cache", true); - if (useCache) - { + if (useCache) { return dao.getCount(dso); } // if we make it this far, we need to manually count - if (dso instanceof Collection) - { + if (dso instanceof Collection) { try { return itemService.countItems(context, (Collection) dso); } catch (SQLException e) { @@ -96,8 +93,7 @@ public class ItemCounter } } - if (dso instanceof Community) - { + if (dso instanceof Community) { try { return itemService.countItems(context, ((Community) dso)); } catch (SQLException e) { diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemListConfig.java b/dspace-api/src/main/java/org/dspace/browse/ItemListConfig.java index 98c892a72d..58e3d83a0c 100644 --- a/dspace-api/src/main/java/org/dspace/browse/ItemListConfig.java +++ b/dspace-api/src/main/java/org/dspace/browse/ItemListConfig.java @@ -11,133 +11,125 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.ArrayUtils; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; /** * Class to mediate with the item list configuration - * - * @author Richard Jones * + * @author Richard Jones */ -public class ItemListConfig -{ - /** a map of column number to metadata value */ - private Map metadata = new HashMap(); - - /** a map of column number to data type */ - private Map types = new HashMap(); - - /** constant for a DATE column */ - private static final int DATE = 1; - - /** constant for a TEXT column */ - private static final int TEXT = 2; +public class ItemListConfig { + /** + * a map of column number to metadata value + */ + private Map metadata = new HashMap(); - private final transient ConfigurationService configurationService - = DSpaceServicesFactory.getInstance().getConfigurationService(); - - /** - * Create a new instance of the Item list configuration. This loads - * all the required information from configuration - * - * @throws BrowseException if count error - */ - public ItemListConfig() - throws BrowseException - { - try - { - String[] browseFields = configurationService.getArrayProperty("webui.itemlist.columns"); - - if (ArrayUtils.isEmpty(browseFields)) - { - throw new BrowseException("There is no configuration for webui.itemlist.columns"); - } - - // parse the config - int i = 1; - for(String token : browseFields) - { - Integer key = Integer.valueOf(i); + /** + * a map of column number to data type + */ + private Map types = new HashMap(); - // find out if the field is a date - if (token.indexOf("(date)") > 0) - { - token = token.replaceAll("\\(date\\)", ""); - types.put(key, Integer.valueOf(ItemListConfig.DATE)); - } - else - { - types.put(key, Integer.valueOf(ItemListConfig.TEXT)); - } - - String[] mdBits = interpretField(token.trim(), null); - metadata.put(key, mdBits); - - // don't forget to increment the key counter - i++; - } - } - catch (IOException e) - { - throw new BrowseException(e); - } - } + /** + * constant for a DATE column + */ + private static final int DATE = 1; - /** - * how many columns are there? - * - * @return the number of columns - */ - public int numCols() - { - return metadata.size(); - } - - /** - * What metadata is to go in the given column number? - * - * @param col column - * @return array of metadata - */ - public String[] getMetadata(int col) - { - return metadata.get(Integer.valueOf(col)); - } - - /** + /** + * constant for a TEXT column + */ + private static final int TEXT = 2; + + private final transient ConfigurationService configurationService + = DSpaceServicesFactory.getInstance().getConfigurationService(); + + /** + * Create a new instance of the Item list configuration. This loads + * all the required information from configuration + * + * @throws BrowseException if count error + */ + public ItemListConfig() + throws BrowseException { + try { + String[] browseFields = configurationService.getArrayProperty("webui.itemlist.columns"); + + if (ArrayUtils.isEmpty(browseFields)) { + throw new BrowseException("There is no configuration for webui.itemlist.columns"); + } + + // parse the config + int i = 1; + for (String token : browseFields) { + Integer key = Integer.valueOf(i); + + // find out if the field is a date + if (token.indexOf("(date)") > 0) { + token = token.replaceAll("\\(date\\)", ""); + types.put(key, Integer.valueOf(ItemListConfig.DATE)); + } else { + types.put(key, Integer.valueOf(ItemListConfig.TEXT)); + } + + String[] mdBits = interpretField(token.trim(), null); + metadata.put(key, mdBits); + + // don't forget to increment the key counter + i++; + } + } catch (IOException e) { + throw new BrowseException(e); + } + } + + /** + * how many columns are there? + * + * @return the number of columns + */ + public int numCols() { + return metadata.size(); + } + + /** + * What metadata is to go in the given column number? + * + * @param col column + * @return array of metadata + */ + public String[] getMetadata(int col) { + return metadata.get(Integer.valueOf(col)); + } + + /** * Take a string representation of a metadata field, and return it as an array. - * This is just a convenient utility method to basically break the metadata + * This is just a convenient utility method to basically break the metadata * representation up by its delimiter (.), and stick it in an array, inserting * the value of the init parameter when there is no metadata field part. - * - * @param mfield the string representation of the metadata - * @param init the default value of the array elements - * @return a three element array with schema, element and qualifier respectively + * + * @param mfield the string representation of the metadata + * @param init the default value of the array elements + * @return a three element array with schema, element and qualifier respectively * @throws IOException if IO error */ public final String[] interpretField(String mfield, String init) - throws IOException - { - StringTokenizer sta = new StringTokenizer(mfield, "."); - String[] field = {init, init, init}; - - int i = 0; - while (sta.hasMoreTokens()) - { - field[i++] = sta.nextToken(); - } - - // error checks to make sure we have at least a schema and qualifier for both - if (field[0] == null || field[1] == null) - { - throw new IOException("at least a schema and element be " + - "specified in configuration. You supplied: " + mfield); - } - - return field; + throws IOException { + StringTokenizer sta = new StringTokenizer(mfield, "."); + String[] field = {init, init, init}; + + int i = 0; + while (sta.hasMoreTokens()) { + field[i++] = sta.nextToken(); + } + + // error checks to make sure we have at least a schema and qualifier for both + if (field[0] == null || field[1] == null) { + throw new IOException("at least a schema and element be " + + "specified in configuration. You supplied: " + mfield); + } + + return field; } } diff --git a/dspace-api/src/main/java/org/dspace/browse/LocaleOrderingFilter.java b/dspace-api/src/main/java/org/dspace/browse/LocaleOrderingFilter.java index 8024f3071b..40f889233a 100644 --- a/dspace-api/src/main/java/org/dspace/browse/LocaleOrderingFilter.java +++ b/dspace-api/src/main/java/org/dspace/browse/LocaleOrderingFilter.java @@ -9,60 +9,56 @@ package org.dspace.browse; import java.util.Locale; +import com.ibm.icu.text.CollationElementIterator; +import com.ibm.icu.text.Collator; +import com.ibm.icu.text.RuleBasedCollator; import org.apache.log4j.Logger; import org.dspace.core.ConfigurationManager; import org.dspace.text.filter.TextFilter; -import com.ibm.icu.text.CollationElementIterator; -import com.ibm.icu.text.Collator; -import com.ibm.icu.text.RuleBasedCollator; - /** * Makes a sort string that is Locale dependent. * Uses the same Locale for all items, regardless of source language. - * + * * You can set the Locale to use by setting 'webui.browse.sort.locale' * in the dspace.cfg to an ISO code. - * + * * If you do not specify a Locale, then it defaults to Locale.ENGLISH. - * + * * IMPORTANT: The strings that this generates are NOT human readable. * Also, you will not be able to meaningfully apply any filters *after* this, * however, you can apply other filters before. - * + * * @author Graham Triggs */ -public class LocaleOrderingFilter implements TextFilter -{ +public class LocaleOrderingFilter implements TextFilter { private static Logger log = Logger.getLogger(LocaleOrderingFilter.class); /** * Uses a Locale dependent Collator to generate a sort string + * * @param str The string to parse * @return String the sort ordering text */ @Override - public String filter(String str) - { + public String filter(String str) { RuleBasedCollator collator = getCollator(); // Have we got a collator? - if (collator != null) - { + if (collator != null) { int element; StringBuffer buf = new StringBuffer(); // Iterate through the elements of the collator CollationElementIterator iter = collator.getCollationElementIterator(str); - - while ((element = iter.next()) != CollationElementIterator.NULLORDER) - { + + while ((element = iter.next()) != CollationElementIterator.NULLORDER) { // Generate a hexadecimal string representation of the Collation element // This can then be compared in a text sort ;-) String test = Integer.toString(element, 16); buf.append(test); } - + return buf.toString(); } @@ -72,74 +68,63 @@ public class LocaleOrderingFilter implements TextFilter /** * We don't need to use the language parameter, so map this to * the standard sort string filter - * @param str string + * + * @param str string * @param lang language * @return string */ @Override - public String filter(String str, String lang) - { + public String filter(String str, String lang) { return filter(str); } - + /** * Get a Locale dependent collator - * + * * @return The collator to use */ - private static RuleBasedCollator getCollator() - { + private static RuleBasedCollator getCollator() { // Get the Locale to use Locale locale = getSortLocale(); - - if (locale != null) - { + + if (locale != null) { // Get collator for the supplied Locale - RuleBasedCollator collator = (RuleBasedCollator)Collator.getInstance(locale); - - if (collator != null) - { + RuleBasedCollator collator = (RuleBasedCollator) Collator.getInstance(locale); + + if (collator != null) { return collator; } } return null; } - + /** * Get a Locale to use for the sorting - * + * * @return The Locale to use */ - private static Locale getSortLocale() - { + private static Locale getSortLocale() { Locale theLocale = null; - + // Get a Locale configuration from the dspace.cfg String locale = ConfigurationManager.getProperty("webui.browse.sort.locale"); - - if (locale != null) - { + + if (locale != null) { // Attempt to create Locale for the configured value String[] localeArr = locale.split("_"); - if (localeArr.length > 1) - { + if (localeArr.length > 1) { theLocale = new Locale(localeArr[0], localeArr[1]); - } - else - { + } else { theLocale = new Locale(locale); } - + // Return the configured locale, or English default - if (theLocale == null) - { + if (theLocale == null) { log.warn("Could not create the supplied Locale: webui.browse.sort.locale=" + locale); return Locale.ENGLISH; } - } - else - { + } else { return Locale.ENGLISH; } diff --git a/dspace-api/src/main/java/org/dspace/browse/MappingResults.java b/dspace-api/src/main/java/org/dspace/browse/MappingResults.java index aa5155ab52..de69247e77 100644 --- a/dspace-api/src/main/java/org/dspace/browse/MappingResults.java +++ b/dspace-api/src/main/java/org/dspace/browse/MappingResults.java @@ -9,9 +9,10 @@ package org.dspace.browse; import java.util.List; -interface MappingResults -{ +interface MappingResults { List getAddedDistinctIds(); + List getRetainedDistinctIds(); + List getRemovedDistinctIds(); } diff --git a/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java b/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java index f6d3ddb1b6..3e5415f7d4 100644 --- a/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java +++ b/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java @@ -9,8 +9,13 @@ package org.dspace.browse; import java.io.Serializable; import java.sql.SQLException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; @@ -30,35 +35,27 @@ import org.dspace.discovery.configuration.DiscoveryConfigurationParameters; import org.dspace.services.factory.DSpaceServicesFactory; /** - * * @author Andrea Bollini (CILEA) * @author Adán Román Ruiz at arvo.es (bugfix) * @author Panagiotis Koutsourakis (National Documentation Centre) (bugfix) * @author Kostas Stamatis (National Documentation Centre) (bugfix) - * */ -public class SolrBrowseDAO implements BrowseDAO -{ - public SolrBrowseDAO(Context context) - { +public class SolrBrowseDAO implements BrowseDAO { + public SolrBrowseDAO(Context context) { this.context = context; } static private class FacetValueComparator - implements Comparator, Serializable - { + implements Comparator, Serializable { @Override - public int compare(Object o1, Object o2) - { - String s1 = "", s2 = ""; - if (o1 instanceof FacetResult && o2 instanceof String) - { + public int compare(Object o1, Object o2) { + String s1 = ""; + String s2 = ""; + if (o1 instanceof FacetResult && o2 instanceof String) { FacetResult c = (FacetResult) o1; s1 = c.getSortValue(); s2 = (String) o2; - } - else if (o2 instanceof FacetResult && o1 instanceof String) - { + } else if (o2 instanceof FacetResult && o1 instanceof String) { FacetResult c = (FacetResult) o2; s1 = (String) o1; s2 = c.getSortValue(); @@ -68,35 +65,55 @@ public class SolrBrowseDAO implements BrowseDAO } } - /** Log4j log */ + /** + * Log4j log + */ private static final Logger log = Logger.getLogger(SolrBrowseDAO.class); - /** The DSpace context */ + /** + * The DSpace context + */ private final Context context; // SQL query related attributes for this class - /** table(s) to select from */ + /** + * table(s) to select from + */ private String table = null; - /** field to look for focus value in */ + /** + * field to look for focus value in + */ private String focusField = null; - /** value to start browse from in focus field */ + /** + * value to start browse from in focus field + */ private String focusValue = null; - /** field to look for value in */ + private String startsWith = null; + + /** + * field to look for value in + */ private String valueField = null; - /** value to restrict browse to (e.g. author name) */ + /** + * value to restrict browse to (e.g. author name) + */ private String value = null; private String authority = null; - /** exact or partial matching of the value */ + /** + * exact or partial matching of the value + */ private boolean valuePartial = false; - /** the table that defines the mapping for the relevant container */ + /** + * the table that defines the mapping for the relevant container + */ private String containerTable = null; /** @@ -105,36 +122,50 @@ public class SolrBrowseDAO implements BrowseDAO */ private String containerIDField = null; - /** the database id of the container we are constraining to */ + /** + * the database id of the container we are constraining to + */ private UUID containerID = null; - /** the column that we are sorting results by */ + /** + * the column that we are sorting results by + */ private String orderField = null; - /** whether to sort results ascending or descending */ + /** + * whether to sort results ascending or descending + */ private boolean ascending = true; - /** the limit of number of results to return */ + /** + * the limit of number of results to return + */ private int limit = -1; - /** the offset of the start point */ + /** + * the offset of the start point + */ private int offset = 0; - /** whether to use the equals comparator in value comparisons */ + /** + * whether to use the equals comparator in value comparisons + */ private boolean equalsComparator = true; - /** whether this is a distinct browse or not */ + /** + * whether this is a distinct browse or not + */ private boolean distinct = false; private String facetField; - + protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); - + // administrative attributes for this class SearchService searcher = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName( - SearchService.class.getName(), SearchService.class); + SearchService.class.getName(), SearchService.class); private DiscoverResult sResponse = null; @@ -143,120 +174,95 @@ public class SolrBrowseDAO implements BrowseDAO private boolean showFrequencies; - private DiscoverResult getSolrResponse() throws BrowseException - { - if (sResponse == null) - { + private DiscoverResult getSolrResponse() throws BrowseException { + if (sResponse == null) { DiscoverQuery query = new DiscoverQuery(); addLocationScopeFilter(query); addStatusFilter(query); - if (distinct) - { - DiscoverFacetField dff = new DiscoverFacetField(facetField, + if (distinct) { + DiscoverFacetField dff; + if (StringUtils.isNotBlank(startsWith)) { + dff = new DiscoverFacetField(facetField, + DiscoveryConfigurationParameters.TYPE_TEXT, -1, + DiscoveryConfigurationParameters.SORT.VALUE, startsWith); + } else { + dff = new DiscoverFacetField(facetField, DiscoveryConfigurationParameters.TYPE_TEXT, -1, DiscoveryConfigurationParameters.SORT.VALUE); + } query.addFacetField(dff); query.setFacetMinCount(1); query.setMaxResults(0); - } - else - { + } else { query.setMaxResults(limit/* > 0 ? limit : 20*/); - if (offset > 0) - { + if (offset > 0) { query.setStart(offset); } // caution check first authority, value is always present! - if (authority != null) - { - query.addFilterQueries("{!field f="+facetField + "_authority_filter}" - + authority); - } - else if (value != null && !valuePartial) - { - query.addFilterQueries("{!field f="+facetField + "_value_filter}" + value); - } - else if (valuePartial) - { - query.addFilterQueries("{!field f="+facetField + "_partial}" + value); + if (authority != null) { + query.addFilterQueries("{!field f=" + facetField + "_authority_filter}" + + authority); + } else if (value != null && !valuePartial) { + query.addFilterQueries("{!field f=" + facetField + "_value_filter}" + value); + } else if (valuePartial) { + query.addFilterQueries("{!field f=" + facetField + "_partial}" + value); } // filter on item to be sure to don't include any other object // indexed in the Discovery Search core query.addFilterQueries("search.resourcetype:" + Constants.ITEM); - if (orderField != null) - { + if (orderField != null) { query.setSortField("bi_" + orderField + "_sort", - ascending ? SORT_ORDER.asc : SORT_ORDER.desc); + ascending ? SORT_ORDER.asc : SORT_ORDER.desc); } } - try - { - sResponse = searcher.search(context, query, itemsWithdrawn - || !itemsDiscoverable); - } - catch (SearchServiceException e) - { + try { + sResponse = searcher.search(context, query, itemsWithdrawn + || !itemsDiscoverable); + } catch (SearchServiceException e) { throw new BrowseException(e); } } return sResponse; } - private void addStatusFilter(DiscoverQuery query) - { - if (itemsWithdrawn) - { + private void addStatusFilter(DiscoverQuery query) { + if (itemsWithdrawn) { query.addFilterQueries("withdrawn:true"); - } - else if (!itemsDiscoverable) - { + } else if (!itemsDiscoverable) { query.addFilterQueries("discoverable:false"); // TODO - try - { + try { if (!authorizeService.isAdmin(context) - && (authorizeService.isCommunityAdmin(context) - || authorizeService.isCollectionAdmin(context))) - { - query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context)); + && (authorizeService.isCommunityAdmin(context) + || authorizeService.isCollectionAdmin(context))) { + query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context)); } - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error(ex); } } } - private void addLocationScopeFilter(DiscoverQuery query) - { - if (containerID != null) - { - if (containerIDField.startsWith("collection")) - { + private void addLocationScopeFilter(DiscoverQuery query) { + if (containerID != null) { + if (containerIDField.startsWith("collection")) { query.addFilterQueries("location.coll:" + containerID); - } - else if (containerIDField.startsWith("community")) - { + } else if (containerIDField.startsWith("community")) { query.addFilterQueries("location.comm:" + containerID); } } } @Override - public int doCountQuery() throws BrowseException - { + public int doCountQuery() throws BrowseException { DiscoverResult resp = getSolrResponse(); int count = 0; - if (distinct) - { + if (distinct) { List facetResults = resp.getFacetResult(facetField); count = facetResults.size(); - } - else - { + } else { // we need to cast to int to respect the BrowseDAO contract... count = (int) resp.getTotalSearchResults(); // FIXME null the response cache @@ -268,35 +274,29 @@ public class SolrBrowseDAO implements BrowseDAO } @Override - public List doValueQuery() throws BrowseException - { + public List doValueQuery() throws BrowseException { DiscoverResult resp = getSolrResponse(); List facet = resp.getFacetResult(facetField); int count = doCountQuery(); int start = offset > 0 ? offset : 0; int max = limit > 0 ? limit : count; //if negative, return everything List result = new ArrayList<>(); - if (ascending) - { - for (int i = start; i < (start + max) && i < count; i++) - { + if (ascending) { + for (int i = start; i < (start + max) && i < count; i++) { FacetResult c = facet.get(i); String freq = showFrequencies ? String.valueOf(c.getCount()) - : ""; - result.add(new String[] { c.getDisplayedValue(), - c.getAuthorityKey(), freq }); + : ""; + result.add(new String[] {c.getDisplayedValue(), + c.getAuthorityKey(), freq}); } - } - else - { + } else { for (int i = count - start - 1; i >= count - (start + max) - && i >= 0; i--) - { + && i >= 0; i--) { FacetResult c = facet.get(i); String freq = showFrequencies ? String.valueOf(c.getCount()) - : ""; - result.add(new String[] { c.getDisplayedValue(), - c.getAuthorityKey(), freq }); + : ""; + result.add(new String[] {c.getDisplayedValue(), + c.getAuthorityKey(), freq}); } } @@ -304,13 +304,11 @@ public class SolrBrowseDAO implements BrowseDAO } @Override - public List doQuery() throws BrowseException - { + public List doQuery() throws BrowseException { DiscoverResult resp = getSolrResponse(); List bitems = new ArrayList<>(); - for (DSpaceObject solrDoc : resp.getDspaceObjects()) - { + for (DSpaceObject solrDoc : resp.getDspaceObjects()) { // FIXME introduce project, don't retrieve Item immediately when // processing the query... Item item = (Item) solrDoc; @@ -321,25 +319,20 @@ public class SolrBrowseDAO implements BrowseDAO @Override public String doMaxQuery(String column, String table, int itemID) - throws BrowseException - { + throws BrowseException { DiscoverQuery query = new DiscoverQuery(); query.setQuery("search.resourceid:" + itemID - + " AND search.resourcetype:" + Constants.ITEM); + + " AND search.resourcetype:" + Constants.ITEM); query.setMaxResults(1); DiscoverResult resp = null; - try - { + try { resp = searcher.search(context, query); - } - catch (SearchServiceException e) - { + } catch (SearchServiceException e) { throw new BrowseException(e); } - if (resp.getTotalSearchResults() > 0) - { + if (resp.getTotalSearchResults() > 0) { SearchDocument doc = resp.getSearchDocument( - resp.getDspaceObjects().get(0)).get(0); + resp.getDspaceObjects().get(0)).get(0); return (String) doc.getSearchFieldValues(column).get(0); } return null; @@ -347,8 +340,7 @@ public class SolrBrowseDAO implements BrowseDAO @Override public int doOffsetQuery(String column, String value, boolean isAscending) - throws BrowseException - { + throws BrowseException { DiscoverQuery query = new DiscoverQuery(); addLocationScopeFilter(query); addStatusFilter(query); @@ -356,37 +348,26 @@ public class SolrBrowseDAO implements BrowseDAO query.addFilterQueries("search.resourcetype:" + Constants.ITEM); // We need to take into account the fact that we may be in a subset of the items - if (authority != null) - { - query.addFilterQueries("{!field f="+facetField + "_authority_filter}" - + authority); - } - else if (this.value != null && !valuePartial) - { - query.addFilterQueries("{!field f="+facetField + "_value_filter}" + this.value); - } - else if (valuePartial) - { - query.addFilterQueries("{!field f="+facetField + "_partial}" + this.value); + if (authority != null) { + query.addFilterQueries("{!field f=" + facetField + "_authority_filter}" + + authority); + } else if (this.value != null && !valuePartial) { + query.addFilterQueries("{!field f=" + facetField + "_value_filter}" + this.value); + } else if (valuePartial) { + query.addFilterQueries("{!field f=" + facetField + "_partial}" + this.value); } - if (isAscending) - { - query.setQuery("bi_"+column + "_sort" + ": [* TO \"" + value + "\"}"); - } - else - { + if (isAscending) { + query.setQuery("bi_" + column + "_sort" + ": [* TO \"" + value + "\"}"); + } else { query.setQuery("bi_" + column + "_sort" + ": {\"" + value + "\" TO *]"); - query.addFilterQueries("-(bi_" + column + "_sort" + ":" + value + "*)"); + query.addFilterQueries("-(bi_" + column + "_sort" + ":" + value + "*)"); } - boolean includeUnDiscoverable = itemsWithdrawn || !itemsDiscoverable; + boolean includeUnDiscoverable = itemsWithdrawn || !itemsDiscoverable; DiscoverResult resp = null; - try - { + try { resp = searcher.search(context, query, includeUnDiscoverable); - } - catch (SearchServiceException e) - { + } catch (SearchServiceException e) { throw new BrowseException(e); } return (int) resp.getTotalSearchResults(); @@ -394,33 +375,27 @@ public class SolrBrowseDAO implements BrowseDAO @Override public int doDistinctOffsetQuery(String column, String value, - boolean isAscending) throws BrowseException - { + boolean isAscending) throws BrowseException { DiscoverResult resp = getSolrResponse(); List facets = resp.getFacetResult(facetField); Comparator comparator = new SolrBrowseDAO.FacetValueComparator(); Collections.sort(facets, comparator); int x = Collections.binarySearch(facets, value, comparator); int ascValue = (x >= 0) ? x : -(x + 1); - if (isAscending) - { + if (isAscending) { return ascValue; - } - else - { + } else { return doCountQuery() - ascValue; } } @Override - public boolean isEnableBrowseFrequencies() - { + public boolean isEnableBrowseFrequencies() { return showFrequencies; } @Override - public void setEnableBrowseFrequencies(boolean enableBrowseFrequencies) - { + public void setEnableBrowseFrequencies(boolean enableBrowseFrequencies) { showFrequencies = enableBrowseFrequencies; } @@ -430,8 +405,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getContainerID() */ @Override - public UUID getContainerID() - { + public UUID getContainerID() { return containerID; } @@ -441,8 +415,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getContainerIDField() */ @Override - public String getContainerIDField() - { + public String getContainerIDField() { return containerIDField; } @@ -452,15 +425,13 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getContainerTable() */ @Override - public String getContainerTable() - { + public String getContainerTable() { return containerTable; } // FIXME is this in use? @Override - public String[] getCountValues() - { + public String[] getCountValues() { return null; } @@ -470,8 +441,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getFocusField() */ @Override - public String getJumpToField() - { + public String getJumpToField() { return focusField; } @@ -481,19 +451,27 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getFocusValue() */ @Override - public String getJumpToValue() - { + public String getJumpToValue() { return focusValue; } - /* + @Override + public void setStartsWith(String startsWith) { + this.startsWith = startsWith; + } + + @Override + public String getStartsWith() { + return startsWith; + } + + /* * (non-Javadoc) * * @see org.dspace.browse.BrowseDAO#getLimit() */ @Override - public int getLimit() - { + public int getLimit() { return limit; } @@ -503,8 +481,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getOffset() */ @Override - public int getOffset() - { + public int getOffset() { return offset; } @@ -514,15 +491,13 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getOrderField() */ @Override - public String getOrderField() - { + public String getOrderField() { return orderField; } // is this in use? @Override - public String[] getSelectValues() - { + public String[] getSelectValues() { return null; } @@ -532,8 +507,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getTable() */ @Override - public String getTable() - { + public String getTable() { return table; } @@ -543,8 +517,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getValue() */ @Override - public String getFilterValue() - { + public String getFilterValue() { return value; } @@ -554,8 +527,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#getValueField() */ @Override - public String getFilterValueField() - { + public String getFilterValueField() { return valueField; } @@ -565,8 +537,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#isAscending() */ @Override - public boolean isAscending() - { + public boolean isAscending() { return ascending; } @@ -576,8 +547,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#isDistinct() */ @Override - public boolean isDistinct() - { + public boolean isDistinct() { return this.distinct; } @@ -587,8 +557,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setAscending(boolean) */ @Override - public void setAscending(boolean ascending) - { + public void setAscending(boolean ascending) { this.ascending = ascending; } @@ -599,8 +568,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setContainerID(int) */ @Override - public void setContainerID(UUID containerID) - { + public void setContainerID(UUID containerID) { this.containerID = containerID; } @@ -611,8 +579,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setContainerIDField(java.lang.String) */ @Override - public void setContainerIDField(String containerIDField) - { + public void setContainerIDField(String containerIDField) { this.containerIDField = containerIDField; } @@ -623,16 +590,14 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setContainerTable(java.lang.String) */ @Override - public void setContainerTable(String containerTable) - { + public void setContainerTable(String containerTable) { this.containerTable = containerTable; } // is this in use? @Override - public void setCountValues(String[] fields) - { + public void setCountValues(String[] fields) { // this.countValues = fields; } @@ -643,8 +608,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setDistinct(boolean) */ @Override - public void setDistinct(boolean bool) - { + public void setDistinct(boolean bool) { this.distinct = bool; } @@ -655,8 +619,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setEqualsComparator(boolean) */ @Override - public void setEqualsComparator(boolean equalsComparator) - { + public void setEqualsComparator(boolean equalsComparator) { this.equalsComparator = equalsComparator; } @@ -667,8 +630,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setFocusField(java.lang.String) */ @Override - public void setJumpToField(String focusField) - { + public void setJumpToField(String focusField) { this.focusField = focusField; } @@ -679,8 +641,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setFocusValue(java.lang.String) */ @Override - public void setJumpToValue(String focusValue) - { + public void setJumpToValue(String focusValue) { this.focusValue = focusValue; } @@ -691,8 +652,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setLimit(int) */ @Override - public void setLimit(int limit) - { + public void setLimit(int limit) { this.limit = limit; } @@ -703,8 +663,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setOffset(int) */ @Override - public void setOffset(int offset) - { + public void setOffset(int offset) { this.offset = offset; } @@ -715,16 +674,14 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setOrderField(java.lang.String) */ @Override - public void setOrderField(String orderField) - { + public void setOrderField(String orderField) { this.orderField = orderField; } // is this in use? @Override - public void setSelectValues(String[] selectValues) - { + public void setSelectValues(String[] selectValues) { // this.selectValues = selectValues; } @@ -735,24 +692,18 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setTable(java.lang.String) */ @Override - public void setTable(String table) - { - if (table.equals(BrowseIndex.getWithdrawnBrowseIndex().getTableName())) - { + public void setTable(String table) { + if (table.equals(BrowseIndex.getWithdrawnBrowseIndex().getTableName())) { itemsWithdrawn = true; - } - else if (table.equals(BrowseIndex.getPrivateBrowseIndex().getTableName())) - { + } else if (table.equals(BrowseIndex.getPrivateBrowseIndex().getTableName())) { itemsDiscoverable = false; } facetField = table; } @Override - public void setFilterMappingTables(String tableDis, String tableMap) - { - if (tableDis != null) - { + public void setFilterMappingTables(String tableDis, String tableMap) { + if (tableDis != null) { this.facetField = tableDis; } // this.fields = tableDis; @@ -765,8 +716,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setValue(java.lang.String) */ @Override - public void setFilterValue(String value) - { + public void setFilterValue(String value) { this.value = value; } @@ -777,8 +727,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setFilterValuePartial(boolean) */ @Override - public void setFilterValuePartial(boolean part) - { + public void setFilterValuePartial(boolean part) { this.valuePartial = part; } @@ -789,8 +738,7 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#setValueField(java.lang.String) */ @Override - public void setFilterValueField(String valueField) - { + public void setFilterValueField(String valueField) { this.valueField = valueField; } @@ -801,20 +749,17 @@ public class SolrBrowseDAO implements BrowseDAO * @see org.dspace.browse.BrowseDAO#useEqualsComparator() */ @Override - public boolean useEqualsComparator() - { + public boolean useEqualsComparator() { return equalsComparator; } @Override - public String getAuthorityValue() - { + public String getAuthorityValue() { return authority; } @Override - public void setAuthorityValue(String value) - { + public void setAuthorityValue(String value) { this.authority = value; } } diff --git a/dspace-api/src/main/java/org/dspace/checker/BitstreamDispatcher.java b/dspace-api/src/main/java/org/dspace/checker/BitstreamDispatcher.java index 721ce04bfb..62077c14e8 100644 --- a/dspace-api/src/main/java/org/dspace/checker/BitstreamDispatcher.java +++ b/dspace-api/src/main/java/org/dspace/checker/BitstreamDispatcher.java @@ -7,17 +7,16 @@ */ package org.dspace.checker; +import java.sql.SQLException; import org.dspace.content.Bitstream; -import java.sql.SQLException; - /** *

    * BitstreamDispatchers are strategy objects that hand bitstream ids out to * workers. Implementations must be threadsafe. *

    - * + * *

    * The rationale behind the use of the Sentinel pattern (rather than the more * traditional iterator pattern or a cursor c.f. java.sql.ResultSet): - @@ -29,15 +28,12 @@ import java.sql.SQLException; *

  • Shouldn't an exception as the sentinel, as reaching the end of a loop is * not an exceptional condition.
  • * - * - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ -public interface BitstreamDispatcher -{ +public interface BitstreamDispatcher { /** * This value should be returned by next() to indicate that * there are no more values. @@ -47,11 +43,10 @@ public interface BitstreamDispatcher /** * Returns the next id for checking, or a sentinel value if there are no * more to check. - * + * * @return the next bitstream id, or BitstreamDispatcher.SENTINEL if there - * isn't another value + * isn't another value * @throws SQLException if database error - * */ public Bitstream next() throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/checker/CheckerCommand.java b/dspace-api/src/main/java/org/dspace/checker/CheckerCommand.java index ca403fad2f..2ae27e5ec6 100644 --- a/dspace-api/src/main/java/org/dspace/checker/CheckerCommand.java +++ b/dspace-api/src/main/java/org/dspace/checker/CheckerCommand.java @@ -7,7 +7,12 @@ */ package org.dspace.checker; -import org.apache.commons.collections.MapUtils; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Date; +import java.util.Map; + +import org.apache.commons.collections4.MapUtils; import org.apache.log4j.Logger; import org.dspace.checker.factory.CheckerServiceFactory; import org.dspace.checker.service.ChecksumHistoryService; @@ -18,34 +23,32 @@ import org.dspace.core.Context; import org.dspace.storage.bitstore.factory.StorageServiceFactory; import org.dspace.storage.bitstore.service.BitstreamStorageService; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Date; -import java.util.Map; - /** *

    * Main class for the checksum checker tool, which calculates checksums for each * bitstream whose ID is in the most_recent_checksum table, and compares it * against the last calculated checksum for that bitstream. *

    - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * - * + * + * * TODO the accessor methods are currently unused - are they useful? * TODO check for any existing resource problems */ -public final class CheckerCommand -{ - /** Usual Log4J logger. */ +public final class CheckerCommand { + /** + * Usual Log4J logger. + */ private static final Logger LOG = Logger.getLogger(CheckerCommand.class); private Context context; - /** BitstreamInfoDAO dependency. */ + /** + * BitstreamInfoDAO dependency. + */ private MostRecentChecksumService checksumService = null; /** @@ -55,7 +58,9 @@ public final class CheckerCommand private BitstreamStorageService bitstreamStorageService = null; private ChecksumResultService checksumResultService = null; - /** start time for current process. */ + /** + * start time for current process. + */ private Date processStartDate = null; /** @@ -68,15 +73,17 @@ public final class CheckerCommand */ private ChecksumResultsCollector collector = null; - /** Report all processing */ + /** + * Report all processing + */ private boolean reportVerbose = false; /** * Default constructor uses DSpace plugin manager to construct dependencies. + * * @param context Context */ - public CheckerCommand(Context context) - { + public CheckerCommand(Context context) { checksumService = CheckerServiceFactory.getInstance().getMostRecentChecksumService(); checksumHistoryService = CheckerServiceFactory.getInstance().getChecksumHistoryService(); bitstreamStorageService = StorageServiceFactory.getInstance().getBitstreamStorageService(); @@ -90,23 +97,22 @@ public final class CheckerCommand * and then accepts bitstream ids from the dispatcher and checks their * bitstreams against the db records. *

    - * + * *

    * N.B. a valid BitstreamDispatcher must be provided using * setBitstreamDispatcher before calling this method *

    + * * @throws SQLException if database error */ public void process() throws SQLException { LOG.debug("Begin Checker Processing"); - if (dispatcher == null) - { + if (dispatcher == null) { throw new IllegalStateException("No BitstreamDispatcher provided"); } - if (collector == null) - { + if (collector == null) { collector = new ResultsLogger(processStartDate); } @@ -116,14 +122,12 @@ public final class CheckerCommand Bitstream bitstream = dispatcher.next(); - while (bitstream != null) - { + while (bitstream != null) { LOG.debug("Processing bitstream id = " + bitstream.getID()); MostRecentChecksum info = checkBitstream(bitstream); if (reportVerbose - || !ChecksumResultCode.CHECKSUM_MATCH.equals(info.getChecksumResult().getResultCode())) - { + || !ChecksumResultCode.CHECKSUM_MATCH.equals(info.getChecksumResult().getResultCode())) { collector.collect(context, info); } @@ -134,10 +138,8 @@ public final class CheckerCommand /** * Check a specified bitstream. - * - * @param bitstream - * the bitstream - * + * + * @param bitstream the bitstream * @return the information about the bitstream and its checksum data * @throws SQLException if database error */ @@ -147,29 +149,22 @@ public final class CheckerCommand // requested id was not found in bitstream // or most_recent_checksum table - if (info == null) - { + if (info == null) { // Note: this case should only occur if id is requested at // command line, since ref integrity checks should // prevent id from appearing in most_recent_checksum // but not bitstream table, or vice versa info = checksumService.getNonPersistedObject(); processNullInfoBitstream(info); - } - else if (!info.isToBeProcessed()) - { + } else if (!info.isToBeProcessed()) { // most_recent_checksum.to_be_processed is marked // 'false' for this bitstream id. // Do not do any db updates info.setChecksumResult(getChecksumResultByCode(ChecksumResultCode.BITSTREAM_NOT_PROCESSED)); - } - else if (info.getBitstream().isDeleted()) - { + } else if (info.getBitstream().isDeleted()) { // bitstream id is marked 'deleted' in bitstream table. processDeletedBitstream(info); - } - else - { + } else { processBitstream(info); } @@ -178,24 +173,18 @@ public final class CheckerCommand /** * Compares two checksums. - * - * @param checksumA - * the first checksum - * @param checksumB - * the second checksum - * + * + * @param checksumA the first checksum + * @param checksumB the second checksum * @return a result code (constants defined in Util) * @throws SQLException if database error */ protected ChecksumResult compareChecksums(String checksumA, String checksumB) throws SQLException { ChecksumResult result = getChecksumResultByCode(ChecksumResultCode.CHECKSUM_NO_MATCH); - if ((checksumA == null) || (checksumB == null)) - { + if ((checksumA == null) || (checksumB == null)) { result = getChecksumResultByCode(ChecksumResultCode.CHECKSUM_PREV_NOT_FOUND); - } - else if (checksumA.equals(checksumB)) - { + } else if (checksumA.equals(checksumB)) { result = getChecksumResultByCode(ChecksumResultCode.CHECKSUM_MATCH); } @@ -207,9 +196,8 @@ public final class CheckerCommand * bitstream should only be checked once afterwards it should be marked * 'to_be_processed=false'. Note that to_be_processed must be manually * updated in db to allow for future processing. - * - * @param info - * a deleted bitstream. + * + * @param info a deleted bitstream. * @throws SQLException if database error */ protected void processDeletedBitstream(MostRecentChecksum info) throws SQLException { @@ -225,10 +213,9 @@ public final class CheckerCommand * Process bitstream whose ID was not found in most_recent_checksum or * bitstream table. No updates can be done. The missing bitstream is output * to the log file. - * - * @param info - * A not found BitStreamInfo - * TODO is this method required? + * + * @param info A not found BitStreamInfo + * TODO is this method required? * @throws SQLException if database error */ protected void processNullInfoBitstream(MostRecentChecksum info) throws SQLException { @@ -242,57 +229,50 @@ public final class CheckerCommand *

    * Process general case bitstream. *

    - * + * *

    * Note: bitstream will have timestamp indicating it was "checked", even if * actual checksumming never took place. *

    - * + * * TODO Why does bitstream have a timestamp indicating it's checked if - * checksumming doesn't occur? - * - * @param info - * BitstreamInfo to handle + * checksumming doesn't occur? + * + * @param info BitstreamInfo to handle * @throws SQLException if database error */ protected void processBitstream(MostRecentChecksum info) throws SQLException { info.setProcessStartDate(new Date()); - try - { + try { Map checksumMap = bitstreamStorageService.computeChecksum(context, info.getBitstream()); - if(MapUtils.isNotEmpty(checksumMap)) { + if (MapUtils.isNotEmpty(checksumMap)) { info.setBitstreamFound(true); - if(checksumMap.containsKey("checksum")) { + if (checksumMap.containsKey("checksum")) { info.setCurrentChecksum(checksumMap.get("checksum").toString()); } - if(checksumMap.containsKey("checksum_algorithm")) { + if (checksumMap.containsKey("checksum_algorithm")) { info.setChecksumAlgorithm(checksumMap.get("checksum_algorithm").toString()); } } // compare new checksum to previous checksum info.setChecksumResult(compareChecksums(info.getExpectedChecksum(), info.getCurrentChecksum())); - } - catch (IOException e) - { + } catch (IOException e) { // bitstream located, but file missing from asset store info.setChecksumResult(getChecksumResultByCode(ChecksumResultCode.BITSTREAM_NOT_FOUND)); info.setToBeProcessed(false); LOG.error("Error retrieving bitstream ID " + info.getBitstream().getID() - + " from " + "asset store.", e); - } - catch (SQLException e) - { + + " from " + "asset store.", e); + } catch (SQLException e) { // ??this code only executes if an SQL // exception occurs in *DSpace* code, probably // indicating a general db problem? info.setChecksumResult(getChecksumResultByCode(ChecksumResultCode.BITSTREAM_INFO_NOT_FOUND)); LOG.error("Error retrieving metadata for bitstream ID " - + info.getBitstream().getID(), e); - } finally - { + + info.getBitstream().getID(), e); + } finally { info.setProcessEndDate(new Date()); // record new checksum and comparison result in db @@ -307,85 +287,73 @@ public final class CheckerCommand /** * Get dispatcher being used by this run of the checker. - * + * * @return the dispatcher being used by this run. */ - public BitstreamDispatcher getDispatcher() - { + public BitstreamDispatcher getDispatcher() { return dispatcher; } /** * Set the dispatcher to be used by this run of the checker. - * - * @param dispatcher - * Dispatcher to use. + * + * @param dispatcher Dispatcher to use. */ - public void setDispatcher(BitstreamDispatcher dispatcher) - { + public void setDispatcher(BitstreamDispatcher dispatcher) { this.dispatcher = dispatcher; } /** * Get the collector that holds/logs the results for this process run. - * + * * @return The ChecksumResultsCollector being used. */ - public ChecksumResultsCollector getCollector() - { + public ChecksumResultsCollector getCollector() { return collector; } /** * Set the collector that holds/logs the results for this process run. - * - * @param collector - * the collector to be used for this run + * + * @param collector the collector to be used for this run */ - public void setCollector(ChecksumResultsCollector collector) - { + public void setCollector(ChecksumResultsCollector collector) { this.collector = collector; } /** * Get time at which checker process began. - * + * * @return start time */ - public Date getProcessStartDate() - { + public Date getProcessStartDate() { return processStartDate == null ? null : new Date(processStartDate.getTime()); } /** * Set time at which checker process began. - * - * @param startDate - * start time + * + * @param startDate start time */ - public void setProcessStartDate(Date startDate) - { + public void setProcessStartDate(Date startDate) { processStartDate = startDate == null ? null : new Date(startDate.getTime()); } /** * Determine if any errors are reported - * + * * @return true if only errors reported */ - public boolean isReportVerbose() - { + public boolean isReportVerbose() { return reportVerbose; } /** * Set report errors only - * - * @param reportVerbose - * true to report only errors in the logs. + * + * @param reportVerbose true to report only errors in the logs. */ - public void setReportVerbose(boolean reportVerbose) - { + public void setReportVerbose(boolean reportVerbose) { this.reportVerbose = reportVerbose; } } diff --git a/dspace-api/src/main/java/org/dspace/checker/CheckerConsumer.java b/dspace-api/src/main/java/org/dspace/checker/CheckerConsumer.java index 93eb7aa260..f4266a7a79 100644 --- a/dspace-api/src/main/java/org/dspace/checker/CheckerConsumer.java +++ b/dspace-api/src/main/java/org/dspace/checker/CheckerConsumer.java @@ -22,67 +22,66 @@ import org.dspace.event.Event; * * @version $Revision$ */ -public class CheckerConsumer implements Consumer -{ - /** log4j logger */ +public class CheckerConsumer implements Consumer { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(CheckerConsumer.class); - - protected ChecksumHistoryService checksumHistoryService = CheckerServiceFactory.getInstance().getChecksumHistoryService(); + + protected ChecksumHistoryService checksumHistoryService = CheckerServiceFactory.getInstance() + .getChecksumHistoryService(); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - + /** * Initialize - allocate any resources required to operate. * Called at the start of ANY sequence of event consume() calls. + * * @throws Exception if error */ @Override - public void initialize() throws Exception - { - // no-op + public void initialize() throws Exception { + // no-op } - + /** * Consume an event * - * @param ctx the execution context object - * + * @param ctx the execution context object * @param event the content event * @throws Exception if error */ @Override - public void consume(Context ctx, Event event) throws Exception - { - - if (event.getEventType() == Event.DELETE) - { + public void consume(Context ctx, Event event) throws Exception { + + if (event.getEventType() == Event.DELETE) { Bitstream bitstream = bitstreamService.find(ctx, event.getSubjectID()); log.debug("Attempting to remove Checker Info"); checksumHistoryService.deleteByBitstream(ctx, bitstream); log.debug("Completed removing Checker Info"); - } + } } - + /** * Signal that there are no more events queued in this * event stream. + * * @param ctx Context * @throws Exception if error */ @Override - public void end(Context ctx) throws Exception - { - // no-op + public void end(Context ctx) throws Exception { + // no-op } - + /** * Finish - free any allocated resources. * Called when consumer is being released + * * @param ctx Context * @throws Exception if error */ @Override - public void finish(Context ctx) throws Exception - { - // no-op + public void finish(Context ctx) throws Exception { + // no-op } } diff --git a/dspace-api/src/main/java/org/dspace/checker/ChecksumHistory.java b/dspace-api/src/main/java/org/dspace/checker/ChecksumHistory.java index 5e1e943ab8..63779cda02 100644 --- a/dspace-api/src/main/java/org/dspace/checker/ChecksumHistory.java +++ b/dspace-api/src/main/java/org/dspace/checker/ChecksumHistory.java @@ -7,12 +7,23 @@ */ package org.dspace.checker; -import org.dspace.core.Context; -import org.dspace.content.Bitstream; -import org.dspace.core.ReloadableEntity; - -import javax.persistence.*; import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.dspace.content.Bitstream; +import org.dspace.core.Context; +import org.dspace.core.ReloadableEntity; /** *

    @@ -22,18 +33,17 @@ import java.util.Date; * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ @Entity -@Table(name="checksum_history") -public class ChecksumHistory implements ReloadableEntity -{ +@Table(name = "checksum_history") +public class ChecksumHistory implements ReloadableEntity { @Id - @Column(name="check_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="checksum_history_check_id_seq") - @SequenceGenerator(name="checksum_history_check_id_seq", sequenceName="checksum_history_check_id_seq", allocationSize = 1) + @Column(name = "check_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "checksum_history_check_id_seq") + @SequenceGenerator(name = "checksum_history_check_id_seq", sequenceName = "checksum_history_check_id_seq", + allocationSize = 1) private Long id; @ManyToOne(fetch = FetchType.LAZY) @@ -48,10 +58,10 @@ public class ChecksumHistory implements ReloadableEntity @Column(name = "process_end_date", nullable = false) private Date processEndDate; - @Column(name= "checksum_expected", nullable = false) + @Column(name = "checksum_expected", nullable = false) private String checksumExpected; - @Column(name= "checksum_calculated", nullable = false) + @Column(name = "checksum_calculated", nullable = false) private String checksumCalculated; @ManyToOne @@ -63,8 +73,7 @@ public class ChecksumHistory implements ReloadableEntity * Protected constructor, create object using: * {@link org.dspace.checker.service.ChecksumHistoryService#addHistory(Context, MostRecentChecksum)} */ - protected ChecksumHistory() - { + protected ChecksumHistory() { } public Long getID() { @@ -74,8 +83,7 @@ public class ChecksumHistory implements ReloadableEntity /** * @return Returns the bitstreamId. */ - public Bitstream getBitstream() - { + public Bitstream getBitstream() { return bitstream; } @@ -86,19 +94,16 @@ public class ChecksumHistory implements ReloadableEntity /** * @return Returns the checksumCalculated. */ - public String getChecksumCalculated() - { + public String getChecksumCalculated() { return checksumCalculated; } /** * Set the checksum calculated. * - * @param checksumCalculated - * The checksumCalculated to set. + * @param checksumCalculated The checksumCalculated to set. */ - public void setChecksumCalculated(String checksumCalculated) - { + public void setChecksumCalculated(String checksumCalculated) { this.checksumCalculated = checksumCalculated; } @@ -107,19 +112,16 @@ public class ChecksumHistory implements ReloadableEntity * * @return Returns the checksumExpected. */ - public String getChecksumExpected() - { + public String getChecksumExpected() { return checksumExpected; } /** * Set the expected checksum. * - * @param checksumExpected - * The checksumExpected to set. + * @param checksumExpected The checksumExpected to set. */ - public void setChecksumExpected(String checksumExpected) - { + public void setChecksumExpected(String checksumExpected) { this.checksumExpected = checksumExpected; } @@ -128,19 +130,16 @@ public class ChecksumHistory implements ReloadableEntity * * @return Returns the processEndDate. */ - public Date getProcessEndDate() - { + public Date getProcessEndDate() { return processEndDate == null ? null : new Date(processEndDate.getTime()); } /** * Set the process end date. This is the date and time the processing ended. * - * @param processEndDate - * The processEndDate to set. + * @param processEndDate The processEndDate to set. */ - public void setProcessEndDate(Date processEndDate) - { + public void setProcessEndDate(Date processEndDate) { this.processEndDate = (processEndDate == null ? null : new Date(processEndDate.getTime())); } @@ -150,8 +149,7 @@ public class ChecksumHistory implements ReloadableEntity * * @return Returns the processStartDate. */ - public Date getProcessStartDate() - { + public Date getProcessStartDate() { return processStartDate == null ? null : new Date(processStartDate.getTime()); } @@ -159,31 +157,27 @@ public class ChecksumHistory implements ReloadableEntity * Set the process start date. This is the date and time the processing * started. * - * @param processStartDate - * The processStartDate to set. + * @param processStartDate The processStartDate to set. */ - public void setProcessStartDate(Date processStartDate) - { + public void setProcessStartDate(Date processStartDate) { this.processStartDate = (processStartDate == null ? null : new Date(processStartDate.getTime())); } /** * Return the processing result. + * * @return result */ - public ChecksumResult getResult() - { + public ChecksumResult getResult() { return checksumResult; } /** * Set the checksum processing result. * - * @param result - * The result to set. + * @param result The result to set. */ - public void setResult(ChecksumResult result) - { + public void setResult(ChecksumResult result) { this.checksumResult = result; } } diff --git a/dspace-api/src/main/java/org/dspace/checker/ChecksumHistoryServiceImpl.java b/dspace-api/src/main/java/org/dspace/checker/ChecksumHistoryServiceImpl.java index ec8e602ae7..f8d6560e92 100644 --- a/dspace-api/src/main/java/org/dspace/checker/ChecksumHistoryServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/ChecksumHistoryServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.checker; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.Map; + import org.dspace.checker.dao.ChecksumHistoryDAO; import org.dspace.checker.service.ChecksumHistoryService; import org.dspace.checker.service.ChecksumResultService; @@ -15,11 +20,6 @@ import org.dspace.content.Bitstream; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; -import java.util.Map; - /** * Service implementation for the ChecksumHistory object. * This class is responsible for all business logic calls for the ChecksumHistory object and is autowired by spring. @@ -37,8 +37,7 @@ public class ChecksumHistoryServiceImpl implements ChecksumHistoryService { @Autowired(required = true) protected ChecksumResultService checksumResultService; - protected ChecksumHistoryServiceImpl() - { + protected ChecksumHistoryServiceImpl() { } @@ -72,8 +71,7 @@ public class ChecksumHistoryServiceImpl implements ChecksumHistoryService { checksumHistory.setChecksumExpected(mostRecentChecksum.getExpectedChecksum()); checksumHistory.setChecksumCalculated(mostRecentChecksum.getCurrentChecksum()); ChecksumResult checksumResult; - if(mostRecentChecksum.getBitstream().isDeleted()) - { + if (mostRecentChecksum.getBitstream().isDeleted()) { checksumResult = checksumResultService.findByCode(context, ChecksumResultCode.BITSTREAM_MARKED_DELETED); } else { checksumResult = checksumResultService.findByCode(context, ChecksumResultCode.CHECKSUM_MATCH); @@ -88,17 +86,15 @@ public class ChecksumHistoryServiceImpl implements ChecksumHistoryService { /** * Delete the history records from the database. * - * @param context Context - * @param retentionDate - * any records older than this data are deleted. - * @param checksumResultCode - * result code records must have for them to be deleted. + * @param context Context + * @param retentionDate any records older than this data are deleted. + * @param checksumResultCode result code records must have for them to be deleted. * @return number of records deleted. * @throws SQLException if database error occurs. */ @Override - public int deleteByDateAndCode(Context context, Date retentionDate, ChecksumResultCode checksumResultCode) throws SQLException - { + public int deleteByDateAndCode(Context context, Date retentionDate, ChecksumResultCode checksumResultCode) + throws SQLException { return checksumHistoryDAO.deleteByDateAndCode(context, retentionDate, checksumResultCode); } @@ -114,10 +110,9 @@ public class ChecksumHistoryServiceImpl implements ChecksumHistoryService { public int prune(Context context, Map interests) throws SQLException { long now = System.currentTimeMillis(); int count = 0; - for (Map.Entry interest : interests.entrySet()) - { + for (Map.Entry interest : interests.entrySet()) { count += deleteByDateAndCode(context, new Date(now - interest.getValue().longValue()), - interest.getKey()); + interest.getKey()); } return count; diff --git a/dspace-api/src/main/java/org/dspace/checker/ChecksumResult.java b/dspace-api/src/main/java/org/dspace/checker/ChecksumResult.java index 08d02bb625..57fcdb8e36 100644 --- a/dspace-api/src/main/java/org/dspace/checker/ChecksumResult.java +++ b/dspace-api/src/main/java/org/dspace/checker/ChecksumResult.java @@ -8,7 +8,12 @@ package org.dspace.checker; import java.io.Serializable; -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.Table; /** * Database entity representation of the checksum_results table @@ -16,12 +21,11 @@ import javax.persistence.*; * @author kevinvandevelde at atmire.com */ @Entity -@Table(name="checksum_results") +@Table(name = "checksum_results") public class ChecksumResult - implements Serializable -{ + implements Serializable { @Id - @Column(name="result_code") + @Column(name = "result_code") @Enumerated(EnumType.STRING) private ChecksumResultCode resultCode; @@ -31,10 +35,10 @@ public class ChecksumResult /** * Protected constructor, new object creation impossible */ - protected ChecksumResult() - { + protected ChecksumResult() { } + public ChecksumResultCode getResultCode() { return resultCode; } diff --git a/dspace-api/src/main/java/org/dspace/checker/ChecksumResultCode.java b/dspace-api/src/main/java/org/dspace/checker/ChecksumResultCode.java index 3dc98007f9..a0b5321442 100644 --- a/dspace-api/src/main/java/org/dspace/checker/ChecksumResultCode.java +++ b/dspace-api/src/main/java/org/dspace/checker/ChecksumResultCode.java @@ -10,13 +10,11 @@ package org.dspace.checker; /** * Enumeration of ChecksumCheckResults containing constants for checksum * comparison result that must correspond to values in checksum_result table. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr * @author Kevin Van de Velde - * - * */ public enum ChecksumResultCode { BITSTREAM_NOT_FOUND, diff --git a/dspace-api/src/main/java/org/dspace/checker/ChecksumResultServiceImpl.java b/dspace-api/src/main/java/org/dspace/checker/ChecksumResultServiceImpl.java index 3335ceafd0..a06e3018dc 100644 --- a/dspace-api/src/main/java/org/dspace/checker/ChecksumResultServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/ChecksumResultServiceImpl.java @@ -7,14 +7,14 @@ */ package org.dspace.checker; +import java.sql.SQLException; +import java.util.List; + import org.dspace.checker.dao.ChecksumResultDAO; import org.dspace.checker.service.ChecksumResultService; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.List; - /** * Service implementation for the ChecksumResult object. * This class is responsible for all business logic calls for the ChecksumResult object and is autowired by spring. @@ -27,8 +27,7 @@ public class ChecksumResultServiceImpl implements ChecksumResultService { @Autowired(required = true) private ChecksumResultDAO checksumResultDAO; - protected ChecksumResultServiceImpl() - { + protected ChecksumResultServiceImpl() { } @@ -36,14 +35,12 @@ public class ChecksumResultServiceImpl implements ChecksumResultService { * Get the result description for the given result code * * @param context Context - * @param code - * to get the description for. + * @param code to get the description for. * @return the found description. * @throws SQLException if database error */ @Override - public ChecksumResult findByCode(Context context, ChecksumResultCode code) throws SQLException - { + public ChecksumResult findByCode(Context context, ChecksumResultCode code) throws SQLException { return checksumResultDAO.findByCode(context, code); } diff --git a/dspace-api/src/main/java/org/dspace/checker/ChecksumResultsCollector.java b/dspace-api/src/main/java/org/dspace/checker/ChecksumResultsCollector.java index 615e30b28d..8ff2a3df6f 100644 --- a/dspace-api/src/main/java/org/dspace/checker/ChecksumResultsCollector.java +++ b/dspace-api/src/main/java/org/dspace/checker/ChecksumResultsCollector.java @@ -7,26 +7,23 @@ */ package org.dspace.checker; -import org.dspace.core.Context; - import java.sql.SQLException; +import org.dspace.core.Context; + /** * Component that receives BitstreamInfo results from a checker. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ -public interface ChecksumResultsCollector -{ +public interface ChecksumResultsCollector { /** * Collects results. - * + * * @param context Context - * @param info - * BitstreamInfo representing the check results. + * @param info BitstreamInfo representing the check results. * @throws SQLException if database error */ void collect(Context context, MostRecentChecksum info) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/checker/DailyReportEmailer.java b/dspace-api/src/main/java/org/dspace/checker/DailyReportEmailer.java index 1b32b490e8..0b54ede0c5 100644 --- a/dspace-api/src/main/java/org/dspace/checker/DailyReportEmailer.java +++ b/dspace-api/src/main/java/org/dspace/checker/DailyReportEmailer.java @@ -7,7 +7,20 @@ */ package org.dspace.checker; -import org.apache.commons.cli.*; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Date; +import java.util.GregorianCalendar; +import javax.mail.MessagingException; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.dspace.checker.factory.CheckerServiceFactory; import org.dspace.checker.service.SimpleReporterService; @@ -15,88 +28,74 @@ import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.core.Email; -import javax.mail.MessagingException; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Date; -import java.util.GregorianCalendar; - /** *

    * The email reporter creates and sends emails to an administrator. This only * reports information for today's date. It is expected this will be used just * after the checksum checker has been run. *

    - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * - * */ -public class DailyReportEmailer -{ - /** log4j logger. */ +public class DailyReportEmailer { + /** + * log4j logger. + */ private static Logger log = Logger.getLogger(DailyReportEmailer.class); /** * Default constructor. */ - public DailyReportEmailer() - { + public DailyReportEmailer() { } /** * Send the report through email. - * - * @param attachment - * the file containing the report - * @param numberOfBitstreams - * the number of bitstreams reported - * - * @throws IOException if IO exception occurs + * + * @param attachment the file containing the report + * @param numberOfBitstreams the number of bitstreams reported + * @throws IOException if IO exception occurs * @throws MessagingException if message cannot be sent. */ - public void sendReport(File attachment, int numberOfBitstreams) - throws IOException, javax.mail.MessagingException - { - if (numberOfBitstreams > 0) - { + public void sendReport(File attachment, int numberOfBitstreams) + throws IOException, javax.mail.MessagingException { + if (numberOfBitstreams > 0) { String hostname = ConfigurationManager.getProperty("dspace.hostname"); Email email = new Email(); - email.setSubject("Checksum checker Report - " + numberOfBitstreams + " Bitstreams found with POSSIBLE issues on " + hostname); + email.setSubject( + "Checksum checker Report - " + numberOfBitstreams + " Bitstreams found with POSSIBLE issues on " + + hostname); email.setContent("report is attached ..."); email.addAttachment(attachment, "checksum_checker_report.txt"); email.addRecipient(ConfigurationManager.getProperty("mail.admin")); email.send(); } - } + } /** * Allows users to have email sent to them. The default is to send all * reports in one email - * + * *
    - *
    -h
    - *
    help
    - *
    -d
    - *
    Select deleted bitstreams
    - *
    -m
    - *
    Bitstreams missing from assetstore
    - *
    -c
    - *
    Bitstreams whose checksums were changed
    - *
    -n
    - *
    Bitstreams whose checksums were changed
    - *
    -a
    - *
    Send all reports in one email
    + *
    -h
    + *
    help
    + *
    -d
    + *
    Select deleted bitstreams
    + *
    -m
    + *
    Bitstreams missing from assetstore
    + *
    -c
    + *
    Bitstreams whose checksums were changed
    + *
    -n
    + *
    Bitstreams whose checksums were changed
    + *
    -a
    + *
    Send all reports in one email
    *
    - * + * * @param args the command line arguments given */ - public static void main(String[] args) - { + public static void main(String[] args) { // set up command line parser CommandLineParser parser = new PosixParser(); CommandLine line = null; @@ -106,31 +105,27 @@ public class DailyReportEmailer options.addOption("h", "help", false, "Help"); options.addOption("d", "Deleted", false, - "Send E-mail report for all bitstreams set as deleted for today"); + "Send E-mail report for all bitstreams set as deleted for today"); options.addOption("m", "Missing", false, - "Send E-mail report for all bitstreams not found in assetstore for today"); + "Send E-mail report for all bitstreams not found in assetstore for today"); options.addOption("c", "Changed", false, - "Send E-mail report for all bitstreams where checksum has been changed for today"); + "Send E-mail report for all bitstreams where checksum has been changed for today"); options.addOption("a", "All", false, - "Send all E-mail reports"); + "Send all E-mail reports"); options.addOption("u", "Unchecked", false, - "Send the Unchecked bitstream report"); + "Send the Unchecked bitstream report"); options.addOption("n", "Not Processed", false, - "Send E-mail report for all bitstreams set to longer be processed for today"); + "Send E-mail report for all bitstreams set to longer be processed for today"); - try - { + try { line = parser.parse(options, args); - } - catch (ParseException e) - { + } catch (ParseException e) { log.fatal(e); System.exit(1); } // user asks for help - if (line.hasOption('h')) - { + if (line.hasOption('h')) { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("Checksum Reporter\n", options); @@ -161,8 +156,7 @@ public class DailyReportEmailer FileWriter writer = null; Context context = null; - try - { + try { context = new Context(Context.Mode.READ_ONLY); // the number of bitstreams in report @@ -172,21 +166,17 @@ public class DailyReportEmailer String dirLocation = ConfigurationManager.getProperty("log.report.dir"); File directory = new File(dirLocation); - if (directory.exists() && directory.isDirectory()) - { + if (directory.exists() && directory.isDirectory()) { report = File.createTempFile("checker_report", ".txt", - directory); - } - else - { + directory); + } else { throw new IllegalStateException("directory :" + dirLocation - + " does not exist"); + + " does not exist"); } writer = new FileWriter(report); - if ((line.hasOption("a")) || (line.getOptions().length == 0)) - { + if ((line.hasOption("a")) || (line.getOptions().length == 0)) { writer.write("\n--------------------------------- Begin Reporting ------------------------\n\n"); numBitstreams += reporter.getDeletedBitstreamReport(context, yesterday, tomorrow, writer); writer.write("\n--------------------------------- Report Spacer ---------------------------\n\n"); @@ -201,51 +191,44 @@ public class DailyReportEmailer writer.flush(); writer.close(); emailer.sendReport(report, numBitstreams); - } - else - { - if (line.hasOption("d")) - { + } else { + if (line.hasOption("d")) { writer.write("\n--------------------------------- Begin Reporting ------------------------\n\n"); numBitstreams += reporter.getDeletedBitstreamReport(context, - yesterday, tomorrow, writer); + yesterday, tomorrow, writer); writer.flush(); writer.close(); emailer.sendReport(report, numBitstreams); } - if (line.hasOption("m")) - { + if (line.hasOption("m")) { writer.write("\n--------------------------------- Begin Reporting ------------------------\n\n"); numBitstreams += reporter.getBitstreamNotFoundReport(context, - yesterday, tomorrow, writer); + yesterday, tomorrow, writer); writer.flush(); writer.close(); emailer.sendReport(report, numBitstreams); } - if (line.hasOption("c")) - { + if (line.hasOption("c")) { writer.write("\n--------------------------------- Begin Reporting ------------------------\n\n"); numBitstreams += reporter.getChangedChecksumReport(context, - yesterday, tomorrow, writer); + yesterday, tomorrow, writer); writer.flush(); writer.close(); emailer.sendReport(report, numBitstreams); } - if (line.hasOption("n")) - { + if (line.hasOption("n")) { writer.write("\n--------------------------------- Begin Reporting ------------------------\n\n"); numBitstreams += reporter.getNotToBeProcessedReport(context, - yesterday, tomorrow, writer); + yesterday, tomorrow, writer); writer.flush(); writer.close(); emailer.sendReport(report, numBitstreams); } - if (line.hasOption("u")) - { + if (line.hasOption("u")) { writer.write("\n--------------------------------- Begin Reporting ------------------------\n\n"); numBitstreams += reporter .getUncheckedBitstreamsReport(context, writer); @@ -254,33 +237,22 @@ public class DailyReportEmailer emailer.sendReport(report, numBitstreams); } } - } - catch (MessagingException | SQLException | IOException e) - { + } catch (MessagingException | SQLException | IOException e) { log.fatal(e); - } - finally - { - if (context != null && context.isValid()) - { + } finally { + if (context != null && context.isValid()) { context.abort(); } - if (writer != null) - { - try - { + if (writer != null) { + try { writer.close(); - } - catch (Exception e) - { + } catch (Exception e) { log.fatal("Could not close writer", e); } } - if (report != null && report.exists()) - { - if (!report.delete()) - { + if (report != null && report.exists()) { + if (!report.delete()) { log.error("Unable to delete report file"); } } diff --git a/dspace-api/src/main/java/org/dspace/checker/HandleDispatcher.java b/dspace-api/src/main/java/org/dspace/checker/HandleDispatcher.java index 84e1f8c631..cec2d8f566 100644 --- a/dspace-api/src/main/java/org/dspace/checker/HandleDispatcher.java +++ b/dspace-api/src/main/java/org/dspace/checker/HandleDispatcher.java @@ -25,27 +25,33 @@ import org.dspace.handle.service.HandleService; /** * A BitstreamDispatcher that checks all the bitstreams contained within an * item, collection or community referred to by Handle. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ -public class HandleDispatcher implements BitstreamDispatcher -{ +public class HandleDispatcher implements BitstreamDispatcher { - /** Log 4j logger. */ + /** + * Log 4j logger. + */ private static final Logger LOG = Logger.getLogger(HandleDispatcher.class); protected Context context; - /** Handle to retrieve bitstreams from. */ + /** + * Handle to retrieve bitstreams from. + */ protected String handle = null; - /** Has the type of object the handle refers to been determined. */ + /** + * Has the type of object the handle refers to been determined. + */ protected boolean init = false; - /** the delegate to dispatch to. */ + /** + * the delegate to dispatch to. + */ protected IteratorDispatcher delegate = null; protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); @@ -54,38 +60,33 @@ public class HandleDispatcher implements BitstreamDispatcher /** * Blanked off, no-op constructor. */ - private HandleDispatcher() - { + private HandleDispatcher() { } /** * Main constructor. - * + * * @param context Context - * @param hdl - * the handle to get bitstreams from. + * @param hdl the handle to get bitstreams from. */ - public HandleDispatcher(Context context, String hdl) - { + public HandleDispatcher(Context context, String hdl) { this.context = context; handle = hdl; } /** * Private initialization routine. - * + * * @throws SQLException if database error - * if database access fails. + * if database access fails. */ protected synchronized void init() throws SQLException { - if (!init) - { + if (!init) { DSpaceObject dso = handleService.resolveToObject(context, handle); Iterator ids = new ArrayList().iterator(); - switch (dso.getType()) - { + switch (dso.getType()) { case Constants.BITSTREAM: ids = Arrays.asList(((Bitstream) dso)).iterator(); break; @@ -101,6 +102,8 @@ public class HandleDispatcher implements BitstreamDispatcher case Constants.COMMUNITY: ids = bitstreamService.getCommunityBitstreams(context, (org.dspace.content.Community) dso); break; + default: + break; } delegate = new IteratorDispatcher(ids); @@ -110,14 +113,13 @@ public class HandleDispatcher implements BitstreamDispatcher /** * Initializes this dispatcher on first execution. - * + * * @throws SQLException if database error * @see org.dspace.checker.BitstreamDispatcher#next() */ @Override public Bitstream next() throws SQLException { - if (!init) - { + if (!init) { init(); } diff --git a/dspace-api/src/main/java/org/dspace/checker/IteratorDispatcher.java b/dspace-api/src/main/java/org/dspace/checker/IteratorDispatcher.java index 6d12ac922f..4ed2a64db5 100644 --- a/dspace-api/src/main/java/org/dspace/checker/IteratorDispatcher.java +++ b/dspace-api/src/main/java/org/dspace/checker/IteratorDispatcher.java @@ -7,20 +7,18 @@ */ package org.dspace.checker; -import org.dspace.content.Bitstream; +import java.util.Iterator; -import java.util.*; +import org.dspace.content.Bitstream; /** * Really simple dispatcher that just iterates over a pre-defined list of ids. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ -public class IteratorDispatcher implements BitstreamDispatcher -{ +public class IteratorDispatcher implements BitstreamDispatcher { /** * List of Integer ids. */ @@ -29,17 +27,15 @@ public class IteratorDispatcher implements BitstreamDispatcher /** * Blanked off, no-op constructor. Do not use. */ - private IteratorDispatcher() - { + private IteratorDispatcher() { } /** * Main constructor. - * + * * @param bitstreams bitstream iterator */ - public IteratorDispatcher(Iterator bitstreams) - { + public IteratorDispatcher(Iterator bitstreams) { this.bitstreams = bitstreams; } @@ -47,12 +43,10 @@ public class IteratorDispatcher implements BitstreamDispatcher * @see org.dspace.checker.BitstreamDispatcher#next() */ @Override - public synchronized Bitstream next() - { - if(bitstreams != null && bitstreams.hasNext()) - { + public synchronized Bitstream next() { + if (bitstreams != null && bitstreams.hasNext()) { return bitstreams.next(); - }else{ + } else { return null; } } diff --git a/dspace-api/src/main/java/org/dspace/checker/LimitedCountDispatcher.java b/dspace-api/src/main/java/org/dspace/checker/LimitedCountDispatcher.java index 9e18570890..93ce634a05 100644 --- a/dspace-api/src/main/java/org/dspace/checker/LimitedCountDispatcher.java +++ b/dspace-api/src/main/java/org/dspace/checker/LimitedCountDispatcher.java @@ -7,78 +7,71 @@ */ package org.dspace.checker; -import org.dspace.content.Bitstream; - import java.sql.SQLException; + +import org.dspace.content.Bitstream; import org.dspace.core.factory.CoreServiceFactory; /** * Decorator that dispatches a specified number of bitstreams from a delegate * dispatcher. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ -public class LimitedCountDispatcher implements BitstreamDispatcher -{ - /** The remaining number of bitstreams to iterate through. */ +public class LimitedCountDispatcher implements BitstreamDispatcher { + /** + * The remaining number of bitstreams to iterate through. + */ private int remaining = 1; - /** The dispatcher to delegate to for retrieving bitstreams. */ + /** + * The dispatcher to delegate to for retrieving bitstreams. + */ private BitstreamDispatcher delegate = null; /** * Default constructor uses LegacyPluginServiceImpl */ - public LimitedCountDispatcher() - { + public LimitedCountDispatcher() { this((BitstreamDispatcher) CoreServiceFactory.getInstance().getPluginService() - .getSinglePlugin(BitstreamDispatcher.class)); + .getSinglePlugin(BitstreamDispatcher.class)); } /** * Constructor. - * - * @param del - * The bitstream distpatcher to delegate to. - * @param count - * the number of bitstreams to check. + * + * @param del The bitstream distpatcher to delegate to. + * @param count the number of bitstreams to check. */ - public LimitedCountDispatcher(BitstreamDispatcher del, int count) - { + public LimitedCountDispatcher(BitstreamDispatcher del, int count) { this(del); remaining = count; } /** * Constructor. - * - * @param del - * The bitstream distpatcher to delegate to. + * + * @param del The bitstream distpatcher to delegate to. */ - public LimitedCountDispatcher(BitstreamDispatcher del) - { + public LimitedCountDispatcher(BitstreamDispatcher del) { delegate = del; } /** * Retreives the next bitstream to be checked. - * + * * @return the bitstream * @throws SQLException if database error */ @Override public Bitstream next() throws SQLException { - if (remaining > 0) - { + if (remaining > 0) { remaining--; return delegate.next(); - } - else - { + } else { return null; } } diff --git a/dspace-api/src/main/java/org/dspace/checker/LimitedDurationDispatcher.java b/dspace-api/src/main/java/org/dspace/checker/LimitedDurationDispatcher.java index 21547d280d..08df972af7 100644 --- a/dspace-api/src/main/java/org/dspace/checker/LimitedDurationDispatcher.java +++ b/dspace-api/src/main/java/org/dspace/checker/LimitedDurationDispatcher.java @@ -7,29 +7,27 @@ */ package org.dspace.checker; -import org.dspace.content.Bitstream; - import java.sql.SQLException; import java.util.Date; +import org.dspace.content.Bitstream; + /** *

    * A delegating dispatcher that puts a time limit on the operation of another * dispatcher. *

    - * + * *

    * Unit testing this class would be possible by abstracting the system time into * an abstract clock. We decided this was not worth the candle. *

    - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ -public class LimitedDurationDispatcher implements BitstreamDispatcher -{ +public class LimitedDurationDispatcher implements BitstreamDispatcher { /** * The delegate dispatcher that will actually dispatch the jobs. */ @@ -44,24 +42,20 @@ public class LimitedDurationDispatcher implements BitstreamDispatcher /** * Blanked off constructor - do not use. */ - private LimitedDurationDispatcher() - { + private LimitedDurationDispatcher() { end = 0L; delegate = null; } /** * Main constructor. - * - * @param dispatcher - * Delegate dispatcher that will do the heavy lifting of the - * dispatching work. - * @param endTime - * when this dispatcher will stop returning valid bitstream ids. + * + * @param dispatcher Delegate dispatcher that will do the heavy lifting of the + * dispatching work. + * @param endTime when this dispatcher will stop returning valid bitstream ids. */ public LimitedDurationDispatcher(BitstreamDispatcher dispatcher, - Date endTime) - { + Date endTime) { delegate = dispatcher; end = endTime.getTime(); } diff --git a/dspace-api/src/main/java/org/dspace/checker/MostRecentChecksum.java b/dspace-api/src/main/java/org/dspace/checker/MostRecentChecksum.java index fb3a2f27e3..f6af3d171b 100644 --- a/dspace-api/src/main/java/org/dspace/checker/MostRecentChecksum.java +++ b/dspace-api/src/main/java/org/dspace/checker/MostRecentChecksum.java @@ -7,49 +7,56 @@ */ package org.dspace.checker; +import java.io.Serializable; +import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.dspace.content.Bitstream; -import javax.persistence.*; -import java.io.Serializable; -import java.util.Date; - /** * Database entity representation of the most_recent_checksum table * * @author kevinvandevelde at atmire.com */ @Entity -@Table(name="most_recent_checksum") -public class MostRecentChecksum implements Serializable -{ +@Table(name = "most_recent_checksum") +public class MostRecentChecksum implements Serializable { @Id @OneToOne - @JoinColumn(name="bitstream_id", nullable = false) + @JoinColumn(name = "bitstream_id", nullable = false) private Bitstream bitstream; - @Column(name= "to_be_processed", nullable = false) + @Column(name = "to_be_processed", nullable = false) private boolean toBeProcessed; - @Column(name= "expected_checksum", nullable = false) + @Column(name = "expected_checksum", nullable = false) private String expectedChecksum; - @Column(name= "current_checksum", nullable = false) + @Column(name = "current_checksum", nullable = false) private String currentChecksum; @Temporal(TemporalType.TIMESTAMP) - @Column(name= "last_process_start_date", nullable = false) + @Column(name = "last_process_start_date", nullable = false) private Date processStartDate; @Temporal(TemporalType.TIMESTAMP) - @Column(name= "last_process_end_date", nullable = false) + @Column(name = "last_process_end_date", nullable = false) private Date processEndDate; - @Column(name= "checksum_algorithm", nullable = false) + @Column(name = "checksum_algorithm", nullable = false) private String checksumAlgorithm; - @Column(name= "matched_prev_checksum", nullable = false) + @Column(name = "matched_prev_checksum", nullable = false) private boolean matchedPrevChecksum; @Transient @@ -59,15 +66,14 @@ public class MostRecentChecksum implements Serializable private boolean bitstreamFound; @OneToOne - @JoinColumn(name= "result", referencedColumnName = "result_code") + @JoinColumn(name = "result", referencedColumnName = "result_code") private ChecksumResult checksumResult; /** * Protected constructor, create handled by the * {@link org.dspace.checker.service.MostRecentChecksumService} */ - protected MostRecentChecksum() - { + protected MostRecentChecksum() { } public Bitstream getBitstream() { @@ -160,41 +166,45 @@ public class MostRecentChecksum implements Serializable @Override public boolean equals(Object o) { - if (this == o) return true; + if (this == o) { + return true; + } - if (o == null || getClass() != o.getClass()) return false; + if (o == null || getClass() != o.getClass()) { + return false; + } MostRecentChecksum that = (MostRecentChecksum) o; return new EqualsBuilder() - .append(toBeProcessed, that.toBeProcessed) - .append(matchedPrevChecksum, that.matchedPrevChecksum) - .append(infoFound, that.infoFound) - .append(bitstreamFound, that.bitstreamFound) - .append(bitstream, that.bitstream) - .append(expectedChecksum, that.expectedChecksum) - .append(currentChecksum, that.currentChecksum) - .append(processStartDate, that.processStartDate) - .append(processEndDate, that.processEndDate) - .append(checksumAlgorithm, that.checksumAlgorithm) - .append(checksumResult, that.checksumResult) - .isEquals(); + .append(toBeProcessed, that.toBeProcessed) + .append(matchedPrevChecksum, that.matchedPrevChecksum) + .append(infoFound, that.infoFound) + .append(bitstreamFound, that.bitstreamFound) + .append(bitstream, that.bitstream) + .append(expectedChecksum, that.expectedChecksum) + .append(currentChecksum, that.currentChecksum) + .append(processStartDate, that.processStartDate) + .append(processEndDate, that.processEndDate) + .append(checksumAlgorithm, that.checksumAlgorithm) + .append(checksumResult, that.checksumResult) + .isEquals(); } @Override public int hashCode() { return new HashCodeBuilder(17, 37) - .append(bitstream) - .append(toBeProcessed) - .append(expectedChecksum) - .append(currentChecksum) - .append(processStartDate) - .append(processEndDate) - .append(checksumAlgorithm) - .append(matchedPrevChecksum) - .append(infoFound) - .append(bitstreamFound) - .append(checksumResult) - .toHashCode(); + .append(bitstream) + .append(toBeProcessed) + .append(expectedChecksum) + .append(currentChecksum) + .append(processStartDate) + .append(processEndDate) + .append(checksumAlgorithm) + .append(matchedPrevChecksum) + .append(infoFound) + .append(bitstreamFound) + .append(checksumResult) + .toHashCode(); } } diff --git a/dspace-api/src/main/java/org/dspace/checker/MostRecentChecksumServiceImpl.java b/dspace-api/src/main/java/org/dspace/checker/MostRecentChecksumServiceImpl.java index efe9298168..82a8ace677 100644 --- a/dspace-api/src/main/java/org/dspace/checker/MostRecentChecksumServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/MostRecentChecksumServiceImpl.java @@ -7,6 +7,10 @@ */ package org.dspace.checker; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.checker.dao.MostRecentChecksumDAO; import org.dspace.checker.service.ChecksumResultService; @@ -16,10 +20,6 @@ import org.dspace.content.service.BitstreamService; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; - /** * Service implementation for the MostRecentChecksum object. * This class is responsible for all business logic calls for the MostRecentChecksum object and is autowired by spring. @@ -27,8 +27,7 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class MostRecentChecksumServiceImpl implements MostRecentChecksumService -{ +public class MostRecentChecksumServiceImpl implements MostRecentChecksumService { private static final Logger log = Logger.getLogger(MostRecentChecksumServiceImpl.class); @Autowired(required = true) @@ -40,14 +39,12 @@ public class MostRecentChecksumServiceImpl implements MostRecentChecksumService @Autowired(required = true) protected BitstreamService bitstreamService; - protected MostRecentChecksumServiceImpl() - { + protected MostRecentChecksumServiceImpl() { } @Override - public MostRecentChecksum getNonPersistedObject() - { + public MostRecentChecksum getNonPersistedObject() { return new MostRecentChecksum(); } @@ -60,17 +57,15 @@ public class MostRecentChecksumServiceImpl implements MostRecentChecksumService * Find all bitstreams that were set to not be processed for the specified * date range. * - * @param context Context - * @param startDate - * the start of the date range - * @param endDate - * the end of the date range + * @param context Context + * @param startDate the start of the date range + * @param endDate the end of the date range * @return a list of BitstreamHistoryInfo objects * @throws SQLException if database error */ @Override - public List findNotProcessedBitstreamsReport(Context context, Date startDate, Date endDate) throws SQLException - { + public List findNotProcessedBitstreamsReport(Context context, Date startDate, Date endDate) + throws SQLException { return mostRecentChecksumDAO.findByNotProcessedInDateRange(context, startDate, endDate); } @@ -78,19 +73,16 @@ public class MostRecentChecksumServiceImpl implements MostRecentChecksumService * Select the most recent bitstream for a given date range with the * specified status. * - * @param context Context - * @param startDate - * the start date range - * @param endDate - * the end date range. - * @param resultCode - * the result code - * + * @param context Context + * @param startDate the start date range + * @param endDate the end date range. + * @param resultCode the result code * @return a list of BitstreamHistoryInfo objects * @throws SQLException if database error */ @Override - public List findBitstreamResultTypeReport(Context context, Date startDate, Date endDate, ChecksumResultCode resultCode) throws SQLException { + public List findBitstreamResultTypeReport(Context context, Date startDate, Date endDate, + ChecksumResultCode resultCode) throws SQLException { return mostRecentChecksumDAO.findByResultTypeInDateRange(context, startDate, endDate, resultCode); } @@ -98,6 +90,7 @@ public class MostRecentChecksumServiceImpl implements MostRecentChecksumService * Queries the bitstream table for bitstream IDs that are not yet in the * most_recent_checksum table, and inserts them into the * most_recent_checksum and checksum_history tables. + * * @param context Context * @throws SQLException if database error */ @@ -119,47 +112,42 @@ public class MostRecentChecksumServiceImpl implements MostRecentChecksumService // + "where most_recent_checksum.bitstream_id = bitstream.bitstream_id )"; List unknownBitstreams = bitstreamService.findBitstreamsWithNoRecentChecksum(context); - for (Bitstream bitstream : unknownBitstreams) - { + for (Bitstream bitstream : unknownBitstreams) { log.info(bitstream + " " + bitstream.getID().toString() + " " + bitstream.getName()); MostRecentChecksum mostRecentChecksum = new MostRecentChecksum(); mostRecentChecksum.setBitstream(bitstream); //Only process if our bitstream isn't deleted mostRecentChecksum.setToBeProcessed(!bitstream.isDeleted()); - if(bitstream.getChecksum() == null) - { + if (bitstream.getChecksum() == null) { mostRecentChecksum.setCurrentChecksum(""); mostRecentChecksum.setExpectedChecksum(""); - }else{ + } else { mostRecentChecksum.setCurrentChecksum(bitstream.getChecksum()); mostRecentChecksum.setExpectedChecksum(bitstream.getChecksum()); } mostRecentChecksum.setProcessStartDate(new Date()); mostRecentChecksum.setProcessEndDate(new Date()); - if(bitstream.getChecksumAlgorithm() == null) - { + if (bitstream.getChecksumAlgorithm() == null) { mostRecentChecksum.setChecksumAlgorithm("MD5"); - }else{ + } else { mostRecentChecksum.setChecksumAlgorithm(bitstream.getChecksumAlgorithm()); } mostRecentChecksum.setMatchedPrevChecksum(true); ChecksumResult checksumResult; - if(bitstream.isDeleted()) - { + if (bitstream.isDeleted()) { checksumResult = checksumResultService.findByCode(context, ChecksumResultCode.BITSTREAM_MARKED_DELETED); } else { checksumResult = checksumResultService.findByCode(context, ChecksumResultCode.CHECKSUM_MATCH); } mostRecentChecksum.setChecksumResult(checksumResult); - mostRecentChecksumDAO.create(context, mostRecentChecksum); + mostRecentChecksumDAO.create(context, mostRecentChecksum); mostRecentChecksumDAO.save(context, mostRecentChecksum); } } @Override - public void deleteByBitstream(Context context, Bitstream bitstream) throws SQLException - { + public void deleteByBitstream(Context context, Bitstream bitstream) throws SQLException { mostRecentChecksumDAO.deleteByBitstream(context, bitstream); } @@ -170,11 +158,9 @@ public class MostRecentChecksumServiceImpl implements MostRecentChecksumService * @param context COntext * @return the oldest MostRecentChecksum or NULL if the table is empty * @throws SQLException if database error - * */ @Override - public MostRecentChecksum findOldestRecord(Context context) throws SQLException - { + public MostRecentChecksum findOldestRecord(Context context) throws SQLException { return mostRecentChecksumDAO.getOldestRecord(context); } @@ -182,20 +168,18 @@ public class MostRecentChecksumServiceImpl implements MostRecentChecksumService * Returns the oldest bitstream that in the set of bitstreams that are less * than the specified date. If no bitstreams are found -1 is returned. * - * @param context context + * @param context context * @param lessThanDate date * @return id of olded bitstream or -1 if not bitstreams are found * @throws SQLException if database error */ @Override - public MostRecentChecksum findOldestRecord(Context context, Date lessThanDate) throws SQLException - { + public MostRecentChecksum findOldestRecord(Context context, Date lessThanDate) throws SQLException { return mostRecentChecksumDAO.getOldestRecord(context, lessThanDate); } @Override - public List findNotInHistory(Context context) throws SQLException - { + public List findNotInHistory(Context context) throws SQLException { return mostRecentChecksumDAO.findNotInHistory(context); } diff --git a/dspace-api/src/main/java/org/dspace/checker/ResultsLogger.java b/dspace-api/src/main/java/org/dspace/checker/ResultsLogger.java index 8ae5364efe..e0cf489d8c 100644 --- a/dspace-api/src/main/java/org/dspace/checker/ResultsLogger.java +++ b/dspace-api/src/main/java/org/dspace/checker/ResultsLogger.java @@ -21,16 +21,12 @@ import org.dspace.core.I18nUtil; *

    * Collects results from a Checksum process and outputs them to a Log4j Logger. *

    - * - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * - * */ -public class ResultsLogger implements ChecksumResultsCollector -{ +public class ResultsLogger implements ChecksumResultsCollector { /** * Usual Log4J logger. */ @@ -53,41 +49,36 @@ public class ResultsLogger implements ChecksumResultsCollector /** * Blanked off, no-op constructor. Do not use. */ - private ResultsLogger() - { + private ResultsLogger() { } /** * Main constructor. - * - * @param startDt - * Date the checking run started. + * + * @param startDt Date the checking run started. */ - public ResultsLogger(Date startDt) - { + public ResultsLogger(Date startDt) { LOG.info(msg("run-start-time") + ": " + DATE_FORMAT.get().format(startDt)); } /** * Get the i18N string. - * - * @param key - * to get the message. + * + * @param key to get the message. * @return the message found. */ - protected String msg(String key) - { + protected String msg(String key) { return I18nUtil.getMessage("org.dspace.checker.ResultsLogger." + key); } /** * Collect a result for logging. - * + * * @param context Context - * @param info - * the BitstreamInfo representing the result. + * @param info the BitstreamInfo representing the result. * @throws SQLException if database error - * @see org.dspace.checker.ChecksumResultsCollector#collect(org.dspace.core.Context, org.dspace.checker.MostRecentChecksum) + * @see org.dspace.checker.ChecksumResultsCollector#collect(org.dspace.core.Context, org.dspace.checker + * .MostRecentChecksum) */ @Override public void collect(Context context, MostRecentChecksum info) throws SQLException { @@ -101,22 +92,24 @@ public class ResultsLogger implements ChecksumResultsCollector LOG.info(msg("internal-id") + ": " + bitstream.getInternalId()); LOG.info(msg("name") + ": " + bitstream.getName()); LOG.info(msg("store-number") + ": " + bitstream.getStoreNumber()); - LOG.info(msg("size") + ": " + bitstream.getSize()); - LOG.info(msg("bitstream-format") + ": " + (bitstream.getFormat(context) != null ? bitstream.getFormat(context).getID() : "-1")); + LOG.info(msg("size") + ": " + bitstream.getSizeBytes()); + LOG.info(msg("bitstream-format") + ": " + (bitstream.getFormat(context) != null ? bitstream.getFormat(context) + .getID() : "-1")); LOG.info(msg("user-format-description") + ": " - + bitstream.getUserFormatDescription()); + + bitstream.getUserFormatDescription()); LOG.info(msg("source") + ": " + bitstream.getSource()); LOG - .info(msg("checksum-algorithm") + ": " - + info.getChecksumAlgorithm()); + .info(msg("checksum-algorithm") + ": " + + info.getChecksumAlgorithm()); LOG.info(msg("previous-checksum") + ": " + info.getExpectedChecksum()); LOG.info(msg("previous-checksum-date") - + ": " - + ((info.getProcessEndDate() != null) ? DATE_FORMAT.get().format(info - .getProcessEndDate()) : "unknown")); + + ": " + + ((info.getProcessEndDate() != null) ? DATE_FORMAT.get().format(info + .getProcessEndDate()) : + "unknown")); LOG.info(msg("new-checksum") + ": " + info.getCurrentChecksum()); LOG.info(msg("checksum-comparison-result") + ": " - + (info.getChecksumResult().getResultCode())); + + (info.getChecksumResult().getResultCode())); LOG.info("\n\n"); } } diff --git a/dspace-api/src/main/java/org/dspace/checker/ResultsPruner.java b/dspace-api/src/main/java/org/dspace/checker/ResultsPruner.java index 64d0222bbc..2d595a19f8 100644 --- a/dspace-api/src/main/java/org/dspace/checker/ResultsPruner.java +++ b/dspace-api/src/main/java/org/dspace/checker/ResultsPruner.java @@ -30,15 +30,12 @@ import org.dspace.core.Utils; * Manages the deletion of results from the checksum history. It uses the * dspace.cfg file as the default configuration file for the deletion settings * and can use a different configuration file if it is passed in. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * - * */ -public final class ResultsPruner -{ +public final class ResultsPruner { /** * Default logger. @@ -48,102 +45,81 @@ public final class ResultsPruner /** * Factory method for the default results pruner configuration using * dspace.cfg - * + * * @param context Context * @return a ResultsPruner that represent the default retention policy */ - public static ResultsPruner getDefaultPruner(Context context) - { - try - { + public static ResultsPruner getDefaultPruner(Context context) { + try { return getPruner(context, ConfigurationManager.getProperties()); - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { throw new IllegalStateException( - "VeryExceptionalException - config file not there! ", e); + "VeryExceptionalException - config file not there! ", e); } } - + /** * Factory method for ResultsPruners - * - * @param context Context - * @param propsFile - * to configure the results pruner. + * + * @param context Context + * @param propsFile to configure the results pruner. * @return the configured results pruner. * @throws FileNotFoundException if file doesn't exist - * it the configuration file cannot be found. + * it the configuration file cannot be found. */ public static ResultsPruner getPruner(Context context, String propsFile) - throws FileNotFoundException - { + throws FileNotFoundException { Properties props = new Properties(); FileInputStream fin = null; - try - { + try { fin = new FileInputStream(propsFile); props.load(fin); - + return getPruner(context, props); - } - catch (IOException e) - { + } catch (IOException e) { throw new IllegalStateException("Problem loading properties file: " - + e.getMessage(), e); - } - finally - { - if (fin != null) - { - try - { + + e.getMessage(), e); + } finally { + if (fin != null) { + try { fin.close(); - } - catch (IOException e) - { + } catch (IOException e) { LOG.warn(e); } } } } - + /** * Factory method for ResultsPruners (used to load ConfigurationManager * properties. - * + * * @param context Context - * @param props Properties + * @param props Properties * @return pruner * @throws FileNotFoundException if file doesn't exist */ public static ResultsPruner getPruner(Context context, Properties props) - throws FileNotFoundException - { - + throws FileNotFoundException { + ResultsPruner rp = new ResultsPruner(context); Pattern retentionPattern = Pattern - .compile("checker\\.retention\\.(.*)"); - for (Enumeration en = (Enumeration)props.propertyNames(); en.hasMoreElements();) - { + .compile("checker\\.retention\\.(.*)"); + for (Enumeration en = (Enumeration) props.propertyNames(); en.hasMoreElements(); ) { String name = en.nextElement(); Matcher matcher = retentionPattern.matcher(name); - if (!matcher.matches()) - { + if (!matcher.matches()) { continue; } String resultCode = matcher.group(1); long duration; - try - { + try { duration = Utils.parseDuration(props.getProperty(name)); - } - catch (ParseException e) - { + } catch (ParseException e) { throw new IllegalStateException("Problem parsing duration: " - + e.getMessage(), e); + + e.getMessage(), e); } if ("default".equals(resultCode)) { rp.setDefaultDuration(duration); @@ -157,10 +133,12 @@ public final class ResultsPruner } } return rp; - + } - /** Ten years */ + /** + * Ten years + */ private long defaultDuration = 31536000000L; /** @@ -178,10 +156,10 @@ public final class ResultsPruner /** * Default Constructor + * * @param context Context */ - public ResultsPruner(Context context) - { + public ResultsPruner(Context context) { this.checksumHistoryService = CheckerServiceFactory.getInstance().getChecksumHistoryService(); this.context = context; } @@ -189,61 +167,49 @@ public final class ResultsPruner /** * Add a result and the length of time before the history with this type of * result is removed from the database. - * - * @param result - * code in the database. - * - * @param duration - * before bitstreams with the specified result type in the - * checksum history is removed. + * + * @param result code in the database. + * @param duration before bitstreams with the specified result type in the + * checksum history is removed. */ - public void addInterested(ChecksumResultCode result, long duration) - { + public void addInterested(ChecksumResultCode result, long duration) { interests.put(result, duration); } /** * Add a result and the length of time before it is removed from the * checksum history table. - * - * @param result - * code in the database. - * - * @param duration - * before bitstreams with the specified result type in the - * checksum history is removed. - * + * + * @param result code in the database. + * @param duration before bitstreams with the specified result type in the + * checksum history is removed. * @throws ParseException if the duration cannot be parsed into a long value. */ public void addInterested(ChecksumResultCode result, String duration) - throws ParseException - { + throws ParseException { addInterested(result, Utils.parseDuration(duration)); } /** * The default amount of time before a result is removed. - * + * * @return the default duration. */ - public long getDefaultDuration() - { + public long getDefaultDuration() { return defaultDuration; } /** * Prunes the results retaining results as configured by the interests * registered with this object. - * + * * @return number of results removed. * @throws SQLException if database error */ public int prune() throws SQLException { ChecksumResultCode[] codes = ChecksumResultCode.values(); - for (ChecksumResultCode code : codes) - { - if (!interests.containsKey(code)) - { + for (ChecksumResultCode code : codes) { + if (!interests.containsKey(code)) { interests.put(code, defaultDuration); } @@ -255,12 +221,10 @@ public final class ResultsPruner /** * The default duration before records are removed from the checksum history * table. - * - * @param defaultDuration - * used before records are removed from the checksum history. + * + * @param defaultDuration used before records are removed from the checksum history. */ - public void setDefaultDuration(long defaultDuration) - { + public void setDefaultDuration(long defaultDuration) { this.defaultDuration = defaultDuration; } } diff --git a/dspace-api/src/main/java/org/dspace/checker/SimpleDispatcher.java b/dspace-api/src/main/java/org/dspace/checker/SimpleDispatcher.java index 9b3ea00a22..b93ce333da 100644 --- a/dspace-api/src/main/java/org/dspace/checker/SimpleDispatcher.java +++ b/dspace-api/src/main/java/org/dspace/checker/SimpleDispatcher.java @@ -7,25 +7,23 @@ */ package org.dspace.checker; +import java.sql.SQLException; +import java.util.Date; + import org.dspace.checker.factory.CheckerServiceFactory; import org.dspace.checker.service.MostRecentChecksumService; import org.dspace.content.Bitstream; import org.dspace.core.Context; -import java.sql.SQLException; -import java.util.Date; - /** * An implementation of the selection strategy that selects bitstreams in the * order that they were last checked, looping endlessly. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ -public class SimpleDispatcher implements BitstreamDispatcher -{ +public class SimpleDispatcher implements BitstreamDispatcher { /** * Should this dispatcher keep on dispatching around the collection? @@ -46,16 +44,13 @@ public class SimpleDispatcher implements BitstreamDispatcher /** * Creates a new SimpleDispatcher. - * - * @param context Context - * @param startTime - * timestamp for beginning of checker process - * @param looping - * indicates whether checker should loop infinitely through - * most_recent_checksum table + * + * @param context Context + * @param startTime timestamp for beginning of checker process + * @param looping indicates whether checker should loop infinitely through + * most_recent_checksum table */ - public SimpleDispatcher(Context context, Date startTime, boolean looping) - { + public SimpleDispatcher(Context context, Date startTime, boolean looping) { checksumService = CheckerServiceFactory.getInstance().getMostRecentChecksumService(); this.context = context; this.processStartTime = (startTime == null ? null : new Date(startTime.getTime())); @@ -65,13 +60,12 @@ public class SimpleDispatcher implements BitstreamDispatcher /** * Blanked off, no-op constructor. Do not use. */ - private SimpleDispatcher() - { + private SimpleDispatcher() { } /** * Selects the next candidate bitstream. - * + * * @throws SQLException if database error * @see org.dspace.checker.BitstreamDispatcher#next() */ @@ -79,23 +73,18 @@ public class SimpleDispatcher implements BitstreamDispatcher public synchronized Bitstream next() throws SQLException { // should process loop infinitely through the // bitstreams in most_recent_checksum table? - if (!loopContinuously && (processStartTime != null)) - { + if (!loopContinuously && (processStartTime != null)) { MostRecentChecksum oldestRecord = checksumService.findOldestRecord(context, processStartTime); - if(oldestRecord != null) - { + if (oldestRecord != null) { return oldestRecord.getBitstream(); - }else{ + } else { return null; } - } - else - { + } else { MostRecentChecksum oldestRecord = checksumService.findOldestRecord(context); - if(oldestRecord != null) - { + if (oldestRecord != null) { return oldestRecord.getBitstream(); - }else{ + } else { return null; } } diff --git a/dspace-api/src/main/java/org/dspace/checker/SimpleReporterServiceImpl.java b/dspace-api/src/main/java/org/dspace/checker/SimpleReporterServiceImpl.java index daeba9c0f1..849cddfb61 100644 --- a/dspace-api/src/main/java/org/dspace/checker/SimpleReporterServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/SimpleReporterServiceImpl.java @@ -23,58 +23,50 @@ import org.dspace.core.I18nUtil; import org.springframework.beans.factory.annotation.Autowired; /** - * * Simple Reporter implementation. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * + * * TODO estimate string buffer sizes. */ -public class SimpleReporterServiceImpl implements SimpleReporterService -{ +public class SimpleReporterServiceImpl implements SimpleReporterService { @Autowired(required = true) protected MostRecentChecksumService mostRecentChecksumService = null; @Autowired(required = true) protected BitstreamService bitstreamService = null; - private String msg(String key) - { + private String msg(String key) { return I18nUtil.getMessage("org.dspace.checker.SimpleReporterImpl." + key); } /** * Main Constructor. */ - protected SimpleReporterServiceImpl() - { + protected SimpleReporterServiceImpl() { } /** * Sends the Deleted bitstream report to an administrator. for the * specified date range. - * - * @param context context - * @param startDate - * the start date for the range - * @param endDate - * the end date for the range - * @param osw - * the output stream writer to write to. - * + * + * @param context context + * @param startDate the start date for the range + * @param endDate the end date for the range + * @param osw the output stream writer to write to. * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ @Override public int getDeletedBitstreamReport(Context context, Date startDate, Date endDate, - OutputStreamWriter osw) throws IOException, SQLException { + OutputStreamWriter osw) throws IOException, SQLException { // get all the bitstreams marked deleted for today - List recentChecksums = mostRecentChecksumService.findBitstreamResultTypeReport(context, startDate, - endDate, ChecksumResultCode.BITSTREAM_MARKED_DELETED); + List recentChecksums = mostRecentChecksumService + .findBitstreamResultTypeReport(context, startDate, + endDate, ChecksumResultCode.BITSTREAM_MARKED_DELETED); osw.write("\n"); osw.write(msg("deleted-bitstream-intro")); @@ -85,14 +77,11 @@ public class SimpleReporterServiceImpl implements SimpleReporterService osw.write(applyDateFormatShort(endDate)); osw.write("\n\n\n"); - if (recentChecksums.size() == 0) - { + if (recentChecksums.size() == 0) { osw.write("\n\n"); osw.write(msg("no-bitstreams-to-delete")); osw.write("\n"); - } - else - { + } else { printHistoryRecords(recentChecksums, osw); } @@ -101,27 +90,23 @@ public class SimpleReporterServiceImpl implements SimpleReporterService /** * Send the checksum changed report for the specified date range. - * - * @param context context - * @param startDate - * the start date for the range - * @param endDate - * the end date for the range - * @param osw - * the output stream writer to write to. - * + * + * @param context context + * @param startDate the start date for the range + * @param endDate the end date for the range + * @param osw the output stream writer to write to. * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ @Override public int getChangedChecksumReport(Context context, Date startDate, Date endDate, - OutputStreamWriter osw) throws IOException, SQLException { + OutputStreamWriter osw) throws IOException, SQLException { // get all the bitstreams marked deleted for today - List history = mostRecentChecksumService.findBitstreamResultTypeReport(context, startDate, - endDate, ChecksumResultCode.CHECKSUM_NO_MATCH); + List history = + mostRecentChecksumService.findBitstreamResultTypeReport(context, startDate, endDate, + ChecksumResultCode.CHECKSUM_NO_MATCH); osw.write("\n"); osw.write(msg("checksum-did-not-match")); @@ -134,14 +119,11 @@ public class SimpleReporterServiceImpl implements SimpleReporterService osw.write(applyDateFormatShort(endDate)); osw.write("\n\n\n"); - if (history.size() == 0) - { + if (history.size() == 0) { osw.write("\n\n"); osw.write(msg("no-changed-bitstreams")); osw.write("\n"); - } - else - { + } else { printHistoryRecords(history, osw); } @@ -150,27 +132,23 @@ public class SimpleReporterServiceImpl implements SimpleReporterService /** * Send the bitstream not found report for the specified date range. - * - * @param context context - * @param startDate - * the start date for the range. - * @param endDate - * the end date for the range. - * @param osw - * the output stream writer to write to. - * + * + * @param context context + * @param startDate the start date for the range. + * @param endDate the end date for the range. + * @param osw the output stream writer to write to. * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ @Override public int getBitstreamNotFoundReport(Context context, Date startDate, Date endDate, - OutputStreamWriter osw) throws IOException, SQLException { + OutputStreamWriter osw) throws IOException, SQLException { // get all the bitstreams marked deleted for today - List history = mostRecentChecksumService.findBitstreamResultTypeReport(context, startDate, - endDate, ChecksumResultCode.BITSTREAM_NOT_FOUND); + List history = + mostRecentChecksumService.findBitstreamResultTypeReport(context, startDate, endDate, + ChecksumResultCode.BITSTREAM_NOT_FOUND); osw.write("\n"); osw.write(msg("bitstream-not-found-report")); @@ -181,14 +159,11 @@ public class SimpleReporterServiceImpl implements SimpleReporterService osw.write(applyDateFormatShort(endDate)); osw.write("\n\n\n"); - if (history.size() == 0) - { + if (history.size() == 0) { osw.write("\n\n"); osw.write(msg("no-bitstreams-changed")); osw.write("\n"); - } - else - { + } else { printHistoryRecords(history, osw); } @@ -198,27 +173,23 @@ public class SimpleReporterServiceImpl implements SimpleReporterService /** * Send the bitstreams that were set to not be processed report for the * specified date range. - * - * @param context context - * @param startDate - * the start date for the range - * @param endDate - * the end date for the range - * @param osw - * the output stream writer to write to. - * + * + * @param context context + * @param startDate the start date for the range + * @param endDate the end date for the range + * @param osw the output stream writer to write to. * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ @Override public int getNotToBeProcessedReport(Context context, Date startDate, Date endDate, - OutputStreamWriter osw) throws IOException, SQLException { + OutputStreamWriter osw) throws IOException, SQLException { // get all the bitstreams marked deleted for today - List mostRecentChecksums = mostRecentChecksumService.findNotProcessedBitstreamsReport(context, startDate, - endDate); + List mostRecentChecksums = mostRecentChecksumService + .findNotProcessedBitstreamsReport(context, startDate, + endDate); osw.write("\n"); osw.write(msg("bitstream-will-no-longer-be-processed")); @@ -230,14 +201,11 @@ public class SimpleReporterServiceImpl implements SimpleReporterService osw.write(applyDateFormatShort(endDate)); osw.write("\n\n\n"); - if (mostRecentChecksums.size() == 0) - { + if (mostRecentChecksums.size() == 0) { osw.write("\n\n"); osw.write(msg("no-bitstreams-to-no-longer-be-processed")); osw.write("\n"); - } - else - { + } else { printHistoryRecords(mostRecentChecksums, osw); } @@ -246,20 +214,17 @@ public class SimpleReporterServiceImpl implements SimpleReporterService /** * Get any bitstreams that are not checked by the checksum checker. - * + * * @param context context - * @param osw - * the OutputStreamWriter to write to - * + * @param osw the OutputStreamWriter to write to * @return the number of unchecked bitstreams - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ @Override public int getUncheckedBitstreamsReport(Context context, OutputStreamWriter osw) - throws IOException, SQLException { + throws IOException, SQLException { // get all the bitstreams marked deleted for today List bitstreams = bitstreamService.findBitstreamsWithNoRecentChecksum(context); @@ -268,14 +233,11 @@ public class SimpleReporterServiceImpl implements SimpleReporterService osw.write(applyDateFormatShort(new Date())); osw.write("\n\n\n"); - if (bitstreams.size() == 0) - { + if (bitstreams.size() == 0) { osw.write("\n\n"); osw.write(msg("no-unchecked-bitstreams")); osw.write("\n"); - } - else - { + } else { osw.write(msg("howto-add-unchecked-bitstreams")); osw.write("\n\n\n"); this.printDSpaceInfoRecords(context, bitstreams, osw); @@ -286,35 +248,31 @@ public class SimpleReporterServiceImpl implements SimpleReporterService /** * Create a list of the found history records. - * - * @param mostRecentChecksums - * the list of history records to be iterated over. - * @param osw - * the output stream writer to write to. - * + * + * @param mostRecentChecksums the list of history records to be iterated over. + * @param osw the output stream writer to write to. * @throws IOException if IO error - * if io error occurs + * if io error occurs */ protected void printHistoryRecords(List mostRecentChecksums, OutputStreamWriter osw) - throws IOException - { + throws IOException { for (MostRecentChecksum mostRecentChecksum : mostRecentChecksums) { StringBuffer buf = new StringBuffer(1000); buf.append("------------------------------------------------ \n"); buf.append(msg("bitstream-id")).append(" = ").append( - mostRecentChecksum.getBitstream().getID()).append("\n"); + mostRecentChecksum.getBitstream().getID()).append("\n"); buf.append(msg("process-start-date")).append(" = ").append( - applyDateFormatLong(mostRecentChecksum.getProcessStartDate())) - .append("\n"); + applyDateFormatLong(mostRecentChecksum.getProcessStartDate())) + .append("\n"); buf.append(msg("process-end-date")).append(" = ").append( - applyDateFormatLong(mostRecentChecksum.getProcessEndDate())) - .append("\n"); + applyDateFormatLong(mostRecentChecksum.getProcessEndDate())) + .append("\n"); buf.append(msg("checksum-expected")).append(" = ").append( - mostRecentChecksum.getExpectedChecksum()).append("\n"); + mostRecentChecksum.getExpectedChecksum()).append("\n"); buf.append(msg("checksum-calculated")).append(" = ").append( - mostRecentChecksum.getCurrentChecksum()).append("\n"); + mostRecentChecksum.getCurrentChecksum()).append("\n"); buf.append(msg("result")).append(" = ").append( - mostRecentChecksum.getChecksumResult().getResultCode()).append("\n"); + mostRecentChecksum.getChecksumResult().getResultCode()).append("\n"); buf.append("----------------------------------------------- \n\n"); osw.write(buf.toString()); } @@ -322,58 +280,52 @@ public class SimpleReporterServiceImpl implements SimpleReporterService /** * Create a list of the found history records. - * - * @param context context - * @param bitstreams - * the list of history records to be iterated over. - * @param osw - * the output stream to write to. - * - * @throws IOException if IO error - * if io error occurs + * + * @param context context + * @param bitstreams the list of history records to be iterated over. + * @param osw the output stream to write to. + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ protected void printDSpaceInfoRecords(Context context, List bitstreams, OutputStreamWriter osw) - throws IOException, SQLException { + throws IOException, SQLException { - for (Bitstream info : bitstreams) - { + for (Bitstream info : bitstreams) { StringBuffer buf = new StringBuffer(1000); buf.append("------------------------------------------------ \n"); buf.append(msg("format-id")).append(" = ").append( - info.getFormat(context).getID()).append("\n"); + info.getFormat(context).getID()).append("\n"); buf.append(msg("deleted")).append(" = ").append(info.isDeleted()) - .append("\n"); + .append("\n"); buf.append(msg("bitstream-id")).append(" = ").append( - info.getID()).append("\n"); + info.getID()).append("\n"); buf.append(msg("checksum-algorithm")).append(" = ").append( - info.getChecksumAlgorithm()).append("\n"); + info.getChecksumAlgorithm()).append("\n"); buf.append(msg("internal-id")).append(" = ").append( - info.getInternalId()).append("\n"); + info.getInternalId()).append("\n"); buf.append(msg("name")).append(" = ").append(info.getName()) - .append("\n"); - buf.append(msg("size")).append(" = ").append(info.getSize()) - .append("\n"); + .append("\n"); + buf.append(msg("size")).append(" = ").append(info.getSizeBytes()) + .append("\n"); buf.append(msg("source")).append(" = ").append(info.getSource()) - .append("\n"); + .append("\n"); buf.append(msg("checksum")).append(" = ").append( - info.getChecksum()).append("\n"); + info.getChecksum()).append("\n"); buf.append(msg("store-number")).append(" = ").append( - info.getStoreNumber()).append("\n"); + info.getStoreNumber()).append("\n"); buf.append(msg("description")).append(" = ").append( - info.getUserFormatDescription()).append("\n"); + info.getUserFormatDescription()).append("\n"); buf.append("----------------------------------------------- \n\n"); osw.write(buf.toString()); } } - protected String applyDateFormatLong(Date thisDate) - { + protected String applyDateFormatLong(Date thisDate) { return DateFormat.getDateInstance(DateFormat.MEDIUM).format(thisDate); } - protected String applyDateFormatShort(Date thisDate) - { - return DateFormat.getDateInstance(DateFormat.SHORT).format(thisDate); + protected String applyDateFormatShort(Date thisDate) { + return DateFormat.getDateInstance(DateFormat.SHORT).format(thisDate); } } diff --git a/dspace-api/src/main/java/org/dspace/checker/dao/ChecksumHistoryDAO.java b/dspace-api/src/main/java/org/dspace/checker/dao/ChecksumHistoryDAO.java index 06c74dc88c..54e503235c 100644 --- a/dspace-api/src/main/java/org/dspace/checker/dao/ChecksumHistoryDAO.java +++ b/dspace-api/src/main/java/org/dspace/checker/dao/ChecksumHistoryDAO.java @@ -7,18 +7,19 @@ */ package org.dspace.checker.dao; +import java.sql.SQLException; +import java.util.Date; + import org.dspace.checker.ChecksumHistory; import org.dspace.checker.ChecksumResultCode; import org.dspace.content.Bitstream; import org.dspace.core.Context; import org.dspace.core.GenericDAO; -import java.sql.SQLException; -import java.util.Date; - /** * Database Access Object interface class for the ChecksumHistory object. - * The implementation of this class is responsible for all database calls for the ChecksumHistory object and is autowired by spring + * The implementation of this class is responsible for all database calls for the ChecksumHistory object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -29,24 +30,20 @@ public interface ChecksumHistoryDAO extends GenericDAO { * Delete all ChecksumHistory rows with retention date before the given and * the specified result code. * - * @param context - * The relevant DSpace Context. - * @param retentionDate - * row must be older than this to be deleted. - * @param checksumResultCode - * row must have this result to be deleted. + * @param context The relevant DSpace Context. + * @param retentionDate row must be older than this to be deleted. + * @param checksumResultCode row must have this result to be deleted. * @return number of rows deleted. * @throws SQLException if database error */ - public int deleteByDateAndCode(Context context, Date retentionDate, ChecksumResultCode checksumResultCode) throws SQLException; + public int deleteByDateAndCode(Context context, Date retentionDate, ChecksumResultCode checksumResultCode) + throws SQLException; /** * Delete all ChecksumHistory rows for the given Bitstream. * - * @param context - * The relevant DSpace Context. - * @param bitstream - * which bitstream's checksums to delete + * @param context The relevant DSpace Context. + * @param bitstream which bitstream's checksums to delete * @throws SQLException if database error */ public void deleteByBitstream(Context context, Bitstream bitstream) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/checker/dao/ChecksumResultDAO.java b/dspace-api/src/main/java/org/dspace/checker/dao/ChecksumResultDAO.java index 6f688ec10b..9191a2891d 100644 --- a/dspace-api/src/main/java/org/dspace/checker/dao/ChecksumResultDAO.java +++ b/dspace-api/src/main/java/org/dspace/checker/dao/ChecksumResultDAO.java @@ -7,16 +7,17 @@ */ package org.dspace.checker.dao; +import java.sql.SQLException; + import org.dspace.checker.ChecksumResult; import org.dspace.checker.ChecksumResultCode; import org.dspace.core.Context; import org.dspace.core.GenericDAO; -import java.sql.SQLException; - /** * Database Access Object interface class for the ChecksumResult object. - * The implementation of this class is responsible for all database calls for the ChecksumResult object and is autowired by spring + * The implementation of this class is responsible for all database calls for the ChecksumResult object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/checker/dao/MostRecentChecksumDAO.java b/dspace-api/src/main/java/org/dspace/checker/dao/MostRecentChecksumDAO.java index 578abce624..56485c9b4b 100644 --- a/dspace-api/src/main/java/org/dspace/checker/dao/MostRecentChecksumDAO.java +++ b/dspace-api/src/main/java/org/dspace/checker/dao/MostRecentChecksumDAO.java @@ -7,29 +7,31 @@ */ package org.dspace.checker.dao; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; + import org.dspace.checker.ChecksumResultCode; import org.dspace.checker.MostRecentChecksum; import org.dspace.content.Bitstream; import org.dspace.core.Context; import org.dspace.core.GenericDAO; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; - /** * Database Access Object interface class for the MostRecentChecksum object. - * The implementation of this class is responsible for all database calls for the MostRecentChecksum object and is autowired by spring + * The implementation of this class is responsible for all database calls for the MostRecentChecksum object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com */ -public interface MostRecentChecksumDAO extends GenericDAO -{ +public interface MostRecentChecksumDAO extends GenericDAO { - public List findByNotProcessedInDateRange(Context context, Date startDate, Date endDate) throws SQLException; + public List findByNotProcessedInDateRange(Context context, Date startDate, Date endDate) + throws SQLException; - public List findByResultTypeInDateRange(Context context, Date startDate, Date endDate, ChecksumResultCode resultCode) throws SQLException; + public List findByResultTypeInDateRange(Context context, Date startDate, Date endDate, + ChecksumResultCode resultCode) throws SQLException; public void deleteByBitstream(Context context, Bitstream bitstream) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImpl.java b/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImpl.java index 60f13cd238..328d4a717e 100644 --- a/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImpl.java @@ -9,14 +9,15 @@ package org.dspace.checker.dao.impl; import java.sql.SQLException; import java.util.Date; +import javax.persistence.Query; +import javax.persistence.TemporalType; import org.dspace.checker.ChecksumHistory; import org.dspace.checker.ChecksumResultCode; import org.dspace.checker.dao.ChecksumHistoryDAO; import org.dspace.content.Bitstream; -import org.dspace.core.Context; import org.dspace.core.AbstractHibernateDAO; -import org.hibernate.Query; +import org.dspace.core.Context; /** *

    @@ -24,27 +25,27 @@ import org.hibernate.Query; * update,insert and delete database operations should go through this class for * checksum history operations. *

    - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr * @author kevinvandevelde at atmire.com - * - * + * + * */ -public class ChecksumHistoryDAOImpl extends AbstractHibernateDAO implements ChecksumHistoryDAO -{ +public class ChecksumHistoryDAOImpl extends AbstractHibernateDAO implements ChecksumHistoryDAO { - protected ChecksumHistoryDAOImpl() - { + protected ChecksumHistoryDAOImpl() { super(); } @Override - public int deleteByDateAndCode(Context context, Date retentionDate, ChecksumResultCode resultCode) throws SQLException { - String hql = "delete from ChecksumHistory where processEndDate < :processEndDate AND checksumResult.resultCode=:resultCode"; + public int deleteByDateAndCode(Context context, Date retentionDate, ChecksumResultCode resultCode) + throws SQLException { + String hql = "delete from ChecksumHistory where processEndDate < :processEndDate AND checksumResult" + + ".resultCode=:resultCode"; Query query = createQuery(context, hql); - query.setTimestamp("processEndDate", retentionDate); + query.setParameter("processEndDate", retentionDate, TemporalType.TIMESTAMP); query.setParameter("resultCode", resultCode); return query.executeUpdate(); } diff --git a/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumResultDAOImpl.java b/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumResultDAOImpl.java index f68df03c0b..a82b904b28 100644 --- a/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumResultDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumResultDAOImpl.java @@ -7,15 +7,17 @@ */ package org.dspace.checker.dao.impl; +import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.dspace.checker.ChecksumResult; import org.dspace.checker.ChecksumResultCode; +import org.dspace.checker.ChecksumResult_; import org.dspace.checker.dao.ChecksumResultDAO; -import org.dspace.core.Context; import org.dspace.core.AbstractHibernateDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; +import org.dspace.core.Context; /** * Hibernate implementation of the Database Access Object interface class for the ChecksumResult object. @@ -24,18 +26,19 @@ import java.sql.SQLException; * * @author kevinvandevelde at atmire.com */ -public class ChecksumResultDAOImpl extends AbstractHibernateDAO implements ChecksumResultDAO -{ +public class ChecksumResultDAOImpl extends AbstractHibernateDAO implements ChecksumResultDAO { - protected ChecksumResultDAOImpl() - { + protected ChecksumResultDAOImpl() { super(); } @Override public ChecksumResult findByCode(Context context, ChecksumResultCode code) throws SQLException { - Criteria criteria = createCriteria(context, ChecksumResult.class); - criteria.add(Restrictions.eq("resultCode", code)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ChecksumResult.class); + Root checksumResultRoot = criteriaQuery.from(ChecksumResult.class); + criteriaQuery.select(checksumResultRoot); + criteriaQuery.where(criteriaBuilder.equal(checksumResultRoot.get(ChecksumResult_.resultCode), code)); + return uniqueResult(context, criteriaQuery, false, ChecksumResult.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/checker/dao/impl/MostRecentChecksumDAOImpl.java b/dspace-api/src/main/java/org/dspace/checker/dao/impl/MostRecentChecksumDAOImpl.java index 2cff8896d1..66ce666b9d 100644 --- a/dspace-api/src/main/java/org/dspace/checker/dao/impl/MostRecentChecksumDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/dao/impl/MostRecentChecksumDAOImpl.java @@ -7,20 +7,29 @@ */ package org.dspace.checker.dao.impl; -import org.dspace.checker.ChecksumHistory; -import org.dspace.checker.ChecksumResultCode; -import org.dspace.checker.MostRecentChecksum; -import org.dspace.checker.dao.MostRecentChecksumDAO; -import org.dspace.content.Bitstream; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.*; - import java.sql.SQLException; import java.util.Date; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Order; +import javax.persistence.criteria.Root; +import javax.persistence.criteria.Subquery; + +import org.dspace.checker.ChecksumHistory; +import org.dspace.checker.ChecksumHistory_; +import org.dspace.checker.ChecksumResult; +import org.dspace.checker.ChecksumResultCode; +import org.dspace.checker.ChecksumResult_; +import org.dspace.checker.MostRecentChecksum; +import org.dspace.checker.MostRecentChecksum_; +import org.dspace.checker.dao.MostRecentChecksumDAO; +import org.dspace.content.Bitstream; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; /** * Hibernate implementation of the Database Access Object interface class for the MostRecentChecksum object. @@ -29,73 +38,73 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class MostRecentChecksumDAOImpl extends AbstractHibernateDAO implements MostRecentChecksumDAO -{ - protected MostRecentChecksumDAOImpl() - { +public class MostRecentChecksumDAOImpl extends AbstractHibernateDAO + implements MostRecentChecksumDAO { + protected MostRecentChecksumDAOImpl() { super(); } @Override - public List findByNotProcessedInDateRange(Context context, Date startDate, Date endDate) throws SQLException { -// + "most_recent_checksum.last_process_start_date, most_recent_checksum.last_process_end_date, " -// + "most_recent_checksum.expected_checksum, most_recent_checksum.current_checksum, " -// + "result_description " -// + "from checksum_results, most_recent_checksum " -// + "where most_recent_checksum.to_be_processed = false " -// + "and most_recent_checksum.result = checksum_results.result_code " -// + "and most_recent_checksum.last_process_start_date >= ? " -// + "and most_recent_checksum.last_process_start_date < ? " -// + "order by most_recent_checksum.bitstream_id + public List findByNotProcessedInDateRange(Context context, Date startDate, Date endDate) + throws SQLException { - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - criteria.add( - Restrictions.and( - Restrictions.eq("toBeProcessed", false), - Restrictions.le("processStartDate", startDate), - Restrictions.gt("processStartDate", endDate) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(mostRecentChecksumRoot.get(MostRecentChecksum_.toBeProcessed), false), + criteriaBuilder + .lessThanOrEqualTo(mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), startDate), + criteriaBuilder.greaterThan(mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), endDate) + ) ); - criteria.addOrder(Order.asc("bitstream.id")); - return list(criteria); + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream))); + criteriaQuery.orderBy(orderList); + return list(context, criteriaQuery, false, MostRecentChecksum.class, -1, -1); } @Override public MostRecentChecksum findByBitstream(Context context, Bitstream bitstream) throws SQLException { - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - criteria.add(Restrictions.eq("bitstream", bitstream)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery + .where(criteriaBuilder.equal(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream), bitstream)); + return singleResult(context, criteriaQuery); } @Override - public List findByResultTypeInDateRange(Context context, Date startDate, Date endDate, ChecksumResultCode resultCode) throws SQLException { -// "select bitstream_id, last_process_start_date, last_process_end_date, " -// + "expected_checksum, current_checksum, result_description " -// + "from most_recent_checksum, checksum_results " -// + "where most_recent_checksum.result = checksum_results.result_code " -// + "and most_recent_checksum.result= ? " -// + "and most_recent_checksum.last_process_start_date >= ? " -// + "and most_recent_checksum.last_process_start_date < ? " -// + "order by bitstream_id"; - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - criteria.add( - Restrictions.and( - Restrictions.eq("checksumResult.resultCode", resultCode), - Restrictions.le("processStartDate", startDate), - Restrictions.gt("processStartDate", endDate) - ) + public List findByResultTypeInDateRange(Context context, Date startDate, Date endDate, + ChecksumResultCode resultCode) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + Join mostRecentResult = + mostRecentChecksumRoot.join(MostRecentChecksum_.checksumResult); + + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(mostRecentResult.get(ChecksumResult_.resultCode), resultCode), + criteriaBuilder.lessThanOrEqualTo( + mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), startDate), + criteriaBuilder.greaterThan(mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), endDate) + ) ); - criteria.addOrder(Order.asc("bitstream.id")); - return list(criteria); + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream))); + criteriaQuery.orderBy(orderList); + return list(context, criteriaQuery, false, MostRecentChecksum.class, -1, -1); } @Override - public void deleteByBitstream(Context context, Bitstream bitstream) throws SQLException - { + public void deleteByBitstream(Context context, Bitstream bitstream) throws SQLException { String hql = "delete from MostRecentChecksum WHERE bitstream=:bitstream"; Query query = createQuery(context, hql); query.setParameter("bitstream", bitstream); @@ -104,42 +113,52 @@ public class MostRecentChecksumDAOImpl extends AbstractHibernateDAO criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery.where(criteriaBuilder.equal(mostRecentChecksumRoot.get(MostRecentChecksum_.toBeProcessed), true)); + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.processEndDate))); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream))); + criteriaQuery.orderBy(orderList); + return singleResult(context, criteriaQuery); } @Override public MostRecentChecksum getOldestRecord(Context context, Date lessThanDate) throws SQLException { -// "select bitstream_id " -// + "from most_recent_checksum " -// + "where to_be_processed = true " -// + "and last_process_start_date < ? " -// + "order by date_trunc('milliseconds', last_process_end_date), " -// + "bitstream_id " + "ASC LIMIT 1"; - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - criteria.add( - Restrictions.and( - Restrictions.eq("toBeProcessed", true), - Restrictions.lt("processStartDate", lessThanDate) - )); - criteria.addOrder(Order.asc("processEndDate")).addOrder(Order.asc("bitstream.id")); - criteria.setMaxResults(1); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(mostRecentChecksumRoot.get(MostRecentChecksum_.toBeProcessed), true), + criteriaBuilder.lessThan(mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), lessThanDate) + ) + ); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.processEndDate))); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream))); + criteriaQuery.orderBy(orderList); + + return singleResult(context, criteriaQuery); } @Override public List findNotInHistory(Context context) throws SQLException { - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - DetachedCriteria subCriteria = DetachedCriteria.forClass(ChecksumHistory.class); - subCriteria.setProjection(Projections.property("bitstream.id")); - criteria.add(Property.forName("bitstreamId").notIn(subCriteria)); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root checksumRoot = criteriaQuery.from(MostRecentChecksum.class); + + Subquery subQuery = criteriaQuery.subquery(Bitstream.class); + Root historyRoot = subQuery.from(ChecksumHistory.class); + subQuery.select(historyRoot.get(ChecksumHistory_.bitstream)); + + criteriaQuery.where( + criteriaBuilder.not(checksumRoot.get(MostRecentChecksum_.bitstream).in(subQuery))); + + return list(context, criteriaQuery, false, MostRecentChecksum.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/checker/factory/CheckerServiceFactory.java b/dspace-api/src/main/java/org/dspace/checker/factory/CheckerServiceFactory.java index 6c1b29f49a..23ef832d4e 100644 --- a/dspace-api/src/main/java/org/dspace/checker/factory/CheckerServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/checker/factory/CheckerServiceFactory.java @@ -7,14 +7,15 @@ */ package org.dspace.checker.factory; -import org.dspace.checker.service.SimpleReporterService; import org.dspace.checker.service.ChecksumHistoryService; import org.dspace.checker.service.ChecksumResultService; import org.dspace.checker.service.MostRecentChecksumService; +import org.dspace.checker.service.SimpleReporterService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the checker package, use CheckerServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the checker package, use CheckerServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -28,8 +29,8 @@ public abstract class CheckerServiceFactory { public abstract ChecksumResultService getChecksumResultService(); - public static CheckerServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("checkerServiceFactory", CheckerServiceFactory.class); + public static CheckerServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("checkerServiceFactory", CheckerServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/checker/factory/CheckerServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/checker/factory/CheckerServiceFactoryImpl.java index 73b1b4a0dd..51c981f94a 100644 --- a/dspace-api/src/main/java/org/dspace/checker/factory/CheckerServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/factory/CheckerServiceFactoryImpl.java @@ -7,14 +7,15 @@ */ package org.dspace.checker.factory; -import org.dspace.checker.service.SimpleReporterService; import org.dspace.checker.service.ChecksumHistoryService; import org.dspace.checker.service.ChecksumResultService; import org.dspace.checker.service.MostRecentChecksumService; +import org.dspace.checker.service.SimpleReporterService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the checker package, use CheckerServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the checker package, use CheckerServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/checker/service/ChecksumHistoryService.java b/dspace-api/src/main/java/org/dspace/checker/service/ChecksumHistoryService.java index 578214ac1d..b13e4b2137 100644 --- a/dspace-api/src/main/java/org/dspace/checker/service/ChecksumHistoryService.java +++ b/dspace-api/src/main/java/org/dspace/checker/service/ChecksumHistoryService.java @@ -7,18 +7,19 @@ */ package org.dspace.checker.service; +import java.sql.SQLException; +import java.util.Date; +import java.util.Map; + import org.dspace.checker.ChecksumResultCode; import org.dspace.checker.MostRecentChecksum; import org.dspace.content.Bitstream; import org.dspace.core.Context; -import java.sql.SQLException; -import java.util.Date; -import java.util.Map; - /** * Service interface class for the ChecksumHistory object. - * The implementation of this class is responsible for all business logic calls for the ChecksumHistory object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the ChecksumHistory object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -35,11 +36,9 @@ public interface ChecksumHistoryService { /** * Prune the history records from the database. * - * @param context context - * @param interests - * set of results and the duration of time before they are - * removed from the database - * + * @param context context + * @param interests set of results and the duration of time before they are + * removed from the database * @return number of bitstreams deleted * @throws SQLException if database error */ diff --git a/dspace-api/src/main/java/org/dspace/checker/service/ChecksumResultService.java b/dspace-api/src/main/java/org/dspace/checker/service/ChecksumResultService.java index 60726636b2..4a05c40b94 100644 --- a/dspace-api/src/main/java/org/dspace/checker/service/ChecksumResultService.java +++ b/dspace-api/src/main/java/org/dspace/checker/service/ChecksumResultService.java @@ -7,16 +7,17 @@ */ package org.dspace.checker.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.checker.ChecksumResult; import org.dspace.checker.ChecksumResultCode; import org.dspace.core.Context; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the ChecksumResult object. - * The implementation of this class is responsible for all business logic calls for the ChecksumResult object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the ChecksumResult object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/checker/service/MostRecentChecksumService.java b/dspace-api/src/main/java/org/dspace/checker/service/MostRecentChecksumService.java index 9863807757..b1ef87ac97 100644 --- a/dspace-api/src/main/java/org/dspace/checker/service/MostRecentChecksumService.java +++ b/dspace-api/src/main/java/org/dspace/checker/service/MostRecentChecksumService.java @@ -7,18 +7,19 @@ */ package org.dspace.checker.service; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; + import org.dspace.checker.ChecksumResultCode; import org.dspace.checker.MostRecentChecksum; import org.dspace.content.Bitstream; import org.dspace.core.Context; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; - /** * Service interface class for the MostRecentChecksum object. - * The implementation of this class is responsible for all business logic calls for the MostRecentChecksum object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the MostRecentChecksum object and + * is autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -28,9 +29,11 @@ public interface MostRecentChecksumService { public MostRecentChecksum findByBitstream(Context context, Bitstream bitstream) throws SQLException; - public List findNotProcessedBitstreamsReport(Context context, Date startDate, Date endDate) throws SQLException; + public List findNotProcessedBitstreamsReport(Context context, Date startDate, Date endDate) + throws SQLException; - public List findBitstreamResultTypeReport(Context context, Date startDate, Date endDate, ChecksumResultCode resultCode) throws SQLException; + public List findBitstreamResultTypeReport(Context context, Date startDate, Date endDate, + ChecksumResultCode resultCode) throws SQLException; public void updateMissingBitstreams(Context context) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/checker/service/SimpleReporterService.java b/dspace-api/src/main/java/org/dspace/checker/service/SimpleReporterService.java index b4b159890e..1dc56c20a3 100644 --- a/dspace-api/src/main/java/org/dspace/checker/service/SimpleReporterService.java +++ b/dspace-api/src/main/java/org/dspace/checker/service/SimpleReporterService.java @@ -7,123 +7,96 @@ */ package org.dspace.checker.service; -import org.dspace.core.Context; - import java.io.IOException; import java.io.OutputStreamWriter; import java.sql.SQLException; import java.util.Date; +import org.dspace.core.Context; + /** - * * Simple Reporting Class which can return several different reports. - * + * * @author Jim Downing * @author Grace Carpenter * @author Nathan Sarr - * */ -public interface SimpleReporterService -{ +public interface SimpleReporterService { /** * Returns the bitstreams set found to be deleted for the specified date * range. - * - * @param context context - * @param startDate - * the start date range - * @param endDate - * the end date range - * @param osw - * the output stream writer to write to - * + * + * @param context context + * @param startDate the start date range + * @param endDate the end date range + * @param osw the output stream writer to write to * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ public int getDeletedBitstreamReport(Context context, Date startDate, Date endDate, - OutputStreamWriter osw) throws IOException, SQLException; + OutputStreamWriter osw) throws IOException, SQLException; /** * The a report of bitstreams found where the checksum has been changed * since the last check for the specified date range. - * - * @param context context - * @param startDate - * the start date range. - * @param endDate - * then end date range. - * @param osw - * the output stream writer to write to - * + * + * @param context context + * @param startDate the start date range. + * @param endDate then end date range. + * @param osw the output stream writer to write to * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ public int getChangedChecksumReport(Context context, Date startDate, Date endDate, - OutputStreamWriter osw) throws IOException, SQLException; + OutputStreamWriter osw) throws IOException, SQLException; /** * The report of bitstreams for the specified date range where it was * determined the bitstreams can no longer be found. - * - * @param context context - * @param startDate - * the start date range. - * @param endDate - * the end date range. - * @param osw - * the output stream writer to write to - * + * + * @param context context + * @param startDate the start date range. + * @param endDate the end date range. + * @param osw the output stream writer to write to * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error */ public int getBitstreamNotFoundReport(Context context, Date startDate, Date endDate, - OutputStreamWriter osw) throws IOException, SQLException; + OutputStreamWriter osw) throws IOException, SQLException; /** * The bitstreams that were set to not be processed report for the specified * date range. - * - * @param context context - * @param startDate - * the start date range. - * @param endDate - * the end date range. - * @param osw - * the output stream writer to write to + * + * @param context context + * @param startDate the start date range. + * @param endDate the end date range. + * @param osw the output stream writer to write to * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error - * */ public int getNotToBeProcessedReport(Context context, Date startDate, Date endDate, - OutputStreamWriter osw) throws IOException, SQLException; + OutputStreamWriter osw) throws IOException, SQLException; /** * The bitstreams that are not known to the checksum checker. This means * they are in the bitstream table but not in the most recent checksum table - * + * * @param context context - * @param osw - * the output stream writer to write to - * + * @param osw the output stream writer to write to * @return number of bitstreams found - * - * @throws IOException if IO error - * if io error occurs + * @throws IOException if IO error + * if io error occurs * @throws SQLException if database error - * */ public int getUncheckedBitstreamsReport(Context context, OutputStreamWriter osw) - throws IOException, SQLException; + throws IOException, SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/Bitstream.java b/dspace-api/src/main/java/org/dspace/content/Bitstream.java index b0b6c210e4..3be9b1feb1 100644 --- a/dspace-api/src/main/java/org/dspace/content/Bitstream.java +++ b/dspace-api/src/main/java/org/dspace/content/Bitstream.java @@ -11,6 +11,15 @@ import java.io.InputStream; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Transient; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; @@ -18,23 +27,20 @@ import org.dspace.core.Constants; import org.dspace.core.Context; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; - /** * Class representing bitstreams stored in the DSpace system. *

    * When modifying the bitstream metadata, changes are not reflected in the * database until update is called. Note that you cannot alter * the contents of a bitstream; you need to create a new bitstream. - * + * * @author Robert Tansley * @version $Revision$ */ @Entity -@Table(name="bitstream") -public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport -{ - @Column(name="bitstream_id", insertable = false, updatable = false) +@Table(name = "bitstream") +public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport { + @Column(name = "bitstream_id", insertable = false, updatable = false) private Integer legacyId; @Column(name = "sequence_id") @@ -65,10 +71,10 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport @ManyToMany(fetch = FetchType.LAZY, mappedBy = "bitstreams") private List bundles = new ArrayList<>(); - @OneToOne(fetch = FetchType.LAZY, mappedBy="logo") + @OneToOne(fetch = FetchType.LAZY, mappedBy = "logo") private Community community; - @OneToOne(fetch = FetchType.LAZY, mappedBy="logo") + @OneToOne(fetch = FetchType.LAZY, mappedBy = "logo") private Collection collection; @Transient @@ -81,33 +87,28 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * or * {@link org.dspace.content.service.BitstreamService#create(Context, InputStream)} */ - protected Bitstream() - { + protected Bitstream() { } /** * Get the sequence ID of this bitstream - * + * * @return the sequence ID */ - public int getSequenceID() - { - if(sequenceId == null) - { + public int getSequenceID() { + if (sequenceId == null) { return -1; - }else{ + } else { return sequenceId; } } /** * Set the sequence ID of this bitstream - * - * @param sid - * the ID + * + * @param sid the ID */ - public void setSequenceID(int sid) - { + public void setSequenceID(int sid) { sequenceId = sid; setMetadataModified(); addDetails("SequenceID"); @@ -116,20 +117,19 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the name of this bitstream - typically the filename, without any path * information - * + * * @return the name of the bitstream */ @Override - public String getName(){ + public String getName() { return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); } /** * Set the name of the bitstream - * + * * @param context context - * @param n - * the new name of the bitstream + * @param n the new name of the bitstream * @throws SQLException if database error */ public void setName(Context context, String n) throws SQLException { @@ -140,20 +140,18 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * Get the source of this bitstream - typically the filename with path * information (if originally provided) or the name of the tool that * generated this bitstream - * + * * @return the source of the bitstream */ - public String getSource() - { + public String getSource() { return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "source", null, Item.ANY); } /** * Set the source of the bitstream - * + * * @param context context - * @param n - * the new source of the bitstream + * @param n the new source of the bitstream * @throws SQLException if database error */ public void setSource(Context context, String n) throws SQLException { @@ -163,33 +161,32 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the description of this bitstream - optional free text, typically * provided by a user at submission time - * + * * @return the description of the bitstream */ - public String getDescription() - { - return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "description", null, Item.ANY); + public String getDescription() { + return getBitstreamService() + .getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "description", null, Item.ANY); } /** * Set the description of the bitstream - * + * * @param context context - * @param n - * the new description of the bitstream + * @param n the new description of the bitstream * @throws SQLException if database error */ public void setDescription(Context context, String n) throws SQLException { - getBitstreamService().setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "description", null, null, n); + getBitstreamService() + .setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "description", null, null, n); } /** * Get the checksum of the content of the bitstream, for integrity checking - * + * * @return the checksum */ - public String getChecksum() - { + public String getChecksum() { return checksum; } @@ -199,11 +196,10 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the algorithm used to calculate the checksum - * + * * @return the algorithm, e.g. "MD5" */ - public String getChecksumAlgorithm() - { + public String getChecksumAlgorithm() { return checksumAlgorithm; } @@ -213,11 +209,10 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the size of the bitstream - * + * * @return the size in bytes */ - public long getSize() - { + public long getSizeBytes() { return sizeBytes; } @@ -228,28 +223,25 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the user's format description. Returns null if the format is known by * the system. - * + * * @return the user's format description. */ - public String getUserFormatDescription() - { + public String getUserFormatDescription() { return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "format", null, Item.ANY); } - protected BitstreamFormat getBitstreamFormat() - { + protected BitstreamFormat getBitstreamFormat() { return bitstreamFormat; } /** * Get the format of the bitstream - * + * * @param context context * @return the format of this bitstream * @throws SQLException if database error */ - public BitstreamFormat getFormat(Context context) throws SQLException - { + public BitstreamFormat getFormat(Context context) throws SQLException { return getBitstreamService().getFormat(context, this); } @@ -265,8 +257,7 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * @return true if the bitstream has been deleted * @throws SQLException if database error */ - public boolean isDeleted() throws SQLException - { + public boolean isDeleted() throws SQLException { return deleted; } @@ -276,12 +267,11 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the bundles this bitstream appears in - * + * * @return array of Bundle s this bitstream appears in * @throws SQLException if database error */ - public List getBundles() throws SQLException - { + public List getBundles() throws SQLException { return bundles; } @@ -292,12 +282,11 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport /** * return type found in Constants - * + * * @return int Constants.BITSTREAM */ @Override - public int getType() - { + public int getType() { return Constants.BITSTREAM; } @@ -311,7 +300,7 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the asset store number where this bitstream is stored - * + * * @return the asset store number of the bitstream */ public int getStoreNumber() { @@ -336,7 +325,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport } /* - Getters & setters which should be removed on the long run, they are just here to provide all getters & setters to the item object + Getters & setters which should be removed on the long run, they are just here to provide all getters & + setters to the item object */ @@ -344,14 +334,11 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * Set the user's format description. This implies that the format of the * bitstream is uncertain, and the format is set to "unknown." * - * @param context - * The relevant DSpace Context. - * @param desc - * the user's description of the format + * @param context The relevant DSpace Context. + * @param desc the user's description of the format * @throws SQLException if database error */ - public void setUserFormatDescription(Context context, String desc) throws SQLException - { + public void setUserFormatDescription(Context context, String desc) throws SQLException { getBitstreamService().setUserFormatDescription(context, this, desc); } @@ -363,8 +350,7 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * @return a description of the format. * @throws SQLException if database error */ - public String getFormatDescription(Context context) throws SQLException - { + public String getFormatDescription(Context context) throws SQLException { return getBitstreamService().getFormatDescription(context, this); } @@ -374,13 +360,11 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * of this bitstream to "unknown". * * @param context context - * @param f - * the format of this bitstream, or null for - * unknown + * @param f the format of this bitstream, or null for + * unknown * @throws SQLException if database error */ - public void setFormat(Context context, BitstreamFormat f) throws SQLException - { + public void setFormat(Context context, BitstreamFormat f) throws SQLException { getBitstreamService().setFormat(context, this, f); } @@ -390,8 +374,7 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport } private BitstreamService getBitstreamService() { - if(bitstreamService == null) - { + if (bitstreamService == null) { bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); } return bitstreamService; @@ -401,40 +384,46 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * Return true if other is the same Bitstream * as this object, false otherwise * - * @param other - * object to compare to - * + * @param other object to compare to * @return true if object passed in represents the same - * collection as this object + * collection as this object */ - @Override - public boolean equals(Object other) - { - if (other == null) - { - return false; - } - Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(other); - if (this.getClass() != objClass) - { - return false; - } - final Bitstream otherBitstream = (Bitstream) other; - if (!this.getID().equals(otherBitstream.getID())) - { - return false; - } + @Override + public boolean equals(Object other) { + if (other == null) { + return false; + } + Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(other); + if (this.getClass() != objClass) { + return false; + } + final Bitstream otherBitstream = (Bitstream) other; + if (!this.getID().equals(otherBitstream.getID())) { + return false; + } - return true; - } + return true; + } - @Override - public int hashCode() - { - int hash = 5; - hash += 73 * hash + getType(); - hash += 73 * hash + getID().hashCode(); - return hash; - } + @Override + public int hashCode() { + int hash = 5; + hash += 73 * hash + getType(); + hash += 73 * hash + getID().hashCode(); + return hash; + } + + /** + * Add date for bitstream granted (used into the use case for license grant the + * {@link LicenseUtils#grantLicense(Context, Item, String, String)} + * + * @param context the dspace context + * @param acceptanceDate the granted date + * @throws SQLException + */ + public void setAcceptanceDate(Context context, DCDate acceptanceDate) throws SQLException { + getBitstreamService() + .setMetadataSingleValue(context, this, "dcterms", "accessRights", null, null, acceptanceDate.toString()); + } } diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamFormat.java b/dspace-api/src/main/java/org/dspace/content/BitstreamFormat.java index 603230adbf..c1e2a7ec8b 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamFormat.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamFormat.java @@ -11,6 +11,18 @@ import java.io.Serializable; import java.sql.SQLException; import java.util.LinkedList; import java.util.List; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Transient; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; @@ -21,59 +33,54 @@ import org.hibernate.annotations.CollectionId; import org.hibernate.annotations.Type; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.io.Serializable; -import java.sql.SQLException; -import java.util.List; - /** * Class representing a particular bitstream format. *

    * Changes to the bitstream format metadata are only written to the database * when update is called. - * + * * @author Robert Tansley * @version $Revision$ */ @Entity -@Table(name="bitstreamformatregistry") -public class BitstreamFormat implements Serializable, ReloadableEntity -{ +@Table(name = "bitstreamformatregistry") +public class BitstreamFormat implements Serializable, ReloadableEntity { @Id - @Column(name="bitstream_format_id", nullable = false, unique = true) - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="bitstreamformatregistry_seq") - @SequenceGenerator(name="bitstreamformatregistry_seq", sequenceName="bitstreamformatregistry_seq", allocationSize = 1, initialValue = 1) + @Column(name = "bitstream_format_id", nullable = false, unique = true) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "bitstreamformatregistry_seq") + @SequenceGenerator(name = "bitstreamformatregistry_seq", sequenceName = "bitstreamformatregistry_seq", + allocationSize = 1, initialValue = 1) private Integer id; - @Column(name="short_description", length = 128, unique = true) + @Column(name = "short_description", length = 128, unique = true) private String shortDescription; -// @Column(name="description") + // @Column(name="description") // @Lob //Generates a TEXT or LONGTEXT data type - @Column(name="description", columnDefinition = "text") + @Column(name = "description", columnDefinition = "text") private String description; - @Column(name="mimetype", length = 256) + @Column(name = "mimetype", length = 256) private String mimetype; - @Column(name="support_level") + @Column(name = "support_level") private int supportLevel = -1; - @Column(name="internal") + @Column(name = "internal") private boolean internal = false; @ElementCollection(fetch = FetchType.LAZY) - @CollectionTable(name="fileextension", joinColumns=@JoinColumn(name="bitstream_format_id")) - @CollectionId( - columns = @Column(name="file_extension_id"), - type=@Type(type="integer"), - generator = "fileextension_seq" - ) - @SequenceGenerator(name="fileextension_seq", sequenceName="fileextension_seq", allocationSize = 1) - @Column(name="extension") - @Cascade( { org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN }) + @CollectionTable(name = "fileextension", joinColumns = @JoinColumn(name = "bitstream_format_id")) + @CollectionId( + columns = @Column(name = "file_extension_id"), + type = @Type(type = "integer"), + generator = "fileextension_seq" + ) + @SequenceGenerator(name = "fileextension_seq", sequenceName = "fileextension_seq", allocationSize = 1) + @Column(name = "extension") + @Cascade( {org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN}) private List fileExtensions; @Transient @@ -103,30 +110,26 @@ public class BitstreamFormat implements Serializable, ReloadableEntity /** * Protected constructor, create object using: * {@link org.dspace.content.service.BitstreamFormatService#create(Context)} - * */ - protected BitstreamFormat() - { + protected BitstreamFormat() { fileExtensions = new LinkedList<>(); } /** * Get the internal identifier of this bitstream format - * + * * @return the internal identifier */ - public final Integer getID() - { + public final Integer getID() { return id; } /** * Get a short (one or two word) description of this bitstream format - * + * * @return the short description */ - public String getShortDescription() - { + public String getShortDescription() { return shortDescription; } @@ -135,61 +138,52 @@ public class BitstreamFormat implements Serializable, ReloadableEntity } - - /** * Get a description of this bitstream format, including full application or * format name - * + * * @return the description */ - public String getDescription() - { + public String getDescription() { return description; } /** * Set the description of the bitstream format - * - * @param s - * the new description + * + * @param s the new description */ - public void setDescription(String s) - { + public void setDescription(String s) { this.description = s; } /** * Get the MIME type of this bitstream format, for example * text/plain - * + * * @return the MIME type */ - public String getMIMEType() - { + public String getMIMEType() { return mimetype; } /** * Set the MIME type of the bitstream format - * - * @param s - * the new MIME type + * + * @param s the new MIME type */ - public void setMIMEType(String s) - { + public void setMIMEType(String s) { this.mimetype = s; } /** * Get the support level for this bitstream format - one of * UNKNOWN,KNOWN or SUPPORTED. - * + * * @return the support level */ - public int getSupportLevel() - { + public int getSupportLevel() { return supportLevel; } @@ -207,64 +201,57 @@ public class BitstreamFormat implements Serializable, ReloadableEntity * Find out if the bitstream format is an internal format - that is, one * that is used to store system information, rather than the content of * items in the system - * + * * @return true if the bitstream format is an internal type */ - public boolean isInternal() - { + public boolean isInternal() { return internal; } /** * Set whether the bitstream format is an internal format - * - * @param b - * pass in true if the bitstream format is an - * internal type + * + * @param b pass in true if the bitstream format is an + * internal type */ - public void setInternal(boolean b) - { + public void setInternal(boolean b) { internal = b; } /** * Get the filename extensions associated with this format - * + * * @return the extensions */ - public List getExtensions() - { + public List getExtensions() { return fileExtensions; } /** * Set the filename extensions associated with this format - * - * @param exts - * String [] array of extensions + * + * @param exts String [] array of extensions */ - public void setExtensions(List exts) - { + public void setExtensions(List exts) { this.fileExtensions = exts; } /* - Getters & setters which should be removed on the long run, they are just here to provide all getters & setters to the item object + Getters & setters which should be removed on the long run, they are just here to provide all getters & + setters to the item object */ - public void setShortDescription(Context context, String s) throws SQLException - { + public void setShortDescription(Context context, String s) throws SQLException { getBitstreamFormatService().setShortDescription(context, this, s); } - public void setSupportLevel(int sl) - { + public void setSupportLevel(int sl) { getBitstreamFormatService().setSupportLevel(this, sl); } private BitstreamFormatService getBitstreamFormatService() { - if(bitstreamFormatService == null) { + if (bitstreamFormatService == null) { bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); } return bitstreamFormatService; @@ -274,39 +261,32 @@ public class BitstreamFormat implements Serializable, ReloadableEntity * Return true if other is the same Collection * as this object, false otherwise * - * @param other - * object to compare to - * + * @param other object to compare to * @return true if object passed in represents the same - * collection as this object + * collection as this object */ - @Override - public boolean equals(Object other) - { - if (other == null) - { - return false; - } - Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(other); - if (this.getClass() != objClass) - { - return false; - } - final BitstreamFormat otherBitstreamFormat = (BitstreamFormat) other; - if (this.getID() != otherBitstreamFormat.getID() ) - { - return false; - } + @Override + public boolean equals(Object other) { + if (other == null) { + return false; + } + Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(other); + if (this.getClass() != objClass) { + return false; + } + final BitstreamFormat otherBitstreamFormat = (BitstreamFormat) other; + if (this.getID() != otherBitstreamFormat.getID()) { + return false; + } - return true; - } + return true; + } - @Override - public int hashCode() - { - int hash = 5; - hash += 70 * hash + getID(); - return hash; - } + @Override + public int hashCode() { + int hash = 5; + hash += 70 * hash + getID(); + return hash; + } } diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamFormatServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BitstreamFormatServiceImpl.java index 1c300f7ab2..978b3070fc 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamFormatServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamFormatServiceImpl.java @@ -7,7 +7,11 @@ */ package org.dspace.content; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; @@ -17,10 +21,6 @@ import org.dspace.core.Context; import org.dspace.core.LogManager; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Collections; -import java.util.List; - /** * Service implementation for the BitstreamFormat object. * This class is responsible for all business logic calls for the BitstreamFormat object and is autowired by spring. @@ -30,7 +30,9 @@ import java.util.List; */ public class BitstreamFormatServiceImpl implements BitstreamFormatService { - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(BitstreamFormat.class); @Autowired(required = true) @@ -39,52 +41,45 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { @Autowired(required = true) protected AuthorizeService authorizeService; - protected BitstreamFormatServiceImpl() - { + protected BitstreamFormatServiceImpl() { } - /** translate support-level ID to string. MUST keep this table in sync - * with support level definitions above. + /** + * translate support-level ID to string. MUST keep this table in sync + * with support level definitions above. */ protected final String supportLevelText[] = - { "UNKNOWN", "KNOWN", "SUPPORTED" }; + {"UNKNOWN", "KNOWN", "SUPPORTED"}; /** * Get a bitstream format from the database. * - * @param context - * DSpace context object - * @param id - * ID of the bitstream format - * + * @param context DSpace context object + * @param id ID of the bitstream format * @return the bitstream format, or null if the ID is invalid. * @throws SQLException if database error */ @Override public BitstreamFormat find(Context context, int id) - throws SQLException - { + throws SQLException { BitstreamFormat bitstreamFormat = bitstreamFormatDAO.findByID(context, BitstreamFormat.class, id); - if (bitstreamFormat == null) - { - if (log.isDebugEnabled()) - { + if (bitstreamFormat == null) { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, - "find_bitstream_format", - "not_found,bitstream_format_id=" + id)); + "find_bitstream_format", + "not_found,bitstream_format_id=" + id)); } return null; } // not null, return format object - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_bitstream_format", - "bitstream_format_id=" + id)); + "bitstream_format_id=" + id)); } return bitstreamFormat; @@ -96,7 +91,7 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { } @Override - public BitstreamFormat findByShortDescription(Context context, String desc) throws SQLException{ + public BitstreamFormat findByShortDescription(Context context, String desc) throws SQLException { return bitstreamFormatDAO.findByShortDescription(context, desc); } @@ -104,10 +99,9 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { public BitstreamFormat findUnknown(Context context) throws SQLException { BitstreamFormat bf = findByShortDescription(context, "Unknown"); - if (bf == null) - { + if (bf == null) { throw new IllegalStateException( - "No `Unknown' bitstream format in registry"); + "No `Unknown' bitstream format in registry"); } return bf; @@ -125,11 +119,10 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { @Override public BitstreamFormat create(Context context) throws SQLException, AuthorizeException { - // Check authorisation - only administrators can create new formats - if (!authorizeService.isAdmin(context)) - { + // Check authorisation - only administrators can create new formats + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators can create bitstream formats"); + "Only administrators can create bitstream formats"); } // Create a table row @@ -137,31 +130,32 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { log.info(LogManager.getHeader(context, "create_bitstream_format", - "bitstream_format_id=" - + bitstreamFormat.getID())); + "bitstream_format_id=" + + bitstreamFormat.getID())); return bitstreamFormat; } @Override - public void setShortDescription(Context context, BitstreamFormat bitstreamFormat, String shortDescription) throws SQLException { - // You can not reset the unknown's registry's name + public void setShortDescription(Context context, BitstreamFormat bitstreamFormat, String shortDescription) + throws SQLException { + // You can not reset the unknown's registry's name BitstreamFormat unknown = null; - try { - unknown = findUnknown(context); - } catch (IllegalStateException e) { - // No short_description='Unknown' found in bitstreamformatregistry - // table. On first load of registries this is expected because it - // hasn't been inserted yet! So, catch but ignore this runtime - // exception thrown by method findUnknown. - } + try { + unknown = findUnknown(context); + } catch (IllegalStateException e) { + // No short_description='Unknown' found in bitstreamformatregistry + // table. On first load of registries this is expected because it + // hasn't been inserted yet! So, catch but ignore this runtime + // exception thrown by method findUnknown. + } - // If the exception was thrown, unknown will == null so goahead and - // load s. If not, check that the unknown's registry's name is not - // being reset. - if (unknown == null || unknown.getID() != bitstreamFormat.getID()) { + // If the exception was thrown, unknown will == null so goahead and + // load s. If not, check that the unknown's registry's name is not + // being reset. + if (unknown == null || unknown.getID() != bitstreamFormat.getID()) { bitstreamFormat.setShortDescriptionInternal(shortDescription); - } + } } @Override @@ -171,9 +165,8 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { @Override public void setSupportLevel(BitstreamFormat bitstreamFormat, int supportLevel) { - // Sanity check - if ((supportLevel < 0) || (supportLevel > 2)) - { + // Sanity check + if ((supportLevel < 0) || (supportLevel > 2)) { throw new IllegalArgumentException("Invalid support level"); } @@ -186,17 +179,18 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { } @Override - public void update(Context context, List bitstreamFormats) throws SQLException, AuthorizeException { - if(CollectionUtils.isNotEmpty(bitstreamFormats)) { + public void update(Context context, List bitstreamFormats) + throws SQLException, AuthorizeException { + if (CollectionUtils.isNotEmpty(bitstreamFormats)) { // Check authorisation - only administrators can change formats if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators can modify bitstream formats"); + "Only administrators can modify bitstream formats"); } for (BitstreamFormat bitstreamFormat : bitstreamFormats) { log.info(LogManager.getHeader(context, "update_bitstream_format", - "bitstream_format_id=" + bitstreamFormat.getID())); + "bitstream_format_id=" + bitstreamFormat.getID())); bitstreamFormatDAO.save(context, bitstreamFormat); } @@ -205,18 +199,16 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { @Override public void delete(Context context, BitstreamFormat bitstreamFormat) throws SQLException, AuthorizeException { - // Check authorisation - only administrators can delete formats - if (!authorizeService.isAdmin(context)) - { + // Check authorisation - only administrators can delete formats + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators can delete bitstream formats"); + "Only administrators can delete bitstream formats"); } // Find "unknown" type BitstreamFormat unknown = findUnknown(context); - if (unknown.getID() == bitstreamFormat.getID()) - { + if (unknown.getID() == bitstreamFormat.getID()) { throw new IllegalArgumentException("The Unknown bitstream format may not be deleted."); } @@ -227,16 +219,14 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { bitstreamFormatDAO.delete(context, bitstreamFormat); log.info(LogManager.getHeader(context, "delete_bitstream_format", - "bitstream_format_id=" + bitstreamFormat.getID() + ",bitstreams_changed=" - + numberChanged)); + "bitstream_format_id=" + bitstreamFormat.getID() + ",bitstreams_changed=" + + numberChanged)); } @Override public int getSupportLevelID(String supportLevel) { - for (int i = 0; i < supportLevelText.length; i++) - { - if (supportLevelText[i].equals(supportLevel)) - { + for (int i = 0; i < supportLevelText.length; i++) { + if (supportLevelText[i].equals(supportLevel)) { return i; } } @@ -275,8 +265,7 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService { List bitstreamFormats = bitstreamFormatDAO.findByFileExtension(context, extension); - if(CollectionUtils.isNotEmpty(bitstreamFormats)) - { + if (CollectionUtils.isNotEmpty(bitstreamFormats)) { return bitstreamFormats.get(0); } return null; diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java index 2ddf806eff..e5e7cc57e4 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java @@ -7,7 +7,14 @@ */ package org.dspace.content; -import org.apache.commons.collections.CollectionUtils; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; @@ -24,13 +31,6 @@ import org.dspace.event.Event; import org.dspace.storage.bitstore.service.BitstreamStorageService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; - /** * Service implementation for the Bitstream object. * This class is responsible for all business logic calls for the Bitstream object and is autowired by spring. @@ -40,7 +40,9 @@ import java.util.UUID; */ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl implements BitstreamService { - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(BitstreamServiceImpl.class); @@ -59,8 +61,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Autowired(required = true) protected BitstreamStorageService bitstreamStorageService; - protected BitstreamServiceImpl() - { + protected BitstreamServiceImpl() { super(); } @@ -68,36 +69,56 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp public Bitstream find(Context context, UUID id) throws SQLException { Bitstream bitstream = bitstreamDAO.findByID(context, Bitstream.class, id); - if (bitstream == null) - { - if (log.isDebugEnabled()) - { + if (bitstream == null) { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_bitstream", - "not_found,bitstream_id=" + id)); + "not_found,bitstream_id=" + id)); } return null; } - // not null, return Bitstream - if (log.isDebugEnabled()) - { + // not null, return Bitstream + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_bitstream", - "bitstream_id=" + id)); + "bitstream_id=" + id)); } return bitstream; } @Override - public List findAll(Context context) throws SQLException - { + public List findAll(Context context) throws SQLException { return bitstreamDAO.findAll(context, Bitstream.class); } @Override - public Iterator findAll(Context context, int limit, int offset) throws SQLException - { + public Bitstream clone(Context context, Bitstream bitstream) + throws SQLException { + // Create a new bitstream with a new ID. + Bitstream clonedBitstream = bitstreamDAO.create(context, new Bitstream()); + // Set the internal identifier, file size, checksum, and + // checksum algorithm as same as the given bitstream. + clonedBitstream.setInternalId(bitstream.getInternalId()); + clonedBitstream.setSizeBytes(bitstream.getSizeBytes()); + clonedBitstream.setChecksum(bitstream.getChecksum()); + clonedBitstream.setChecksumAlgorithm(bitstream.getChecksumAlgorithm()); + try { + //Update our bitstream but turn off the authorization system since permissions + //haven't been set at this point in time. + context.turnOffAuthorisationSystem(); + update(context, clonedBitstream); + } catch (AuthorizeException e) { + log.error(e); + //Can never happen since we turn off authorization before we update + } finally { + context.restoreAuthSystemState(); + } + return clonedBitstream; + } + + @Override + public Iterator findAll(Context context, int limit, int offset) throws SQLException { return bitstreamDAO.findAll(context, limit, offset); } @@ -107,19 +128,21 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp UUID bitstreamID = bitstreamStorageService.store(context, bitstreamDAO.create(context, new Bitstream()), is); log.info(LogManager.getHeader(context, "create_bitstream", - "bitstream_id=" + bitstreamID)); + "bitstream_id=" + bitstreamID)); // Set the format to "unknown" Bitstream bitstream = find(context, bitstreamID); setFormat(context, bitstream, null); - context.addEvent(new Event(Event.CREATE, Constants.BITSTREAM, bitstreamID, null, getIdentifiers(context, bitstream))); + context.addEvent( + new Event(Event.CREATE, Constants.BITSTREAM, bitstreamID, null, getIdentifiers(context, bitstream))); return bitstream; } @Override - public Bitstream create(Context context, Bundle bundle, InputStream is) throws IOException, SQLException, AuthorizeException { + public Bitstream create(Context context, Bundle bundle, InputStream is) + throws IOException, SQLException, AuthorizeException { // Check authorisation authorizeService.authorizeAction(context, bundle, Constants.ADD); @@ -129,7 +152,8 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp } @Override - public Bitstream register(Context context, Bundle bundle, int assetstore, String bitstreamPath) throws IOException, SQLException, AuthorizeException { + public Bitstream register(Context context, Bundle bundle, int assetstore, String bitstreamPath) + throws IOException, SQLException, AuthorizeException { // check authorisation authorizeService.authorizeAction(context, bundle, Constants.ADD); @@ -146,52 +170,49 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp * check authorisation. The newly created bitstream has the "unknown" * format. * - * @param context DSpace context object - * @param assetstore corresponds to an assetstore in dspace.cfg + * @param context DSpace context object + * @param assetstore corresponds to an assetstore in dspace.cfg * @param bitstreamPath the path and filename relative to the assetstore - * @return the newly registered bitstream - * @throws IOException if IO error - * @throws SQLException if database error + * @return the newly registered bitstream + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public Bitstream register(Context context, - int assetstore, String bitstreamPath) - throws IOException, SQLException, AuthorizeException { + int assetstore, String bitstreamPath) + throws IOException, SQLException, AuthorizeException { // Store the bits Bitstream bitstream = bitstreamDAO.create(context, new Bitstream()); bitstreamStorageService.register( - context, bitstream, assetstore, bitstreamPath); + context, bitstream, assetstore, bitstreamPath); log.info(LogManager.getHeader(context, - "create_bitstream", - "bitstream_id=" + bitstream.getID())); + "create_bitstream", + "bitstream_id=" + bitstream.getID())); // Set the format to "unknown" setFormat(context, bitstream, null); context.addEvent(new Event(Event.CREATE, Constants.BITSTREAM, - bitstream.getID(), "REGISTER", getIdentifiers(context, bitstream))); + bitstream.getID(), "REGISTER", getIdentifiers(context, bitstream))); return bitstream; } @Override public void setUserFormatDescription(Context context, Bitstream bitstream, String desc) throws SQLException { - setFormat(context,bitstream, null); + setFormat(context, bitstream, null); setMetadataSingleValue(context, bitstream, MetadataSchema.DC_SCHEMA, "format", null, null, desc); } @Override - public String getFormatDescription(Context context, Bitstream bitstream) throws SQLException - { - if (bitstream.getFormat(context).getShortDescription().equals("Unknown")) - { + public String getFormatDescription(Context context, Bitstream bitstream) throws SQLException { + if (bitstream.getFormat(context).getShortDescription().equals("Unknown")) { // Get user description if there is one String desc = bitstream.getUserFormatDescription(); - if (desc == null) - { + if (desc == null) { return "Unknown"; } @@ -204,16 +225,15 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public void setFormat(Context context, Bitstream bitstream, BitstreamFormat bitstreamFormat) throws SQLException { - // FIXME: Would be better if this didn't throw an SQLException, + // FIXME: Would be better if this didn't throw an SQLException, // but we need to find the unknown format! - if (bitstreamFormat == null) - { + if (bitstreamFormat == null) { // Use "Unknown" format bitstreamFormat = bitstreamFormatService.findUnknown(context); } // Remove user type description - clearMetadata(context, bitstream, MetadataSchema.DC_SCHEMA,"format",null, Item.ANY); + clearMetadata(context, bitstream, MetadataSchema.DC_SCHEMA, "format", null, Item.ANY); // Update the ID in the table row bitstream.setFormat(bitstreamFormat); @@ -225,16 +245,17 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp authorizeService.authorizeAction(context, bitstream, Constants.WRITE); log.info(LogManager.getHeader(context, "update_bitstream", - "bitstream_id=" + bitstream.getID())); + "bitstream_id=" + bitstream.getID())); super.update(context, bitstream); - if (bitstream.isModified()) - { - context.addEvent(new Event(Event.MODIFY, Constants.BITSTREAM, bitstream.getID(), null, getIdentifiers(context, bitstream))); + if (bitstream.isModified()) { + context.addEvent(new Event(Event.MODIFY, Constants.BITSTREAM, bitstream.getID(), null, + getIdentifiers(context, bitstream))); bitstream.setModified(); } - if (bitstream.isMetadataModified()) - { - context.addEvent(new Event(Event.MODIFY_METADATA, Constants.BITSTREAM, bitstream.getID(), bitstream.getDetails(), getIdentifiers(context, bitstream))); + if (bitstream.isMetadataModified()) { + context.addEvent( + new Event(Event.MODIFY_METADATA, Constants.BITSTREAM, bitstream.getID(), bitstream.getDetails(), + getIdentifiers(context, bitstream))); bitstream.clearModified(); bitstream.clearDetails(); } @@ -249,10 +270,10 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp // Check authorisation authorizeService.authorizeAction(context, bitstream, Constants.DELETE); log.info(LogManager.getHeader(context, "delete_bitstream", - "bitstream_id=" + bitstream.getID())); + "bitstream_id=" + bitstream.getID())); context.addEvent(new Event(Event.DELETE, Constants.BITSTREAM, bitstream.getID(), - String.valueOf(bitstream.getSequenceID()), getIdentifiers(context, bitstream))); + String.valueOf(bitstream.getSequenceID()), getIdentifiers(context, bitstream))); // Remove bitstream itself bitstream.setDeleted(true); @@ -277,7 +298,8 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp } @Override - public InputStream retrieve(Context context, Bitstream bitstream) throws IOException, SQLException, AuthorizeException { + public InputStream retrieve(Context context, Bitstream bitstream) + throws IOException, SQLException, AuthorizeException { // Maybe should return AuthorizeException?? authorizeService.authorizeAction(context, bitstream, Constants.READ); @@ -292,26 +314,17 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public DSpaceObject getParentObject(Context context, Bitstream bitstream) throws SQLException { List bundles = bitstream.getBundles(); - if (CollectionUtils.isNotEmpty(bundles)) - { + if (CollectionUtils.isNotEmpty(bundles)) { // the ADMIN action is not allowed on Bundle object so skip to the item Item item = (Item) bundleService.getParentObject(context, bundles.iterator().next()); - if (item != null) - { + if (item != null) { return item; - } - else - { + } else { return null; } - } - else - if(bitstream.getCommunity() != null) - { + } else if (bitstream.getCommunity() != null) { return bitstream.getCommunity(); - }else - if(bitstream.getCollection() != null) - { + } else if (bitstream.getCollection() != null) { return bitstream.getCollection(); } return null; @@ -320,7 +333,8 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public void updateLastModified(Context context, Bitstream bitstream) { //Also fire a modified event since the bitstream HAS been modified - context.addEvent(new Event(Event.MODIFY, Constants.BITSTREAM, bitstream.getID(), null, getIdentifiers(context, bitstream))); + context.addEvent( + new Event(Event.MODIFY, Constants.BITSTREAM, bitstream.getID(), null, getIdentifiers(context, bitstream))); } @Override @@ -331,8 +345,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public void expunge(Context context, Bitstream bitstream) throws SQLException, AuthorizeException { authorizeService.authorizeAction(context, bitstream, Constants.DELETE); - if(!bitstream.isDeleted()) - { + if (!bitstream.isDeleted()) { throw new IllegalStateException("Bitstream must be deleted before it can be removed from the database"); } bitstreamDAO.delete(context, bitstream); @@ -373,8 +386,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp List bitstreams = bundle.getBitstreams(); for (int j = 0; j < bitstreams.size(); j++) { Bitstream bitstream = bitstreams.get(j); - if(StringUtils.equals(bitstream.getName(), bitstreamName)) - { + if (StringUtils.equals(bitstream.getName(), bitstreamName)) { return bitstream; } } @@ -385,11 +397,9 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public Bitstream getFirstBitstream(Item item, String bundleName) throws SQLException { List bundles = itemService.getBundles(item, bundleName); - if(CollectionUtils.isNotEmpty(bundles)) - { + if (CollectionUtils.isNotEmpty(bundles)) { List bitstreams = bundles.get(0).getBitstreams(); - if(CollectionUtils.isNotEmpty(bitstreams)) - { + if (CollectionUtils.isNotEmpty(bitstreams)) { return bitstreams.get(0); } } @@ -398,10 +408,9 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public BitstreamFormat getFormat(Context context, Bitstream bitstream) throws SQLException { - if(bitstream.getBitstreamFormat() == null) - { + if (bitstream.getBitstreamFormat() == null) { return bitstreamFormatService.findUnknown(context); - }else{ + } else { return bitstream.getBitstreamFormat(); } } @@ -423,12 +432,9 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public Bitstream findByIdOrLegacyId(Context context, String id) throws SQLException { - if(StringUtils.isNumeric(id)) - { + if (StringUtils.isNumeric(id)) { return findByLegacyId(context, Integer.parseInt(id)); - } - else - { + } else { return find(context, UUID.fromString(id)); } } @@ -453,4 +459,8 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp public List getNotReferencedBitstreams(Context context) throws SQLException { return bitstreamDAO.getNotReferencedBitstreams(context); } + + public Long getLastModified(Bitstream bitstream) { + return bitstreamStorageService.getLastModified(bitstream); + } } diff --git a/dspace-api/src/main/java/org/dspace/content/Bundle.java b/dspace-api/src/main/java/org/dspace/content/Bundle.java index 5184771f1a..5fe7100d4f 100644 --- a/dspace-api/src/main/java/org/dspace/content/Bundle.java +++ b/dspace-api/src/main/java/org/dspace/content/Bundle.java @@ -8,17 +8,26 @@ package org.dspace.content; import java.sql.SQLException; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.OneToOne; +import javax.persistence.OrderColumn; +import javax.persistence.Table; +import javax.persistence.Transient; -import org.apache.commons.collections.CollectionUtils; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BundleService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; - /** * Class representing bundles of bitstreams stored in the DSpace system *

    @@ -26,15 +35,14 @@ import javax.persistence.*; * is no metadata associated with bundles - they are simple containers. Thus, * the update method doesn't do much yet. Creating, adding or * removing bitstreams has instant effect in the database. - * + * * @author Robert Tansley * @version $Revision$ */ @Entity -@Table(name="bundle") -public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport -{ - @Column(name="bundle_id", insertable = false, updatable = false) +@Table(name = "bundle") +public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport { + @Column(name = "bundle_id", insertable = false, updatable = false) private Integer legacyId; @OneToOne @@ -43,18 +51,18 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport @ManyToMany(fetch = FetchType.LAZY) @JoinTable( - name="bundle2bitstream", - joinColumns={@JoinColumn(name="bundle_id") }, - inverseJoinColumns={@JoinColumn(name="bitstream_id") } + name = "bundle2bitstream", + joinColumns = {@JoinColumn(name = "bundle_id")}, + inverseJoinColumns = {@JoinColumn(name = "bitstream_id")} ) - @OrderColumn(name="bitstream_order") + @OrderColumn(name = "bitstream_order") private final List bitstreams = new ArrayList<>(); @ManyToMany(fetch = FetchType.LAZY) @JoinTable( - name = "item2bundle", - joinColumns = {@JoinColumn(name = "bundle_id", referencedColumnName = "uuid") }, - inverseJoinColumns = {@JoinColumn(name = "item_id", referencedColumnName = "uuid") } + name = "item2bundle", + joinColumns = {@JoinColumn(name = "bundle_id", referencedColumnName = "uuid")}, + inverseJoinColumns = {@JoinColumn(name = "item_id", referencedColumnName = "uuid")} ) private final List items = new ArrayList<>(); @@ -64,10 +72,8 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport /** * Protected constructor, create object using: * {@link org.dspace.content.service.BundleService#create(Context, Item, String)} - * */ - protected Bundle() - { + protected Bundle() { } @Override @@ -77,47 +83,41 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the name of the bundle - * + * * @return name of the bundle (ORIGINAL, TEXT, THUMBNAIL) or NULL if not set */ @Override - public String getName() - { + public String getName() { return getBundleService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); } /** * Set the name of the bundle - * + * * @param context context - * @param name - * string name of the bundle (ORIGINAL, TEXT, THUMBNAIL) are the - * values currently used + * @param name string name of the bundle (ORIGINAL, TEXT, THUMBNAIL) are the + * values currently used * @throws SQLException if database error */ - public void setName(Context context, String name) throws SQLException - { + public void setName(Context context, String name) throws SQLException { getBundleService().setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "title", null, null, name); } /** * Get the primary bitstream ID of the bundle - * + * * @return primary bitstream ID or -1 if not set */ - public Bitstream getPrimaryBitstream() - { + public Bitstream getPrimaryBitstream() { return primaryBitstream; } /** * Set the primary bitstream ID of the bundle - * - * @param bitstream - * primary bitstream (e.g. index html file) + * + * @param bitstream primary bitstream (e.g. index html file) */ - public void setPrimaryBitstreamID(Bitstream bitstream) - { + public void setPrimaryBitstreamID(Bitstream bitstream) { primaryBitstream = bitstream; setModified(); } @@ -125,16 +125,15 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport /** * Unset the primary bitstream ID of the bundle */ - public void unsetPrimaryBitstreamID() - { - primaryBitstream = null; + public void unsetPrimaryBitstreamID() { + primaryBitstream = null; } - + /** * Get a copy of the bitstream list of this bundle * Note that this is a copy and if you wish to manipulate the bistream list, you should use * {@ref Bundle.addBitstream}, {@ref Bundle.removeBitstream} or {@ref Bundle.clearBitstreams} - * + * * @return the bitstreams */ public List getBitstreams() { @@ -144,9 +143,10 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport /** * Add a new bitstream to this bundle. + * * @param bitstream */ - void addBitstream(Bitstream bitstream){ + void addBitstream(Bitstream bitstream) { bitstreams.add(bitstream); } @@ -159,6 +159,7 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport /** * Remove the given bitstream from this bundles bitstream list + * * @param bitstream The bitstream to remove */ public void removeBitstream(Bitstream bitstream) { @@ -167,7 +168,7 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the items this bundle appears in - * + * * @return array of Item s this bundle appears in */ public List getItems() { @@ -189,30 +190,25 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport @Override public boolean equals(Object obj) { - if (obj == null) - { + if (obj == null) { return false; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (this.getClass() != objClass) - { + if (this.getClass() != objClass) { return false; } final Bundle other = (Bundle) obj; - if (this.getType() != other.getType()) - { + if (this.getType() != other.getType()) { return false; } - if(!this.getID().equals(other.getID())) - { + if (!this.getID().equals(other.getID())) { return false; } return true; } @Override - public int hashCode() - { + public int hashCode() { int hash = 5; hash += 71 * hash + getType(); hash += 71 * hash + getID().hashCode(); @@ -222,18 +218,16 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport /** * return type found in Constants + * * @return bundle type */ @Override - public int getType() - { + public int getType() { return Constants.BUNDLE; } - private BundleService getBundleService() - { - if(bundleService == null) - { + private BundleService getBundleService() { + if (bundleService == null) { bundleService = ContentServiceFactory.getInstance().getBundleService(); } return bundleService; diff --git a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java index 45618289de..d8ee51fadf 100644 --- a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java @@ -7,7 +7,15 @@ */ package org.dspace.content; -import org.apache.commons.collections.CollectionUtils; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeConfiguration; @@ -25,10 +33,6 @@ import org.dspace.core.LogManager; import org.dspace.event.Event; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; - /** * Service implementation for the Bundle object. * This class is responsible for all business logic calls for the Bundle object and is autowired by spring. @@ -38,7 +42,9 @@ import java.util.*; */ public class BundleServiceImpl extends DSpaceObjectServiceImpl implements BundleService { - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(Bundle.class); @Autowired(required = true) @@ -53,32 +59,25 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement @Autowired(required = true) protected ResourcePolicyService resourcePolicyService; - protected BundleServiceImpl() - { + protected BundleServiceImpl() { super(); } @Override - public Bundle find(Context context, UUID id) throws SQLException - { + public Bundle find(Context context, UUID id) throws SQLException { // First check the cache Bundle bundle = bundleDAO.findByID(context, Bundle.class, id); - if (bundle == null) - { - if (log.isDebugEnabled()) - { + if (bundle == null) { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_bundle", - "not_found,bundle_id=" + id)); + "not_found,bundle_id=" + id)); } return null; - } - else - { - if (log.isDebugEnabled()) - { + } else { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_bundle", - "bundle_id=" + id)); + "bundle_id=" + id)); } return bundle; @@ -87,8 +86,7 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement @Override public Bundle create(Context context, Item item, String name) throws SQLException, AuthorizeException { - if (StringUtils.isBlank(name)) - { + if (StringUtils.isBlank(name)) { throw new SQLException("Bundle must be created with non-null name"); } authorizeService.authorizeAction(context, item, Constants.ADD); @@ -98,14 +96,13 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement Bundle bundle = bundleDAO.create(context, new Bundle()); bundle.setName(context, name); itemService.addBundle(context, item, bundle); - if(!bundle.getItems().contains(item)) - { + if (!bundle.getItems().contains(item)) { bundle.addItem(item); } log.info(LogManager.getHeader(context, "create_bundle", "bundle_id=" - + bundle.getID())); + + bundle.getID())); // if we ever use the identifier service for bundles, we should // create the bundle before we create the Event and should add all @@ -130,12 +127,13 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement } @Override - public void addBitstream(Context context, Bundle bundle, Bitstream bitstream) throws SQLException, AuthorizeException { + public void addBitstream(Context context, Bundle bundle, Bitstream bitstream) + throws SQLException, AuthorizeException { // Check authorisation authorizeService.authorizeAction(context, bundle, Constants.ADD); log.info(LogManager.getHeader(context, "add_bitstream", "bundle_id=" - + bundle.getID() + ",bitstream_id=" + bitstream.getID())); + + bundle.getID() + ",bitstream_id=" + bitstream.getID())); // First check that the bitstream isn't already in the list List bitstreams = bundle.getBitstreams(); @@ -148,13 +146,20 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement } } + // Ensure that the last modified from the item is triggered ! + Item owningItem = (Item) getParentObject(context, bundle); + if (owningItem != null) { + itemService.updateLastModified(context, owningItem); + itemService.update(context, owningItem); + } + bundle.addBitstream(bitstream); bitstream.getBundles().add(bundle); context.addEvent(new Event(Event.ADD, Constants.BUNDLE, bundle.getID(), - Constants.BITSTREAM, bitstream.getID(), String.valueOf(bitstream.getSequenceID()), - getIdentifiers(context, bundle))); + Constants.BITSTREAM, bitstream.getID(), String.valueOf(bitstream.getSequenceID()), + getIdentifiers(context, bundle))); // copy authorization policies from bundle to bitstream // FIXME: multiple inclusion is affected by this... @@ -163,22 +168,22 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement } @Override - public void removeBitstream(Context context, Bundle bundle, Bitstream bitstream) throws AuthorizeException, SQLException, IOException { + public void removeBitstream(Context context, Bundle bundle, Bitstream bitstream) + throws AuthorizeException, SQLException, IOException { // Check authorisation authorizeService.authorizeAction(context, bundle, Constants.REMOVE); log.info(LogManager.getHeader(context, "remove_bitstream", - "bundle_id=" + bundle.getID() + ",bitstream_id=" + bitstream.getID())); + "bundle_id=" + bundle.getID() + ",bitstream_id=" + bitstream.getID())); context.addEvent(new Event(Event.REMOVE, Constants.BUNDLE, bundle.getID(), - Constants.BITSTREAM, bitstream.getID(), String.valueOf(bitstream.getSequenceID()), - getIdentifiers(context, bundle))); + Constants.BITSTREAM, bitstream.getID(), String.valueOf(bitstream.getSequenceID()), + getIdentifiers(context, bundle))); //Ensure that the last modified from the item is triggered ! Item owningItem = (Item) getParentObject(context, bundle); - if(owningItem != null) - { + if (owningItem != null) { itemService.updateLastModified(context, owningItem); itemService.update(context, owningItem); } @@ -186,41 +191,42 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement // In the event that the bitstream to remove is actually // the primary bitstream, be sure to unset the primary // bitstream. - if (bitstream.equals(bundle.getPrimaryBitstream())) - { + if (bitstream.equals(bundle.getPrimaryBitstream())) { bundle.unsetPrimaryBitstreamID(); } - // Check if we our bitstream is part of a single bundle: - // If so delete it, if not then remove the link between bundle & bitstream - if(bitstream.getBundles().size() == 1) - { - // We don't need to remove the link between bundle & bitstream, this will be handled in the delete() method. + // Check if our bitstream is part of a single or no bundle. + // Bitstream.getBundles() may be empty (the delete() method clears + // the bundles). We should not delete the bitstream, if it is used + // in another bundle, instead we just remove the link between bitstream + // and this bundle. + if (bitstream.getBundles().size() <= 1) { + // We don't need to remove the link between bundle & bitstream, + // this will be handled in the delete() method. bitstreamService.delete(context, bitstream); - }else{ + } else { bundle.removeBitstream(bitstream); bitstream.getBundles().remove(bundle); } } @Override - public void inheritCollectionDefaultPolicies(Context context, Bundle bundle, Collection collection) throws SQLException, AuthorizeException { + public void inheritCollectionDefaultPolicies(Context context, Bundle bundle, Collection collection) + throws SQLException, AuthorizeException { List policies = authorizeService.getPoliciesActionFilter(context, collection, - Constants.DEFAULT_BITSTREAM_READ); + Constants.DEFAULT_BITSTREAM_READ); // change the action to just READ // just don't call update on the resourcepolicies!!! Iterator i = policies.iterator(); - if (!i.hasNext()) - { + if (!i.hasNext()) { throw new java.sql.SQLException("Collection " + collection.getID() - + " has no default bitstream READ policies"); + + " has no default bitstream READ policies"); } List newPolicies = new ArrayList(); - while (i.hasNext()) - { + while (i.hasNext()) { ResourcePolicy rp = resourcePolicyService.clone(context, i.next()); rp.setAction(Constants.READ); newPolicies.add(rp); @@ -230,12 +236,11 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement } @Override - public void replaceAllBitstreamPolicies(Context context, Bundle bundle, List newpolicies) throws SQLException, AuthorizeException { + public void replaceAllBitstreamPolicies(Context context, Bundle bundle, List newpolicies) + throws SQLException, AuthorizeException { List bitstreams = bundle.getBitstreams(); - if (CollectionUtils.isNotEmpty(bitstreams)) - { - for (Bitstream bs : bitstreams) - { + if (CollectionUtils.isNotEmpty(bitstreams)) { + for (Bitstream bs : bitstreams) { // change bitstream policies authorizeService.removeAllPolicies(context, bs); authorizeService.addPolicies(context, newpolicies, bs); @@ -250,10 +255,8 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement public List getBitstreamPolicies(Context context, Bundle bundle) throws SQLException { List list = new ArrayList(); List bitstreams = bundle.getBitstreams(); - if (CollectionUtils.isNotEmpty(bitstreams)) - { - for (Bitstream bs : bitstreams) - { + if (CollectionUtils.isNotEmpty(bitstreams)) { + for (Bitstream bs : bitstreams) { list.addAll(authorizeService.getPolicies(context, bs)); } } @@ -278,37 +281,40 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement Bitstream bitstream = bitstreamService.find(context, bitstreamId); // If we have an invalid Bitstream ID, just ignore it, but log a warning - if(bitstream == null) { + if (bitstream == null) { //This should never occur but just in case - log.warn(LogManager.getHeader(context, "Invalid bitstream id while changing bitstream order", "Bundle: " + bundle.getID() + ", bitstream id: " + bitstreamId)); + log.warn(LogManager.getHeader(context, "Invalid bitstream id while changing bitstream order", + "Bundle: " + bundle.getID() + ", bitstream id: " + bitstreamId)); continue; } // If we have a Bitstream not in the current list, log a warning & exit immediately - if(!currentBitstreams.contains(bitstream)) - { - log.warn(LogManager.getHeader(context, "Encountered a bitstream not in this bundle while changing bitstream order. Bitstream order will not be changed.", "Bundle: " + bundle.getID() + ", bitstream id: " + bitstreamId)); + if (!currentBitstreams.contains(bitstream)) { + log.warn(LogManager.getHeader(context, + "Encountered a bitstream not in this bundle while changing bitstream " + + "order. Bitstream order will not be changed.", + "Bundle: " + bundle.getID() + ", bitstream id: " + bitstreamId)); return; } updatedBitstreams.add(bitstream); } // If our lists are different sizes, exit immediately - if(updatedBitstreams.size()!=currentBitstreams.size()) - { - log.warn(LogManager.getHeader(context, "Size of old list and new list do not match. Bitstream order will not be changed.", "Bundle: " + bundle.getID())); + if (updatedBitstreams.size() != currentBitstreams.size()) { + log.warn(LogManager.getHeader(context, + "Size of old list and new list do not match. Bitstream order will not be " + + "changed.", + "Bundle: " + bundle.getID())); return; } // As long as the order has changed, update it - if(CollectionUtils.isNotEmpty(updatedBitstreams) && !updatedBitstreams.equals(currentBitstreams)) - { + if (CollectionUtils.isNotEmpty(updatedBitstreams) && !updatedBitstreams.equals(currentBitstreams)) { //First clear out the existing list of bitstreams bundle.clearBitstreams(); // Now add them back in the proper order - for (Bitstream bitstream : updatedBitstreams) - { + for (Bitstream bitstream : updatedBitstreams) { bitstream.getBundles().remove(bundle); bundle.addBitstream(bitstream); bitstream.getBundles().add(bundle); @@ -317,8 +323,7 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement //The order of the bitstreams has changed, ensure that we update the last modified of our item Item owningItem = (Item) getParentObject(context, bundle); - if(owningItem != null) - { + if (owningItem != null) { itemService.updateLastModified(context, owningItem); itemService.update(context, owningItem); @@ -332,51 +337,38 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement Item item = (Item) getParentObject(context, bundle); Collection collection = null; Community community = null; - if (item != null) - { + if (item != null) { collection = item.getOwningCollection(); - if (collection != null) - { + if (collection != null) { community = collection.getCommunities().get(0); } } - switch (action) - { - case Constants.REMOVE: - if (AuthorizeConfiguration.canItemAdminPerformBitstreamDeletion()) - { - adminObject = item; - } - else if (AuthorizeConfiguration.canCollectionAdminPerformBitstreamDeletion()) - { - adminObject = collection; - } - else if (AuthorizeConfiguration - .canCommunityAdminPerformBitstreamDeletion()) - { - adminObject = community; - } - break; - case Constants.ADD: - if (AuthorizeConfiguration.canItemAdminPerformBitstreamCreation()) - { - adminObject = item; - } - else if (AuthorizeConfiguration - .canCollectionAdminPerformBitstreamCreation()) - { - adminObject = collection; - } - else if (AuthorizeConfiguration - .canCommunityAdminPerformBitstreamCreation()) - { - adminObject = community; - } - break; + switch (action) { + case Constants.REMOVE: + if (AuthorizeConfiguration.canItemAdminPerformBitstreamDeletion()) { + adminObject = item; + } else if (AuthorizeConfiguration.canCollectionAdminPerformBitstreamDeletion()) { + adminObject = collection; + } else if (AuthorizeConfiguration + .canCommunityAdminPerformBitstreamDeletion()) { + adminObject = community; + } + break; + case Constants.ADD: + if (AuthorizeConfiguration.canItemAdminPerformBitstreamCreation()) { + adminObject = item; + } else if (AuthorizeConfiguration + .canCollectionAdminPerformBitstreamCreation()) { + adminObject = collection; + } else if (AuthorizeConfiguration + .canCommunityAdminPerformBitstreamCreation()) { + adminObject = community; + } + break; - default: - adminObject = bundle; - break; + default: + adminObject = bundle; + break; } return adminObject; } @@ -384,10 +376,9 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement @Override public DSpaceObject getParentObject(Context context, Bundle bundle) throws SQLException { List items = bundle.getItems(); - if(CollectionUtils.isNotEmpty(items)) - { + if (CollectionUtils.isNotEmpty(items)) { return items.iterator().next(); - }else{ + } else { return null; } } @@ -399,21 +390,21 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement @Override public void update(Context context, Bundle bundle) throws SQLException, AuthorizeException { - // Check authorisation + // Check authorisation //AuthorizeManager.authorizeAction(ourContext, this, Constants.WRITE); log.info(LogManager.getHeader(context, "update_bundle", "bundle_id=" - + bundle.getID())); + + bundle.getID())); super.update(context, bundle); bundleDAO.save(context, bundle); - if (bundle.isModified() || bundle.isMetadataModified()) - { - if(bundle.isMetadataModified()){ - context.addEvent(new Event(Event.MODIFY_METADATA, bundle.getType(), bundle.getID(), bundle.getDetails(), getIdentifiers(context, bundle))); + if (bundle.isModified() || bundle.isMetadataModified()) { + if (bundle.isMetadataModified()) { + context.addEvent(new Event(Event.MODIFY_METADATA, bundle.getType(), bundle.getID(), bundle.getDetails(), + getIdentifiers(context, bundle))); } context.addEvent(new Event(Event.MODIFY, Constants.BUNDLE, bundle.getID(), - null, getIdentifiers(context, bundle))); + null, getIdentifiers(context, bundle))); bundle.clearModified(); bundle.clearDetails(); } @@ -422,12 +413,12 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement @Override public void delete(Context context, Bundle bundle) throws SQLException, AuthorizeException, IOException { log.info(LogManager.getHeader(context, "delete_bundle", "bundle_id=" - + bundle.getID())); + + bundle.getID())); authorizeService.authorizeAction(context, bundle, Constants.DELETE); context.addEvent(new Event(Event.DELETE, Constants.BUNDLE, bundle.getID(), - bundle.getName(), getIdentifiers(context, bundle))); + bundle.getName(), getIdentifiers(context, bundle))); // Remove bitstreams List bitstreams = bundle.getBitstreams(); @@ -453,12 +444,9 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl implement @Override public Bundle findByIdOrLegacyId(Context context, String id) throws SQLException { - if(StringUtils.isNumeric(id)) - { + if (StringUtils.isNumeric(id)) { return findByLegacyId(context, Integer.parseInt(id)); - } - else - { + } else { return find(context, UUID.fromString(id)); } } diff --git a/dspace-api/src/main/java/org/dspace/content/Collection.java b/dspace-api/src/main/java/org/dspace/content/Collection.java index a57f14e619..249c5a19a2 100644 --- a/dspace-api/src/main/java/org/dspace/content/Collection.java +++ b/dspace-api/src/main/java/org/dspace/content/Collection.java @@ -7,19 +7,33 @@ */ package org.dspace.content; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.persistence.Cacheable; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.dspace.authorize.AuthorizeException; import org.dspace.content.comparator.NameAscendingComparator; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; -import org.dspace.core.*; +import org.dspace.core.Constants; +import org.dspace.core.Context; import org.dspace.eperson.Group; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.sql.SQLException; -import java.util.*; -import org.dspace.authorize.AuthorizeException; - /** * Class representing a collection. *

    @@ -35,21 +49,24 @@ import org.dspace.authorize.AuthorizeException; * @version $Revision$ */ @Entity -@Table(name="collection") +@Table(name = "collection") @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, include = "non-lazy") -public class Collection extends DSpaceObject implements DSpaceObjectLegacySupport -{ +public class Collection extends DSpaceObject implements DSpaceObjectLegacySupport { - @Column(name="collection_id", insertable = false, updatable = false) + @Column(name = "collection_id", insertable = false, updatable = false) private Integer legacyId; - /** The logo bitstream */ + /** + * The logo bitstream + */ @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "logo_bitstream_id") private Bitstream logo; - /** The item template */ + /** + * The item template + */ @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "template_item_id") private Item template; @@ -83,9 +100,9 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) @JoinTable( - name = "community2collection", - joinColumns = {@JoinColumn(name = "collection_id") }, - inverseJoinColumns = {@JoinColumn(name = "community_id") } + name = "community2collection", + joinColumns = {@JoinColumn(name = "collection_id")}, + inverseJoinColumns = {@JoinColumn(name = "community_id")} ) private Set communities = new HashSet<>(); @@ -109,17 +126,15 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * {@link org.dspace.content.service.CollectionService#create(Context, Community)} * or * {@link org.dspace.content.service.CollectionService#create(Context, Community, String)} - * */ - protected Collection() - { + protected Collection() { } @Override - public String getName() - { - String value = getCollectionService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + public String getName() { + String value = getCollectionService() + .getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); return value == null ? "" : value; } @@ -129,8 +144,7 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * * @return the logo of the collection, or null */ - public Bitstream getLogo() - { + public Bitstream getLogo() { return logo; } @@ -149,10 +163,9 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * collection_100_submit. * * @return the default group of submitters, or null if there - * is no default group. + * is no default group. */ - public Group getSubmitters() - { + public Group getSubmitters() { return submitters; } @@ -178,10 +191,9 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * collection_100_admin. * * @return group of administrators, or null if there is no - * default group. + * default group. */ - public Group getAdministrators() - { + public Group getAdministrators() { return admins; } @@ -223,8 +235,7 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * * @return the license for this collection */ - public String getLicenseCollection() - { + public String getLicenseCollection() { return getCollectionService().getMetadata(this, "license"); } @@ -249,8 +260,7 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * @return the item template, or null * @throws SQLException if database error */ - public Item getTemplateItem() throws SQLException - { + public Item getTemplateItem() throws SQLException { return template; } @@ -265,11 +275,10 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * @return array of Community objects * @throws SQLException if database error */ - public List getCommunities() throws SQLException - { + public List getCommunities() throws SQLException { // We return a copy because we do not want people to add elements to this collection directly. // We return a list to maintain backwards compatibility - Community[] output = communities.toArray(new Community[]{}); + Community[] output = communities.toArray(new Community[] {}); Arrays.sort(output, new NameAscendingComparator()); return Arrays.asList(output); } @@ -289,41 +298,34 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * Return true if other is the same Collection * as this object, false otherwise * - * @param other - * object to compare to - * + * @param other object to compare to * @return true if object passed in represents the same - * collection as this object + * collection as this object */ - @Override - public boolean equals(Object other) - { - if (other == null) - { - return false; - } - Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(other); - if (this.getClass() != objClass) - { - return false; - } - final Collection otherCollection = (Collection) other; - if (!this.getID().equals(otherCollection.getID() )) - { - return false; - } + @Override + public boolean equals(Object other) { + if (other == null) { + return false; + } + Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(other); + if (this.getClass() != objClass) { + return false; + } + final Collection otherCollection = (Collection) other; + if (!this.getID().equals(otherCollection.getID())) { + return false; + } - return true; - } + return true; + } - @Override - public int hashCode() - { - int hash = 5; - hash += 71 * hash + getType(); - hash += 71 * hash + getID().hashCode(); - return hash; - } + @Override + public int hashCode() { + int hash = 5; + hash += 71 * hash + getType(); + hash += 71 * hash + getID().hashCode(); + return hash; + } /** * return type found in Constants @@ -331,14 +333,12 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor * @return int Constants.COLLECTION */ @Override - public int getType() - { + public int getType() { return Constants.COLLECTION; } public void setWorkflowGroup(Context context, int step, Group g) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { getCollectionService().setWorkflowGroup(context, this, step, g); } @@ -348,8 +348,7 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor } private CollectionService getCollectionService() { - if(collectionService == null) - { + if (collectionService == null) { collectionService = ContentServiceFactory.getInstance().getCollectionService(); } return collectionService; diff --git a/dspace-api/src/main/java/org/dspace/content/CollectionNameComparator.java b/dspace-api/src/main/java/org/dspace/content/CollectionNameComparator.java index 84a637e702..2403d3c944 100644 --- a/dspace-api/src/main/java/org/dspace/content/CollectionNameComparator.java +++ b/dspace-api/src/main/java/org/dspace/content/CollectionNameComparator.java @@ -14,8 +14,7 @@ import java.util.Comparator; * Compares the names of two {@link Collection}s. */ public class CollectionNameComparator - implements Comparator, Serializable -{ + implements Comparator, Serializable { @Override public int compare(Collection collection1, Collection collection2) { return collection1.getName().compareTo(collection2.getName()); diff --git a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java index cbac3cfcfb..bd7034856f 100644 --- a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java @@ -7,7 +7,19 @@ */ package org.dspace.content; -import org.apache.commons.collections.CollectionUtils; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.UUID; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.util.AuthorizeUtil; @@ -15,9 +27,18 @@ import org.dspace.authorize.AuthorizeConfiguration; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.service.AuthorizeService; +import org.dspace.authorize.service.ResourcePolicyService; import org.dspace.content.dao.CollectionDAO; -import org.dspace.content.service.*; -import org.dspace.core.*; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.I18nUtil; +import org.dspace.core.LogManager; import org.dspace.core.service.LicenseService; import org.dspace.eperson.Group; import org.dspace.eperson.service.GroupService; @@ -28,12 +49,6 @@ import org.dspace.harvest.service.HarvestedCollectionService; import org.dspace.workflow.factory.WorkflowServiceFactory; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.*; -import org.dspace.authorize.service.ResourcePolicyService; - /** * Service implementation for the Collection object. * This class is responsible for all business logic calls for the Collection object and is autowired by spring. @@ -43,7 +58,9 @@ import org.dspace.authorize.service.ResourcePolicyService; */ public class CollectionServiceImpl extends DSpaceObjectServiceImpl implements CollectionService { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(CollectionServiceImpl.class); @Autowired(required = true) @@ -68,12 +85,11 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i protected SubscribeService subscribeService; @Autowired(required = true) protected WorkspaceItemService workspaceItemService; - @Autowired(required=true) + @Autowired(required = true) protected HarvestedCollectionService harvestedCollectionService; - protected CollectionServiceImpl() - { + protected CollectionServiceImpl() { super(); } @@ -83,9 +99,9 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } @Override - public Collection create(Context context, Community community, String handle) throws SQLException, AuthorizeException { - if(community == null) - { + public Collection create(Context context, Community community, String handle) + throws SQLException, AuthorizeException { + if (community == null) { throw new IllegalArgumentException("Community cannot be null when creating a new collection."); } @@ -93,32 +109,33 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i //Add our newly created collection to our community, authorization checks occur in THIS method communityService.addCollection(context, community, newCollection); - //Update our community so we have a collection identifier - if(handle == null) - { + //Update our community so we have a collection identifier + if (handle == null) { handleService.createHandle(context, newCollection); - }else{ + } else { handleService.createHandle(context, newCollection, handle); } - // create the default authorization policy for collections + // create the default authorization policy for collections // of 'anonymous' READ Group anonymousGroup = groupService.findByName(context, Group.ANONYMOUS); authorizeService.createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.READ, null); // now create the default policies for submitted items - authorizeService.createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.DEFAULT_ITEM_READ, null); - authorizeService.createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.DEFAULT_BITSTREAM_READ, null); - + authorizeService + .createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.DEFAULT_ITEM_READ, null); + authorizeService + .createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.DEFAULT_BITSTREAM_READ, null); context.addEvent(new Event(Event.CREATE, Constants.COLLECTION, - newCollection.getID(), newCollection.getHandle(), getIdentifiers(context, newCollection))); + newCollection.getID(), newCollection.getHandle(), + getIdentifiers(context, newCollection))); log.info(LogManager.getHeader(context, "create_collection", - "collection_id=" + newCollection.getID()) - + ",handle=" + newCollection.getHandle()); + "collection_id=" + newCollection.getID()) + + ",handle=" + newCollection.getHandle()); collectionDAO.save(context, newCollection); return newCollection; @@ -127,9 +144,9 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public List findAll(Context context) throws SQLException { MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); - if(nameField==null) - { - throw new IllegalArgumentException("Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + if (nameField == null) { + throw new IllegalArgumentException( + "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); } return collectionDAO.findAll(context, nameField); @@ -138,9 +155,9 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public List findAll(Context context, Integer limit, Integer offset) throws SQLException { MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); - if(nameField==null) - { - throw new IllegalArgumentException("Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + if (nameField == null) { + throw new IllegalArgumentException( + "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); } return collectionDAO.findAll(context, nameField, limit, offset); @@ -148,24 +165,22 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public List findAuthorizedOptimized(Context context, int actionID) throws SQLException { - if(! ConfigurationManager.getBooleanProperty("org.dspace.content.Collection.findAuthorizedPerformanceOptimize", false)) { + if (!ConfigurationManager + .getBooleanProperty("org.dspace.content.Collection.findAuthorizedPerformanceOptimize", false)) { // Fallback to legacy query if config says so. The rationale could be that a site found a bug. return findAuthorized(context, null, actionID); } List myResults = new ArrayList<>(); - if(authorizeService.isAdmin(context)) - { + if (authorizeService.isAdmin(context)) { return findAll(context); } //Check eperson->policy List directToCollection = findDirectMapped(context, actionID); - for (int i = 0; i< directToCollection.size(); i++) - { - if(!myResults.contains(directToCollection.get(i))) - { + for (int i = 0; i < directToCollection.size(); i++) { + if (!myResults.contains(directToCollection.get(i))) { myResults.add(directToCollection.get(i)); } } @@ -213,12 +228,14 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public List findDirectMapped(Context context, int actionID) throws SQLException { - return collectionDAO.findAuthorized(context, context.getCurrentUser(), Arrays.asList(Constants.ADD,Constants.ADMIN)); + return collectionDAO + .findAuthorized(context, context.getCurrentUser(), Arrays.asList(Constants.ADD, Constants.ADMIN)); } @Override public List findGroup2CommunityMapped(Context context) throws SQLException { - List communities = communityService.findAuthorizedGroupMapped(context, Arrays.asList(Constants.ADD, Constants.ADMIN)); + List communities = communityService + .findAuthorizedGroupMapped(context, Arrays.asList(Constants.ADD, Constants.ADMIN)); List collections = new ArrayList<>(); for (Community community : communities) { collections.addAll(community.getCollections()); @@ -228,12 +245,14 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public List findGroup2GroupMapped(Context context, int actionID) throws SQLException { - return collectionDAO.findAuthorizedByGroup(context, context.getCurrentUser(), Collections.singletonList(actionID)); + return collectionDAO + .findAuthorizedByGroup(context, context.getCurrentUser(), Collections.singletonList(actionID)); } @Override public List findGroupMapped(Context context, int actionID) throws SQLException { - List communities = communityService.findAuthorized(context, Arrays.asList(Constants.ADD, Constants.ADMIN)); + List communities = communityService + .findAuthorized(context, Arrays.asList(Constants.ADD, Constants.ADMIN)); List collections = new ArrayList<>(); for (Community community : communities) { collections.addAll(community.getCollections()); @@ -247,15 +266,12 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } @Override - public void setMetadata(Context context, Collection collection, String field, String value) throws MissingResourceException, SQLException { - if ((field.trim()).equals("name") && (value == null || value.trim().equals(""))) - { - try - { + public void setMetadata(Context context, Collection collection, String field, String value) + throws MissingResourceException, SQLException { + if ((field.trim()).equals("name") && (value == null || value.trim().equals(""))) { + try { value = I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled"); - } - catch (MissingResourceException e) - { + } catch (MissingResourceException e) { value = "Untitled"; } } @@ -267,13 +283,10 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i * and trim strings to eliminate excess * whitespace. */ - if(value == null) - { + if (value == null) { clearMetadata(context, collection, MDValue[0], MDValue[1], MDValue[2], Item.ANY); collection.setMetadataModified(); - } - else - { + } else { setMetadataSingleValue(context, collection, MDValue[0], MDValue[1], MDValue[2], null, value); } @@ -281,41 +294,38 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } @Override - public Bitstream setLogo(Context context, Collection collection, InputStream is) throws AuthorizeException, IOException, SQLException { + public Bitstream setLogo(Context context, Collection collection, InputStream is) + throws AuthorizeException, IOException, SQLException { // Check authorisation // authorized to remove the logo when DELETE rights // authorized when canEdit if (!((is == null) && authorizeService.authorizeActionBoolean( - context, collection, Constants.DELETE))) - { + context, collection, Constants.DELETE))) { canEdit(context, collection, true); } // First, delete any existing logo - if (collection.getLogo() != null) - { + if (collection.getLogo() != null) { bitstreamService.delete(context, collection.getLogo()); } - if (is == null) - { + if (is == null) { collection.setLogo(null); log.info(LogManager.getHeader(context, "remove_logo", - "collection_id=" + collection.getID())); - } - else - { + "collection_id=" + collection.getID())); + } else { Bitstream newLogo = bitstreamService.create(context, is); collection.setLogo(newLogo); // now create policy for logo bitstream // to match our READ policy - List policies = authorizeService.getPoliciesActionFilter(context, collection, Constants.READ); + List policies = authorizeService + .getPoliciesActionFilter(context, collection, Constants.READ); authorizeService.addPolicies(context, policies, newLogo); log.info(LogManager.getHeader(context, "set_logo", - "collection_id=" + collection.getID() + "logo_bitstream_id=" - + newLogo.getID())); + "collection_id=" + collection.getID() + "logo_bitstream_id=" + + newLogo.getID())); } collection.setModified(); @@ -323,19 +333,19 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } @Override - public Group createWorkflowGroup(Context context, Collection collection, int step) throws SQLException, AuthorizeException { + public Group createWorkflowGroup(Context context, Collection collection, int step) + throws SQLException, AuthorizeException { // Check authorisation - Must be an Admin to create Workflow Group AuthorizeUtil.authorizeManageWorkflowsGroup(context, collection); - if (getWorkflowGroup(collection, step) == null) - { + if (getWorkflowGroup(collection, step) == null) { //turn off authorization so that Collection Admins can create Collection Workflow Groups context.turnOffAuthorisationSystem(); Group g = groupService.create(context); context.restoreAuthSystemState(); groupService.setName(g, - "COLLECTION_" + collection.getID() + "_WORKFLOW_STEP_" + step); + "COLLECTION_" + collection.getID() + "_WORKFLOW_STEP_" + step); groupService.update(context, g); setWorkflowGroup(context, collection, step, g); @@ -346,14 +356,12 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public void setWorkflowGroup(Context context, Collection collection, int step, Group group) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { // we need to store the old group to be able to revoke permissions if granted before Group oldGroup = null; int action; - - switch (step) - { + + switch (step) { case 1: oldGroup = collection.getWorkflowStep1(); action = Constants.WORKFLOW_STEP_1; @@ -372,35 +380,29 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i default: throw new IllegalArgumentException("Illegal step count: " + step); } - + // deal with permissions. - try - { + try { context.turnOffAuthorisationSystem(); // remove the policies for the old group - if (oldGroup != null) - { + if (oldGroup != null) { Iterator oldPolicies = - resourcePolicyService.find(context, collection, oldGroup, action).iterator(); - while (oldPolicies.hasNext()) - { + resourcePolicyService.find(context, collection, oldGroup, action).iterator(); + while (oldPolicies.hasNext()) { resourcePolicyService.delete(context, oldPolicies.next()); } oldPolicies = resourcePolicyService.find(context, collection, oldGroup, Constants.ADD).iterator(); - while (oldPolicies.hasNext()) - { + while (oldPolicies.hasNext()) { ResourcePolicy rp = oldPolicies.next(); - if (rp.getRpType() == ResourcePolicy.TYPE_WORKFLOW) - { + if (rp.getRpType() == ResourcePolicy.TYPE_WORKFLOW) { resourcePolicyService.delete(context, rp); } } } - + // group can be null to delete workflow step. // we need to grant permissions if group is not null - if (group != null) - { + if (group != null) { authorizeService.addPolicy(context, collection, action, group, ResourcePolicy.TYPE_WORKFLOW); authorizeService.addPolicy(context, collection, Constants.ADD, group, ResourcePolicy.TYPE_WORKFLOW); } @@ -412,8 +414,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public Group getWorkflowGroup(Collection collection, int step) { - switch (step) - { + switch (step) { case 1: return collection.getWorkflowStep1(); case 2: @@ -428,20 +429,14 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i /** * Get the value of a metadata field * - * @param collection - * which collection to operate on - * @param field - * the name of the metadata field to get - * + * @param collection which collection to operate on + * @param field the name of the metadata field to get * @return the value of the metadata field - * - * @throws IllegalArgumentException - * if the requested metadata field doesn't exist + * @throws IllegalArgumentException if the requested metadata field doesn't exist */ @Override @Deprecated - public String getMetadata(Collection collection, String field) - { + public String getMetadata(Collection collection, String field) { String[] MDValue = getMDValueByLegacyField(field); String value = getMetadataFirstValue(collection, MDValue[0], MDValue[1], MDValue[2], Item.ANY); return value == null ? "" : value; @@ -453,15 +448,14 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i AuthorizeUtil.authorizeManageSubmittersGroup(context, collection); Group submitters = collection.getSubmitters(); - if (submitters == null) - { + if (submitters == null) { //turn off authorization so that Collection Admins can create Collection Submitters context.turnOffAuthorisationSystem(); submitters = groupService.create(context); context.restoreAuthSystemState(); groupService.setName(submitters, - "COLLECTION_" + collection.getID() + "_SUBMIT"); + "COLLECTION_" + collection.getID() + "_SUBMIT"); groupService.update(context, submitters); } @@ -479,8 +473,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i AuthorizeUtil.authorizeManageSubmittersGroup(context, collection); // just return if there is no administrative group. - if (collection.getSubmitters() == null) - { + if (collection.getSubmitters() == null) { return; } @@ -494,8 +487,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i AuthorizeUtil.authorizeManageAdminGroup(context, collection); Group admins = collection.getAdministrators(); - if (admins == null) - { + if (admins == null) { //turn off authorization so that Community Admins can create Collection Admins context.turnOffAuthorisationSystem(); admins = groupService.create(context); @@ -506,7 +498,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } authorizeService.addPolicy(context, collection, - Constants.ADMIN, admins); + Constants.ADMIN, admins); // register this as the admin group collection.setAdmins(admins); @@ -515,13 +507,12 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public void removeAdministrators(Context context, Collection collection) throws SQLException, AuthorizeException { - // Check authorisation - Must be an Admin of the parent community to delete Admin Group + // Check authorisation - Must be an Admin of the parent community to delete Admin Group AuthorizeUtil.authorizeRemoveAdminGroup(context, collection); Group admins = collection.getAdministrators(); // just return if there is no administrative group. - if (admins == null) - { + if (admins == null) { return; } @@ -533,8 +524,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i public String getLicense(Collection collection) { String license = getMetadata(collection, "license"); - if (license == null || license.trim().equals("")) - { + if (license == null || license.trim().equals("")) { // Fallback to site-wide default license = licenseService.getDefaultSubmissionLicense(); } @@ -550,32 +540,31 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public void createTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException { - // Check authorisation + // Check authorisation AuthorizeUtil.authorizeManageTemplateItem(context, collection); - if (collection.getTemplateItem() == null) - { + if (collection.getTemplateItem() == null) { Item template = itemService.createTemplateItem(context, collection); collection.setTemplateItem(template); log.info(LogManager.getHeader(context, "create_template_item", - "collection_id=" + collection.getID() + ",template_item_id=" - + template.getID())); + "collection_id=" + collection.getID() + ",template_item_id=" + + template.getID())); } } @Override - public void removeTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException, IOException { - // Check authorisation + public void removeTemplateItem(Context context, Collection collection) + throws SQLException, AuthorizeException, IOException { + // Check authorisation AuthorizeUtil.authorizeManageTemplateItem(context, collection); Item template = collection.getTemplateItem(); - if (template != null) - { + if (template != null) { log.info(LogManager.getHeader(context, "remove_template_item", - "collection_id=" + collection.getID() + ",template_item_id=" - + template.getID())); + "collection_id=" + collection.getID() + ",template_item_id=" + + template.getID())); // temporarily turn off auth system, we have already checked the permission on the top of the method // check it again will fail because we have already broken the relation between the collection and the item context.turnOffAuthorisationSystem(); @@ -585,38 +574,37 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } context.addEvent(new Event(Event.MODIFY, Constants.COLLECTION, - collection.getID(), "remove_template_item", getIdentifiers(context, collection))); + collection.getID(), "remove_template_item", getIdentifiers(context, collection))); } @Override public void addItem(Context context, Collection collection, Item item) throws SQLException, AuthorizeException { - // Check authorisation + // Check authorisation authorizeService.authorizeAction(context, collection, Constants.ADD); log.info(LogManager.getHeader(context, "add_item", "collection_id=" - + collection.getID() + ",item_id=" + item.getID())); + + collection.getID() + ",item_id=" + item.getID())); // Create mapping // We do NOT add the item to the collection template since we would have to load in all our items // Instead we add the collection to an item which works in the same way. - if(!item.getCollections().contains(collection)) - { + if (!item.getCollections().contains(collection)) { item.addCollection(collection); } context.addEvent(new Event(Event.ADD, Constants.COLLECTION, collection.getID(), - Constants.ITEM, item.getID(), item.getHandle(), - getIdentifiers(context, collection))); + Constants.ITEM, item.getID(), item.getHandle(), + getIdentifiers(context, collection))); } @Override - public void removeItem(Context context, Collection collection, Item item) throws SQLException, AuthorizeException, IOException { + public void removeItem(Context context, Collection collection, Item item) + throws SQLException, AuthorizeException, IOException { // Check authorisation authorizeService.authorizeAction(context, collection, Constants.REMOVE); //Check if we orphaned our poor item - if (item.getCollections().size() == 1) - { + if (item.getCollections().size() == 1) { // Orphan; delete it itemService.delete(context, item); } else { @@ -626,8 +614,8 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } context.addEvent(new Event(Event.REMOVE, Constants.COLLECTION, - collection.getID(), Constants.ITEM, item.getID(), item.getHandle(), - getIdentifiers(context, collection))); + collection.getID(), Constants.ITEM, item.getID(), item.getHandle(), + getIdentifiers(context, collection))); } @Override @@ -636,19 +624,17 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i canEdit(context, collection, true); log.info(LogManager.getHeader(context, "update_collection", - "collection_id=" + collection.getID())); + "collection_id=" + collection.getID())); super.update(context, collection); collectionDAO.save(context, collection); - if (collection.isModified()) - { + if (collection.isModified()) { context.addEvent(new Event(Event.MODIFY, Constants.COLLECTION, - collection.getID(), null, getIdentifiers(context, collection))); + collection.getID(), null, getIdentifiers(context, collection))); collection.clearModified(); } - if (collection.isMetadataModified()) - { + if (collection.isMetadataModified()) { collection.clearDetails(); } } @@ -660,14 +646,11 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public boolean canEditBoolean(Context context, Collection collection, boolean useInheritance) throws SQLException { - try - { + try { canEdit(context, collection, useInheritance); return true; - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { return false; } } @@ -678,16 +661,17 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } @Override - public void canEdit(Context context, Collection collection, boolean useInheritance) throws SQLException, AuthorizeException { + public void canEdit(Context context, Collection collection, boolean useInheritance) + throws SQLException, AuthorizeException { List parents = communityService.getAllParents(context, collection); for (Community parent : parents) { if (authorizeService.authorizeActionBoolean(context, parent, - Constants.WRITE, useInheritance)) { + Constants.WRITE, useInheritance)) { return; } if (authorizeService.authorizeActionBoolean(context, parent, - Constants.ADD, useInheritance)) { + Constants.ADD, useInheritance)) { return; } } @@ -697,17 +681,16 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public void delete(Context context, Collection collection) throws SQLException, AuthorizeException, IOException { log.info(LogManager.getHeader(context, "delete_collection", - "collection_id=" + collection.getID())); + "collection_id=" + collection.getID())); // remove harvested collections. - HarvestedCollection hc = harvestedCollectionService.find(context,collection); - if(hc!=null) - { + HarvestedCollection hc = harvestedCollectionService.find(context, collection); + if (hc != null) { harvestedCollectionService.delete(context, hc); } context.addEvent(new Event(Event.DELETE, Constants.COLLECTION, - collection.getID(), collection.getHandle(), getIdentifiers(context, collection))); + collection.getID(), collection.getHandle(), getIdentifiers(context, collection))); // remove subscriptions - hmm, should this be in Subscription.java? subscribeService.deleteByCollection(context, collection); @@ -718,19 +701,15 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i // Remove items // Remove items Iterator items = itemService.findAllByCollection(context, collection); - while (items.hasNext()) - { + while (items.hasNext()) { Item item = items.next(); // items.remove(); - if (itemService.isOwningCollection(item, collection)) - { + if (itemService.isOwningCollection(item, collection)) { // the collection to be deleted is the owning collection, thus remove // the item from all collections it belongs to itemService.delete(context, item); - } - // the item was only mapped to this collection, so just remove it - else - { + } else { + // the item was only mapped to this collection, so just remove it removeItem(context, collection, item); } } @@ -756,24 +735,21 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i // Remove any workflow groups - must happen after deleting collection Group g = collection.getWorkflowStep1(); - if (g != null) - { + if (g != null) { collection.setWorkflowStep1(null); groupService.delete(context, g); } g = collection.getWorkflowStep2(); - if (g != null) - { + if (g != null) { collection.setWorkflowStep2(null); groupService.delete(context, g); } g = collection.getWorkflowStep3(); - if (g != null) - { + if (g != null) { collection.setWorkflowStep3(null); groupService.delete(context, g); } @@ -781,8 +757,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i // Remove default administrators group g = collection.getAdministrators(); - if (g != null) - { + if (g != null) { collection.setAdmins(null); groupService.delete(context, g); } @@ -790,15 +765,13 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i // Remove default submitters group g = collection.getSubmitters(); - if (g != null) - { + if (g != null) { collection.setSubmitters(null); groupService.delete(context, g); } Iterator owningCommunities = collection.getCommunities().iterator(); - while (owningCommunities.hasNext()) - { + while (owningCommunities.hasNext()) { Community owningCommunity = owningCommunities.next(); collection.removeCommunity(owningCommunity); owningCommunity.removeCollection(collection); @@ -818,19 +791,16 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i List myCollections; - if (community != null) - { + if (community != null) { myCollections = community.getCollections(); - } - else - { + } else { myCollections = findAll(context); } // now build a list of collections you have authorization for for (Collection myCollection : myCollections) { if (authorizeService.authorizeActionBoolean(context, - myCollection, actionID)) { + myCollection, actionID)) { myResults.add(myCollection); } } @@ -852,27 +822,21 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i DSpaceObject adminObject = null; Community community = null; List communities = collection.getCommunities(); - if (CollectionUtils.isNotEmpty(communities)) - { + if (CollectionUtils.isNotEmpty(communities)) { community = communities.get(0); } - switch (action) - { + switch (action) { case Constants.REMOVE: - if (AuthorizeConfiguration.canCollectionAdminPerformItemDeletion()) - { + if (AuthorizeConfiguration.canCollectionAdminPerformItemDeletion()) { adminObject = collection; - } - else if (AuthorizeConfiguration.canCommunityAdminPerformItemDeletion()) - { + } else if (AuthorizeConfiguration.canCommunityAdminPerformItemDeletion()) { adminObject = community; } break; case Constants.DELETE: - if (AuthorizeConfiguration.canCommunityAdminPerformSubelementDeletion()) - { + if (AuthorizeConfiguration.canCommunityAdminPerformSubelementDeletion()) { adminObject = community; } break; @@ -886,9 +850,9 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public DSpaceObject getParentObject(Context context, Collection collection) throws SQLException { List communities = collection.getCommunities(); - if(CollectionUtils.isNotEmpty(communities)){ + if (CollectionUtils.isNotEmpty(communities)) { return communities.get(0); - }else{ + } else { return null; } } @@ -897,17 +861,14 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i public void updateLastModified(Context context, Collection collection) throws SQLException, AuthorizeException { //Also fire a modified event since the collection HAS been modified context.addEvent(new Event(Event.MODIFY, Constants.COLLECTION, - collection.getID(), null, getIdentifiers(context, collection))); + collection.getID(), null, getIdentifiers(context, collection))); } @Override public Collection findByIdOrLegacyId(Context context, String id) throws SQLException { - if(StringUtils.isNumeric(id)) - { + if (StringUtils.isNumeric(id)) { return findByLegacyId(context, Integer.parseInt(id)); - } - else - { + } else { return find(context, UUID.fromString(id)); } } @@ -923,7 +884,8 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } @Override - public List> getCollectionsWithBitstreamSizesTotal(Context context) throws SQLException { + public List> getCollectionsWithBitstreamSizesTotal(Context context) + throws SQLException { return collectionDAO.getCollectionsWithBitstreamSizesTotal(context); } } diff --git a/dspace-api/src/main/java/org/dspace/content/Community.java b/dspace-api/src/main/java/org/dspace/content/Community.java index 123e32e6ee..448e86e039 100644 --- a/dspace-api/src/main/java/org/dspace/content/Community.java +++ b/dspace-api/src/main/java/org/dspace/content/Community.java @@ -7,46 +7,61 @@ */ package org.dspace.content; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.persistence.Cacheable; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Transient; + import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.log4j.Logger; import org.dspace.content.comparator.NameAscendingComparator; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CommunityService; -import org.dspace.core.*; +import org.dspace.core.Constants; +import org.dspace.core.Context; import org.dspace.eperson.Group; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.util.*; - /** * Class representing a community *

    * The community's metadata (name, introductory text etc.) is loaded into' * memory. Changes to this metadata are only reflected in the database after * update is called. - * + * * @author Robert Tansley * @version $Revision$ */ @Entity -@Table(name="community") +@Table(name = "community") @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, include = "non-lazy") -public class Community extends DSpaceObject implements DSpaceObjectLegacySupport -{ - /** log4j category */ +public class Community extends DSpaceObject implements DSpaceObjectLegacySupport { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(Community.class); - @Column(name="community_id", insertable = false, updatable = false) + @Column(name = "community_id", insertable = false, updatable = false) private Integer legacyId; @ManyToMany(fetch = FetchType.LAZY) @JoinTable( - name = "community2community", - joinColumns = {@JoinColumn(name = "parent_comm_id") }, - inverseJoinColumns = {@JoinColumn(name = "child_comm_id") } + name = "community2community", + joinColumns = {@JoinColumn(name = "parent_comm_id")}, + inverseJoinColumns = {@JoinColumn(name = "child_comm_id")} ) private Set subCommunities = new HashSet<>(); @@ -61,7 +76,9 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport /** The default group of administrators */ private Group admins; - /** The logo bitstream */ + /** + * The logo bitstream + */ @OneToOne @JoinColumn(name = "logo_bitstream_id") private Bitstream logo = null; @@ -80,21 +97,17 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport * {@link org.dspace.content.service.CommunityService#create(Community, Context)} * or * {@link org.dspace.content.service.CommunityService#create(Community, Context, String)} - * */ - protected Community() - { + protected Community() { } - void addSubCommunity(Community subCommunity) - { + void addSubCommunity(Community subCommunity) { subCommunities.add(subCommunity); setModified(); } - void removeSubCommunity(Community subCommunity) - { + void removeSubCommunity(Community subCommunity) { subCommunities.remove(subCommunity); setModified(); } @@ -102,11 +115,10 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the logo for the community. null is return if the * community does not have a logo. - * + * * @return the logo of the community, or null */ - public Bitstream getLogo() - { + public Bitstream getLogo() { return logo; } @@ -122,12 +134,11 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport *

    * The default group of administrators for community 100 is the one called * community_100_admin. - * + * * @return group of administrators, or null if there is no - * default group. + * default group. */ - public Group getAdministrators() - { + public Group getAdministrators() { return admins; } @@ -139,25 +150,22 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the collections in this community. Throws an SQLException because * creating a community object won't load in all collections. - * + * * @return array of Collection objects */ - public List getCollections() - { + public List getCollections() { // We return a copy because we do not want people to add elements to this collection directly. // We return a list to maintain backwards compatibility - Collection[] output = collections.toArray(new Collection[]{}); + Collection[] output = collections.toArray(new Collection[] {}); Arrays.sort(output, new NameAscendingComparator()); return Arrays.asList(output); } - void addCollection(Collection collection) - { + void addCollection(Collection collection) { collections.add(collection); } - void removeCollection(Collection collection) - { + void removeCollection(Collection collection) { collections.remove(collection); } @@ -165,14 +173,13 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport * Get the immediate sub-communities of this community. Throws an * SQLException because creating a community object won't load in all * collections. - * + * * @return array of Community objects */ - public List getSubcommunities() - { + public List getSubcommunities() { // We return a copy because we do not want people to add elements to this collection directly. // We return a list to maintain backwards compatibility - Community[] output = subCommunities.toArray(new Community[]{}); + Community[] output = subCommunities.toArray(new Community[] {}); Arrays.sort(output, new NameAscendingComparator()); return Arrays.asList(output); } @@ -180,14 +187,13 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport /** * Return the parent community of this community, or null if the community * is top-level - * + * * @return the immediate parent community, or null if top-level */ - public List getParentCommunities() - { + public List getParentCommunities() { // We return a copy because we do not want people to add elements to this collection directly. // We return a list to maintain backwards compatibility - Community[] output = parentCommunities.toArray(new Community[]{}); + Community[] output = parentCommunities.toArray(new Community[] {}); Arrays.sort(output, new NameAscendingComparator()); return Arrays.asList(output); } @@ -196,12 +202,11 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport parentCommunities.add(parentCommunity); } - void clearParentCommunities(){ + void clearParentCommunities() { parentCommunities.clear(); } - public void removeParentCommunity(Community parentCommunity) - { + public void removeParentCommunity(Community parentCommunity) { parentCommunities.remove(parentCommunity); setModified(); } @@ -209,28 +214,22 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport /** * Return true if other is the same Community * as this object, false otherwise - * - * @param other - * object to compare to - * + * + * @param other object to compare to * @return true if object passed in represents the same - * community as this object + * community as this object */ @Override - public boolean equals(Object other) - { - if (other == null) - { + public boolean equals(Object other) { + if (other == null) { return false; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(other); - if (this.getClass() != objClass) - { + if (this.getClass() != objClass) { return false; } final Community otherCommunity = (Community) other; - if (!this.getID().equals(otherCommunity.getID() )) - { + if (!this.getID().equals(otherCommunity.getID())) { return false; } @@ -238,24 +237,24 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport } @Override - public int hashCode() - { + public int hashCode() { return new HashCodeBuilder().append(getID()).toHashCode(); } /** * return type found in Constants + * * @return Community type */ @Override - public int getType() - { + public int getType() { return Constants.COMMUNITY; } @Override public String getName() { - String value = getCommunityService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + String value = getCommunityService() + .getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); return value == null ? "" : value; } @@ -265,8 +264,7 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport } private CommunityService getCommunityService() { - if(communityService == null) - { + if (communityService == null) { communityService = ContentServiceFactory.getInstance().getCommunityService(); } return communityService; diff --git a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java index f93e6d441c..667b0268b1 100644 --- a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java @@ -7,7 +7,16 @@ */ package org.dspace.content; -import org.apache.commons.collections.CollectionUtils; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.MissingResourceException; +import java.util.UUID; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.util.AuthorizeUtil; @@ -16,7 +25,11 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.dao.CommunityDAO; -import org.dspace.content.service.*; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.SiteService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.I18nUtil; @@ -26,11 +39,6 @@ import org.dspace.eperson.service.GroupService; import org.dspace.event.Event; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.*; - /** * Service implementation for the Community object. * This class is responsible for all business logic calls for the Community object and is autowired by spring. @@ -40,7 +48,9 @@ import java.util.*; */ public class CommunityServiceImpl extends DSpaceObjectServiceImpl implements CommunityService { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(CommunityServiceImpl.class); @Autowired(required = true) @@ -60,8 +70,7 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Autowired(required = true) protected SiteService siteService; - protected CommunityServiceImpl() - { + protected CommunityServiceImpl() { super(); } @@ -74,31 +83,25 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public Community create(Community parent, Context context, String handle) throws SQLException, AuthorizeException { if (!(authorizeService.isAdmin(context) || - (parent != null && authorizeService.authorizeActionBoolean(context, parent, Constants.ADD)))) - { + (parent != null && authorizeService.authorizeActionBoolean(context, parent, Constants.ADD)))) { throw new AuthorizeException( - "Only administrators can create communities"); + "Only administrators can create communities"); } Community newCommunity = communityDAO.create(context, new Community()); - try - { - if(handle == null) - { + try { + if (handle == null) { handleService.createHandle(context, newCommunity); } else { handleService.createHandle(context, newCommunity, handle); } - } - catch(IllegalStateException ie) - { + } catch (IllegalStateException ie) { //If an IllegalStateException is thrown, then an existing object is already using this handle throw ie; } - if(parent != null) - { + if (parent != null) { parent.addSubCommunity(newCommunity); newCommunity.addParentCommunity(parent); } @@ -112,19 +115,19 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp communityDAO.save(context, newCommunity); - context.addEvent(new Event(Event.CREATE, Constants.COMMUNITY, newCommunity.getID(), newCommunity.getHandle(), getIdentifiers(context, newCommunity))); + context.addEvent(new Event(Event.CREATE, Constants.COMMUNITY, newCommunity.getID(), newCommunity.getHandle(), + getIdentifiers(context, newCommunity))); - // if creating a top-level Community, simulate an ADD event at the Site. - if (parent == null) - { + // if creating a top-level Community, simulate an ADD event at the Site. + if (parent == null) { context.addEvent(new Event(Event.ADD, Constants.SITE, siteService.findSite(context).getID(), - Constants.COMMUNITY, newCommunity.getID(), newCommunity.getHandle(), - getIdentifiers(context, newCommunity))); + Constants.COMMUNITY, newCommunity.getID(), newCommunity.getHandle(), + getIdentifiers(context, newCommunity))); } log.info(LogManager.getHeader(context, "create_community", - "community_id=" + newCommunity.getID()) - + ",handle=" + newCommunity.getHandle()); + "community_id=" + newCommunity.getID()) + + ",handle=" + newCommunity.getHandle()); return newCommunity; } @@ -137,9 +140,9 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public List findAll(Context context) throws SQLException { MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); - if(sortField==null) - { - throw new IllegalArgumentException("Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + if (sortField == null) { + throw new IllegalArgumentException( + "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); } return communityDAO.findAll(context, sortField); @@ -148,22 +151,21 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public List findAll(Context context, Integer limit, Integer offset) throws SQLException { MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); - if(nameField==null) - { - throw new IllegalArgumentException("Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + if (nameField == null) { + throw new IllegalArgumentException( + "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); } return communityDAO.findAll(context, nameField, limit, offset); } @Override - public List findAllTop(Context context) throws SQLException - { + public List findAllTop(Context context) throws SQLException { // get all communities that are not children MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); - if(sortField==null) - { - throw new IllegalArgumentException("Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + if (sortField == null) { + throw new IllegalArgumentException( + "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); } return communityDAO.findAllNoParent(context, sortField); @@ -177,16 +179,13 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp } @Override - public void setMetadata(Context context, Community community, String field, String value) throws MissingResourceException, SQLException { + public void setMetadata(Context context, Community community, String field, String value) + throws MissingResourceException, SQLException { if ((field.trim()).equals("name") - && (value == null || value.trim().equals(""))) - { - try - { + && (value == null || value.trim().equals(""))) { + try { value = I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled"); - } - catch (MissingResourceException e) - { + } catch (MissingResourceException e) { value = "Untitled"; } } @@ -198,51 +197,47 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp * and trim strings to eliminate excess * whitespace. */ - if(value == null) - { + if (value == null) { clearMetadata(context, community, MDValue[0], MDValue[1], MDValue[2], Item.ANY); - } - else - { + } else { setMetadataSingleValue(context, community, MDValue[0], MDValue[1], MDValue[2], null, value); } community.addDetails(field); } @Override - public Bitstream setLogo(Context context, Community community, InputStream is) throws AuthorizeException, IOException, SQLException { + public Bitstream setLogo(Context context, Community community, InputStream is) + throws AuthorizeException, IOException, SQLException { // Check authorisation // authorized to remove the logo when DELETE rights // authorized when canEdit if (!((is == null) && authorizeService.authorizeActionBoolean( - context, community, Constants.DELETE))) - { + context, community, Constants.DELETE))) { canEdit(context, community); } // First, delete any existing logo Bitstream oldLogo = community.getLogo(); - if (oldLogo != null) - { + if (oldLogo != null) { log.info(LogManager.getHeader(context, "remove_logo", - "community_id=" + community.getID())); + "community_id=" + community.getID())); community.setLogo(null); bitstreamService.delete(context, oldLogo); } - if (is != null) - { + if (is != null) { Bitstream newLogo = bitstreamService.create(context, is); community.setLogo(newLogo); // now create policy for logo bitstream // to match our READ policy - List policies = authorizeService.getPoliciesActionFilter(context, community, Constants.READ); + List policies = authorizeService + .getPoliciesActionFilter(context, community, Constants.READ); authorizeService.addPolicies(context, policies, newLogo); log.info(LogManager.getHeader(context, "set_logo", - "community_id=" + community.getID() + "logo_bitstream_id=" - + newLogo.getID())); + "community_id=" + community.getID() + "logo_bitstream_id=" + + newLogo.getID())); } return community.getLogo(); @@ -250,23 +245,24 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public void update(Context context, Community community) throws SQLException, AuthorizeException { - // Check authorisation + // Check authorisation canEdit(context, community); log.info(LogManager.getHeader(context, "update_community", - "community_id=" + community.getID())); + "community_id=" + community.getID())); super.update(context, community); communityDAO.save(context, community); - if (community.isModified()) - { - context.addEvent(new Event(Event.MODIFY, Constants.COMMUNITY, community.getID(), null, getIdentifiers(context, community))); - community.setModified(); + if (community.isModified()) { + context.addEvent(new Event(Event.MODIFY, Constants.COMMUNITY, community.getID(), null, + getIdentifiers(context, community))); + community.clearModified(); } - if (community.isMetadataModified()) - { - context.addEvent(new Event(Event.MODIFY_METADATA, Constants.COMMUNITY, community.getID(), community.getDetails(), getIdentifiers(context, community))); + if (community.isMetadataModified()) { + context.addEvent( + new Event(Event.MODIFY_METADATA, Constants.COMMUNITY, community.getID(), community.getDetails(), + getIdentifiers(context, community))); community.clearModified(); } community.clearDetails(); @@ -278,8 +274,7 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp AuthorizeUtil.authorizeManageAdminGroup(context, community); Group admins = community.getAdministrators(); - if (admins == null) - { + if (admins == null) { //turn off authorization so that Community Admins can create Sub-Community Admins context.turnOffAuthorisationSystem(); admins = groupService.create(context); @@ -302,8 +297,7 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp AuthorizeUtil.authorizeRemoveAdminGroup(context, community); // just return if there is no administrative group. - if (community.getAdministrators() == null) - { + if (community.getAdministrators() == null) { return; } @@ -315,8 +309,7 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp public List getAllParents(Context context, Community community) throws SQLException { List parentList = new ArrayList(); Community parent = (Community) getParentObject(context, community); - while (parent != null) - { + while (parent != null) { parentList.add(parent); parent = (Community) getParentObject(context, parent); } @@ -338,14 +331,12 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp public List getAllCollections(Context context, Community community) throws SQLException { List collectionList = new ArrayList(); List subCommunities = community.getSubcommunities(); - for (Community subCommunity : subCommunities) - { + for (Community subCommunity : subCommunities) { addCollectionList(subCommunity, collectionList); } List collections = community.getCollections(); - for (Collection collection : collections) - { + for (Collection collection : collections) { collectionList.add(collection); } return collectionList; @@ -354,47 +345,49 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp /** * Internal method to process subcommunities recursively - * @param community community + * + * @param community community * @param collectionList list of collections * @throws SQLException if database error */ - protected void addCollectionList(Community community, List collectionList) throws SQLException - { - for (Community subcommunity : community.getSubcommunities()) - { + protected void addCollectionList(Community community, List collectionList) throws SQLException { + for (Community subcommunity : community.getSubcommunities()) { addCollectionList(subcommunity, collectionList); } - for (Collection collection : community.getCollections()) - { + for (Collection collection : community.getCollections()) { collectionList.add(collection); } } @Override - public void addCollection(Context context, Community community, Collection collection) throws SQLException, AuthorizeException { + public void addCollection(Context context, Community community, Collection collection) + throws SQLException, AuthorizeException { // Check authorisation authorizeService.authorizeAction(context, community, Constants.ADD); log.info(LogManager.getHeader(context, "add_collection", - "community_id=" + community.getID() + ",collection_id=" + collection.getID())); + "community_id=" + community.getID() + ",collection_id=" + collection.getID())); - if(!community.getCollections().contains(collection)) - { + if (!community.getCollections().contains(collection)) { community.addCollection(collection); collection.addCommunity(community); } - context.addEvent(new Event(Event.ADD, Constants.COMMUNITY, community.getID(), Constants.COLLECTION, collection.getID(), community.getHandle(), getIdentifiers(context, community))); + context.addEvent( + new Event(Event.ADD, Constants.COMMUNITY, community.getID(), Constants.COLLECTION, collection.getID(), + community.getHandle(), getIdentifiers(context, community))); } @Override - public Community createSubcommunity(Context context, Community parentCommunity) throws SQLException, AuthorizeException { + public Community createSubcommunity(Context context, Community parentCommunity) + throws SQLException, AuthorizeException { return createSubcommunity(context, parentCommunity, null); } @Override - public Community createSubcommunity(Context context, Community parentCommunity, String handle) throws SQLException, AuthorizeException { - // Check authorisation + public Community createSubcommunity(Context context, Community parentCommunity, String handle) + throws SQLException, AuthorizeException { + // Check authorisation authorizeService.authorizeAction(context, parentCommunity, Constants.ADD); Community c = create(parentCommunity, context, handle); @@ -404,23 +397,27 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp } @Override - public void addSubcommunity(Context context, Community parentCommunity, Community childCommunity) throws SQLException, AuthorizeException { + public void addSubcommunity(Context context, Community parentCommunity, Community childCommunity) + throws SQLException, AuthorizeException { // Check authorisation authorizeService.authorizeAction(context, parentCommunity, Constants.ADD); log.info(LogManager.getHeader(context, "add_subcommunity", - "parent_comm_id=" + parentCommunity.getID() + ",child_comm_id=" + childCommunity.getID())); + "parent_comm_id=" + parentCommunity.getID() + ",child_comm_id=" + childCommunity + .getID())); - if(!parentCommunity.getSubcommunities().contains(childCommunity)) - { + if (!parentCommunity.getSubcommunities().contains(childCommunity)) { parentCommunity.addSubCommunity(childCommunity); childCommunity.addParentCommunity(parentCommunity); } - context.addEvent(new Event(Event.ADD, Constants.COMMUNITY, parentCommunity.getID(), Constants.COMMUNITY, childCommunity.getID(),parentCommunity.getHandle(), getIdentifiers(context, parentCommunity))); + context.addEvent(new Event(Event.ADD, Constants.COMMUNITY, parentCommunity.getID(), Constants.COMMUNITY, + childCommunity.getID(), parentCommunity.getHandle(), + getIdentifiers(context, parentCommunity))); } @Override - public void removeCollection(Context context, Community community, Collection collection) throws SQLException, AuthorizeException, IOException { + public void removeCollection(Context context, Community community, Collection collection) + throws SQLException, AuthorizeException, IOException { // Check authorisation authorizeService.authorizeAction(context, community, Constants.REMOVE); @@ -428,25 +425,25 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp String removedHandle = collection.getHandle(); UUID removedId = collection.getID(); - if(collection.getCommunities().size() == 1) - { + if (collection.getCommunities().size() == 1) { collectionService.delete(context, collection); - }else{ + } else { community.removeCollection(collection); collection.removeCommunity(community); } log.info(LogManager.getHeader(context, "remove_collection", - "community_id=" + community.getID() + ",collection_id=" + collection.getID())); + "community_id=" + community.getID() + ",collection_id=" + collection.getID())); // Remove any mappings context.addEvent(new Event(Event.REMOVE, Constants.COMMUNITY, community.getID(), - Constants.COLLECTION, removedId, removedHandle, removedIdentifiers)); + Constants.COLLECTION, removedId, removedHandle, removedIdentifiers)); } @Override - public void removeSubcommunity(Context context, Community parentCommunity, Community childCommunity) throws SQLException, AuthorizeException, IOException { - // Check authorisation + public void removeSubcommunity(Context context, Community parentCommunity, Community childCommunity) + throws SQLException, AuthorizeException, IOException { + // Check authorisation authorizeService.authorizeAction(context, parentCommunity, Constants.REMOVE); ArrayList removedIdentifiers = getIdentifiers(context, childCommunity); @@ -455,13 +452,13 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp rawDelete(context, childCommunity); - childCommunity.removeParentCommunity(parentCommunity); - parentCommunity.removeSubCommunity(childCommunity); - log.info(LogManager.getHeader(context, "remove_subcommunity", - "parent_comm_id=" + parentCommunity.getID() + ",child_comm_id=" + childCommunity.getID())); + "parent_comm_id=" + parentCommunity.getID() + ",child_comm_id=" + childCommunity + .getID())); - context.addEvent(new Event(Event.REMOVE, Constants.COMMUNITY, parentCommunity.getID(), Constants.COMMUNITY, removedId, removedHandle, removedIdentifiers)); + context.addEvent( + new Event(Event.REMOVE, Constants.COMMUNITY, parentCommunity.getID(), Constants.COMMUNITY, removedId, + removedHandle, removedIdentifiers)); } @Override @@ -473,8 +470,7 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp // But since this is also the case for top-level communities, we would // give everyone rights to remove the top-level communities. // The same problem occurs in removing the logo - if (!authorizeService.authorizeActionBoolean(context, getParentObject(context, community), Constants.REMOVE)) - { + if (!authorizeService.authorizeActionBoolean(context, getParentObject(context, community), Constants.REMOVE)) { authorizeService.authorizeAction(context, community, Constants.DELETE); } ArrayList removedIdentifiers = getIdentifiers(context, community); @@ -486,8 +482,7 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp // will call rawDelete() before removing the linkage Community parent = (Community) getParentObject(context, community); - if (parent != null) - { + if (parent != null) { // remove the subcommunities first Iterator subcommunities = community.getSubcommunities().iterator(); while (subcommunities.hasNext()) { @@ -502,7 +497,9 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp } rawDelete(context, community); - context.addEvent(new Event(Event.REMOVE, Constants.SITE, siteService.findSite(context).getID(), Constants.COMMUNITY, removedId, removedHandle, removedIdentifiers)); + context.addEvent( + new Event(Event.REMOVE, Constants.SITE, siteService.findSite(context).getID(), Constants.COMMUNITY, + removedId, removedHandle, removedIdentifiers)); } @@ -516,24 +513,24 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp * Internal method to remove the community and all its children from the * database, and perform any pre/post-cleanup * - * @param context context + * @param context context * @param community community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ - protected void rawDelete(Context context, Community community) throws SQLException, AuthorizeException, IOException - { + protected void rawDelete(Context context, Community community) + throws SQLException, AuthorizeException, IOException { log.info(LogManager.getHeader(context, "delete_community", - "community_id=" + community.getID())); + "community_id=" + community.getID())); - context.addEvent(new Event(Event.DELETE, Constants.COMMUNITY, community.getID(), community.getHandle(), getIdentifiers(context, community))); + context.addEvent(new Event(Event.DELETE, Constants.COMMUNITY, community.getID(), community.getHandle(), + getIdentifiers(context, community))); // Remove collections Iterator collections = community.getCollections().iterator(); - while (collections.hasNext()) - { + while (collections.hasNext()) { Collection collection = collections.next(); community.removeCollection(collection); removeCollection(context, community, collection); @@ -541,8 +538,7 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp // delete subcommunities Iterator subCommunities = community.getSubcommunities().iterator(); - while (subCommunities.hasNext()) - { + while (subCommunities.hasNext()) { Community subComm = subCommunities.next(); community.removeSubCommunity(subComm); delete(context, subComm); @@ -554,6 +550,13 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp // Remove any Handle handleService.unbindHandle(context, community); + // Remove the parent-child relationship for the community we want to delete + Community parent = (Community) getParentObject(context, community); + if (parent != null) { + community.removeParentCommunity(parent); + parent.removeSubCommunity(community); + } + Group g = community.getAdministrators(); // Delete community row @@ -561,22 +564,18 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp // Remove administrators group - must happen after deleting community - if (g != null) - { + if (g != null) { groupService.delete(context, g); } } @Override public boolean canEditBoolean(Context context, Community community) throws SQLException { - try - { + try { canEdit(context, community); return true; - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { return false; } } @@ -587,12 +586,12 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp for (Community parent : parents) { if (authorizeService.authorizeActionBoolean(context, parent, - Constants.WRITE)) { + Constants.WRITE)) { return; } if (authorizeService.authorizeActionBoolean(context, parent, - Constants.ADD)) { + Constants.ADD)) { return; } } @@ -616,48 +615,39 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp } @Override - public DSpaceObject getAdminObject(Context context, Community community, int action) throws SQLException - { + public DSpaceObject getAdminObject(Context context, Community community, int action) throws SQLException { DSpaceObject adminObject = null; - switch (action) - { - case Constants.REMOVE: - if (AuthorizeConfiguration.canCommunityAdminPerformSubelementDeletion()) - { - adminObject = community; - } - break; + switch (action) { + case Constants.REMOVE: + if (AuthorizeConfiguration.canCommunityAdminPerformSubelementDeletion()) { + adminObject = community; + } + break; - case Constants.DELETE: - if (AuthorizeConfiguration.canCommunityAdminPerformSubelementDeletion()) - { - adminObject = getParentObject(context, community); - } - break; - case Constants.ADD: - if (AuthorizeConfiguration.canCommunityAdminPerformSubelementCreation()) - { + case Constants.DELETE: + if (AuthorizeConfiguration.canCommunityAdminPerformSubelementDeletion()) { + adminObject = getParentObject(context, community); + } + break; + case Constants.ADD: + if (AuthorizeConfiguration.canCommunityAdminPerformSubelementCreation()) { + adminObject = community; + } + break; + default: adminObject = community; - } - break; - default: - adminObject = community; - break; + break; } return adminObject; } @Override - public DSpaceObject getParentObject(Context context, Community community) throws SQLException - { + public DSpaceObject getParentObject(Context context, Community community) throws SQLException { List parentCommunities = community.getParentCommunities(); - if (CollectionUtils.isNotEmpty(parentCommunities)) - { + if (CollectionUtils.isNotEmpty(parentCommunities)) { return parentCommunities.iterator().next(); - } - else - { + } else { return null; } } @@ -666,18 +656,15 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp public void updateLastModified(Context context, Community community) { //Also fire a modified event since the community HAS been modified context.addEvent(new Event(Event.MODIFY, Constants.COMMUNITY, - community.getID(), null, getIdentifiers(context, community))); + community.getID(), null, getIdentifiers(context, community))); } @Override public Community findByIdOrLegacyId(Context context, String id) throws SQLException { - if(StringUtils.isNumeric(id)) - { + if (StringUtils.isNumeric(id)) { return findByLegacyId(context, Integer.parseInt(id)); - } - else - { + } else { return find(context, UUID.fromString(id)); } } diff --git a/dspace-api/src/main/java/org/dspace/content/DCDate.java b/dspace-api/src/main/java/org/dspace/content/DCDate.java index e3363e1ba0..729b1d3753 100644 --- a/dspace-api/src/main/java/org/dspace/content/DCDate.java +++ b/dspace-api/src/main/java/org/dspace/content/DCDate.java @@ -8,9 +8,15 @@ package org.dspace.content; import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; import java.text.ParseException; -import java.util.*; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; import org.apache.log4j.Logger; @@ -35,9 +41,10 @@ import org.apache.log4j.Logger; * @author Larry Stone * @version $Revision$ */ -public class DCDate -{ - /** Logger */ +public class DCDate { + /** + * Logger + */ private static Logger log = Logger.getLogger(DCDate.class); // UTC timezone @@ -50,6 +57,7 @@ public class DCDate private GregorianCalendar localCalendar = null; private enum DateGran { YEAR, MONTH, DAY, TIME } + DateGran granularity = null; // Full ISO 8601 is e.g. "2009-07-16T13:59:21Z" @@ -72,21 +80,18 @@ public class DCDate // just year, "2009" private final SimpleDateFormat yearIso = new SimpleDateFormat("yyyy"); - + private static Map dfsLocaleMap = new HashMap(); /** * Construct a date object from a Java Date object. * - * @param date - * the Java Date object. + * @param date the Java Date object. */ - public DCDate(Date date) - { + public DCDate(Date date) { setUTCForFormatting(); - if (date == null) - { + if (date == null) { return; } @@ -96,31 +101,24 @@ public class DCDate // Set the local calendar. localCalendar = new GregorianCalendar(); localCalendar.setTime(date); - + // Now set the UTC equivalent. calendar = new GregorianCalendar(utcZone); calendar.setTime(date); - } + } /** * Construct a date object from a bunch of component parts. The date passed in is assumed to be in the current - * time zone. Unknown values should be given as -1. + * time zone. Unknown values should be given as -1. * - * @param yyyy - * the year - * @param mm - * the month - * @param dd - * the day - * @param hh - * the hours - * @param mn - * the minutes - * @param ss - * the seconds + * @param yyyy the year + * @param mm the month + * @param dd the day + * @param hh the hours + * @param mn the minutes + * @param ss the seconds */ - public DCDate(int yyyy, int mm, int dd, int hh, int mn, int ss) - { + public DCDate(int yyyy, int mm, int dd, int hh, int mn, int ss) { setUTCForFormatting(); // default values @@ -131,131 +129,106 @@ public class DCDate int lmonth = 1; int lday = 1; - if (yyyy > 0) - { + if (yyyy > 0) { lyear = yyyy; granularity = DateGran.YEAR; } - if (mm > 0) - { + if (mm > 0) { lmonth = mm; granularity = DateGran.MONTH; } - if (dd > 0) - { + if (dd > 0) { lday = dd; granularity = DateGran.DAY; } - if (hh >= 0) - { + if (hh >= 0) { lhours = hh; granularity = DateGran.TIME; } - if (mn >= 0) - { + if (mn >= 0) { lminutes = mn; granularity = DateGran.TIME; } - if (ss >= 0) - { + if (ss >= 0) { lseconds = ss; granularity = DateGran.TIME; } // Set the local calendar. localCalendar = new GregorianCalendar(lyear, lmonth - 1, lday, - lhours, lminutes, lseconds); + lhours, lminutes, lseconds); - if (granularity == DateGran.TIME) - { + if (granularity == DateGran.TIME) { // Now set the UTC equivalent. calendar = new GregorianCalendar(utcZone); calendar.setTime(localCalendar.getTime()); - } - else - { + } else { // No Time component so just set the UTC date to be the same as the local Year, Month, and Day. - calendar = new GregorianCalendar(localCalendar.get(Calendar.YEAR), localCalendar.get(Calendar.MONTH), localCalendar.get(Calendar.DAY_OF_MONTH)); + calendar = new GregorianCalendar(localCalendar.get(Calendar.YEAR), localCalendar.get(Calendar.MONTH), + localCalendar.get(Calendar.DAY_OF_MONTH)); } } /** * Construct a date from a Dublin Core value * - * @param fromDC - * the date string, in ISO 8601 (no timezone, always use UTC) + * @param fromDC the date string, in ISO 8601 (no timezone, always use UTC) */ - public DCDate(String fromDC) - { + public DCDate(String fromDC) { setUTCForFormatting(); // An empty date is OK - if ((fromDC == null) || fromDC.equals("")) - { + if ((fromDC == null) || fromDC.equals("")) { return; } // default granularity granularity = DateGran.TIME; Date date = tryParse(fullIso, fromDC); - if (date == null) - { + if (date == null) { date = tryParse(fullIso2, fromDC); } - if (date == null) - { + if (date == null) { date = tryParse(fullIso3, fromDC); } - if (date == null) - { + if (date == null) { date = tryParse(fullIso4, fromDC); } - if (date == null) - { + if (date == null) { // Seems there is no time component to the date. date = tryParse(dateIso, fromDC); - if (date != null) - { + if (date != null) { granularity = DateGran.DAY; } } - if (date == null) - { + if (date == null) { date = tryParse(yearMonthIso, fromDC); - if (date != null) - { + if (date != null) { granularity = DateGran.MONTH; } } - if (date == null) - { + if (date == null) { date = tryParse(yearIso, fromDC); - if (date != null) - { + if (date != null) { granularity = DateGran.YEAR; } } - if (date == null) - { + if (date == null) { log.warn("Mangled date: " + fromDC + " ..failed all attempts to parse as date."); - } - else - { + } else { // Set the UTC time. calendar = new GregorianCalendar(utcZone); calendar.setTime(date); // Now set the local equivalent. - if (granularity == DateGran.TIME) - { + if (granularity == DateGran.TIME) { localCalendar = new GregorianCalendar(); localCalendar.setTime(date); - } - else - { + } else { // No Time component so just set the local date to be the same as the UTC Year, Month, and Day. - localCalendar = new GregorianCalendar(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); + localCalendar = new GregorianCalendar(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH)); } } } @@ -264,8 +237,7 @@ public class DCDate * Set all the formatters to use UTC. SimpleDateFormat is not thread-safe which * is why they are not static variables initialised once. */ - private void setUTCForFormatting() - { + private void setUTCForFormatting() { fullIso.setTimeZone(utcZone); fullIso2.setTimeZone(utcZone); fullIso3.setTimeZone(utcZone); @@ -276,25 +248,20 @@ public class DCDate } // Attempt to parse, swallowing errors; return null for failure. - private synchronized Date tryParse(SimpleDateFormat sdf, String source) - { - try - { + private synchronized Date tryParse(SimpleDateFormat sdf, String source) { + try { return sdf.parse(source); - } - catch (ParseException pe) - { + } catch (ParseException pe) { return null; } } - + /** * Get the year, adjusting for current time zone. * * @return the year */ - public int getYear() - { + public int getYear() { return (!withinGranularity(DateGran.YEAR)) ? -1 : localCalendar.get(Calendar.YEAR); } @@ -303,8 +270,7 @@ public class DCDate * * @return the month */ - public int getMonth() - { + public int getMonth() { return (!withinGranularity(DateGran.MONTH)) ? -1 : localCalendar.get(Calendar.MONTH) + 1; } @@ -313,8 +279,7 @@ public class DCDate * * @return the day */ - public int getDay() - { + public int getDay() { return (!withinGranularity(DateGran.DAY)) ? -1 : localCalendar.get(Calendar.DAY_OF_MONTH); } @@ -323,9 +288,8 @@ public class DCDate * * @return the hour */ - public int getHour() - { - return (!withinGranularity(DateGran.TIME)) ? -1 : localCalendar.get(Calendar.HOUR_OF_DAY); + public int getHour() { + return (!withinGranularity(DateGran.TIME)) ? -1 : localCalendar.get(Calendar.HOUR_OF_DAY); } /** @@ -333,8 +297,7 @@ public class DCDate * * @return the minute */ - public int getMinute() - { + public int getMinute() { return (!withinGranularity(DateGran.TIME)) ? -1 : localCalendar.get(Calendar.MINUTE); } @@ -343,8 +306,7 @@ public class DCDate * * @return the second */ - public int getSecond() - { + public int getSecond() { return (!withinGranularity(DateGran.TIME)) ? -1 : localCalendar.get(Calendar.SECOND); } @@ -353,8 +315,7 @@ public class DCDate * * @return the year */ - public int getYearUTC() - { + public int getYearUTC() { return (!withinGranularity(DateGran.YEAR)) ? -1 : calendar.get(Calendar.YEAR); } @@ -363,8 +324,7 @@ public class DCDate * * @return the month */ - public int getMonthUTC() - { + public int getMonthUTC() { return (!withinGranularity(DateGran.MONTH)) ? -1 : calendar.get(Calendar.MONTH) + 1; } @@ -373,8 +333,7 @@ public class DCDate * * @return the day */ - public int getDayUTC() - { + public int getDayUTC() { return (!withinGranularity(DateGran.DAY)) ? -1 : calendar.get(Calendar.DAY_OF_MONTH); } @@ -383,8 +342,7 @@ public class DCDate * * @return the hour */ - public int getHourUTC() - { + public int getHourUTC() { return (!withinGranularity(DateGran.TIME)) ? -1 : calendar.get(Calendar.HOUR_OF_DAY); } @@ -393,8 +351,7 @@ public class DCDate * * @return the minute */ - public int getMinuteUTC() - { + public int getMinuteUTC() { return (!withinGranularity(DateGran.TIME)) ? -1 : calendar.get(Calendar.MINUTE); } @@ -403,8 +360,7 @@ public class DCDate * * @return the second */ - public int getSecondUTC() - { + public int getSecondUTC() { return (!withinGranularity(DateGran.TIME)) ? -1 : calendar.get(Calendar.SECOND); } @@ -414,31 +370,21 @@ public class DCDate * * @return The date as a string. */ - public String toString() - { - if (calendar == null) - { + public String toString() { + if (calendar == null) { return "null"; } return toStringInternal(); } - private synchronized String toStringInternal() - { - if (granularity == DateGran.YEAR) - { + private synchronized String toStringInternal() { + if (granularity == DateGran.YEAR) { return String.format("%4d", getYearUTC()); - } - else if (granularity == DateGran.MONTH) - { + } else if (granularity == DateGran.MONTH) { return String.format("%4d-%02d", getYearUTC(), getMonthUTC()); - } - else if (granularity == DateGran.DAY) - { + } else if (granularity == DateGran.DAY) { return String.format("%4d-%02d-%02d", getYearUTC(), getMonthUTC(), getDayUTC()); - } - else - { + } else { return fullIso.format(calendar.getTime()); } } @@ -448,14 +394,10 @@ public class DCDate * * @return a Date object */ - public Date toDate() - { - if (calendar == null) - { + public Date toDate() { + if (calendar == null) { return null; - } - else - { + } else { return calendar.getTime(); } } @@ -467,125 +409,93 @@ public class DCDate * * FIXME: This should probably be replaced with a localized DateFormat. * - * @param showTime - * if true, display the time with the date - * @param isLocalTime - * if true, adjust for local time zone, otherwise UTC - * @param locale - * locale of the user - * + * @param showTime if true, display the time with the date + * @param isLocalTime if true, adjust for local time zone, otherwise UTC + * @param locale locale of the user * @return String with the date in a human-readable form. */ - public String displayDate(boolean showTime, boolean isLocalTime, Locale locale) - { - if (isLocalTime) - { + public String displayDate(boolean showTime, boolean isLocalTime, Locale locale) { + if (isLocalTime) { return displayLocalDate(showTime, locale); - } - else - { + } else { return displayUTCDate(showTime, locale); } } - public String displayLocalDate(boolean showTime, Locale locale) - { - // forcibly truncate month name to 3 chars -- XXX FIXME? + public String displayLocalDate(boolean showTime, Locale locale) { + // forcibly truncate month name to 3 chars -- XXX FIXME? String monthName = getMonthName(getMonth(), locale); - if (monthName.length() > 2) + if (monthName.length() > 2) { monthName = monthName.substring(0, 3); + } // display date and time - if (showTime && granularity == DateGran.TIME) - { - return String.format("%d-%s-%4d %02d:%02d:%02d", getDay(), monthName, getYear(), getHour(), getMinute(), getSecond()); - } - else if (granularity == DateGran.YEAR) - { + if (showTime && granularity == DateGran.TIME) { + return String.format("%d-%s-%4d %02d:%02d:%02d", getDay(), monthName, getYear(), getHour(), getMinute(), + getSecond()); + } else if (granularity == DateGran.YEAR) { return String.format("%4d", getYear()); - } - else if (granularity == DateGran.MONTH) - { + } else if (granularity == DateGran.MONTH) { return String.format("%s-%4d", monthName, getYear()); - } - else - { + } else { return String.format("%d-%s-%4d", getDay(), monthName, getYear()); } } - public String displayUTCDate(boolean showTime, Locale locale) - { + public String displayUTCDate(boolean showTime, Locale locale) { // forcibly truncate month name to 3 chars -- XXX FIXME? String monthName = getMonthName(getMonthUTC(), locale); - if (monthName.length() > 2) + if (monthName.length() > 2) { monthName = monthName.substring(0, 3); + } // display date and time - if (showTime && granularity == DateGran.TIME) - { - return String.format("%d-%s-%4d %02d:%02d:%02d", getDayUTC(), monthName, getYearUTC(), getHourUTC(), getMinuteUTC(), getSecondUTC()); - } - else if (granularity == DateGran.YEAR) - { + if (showTime && granularity == DateGran.TIME) { + return String + .format("%d-%s-%4d %02d:%02d:%02d", getDayUTC(), monthName, getYearUTC(), getHourUTC(), getMinuteUTC(), + getSecondUTC()); + } else if (granularity == DateGran.YEAR) { return String.format("%4d", getYearUTC()); - } - else if (granularity == DateGran.MONTH) - { + } else if (granularity == DateGran.MONTH) { return String.format("%s-%4d", monthName, getYearUTC()); - } - else - { + } else { return String.format("%d-%s-%4d", getDayUTC(), monthName, getYearUTC()); } } - /** - * Test if the requested level of granularity is within that of the date. - * - * @param dg - * The requested level of granularity. - * @return - * true or false. - * - */ - private boolean withinGranularity(DateGran dg) - { - if (granularity == DateGran.TIME) - { - if ((dg == DateGran.TIME) || (dg == DateGran.DAY) || (dg == DateGran.MONTH) || (dg == DateGran.YEAR)) - { - return true; - } - } + /** + * Test if the requested level of granularity is within that of the date. + * + * @param dg The requested level of granularity. + * @return true or false. + */ + private boolean withinGranularity(DateGran dg) { + if (granularity == DateGran.TIME) { + if ((dg == DateGran.TIME) || (dg == DateGran.DAY) || (dg == DateGran.MONTH) || (dg == DateGran.YEAR)) { + return true; + } + } - if (granularity == DateGran.DAY) - { - if ((dg == DateGran.DAY) || (dg == DateGran.MONTH) || (dg == DateGran.YEAR)) - { - return true; - } - } + if (granularity == DateGran.DAY) { + if ((dg == DateGran.DAY) || (dg == DateGran.MONTH) || (dg == DateGran.YEAR)) { + return true; + } + } - if (granularity == DateGran.MONTH) - { - if ((dg == DateGran.MONTH) || (dg == DateGran.YEAR)) - { - return true; - } - } + if (granularity == DateGran.MONTH) { + if ((dg == DateGran.MONTH) || (dg == DateGran.YEAR)) { + return true; + } + } - if (granularity == DateGran.YEAR) - { - if (dg == DateGran.YEAR) - { - return true; - } - } - - return false; - } + if (granularity == DateGran.YEAR) { + if (dg == DateGran.YEAR) { + return true; + } + } + return false; + } /************** Some utility methods ******************/ @@ -595,8 +505,7 @@ public class DCDate * * @return a DSpaceDate object representing the current instant. */ - public static DCDate getCurrent() - { + public static DCDate getCurrent() { return (new DCDate(new Date())); } @@ -604,27 +513,20 @@ public class DCDate * Get a month's name for a month between 1 and 12. Any invalid month value * (e.g. 0 or -1) will return a value of "Unspecified". * - * @param m - * the month number - * @param locale - * which locale to render the month name in + * @param m the month number + * @param locale which locale to render the month name in * @return the month name. */ - public static String getMonthName(int m, Locale locale) - { - if ((m > 0) && (m < 13)) - { + public static String getMonthName(int m, Locale locale) { + if ((m > 0) && (m < 13)) { DateFormatSymbols dfs = dfsLocaleMap.get(locale); - if (dfs == null) - { + if (dfs == null) { dfs = new DateFormatSymbols(locale); dfsLocaleMap.put(locale, dfs); } - return dfs.getMonths()[m-1]; - } - else - { + return dfs.getMonths()[m - 1]; + } else { return "Unspecified"; } diff --git a/dspace-api/src/main/java/org/dspace/content/DCLanguage.java b/dspace-api/src/main/java/org/dspace/content/DCLanguage.java index 38c2277420..aed9419317 100644 --- a/dspace-api/src/main/java/org/dspace/content/DCLanguage.java +++ b/dspace-api/src/main/java/org/dspace/content/DCLanguage.java @@ -11,80 +11,64 @@ import java.util.Locale; /** * Utility class for dealing with languages - * + * * @author Robert Tansley * @version $Revision$ */ -public class DCLanguage -{ - /** The country code */ +public class DCLanguage { + /** + * The country code + */ private String country; - /** The language code. Special values: "" and "other". */ + /** + * The language code. Special values: "" and "other". + */ private String language; /** * Construct a language object from a database entry - * - * @param l - * the language text from the database + * + * @param l the language text from the database */ - public DCLanguage(String l) - { + public DCLanguage(String l) { setLanguage(l); } /** * Write the language out to the database - * + * * @return the language in a form for writing to the DCValue table */ - public String toString() - { - if (language.equals("")) - { + public String toString() { + if (language.equals("")) { return ""; - } - else if (country.equals("")) - { + } else if (country.equals("")) { return language; - } - else - { + } else { return country + "_" + language; } } /** * Set the language and country - * - * @param l - * The language and country code, e.g. "en_US" or "fr" + * + * @param l The language and country code, e.g. "en_US" or "fr" */ - public final void setLanguage(String l) - { - if(l == null) - { + public final void setLanguage(String l) { + if (l == null) { language = ""; country = ""; - } - else if("other".equals(l)) - { + } else if ("other".equals(l)) { language = "other"; country = ""; - } - else if (l.length() == 2) - { + } else if (l.length() == 2) { language = l; country = ""; - } - else if (l.length() == 5) - { + } else if (l.length() == 5) { language = l.substring(0, 2); country = l.substring(3); - } - else - { + } else { language = ""; country = ""; } @@ -92,23 +76,17 @@ public class DCLanguage /** * Get the displayable name for this language - * + * * @return the displayable name */ - public String getDisplayName() - { + public String getDisplayName() { Locale locale; - if (language.equals("other")) - { + if (language.equals("other")) { return "(Other)"; - } - else if (language.equals("")) - { + } else if (language.equals("")) { return "N/A"; - } - else - { + } else { locale = new Locale(language, country); return locale.getDisplayName(); diff --git a/dspace-api/src/main/java/org/dspace/content/DCPersonName.java b/dspace-api/src/main/java/org/dspace/content/DCPersonName.java index cd1145961f..cdcff55c37 100644 --- a/dspace-api/src/main/java/org/dspace/content/DCPersonName.java +++ b/dspace-api/src/main/java/org/dspace/content/DCPersonName.java @@ -16,59 +16,56 @@ package org.dspace.content; * Lastname, First name(s) *

    * FIXME: No policy for dealing with "van"/"van der" and "Jr." - * + * * @author Robert Tansley * @version $Revision$ */ -public class DCPersonName -{ - /** The person's last name */ +public class DCPersonName { + /** + * The person's last name + */ private String lastName; - /** The person's first name(s) */ + /** + * The person's first name(s) + */ private String firstNames; - /** Construct a blank name */ - public DCPersonName() - { + /** + * Construct a blank name + */ + public DCPersonName() { lastName = null; firstNames = null; } /** * Construct a name from a raw DC value - * - * @param rawValue - * the value entry from the database + * + * @param rawValue the value entry from the database */ - public DCPersonName(String rawValue) - { + public DCPersonName(String rawValue) { // Null by default (representing noone) lastName = null; firstNames = null; // Check we've actually been passed a name - if ((rawValue != null) && !rawValue.equals("")) - { + if ((rawValue != null) && !rawValue.equals("")) { // Extract the last name and first name components int commaIndex = rawValue.indexOf(','); // Just in case there's no comma, assume whole thing is // last name - if (commaIndex == -1) - { + if (commaIndex == -1) { commaIndex = rawValue.length(); } lastName = rawValue.substring(0, commaIndex).trim(); // Just in case the first name is blank - if (rawValue.length() > (commaIndex + 1)) - { + if (rawValue.length() > (commaIndex + 1)) { firstNames = rawValue.substring(commaIndex + 1).trim(); - } - else - { + } else { // Since we have a name, we don't want to // leave the first name as null firstNames = ""; @@ -78,33 +75,27 @@ public class DCPersonName /** * Construct a name from a last name and first name - * - * @param lastNameIn - * the last name - * @param firstNamesIn - * the first names + * + * @param lastNameIn the last name + * @param firstNamesIn the first names */ - public DCPersonName(String lastNameIn, String firstNamesIn) - { + public DCPersonName(String lastNameIn, String firstNamesIn) { lastName = lastNameIn; firstNames = firstNamesIn; } /** * Return a string for writing the name to the database - * + * * @return the name, suitable for putting in the database */ - public String toString() - { + public String toString() { StringBuffer out = new StringBuffer(); - if (lastName != null) - { + if (lastName != null) { out.append(lastName); - if ((firstNames != null) && !firstNames.equals("")) - { + if ((firstNames != null) && !firstNames.equals("")) { out.append(", ").append(firstNames); } } @@ -114,21 +105,19 @@ public class DCPersonName /** * Get the first name(s). Guaranteed non-null. - * + * * @return the first name(s), or an empty string if none */ - public String getFirstNames() - { + public String getFirstNames() { return ((firstNames == null) ? "" : firstNames); } /** * Get the last name. Guaranteed non-null. - * + * * @return the last name, or an empty string if none */ - public String getLastName() - { + public String getLastName() { return ((lastName == null) ? "" : lastName); } } diff --git a/dspace-api/src/main/java/org/dspace/content/DCSeriesNumber.java b/dspace-api/src/main/java/org/dspace/content/DCSeriesNumber.java index 9820687d49..bec81494be 100644 --- a/dspace-api/src/main/java/org/dspace/content/DCSeriesNumber.java +++ b/dspace-api/src/main/java/org/dspace/content/DCSeriesNumber.java @@ -9,103 +9,92 @@ package org.dspace.content; /** * Series and report number, as stored in relation.ispartofseries - * + * * @author Robert Tansley * @version $Id$ */ -public class DCSeriesNumber -{ - /** Series */ +public class DCSeriesNumber { + /** + * Series + */ private String series; - /** Number */ + /** + * Number + */ private String number; - /** Construct clean series number */ - public DCSeriesNumber() - { + /** + * Construct clean series number + */ + public DCSeriesNumber() { series = null; number = null; } /** * Construct from raw DC value - * - * @param value - * value from database + * + * @param value value from database */ - public DCSeriesNumber(String value) - { + public DCSeriesNumber(String value) { this(); int semicolon = -1; - if (value != null) - { + if (value != null) { semicolon = value.indexOf(';'); } - if (semicolon >= 0) - { + if (semicolon >= 0) { series = value.substring(0, semicolon); number = value.substring(semicolon + 1); - } - else - { + } else { series = value; } } /** * Construct from given values - * - * @param s - * the series - * @param n - * the number + * + * @param s the series + * @param n the number */ - public DCSeriesNumber(String s, String n) - { + public DCSeriesNumber(String s, String n) { series = s; number = n; } /** * Write as raw DC value - * + * * @return the series and number as they should be stored in the DB */ - public String toString() - { - if (series == null) - { + public String toString() { + if (series == null) { return (null); - } - else if (number == null) - { + } else if (number == null) { return (series); - } - else - { + } else { return (series + ";" + number); } } /** * Get the series name - guaranteed non-null + * * @return name */ - public String getSeries() - { + public String getSeries() { return ((series == null) ? "" : series); } /** * Get the number - guaranteed non-null + * * @return number */ - public String getNumber() - { + public String getNumber() { return ((number == null) ? "" : number); } } diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java index 5243b8e933..a486fed82a 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java @@ -7,27 +7,36 @@ */ package org.dspace.content; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.apache.commons.collections4.CollectionUtils; import org.dspace.authorize.ResourcePolicy; import org.dspace.core.ReloadableEntity; import org.dspace.handle.Handle; import org.hibernate.annotations.GenericGenerator; -import java.io.Serializable; -import java.util.*; - -import javax.persistence.*; - /** * Abstract base class for DSpace objects */ @Entity -@Inheritance(strategy= InheritanceType.JOINED) +@Inheritance(strategy = InheritanceType.JOINED) @Table(name = "dspaceobject") -public abstract class DSpaceObject implements Serializable, ReloadableEntity -{ +public abstract class DSpaceObject implements Serializable, ReloadableEntity { @Id @GeneratedValue(generator = "system-uuid") @GenericGenerator(name = "system-uuid", strategy = "uuid2") @@ -38,14 +47,15 @@ public abstract class DSpaceObject implements Serializable, ReloadableEntity metadata = new ArrayList<>(); @OneToMany(fetch = FetchType.LAZY, mappedBy = "dso") // Order by is here to ensure that the oldest handle is retrieved first, - // multiple handles are assigned to the latest version of an item the original handle will have the lowest identifier + // multiple handles are assigned to the latest version of an item the original handle will have the lowest + // identifier // This handle is the preferred handle. @OrderBy("id ASC") private List handles = new ArrayList<>(); @@ -60,20 +70,20 @@ public abstract class DSpaceObject implements Serializable, ReloadableEntitynull - * + * * @return Handle of the object, or null if it doesn't have - * one + * one */ - public String getHandle() - { + public String getHandle() { return (CollectionUtils.isNotEmpty(handles) ? handles.get(0).getHandle() : null); } - void setHandle(List handle) - { + void setHandle(List handle) { this.handles = handle; } - public void addHandle(Handle handle) - { + public void addHandle(Handle handle) { this.handles.add(handle); } @@ -155,14 +158,12 @@ public abstract class DSpaceObject implements Serializable, ReloadableEntity metadataValues) - { + protected void removeMetadata(List metadataValues) { setMetadataModified(); getMetadata().removeAll(metadataValues); } @@ -189,11 +190,13 @@ public abstract class DSpaceObject implements Serializable, ReloadableEntity class type + * @author kevinvandevelde at atmire.com */ public abstract class DSpaceObjectServiceImpl implements DSpaceObjectService { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(DSpaceObjectServiceImpl.class); @Autowired(required = true) @@ -52,8 +61,7 @@ public abstract class DSpaceObjectServiceImpl implements @Autowired(required = true) protected MetadataAuthorityService metadataAuthorityService; - public DSpaceObjectServiceImpl() - { + public DSpaceObjectServiceImpl() { } @@ -65,30 +73,25 @@ public abstract class DSpaceObjectServiceImpl implements @Override public ArrayList getIdentifiers(Context context, T dso) { - ArrayList identifiers = new ArrayList<>(); + ArrayList identifiers = new ArrayList<>(); IdentifierService identifierService = - new DSpace().getSingletonService(IdentifierService.class); + new DSpace().getSingletonService(IdentifierService.class); - if (identifierService != null) - { + if (identifierService != null) { identifiers.addAll(identifierService.lookup(context, dso)); } else { log.warn("No IdentifierService found, will return an list containing " - + "the Handle only."); - if (dso.getHandle() != null) - { + + "the Handle only."); + if (dso.getHandle() != null) { identifiers.add(handleService.getCanonicalForm(dso.getHandle())); } } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { StringBuilder dbgMsg = new StringBuilder(); - for (String id : identifiers) - { - if (dbgMsg.capacity() == 0) - { + for (String id : identifiers) { + if (dbgMsg.capacity() == 0) { dbgMsg.append("This DSO's Identifiers are: "); } else { dbgMsg.append(", "); @@ -103,15 +106,13 @@ public abstract class DSpaceObjectServiceImpl implements } @Override - public DSpaceObject getParentObject(Context context, T dso) throws SQLException - { + public DSpaceObject getParentObject(Context context, T dso) throws SQLException { return null; } @Override public DSpaceObject getAdminObject(Context context, T dso, int action) throws SQLException { - if (action == Constants.ADMIN) - { + if (action == Constants.ADMIN) { throw new IllegalArgumentException("Illegal call to the DSpaceObject.getAdminObject method"); } return dso; @@ -126,10 +127,8 @@ public abstract class DSpaceObjectServiceImpl implements public List getMetadata(T dso, String schema, String element, String qualifier, String lang) { // Build up list of matching values List values = new ArrayList(); - for (MetadataValue dcv : dso.getMetadata()) - { - if (match(schema, element, qualifier, lang, dcv)) - { + for (MetadataValue dcv : dso.getMetadata()) { + if (match(schema, element, qualifier, lang, dcv)) { values.add(dcv); } } @@ -139,14 +138,12 @@ public abstract class DSpaceObjectServiceImpl implements } @Override - public List getMetadataByMetadataString(T dso, String mdString) - { + public List getMetadataByMetadataString(T dso, String mdString) { StringTokenizer dcf = new StringTokenizer(mdString, "."); - String[] tokens = { "", "", "" }; + String[] tokens = {"", "", ""}; int i = 0; - while(dcf.hasMoreTokens()) - { + while (dcf.hasMoreTokens()) { tokens[i] = dcf.nextToken().trim(); i++; } @@ -154,20 +151,20 @@ public abstract class DSpaceObjectServiceImpl implements String element = tokens[1]; String qualifier = tokens[2]; + List values = getMetadata(dso, schema, element, qualifier); + + return values; + } + + private List getMetadata(T dso, String schema, String element, String qualifier) { List values; - if (Item.ANY.equals(qualifier)) - { + if (Item.ANY.equals(qualifier)) { values = getMetadata(dso, schema, element, Item.ANY, Item.ANY); - } - else if ("".equals(qualifier)) - { + } else if ("".equals(qualifier)) { values = getMetadata(dso, schema, element, null, Item.ANY); - } - else - { + } else { values = getMetadata(dso, schema, element, qualifier, Item.ANY); } - return values; } @@ -175,7 +172,7 @@ public abstract class DSpaceObjectServiceImpl implements public String getMetadata(T dso, String value) { List metadataValues = getMetadataByMetadataString(dso, value); - if(CollectionUtils.isNotEmpty(metadataValues)) { + if (CollectionUtils.isNotEmpty(metadataValues)) { return metadataValues.iterator().next().getValue(); } return null; @@ -188,7 +185,8 @@ public abstract class DSpaceObjectServiceImpl implements } @Override - public List getMetadata(T dso, String schema, String element, String qualifier, String lang, String authority){ + public List getMetadata(T dso, String schema, String element, String qualifier, String lang, + String authority) { List metadata = getMetadata(dso, schema, element, qualifier, lang); List result = new ArrayList<>(metadata); if (!authority.equals(Item.ANY)) { @@ -204,35 +202,42 @@ public abstract class DSpaceObjectServiceImpl implements } @Override - public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, List values) throws SQLException { + public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + List values) throws SQLException { MetadataField metadataField = metadataFieldService.findByElement(context, schema, element, qualifier); if (metadataField == null) { - throw new SQLException("bad_dublin_core schema=" + schema + "." + element + "." + qualifier + ". Metadata field does not exist!"); + throw new SQLException( + "bad_dublin_core schema=" + schema + "." + element + "." + qualifier + ". Metadata field does not " + + "exist!"); } addMetadata(context, dso, metadataField, lang, values); } @Override - public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, List values, List authorities, List confidences) throws SQLException { + public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + List values, List authorities, List confidences) + throws SQLException { // We will not verify that they are valid entries in the registry // until update() is called. MetadataField metadataField = metadataFieldService.findByElement(context, schema, element, qualifier); if (metadataField == null) { - throw new SQLException("bad_dublin_core schema=" + schema + "." + element + "." + qualifier + ". Metadata field does not exist!"); + throw new SQLException( + "bad_dublin_core schema=" + schema + "." + element + "." + qualifier + ". Metadata field does not " + + "exist!"); } addMetadata(context, dso, metadataField, lang, values, authorities, confidences); } @Override - public void addMetadata(Context context, T dso, MetadataField metadataField, String lang, List values, List authorities, List confidences) throws SQLException { + public void addMetadata(Context context, T dso, MetadataField metadataField, String lang, List values, + List authorities, List confidences) throws SQLException { boolean authorityControlled = metadataAuthorityService.isAuthorityControlled(metadataField); boolean authorityRequired = metadataAuthorityService.isAuthorityRequired(metadataField); // We will not verify that they are valid entries in the registry // until update() is called. - for (int i = 0; i < values.size(); i++) - { + for (int i = 0; i < values.size(); i++) { MetadataValue metadataValue = metadataValueService.create(context, dso, metadataField); metadataValue.setLanguage(lang == null ? null : lang.trim()); @@ -240,47 +245,43 @@ public abstract class DSpaceObjectServiceImpl implements // Logic to set Authority and Confidence: // - normalize an empty string for authority to NULL. // - if authority key is present, use given confidence or NOVALUE if not given - // - otherwise, preserve confidence if meaningful value was given since it may document a failed authority lookup + // - otherwise, preserve confidence if meaningful value was given since it may document a failed + // authority lookup // - CF_UNSET signifies no authority nor meaningful confidence. // - it's possible to have empty authority & CF_ACCEPTED if e.g. user deletes authority key - if (authorityControlled) - { - if (authorities != null && authorities.get(i) != null && authorities.get(i).length() > 0) - { + if (authorityControlled) { + if (authorities != null && authorities.get(i) != null && authorities.get(i).length() > 0) { metadataValue.setAuthority(authorities.get(i)); metadataValue.setConfidence(confidences == null ? Choices.CF_NOVALUE : confidences.get(i)); - } - else - { + } else { metadataValue.setAuthority(null); metadataValue.setConfidence(confidences == null ? Choices.CF_UNSET : confidences.get(i)); } // authority sanity check: if authority is required, was it supplied? - // XXX FIXME? can't throw a "real" exception here without changing all the callers to expect it, so use a runtime exception - if (authorityRequired && (metadataValue.getAuthority() == null || metadataValue.getAuthority().length() == 0)) - { - throw new IllegalArgumentException("The metadata field \"" + metadataField.toString() + "\" requires an authority key but none was provided. Value=\"" + values.get(i) + "\""); + // XXX FIXME? can't throw a "real" exception here without changing all the callers to expect it, so + // use a runtime exception + if (authorityRequired && (metadataValue.getAuthority() == null || metadataValue.getAuthority() + .length() == 0)) { + throw new IllegalArgumentException("The metadata field \"" + metadataField + .toString() + "\" requires an authority key but none was provided. Value=\"" + values + .get(i) + "\""); } } - if (values.get(i) != null) - { + if (values.get(i) != null) { // remove control unicode char String temp = values.get(i).trim(); char[] dcvalue = temp.toCharArray(); - for (int charPos = 0; charPos < dcvalue.length; charPos++) - { + for (int charPos = 0; charPos < dcvalue.length; charPos++) { if (Character.isISOControl(dcvalue[charPos]) && - !String.valueOf(dcvalue[charPos]).equals("\u0009") && - !String.valueOf(dcvalue[charPos]).equals("\n") && - !String.valueOf(dcvalue[charPos]).equals("\r")) - { + !String.valueOf(dcvalue[charPos]).equals("\u0009") && + !String.valueOf(dcvalue[charPos]).equals("\n") && + !String.valueOf(dcvalue[charPos]).equals("\r")) { dcvalue[charPos] = ' '; } } - metadataValue.setValue(String.valueOf(dcvalue));; - } - else - { + metadataValue.setValue(String.valueOf(dcvalue)); + ; + } else { metadataValue.setValue(null); } //An update here isn't needed, this is persited upon the merge of the owning object @@ -290,30 +291,38 @@ public abstract class DSpaceObjectServiceImpl implements } @Override - public void addMetadata(Context context, T dso, MetadataField metadataField, String language, String value, String authority, int confidence) throws SQLException { - addMetadata(context, dso, metadataField, language, Arrays.asList(value), Arrays.asList(authority), Arrays.asList(confidence)); + public void addMetadata(Context context, T dso, MetadataField metadataField, String language, String value, + String authority, int confidence) throws SQLException { + addMetadata(context, dso, metadataField, language, Arrays.asList(value), Arrays.asList(authority), + Arrays.asList(confidence)); } @Override - public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, String value) throws SQLException { + public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + String value) throws SQLException { addMetadata(context, dso, schema, element, qualifier, lang, Arrays.asList(value)); } @Override - public void addMetadata(Context context, T dso, MetadataField metadataField, String language, String value) throws SQLException { + public void addMetadata(Context context, T dso, MetadataField metadataField, String language, String value) + throws SQLException { addMetadata(context, dso, metadataField, language, Arrays.asList(value)); } @Override - public void addMetadata(Context context, T dso, MetadataField metadataField, String language, List values) throws SQLException { - if(metadataField != null) { - String fieldKey = metadataAuthorityService.makeFieldKey(metadataField.getMetadataSchema().getName(), metadataField.getElement(), metadataField.getQualifier()); + public void addMetadata(Context context, T dso, MetadataField metadataField, String language, List values) + throws SQLException { + if (metadataField != null) { + String fieldKey = metadataAuthorityService + .makeFieldKey(metadataField.getMetadataSchema().getName(), metadataField.getElement(), + metadataField.getQualifier()); if (metadataAuthorityService.isAuthorityControlled(fieldKey)) { List authorities = new ArrayList(); List confidences = new ArrayList(); for (int i = 0; i < values.size(); ++i) { if (dso instanceof Item) { - getAuthoritiesAndConfidences(fieldKey, ((Item) dso).getOwningCollection(), values, authorities, confidences, i); + getAuthoritiesAndConfidences(fieldKey, ((Item) dso).getOwningCollection(), values, authorities, + confidences, i); } else { getAuthoritiesAndConfidences(fieldKey, null, values, authorities, confidences, i); } @@ -326,19 +335,20 @@ public abstract class DSpaceObjectServiceImpl implements } @Override - public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, String value, String authority, int confidence) throws SQLException { - addMetadata(context, dso, schema, element, qualifier, lang, Arrays.asList(value), Arrays.asList(authority), Arrays.asList(confidence)); + public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + String value, String authority, int confidence) throws SQLException { + addMetadata(context, dso, schema, element, qualifier, lang, Arrays.asList(value), Arrays.asList(authority), + Arrays.asList(confidence)); } @Override - public void clearMetadata(Context context, T dso, String schema, String element, String qualifier, String lang) throws SQLException { + public void clearMetadata(Context context, T dso, String schema, String element, String qualifier, String lang) + throws SQLException { Iterator metadata = dso.getMetadata().iterator(); - while (metadata.hasNext()) - { + while (metadata.hasNext()) { MetadataValue metadataValue = metadata.next(); // If this value matches, delete it - if (match(schema, element, qualifier, lang, metadataValue)) - { + if (match(schema, element, qualifier, lang, metadataValue)) { metadata.remove(); metadataValueService.delete(context, metadataValue); } @@ -351,8 +361,7 @@ public abstract class DSpaceObjectServiceImpl implements Iterator metadata = dso.getMetadata().iterator(); while (metadata.hasNext()) { MetadataValue metadataValue = metadata.next(); - if(values.contains(metadataValue)) - { + if (values.contains(metadataValue)) { metadata.remove(); metadataValueService.delete(context, metadataValue); } @@ -362,23 +371,19 @@ public abstract class DSpaceObjectServiceImpl implements /** * Retrieve first metadata field value - * @param dso - * The DSpaceObject which we ask for metadata. - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the element to match, or Item.ANY - * @param qualifier - * the qualifier to match, or Item.ANY - * @param language - * the language to match, or Item.ANY + * + * @param dso The DSpaceObject which we ask for metadata. + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the element to match, or Item.ANY + * @param qualifier the qualifier to match, or Item.ANY + * @param language the language to match, or Item.ANY * @return the first metadata field value */ @Override - public String getMetadataFirstValue(T dso, String schema, String element, String qualifier, String language){ + public String getMetadataFirstValue(T dso, String schema, String element, String qualifier, String language) { List metadataValues = getMetadata(dso, schema, element, qualifier, language); - if(CollectionUtils.isNotEmpty(metadataValues)){ + if (CollectionUtils.isNotEmpty(metadataValues)) { return metadataValues.iterator().next().getValue(); } return null; @@ -386,12 +391,13 @@ public abstract class DSpaceObjectServiceImpl implements /** * Set first metadata field value + * * @throws SQLException if database error */ @Override - public void setMetadataSingleValue(Context context, T dso, String schema, String element, String qualifier, String language, String value) throws SQLException { - if(value != null) - { + public void setMetadataSingleValue(Context context, T dso, String schema, String element, String qualifier, + String language, String value) throws SQLException { + if (value != null) { clearMetadata(context, dso, schema, element, qualifier, language); addMetadata(context, dso, schema, element, qualifier, language, value); dso.setMetadataModified(); @@ -406,72 +412,53 @@ public abstract class DSpaceObjectServiceImpl implements * in. Any or all of the element, qualifier and language passed * in can be the Item.ANY wildcard. * - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the element to match, or Item.ANY - * @param qualifier - * the qualifier to match, or Item.ANY - * @param language - * the language to match, or Item.ANY - * @param metadataValue - * the Dublin Core value + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the element to match, or Item.ANY + * @param qualifier the qualifier to match, or Item.ANY + * @param language the language to match, or Item.ANY + * @param metadataValue the Dublin Core value * @return true if there is a match */ protected boolean match(String schema, String element, String qualifier, - String language, MetadataValue metadataValue) - { + String language, MetadataValue metadataValue) { MetadataField metadataField = metadataValue.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); // We will attempt to disprove a match - if we can't we have a match - if (!element.equals(Item.ANY) && !element.equals(metadataField.getElement())) - { + if (!element.equals(Item.ANY) && !element.equals(metadataField.getElement())) { // Elements do not match, no wildcard return false; } - if (qualifier == null) - { + if (StringUtils.isBlank(qualifier)) { // Value must be unqualified - if (metadataField.getQualifier() != null) - { + if (metadataField.getQualifier() != null) { // Value is qualified, so no match return false; } - } - else if (!qualifier.equals(Item.ANY)) - { + } else if (!qualifier.equals(Item.ANY)) { // Not a wildcard, so qualifier must match exactly - if (!qualifier.equals(metadataField.getQualifier())) - { + if (!qualifier.equals(metadataField.getQualifier())) { return false; } } - if (language == null) - { + if (language == null) { // Value must be null language to match - if (metadataValue.getLanguage() != null) - { + if (metadataValue.getLanguage() != null) { // Value is qualified, so no match return false; } - } - else if (!language.equals(Item.ANY)) - { + } else if (!language.equals(Item.ANY)) { // Not a wildcard, so language must match exactly - if (!language.equals(metadataValue.getLanguage())) - { + if (!language.equals(metadataValue.getLanguage())) { return false; } } - if (!schema.equals(Item.ANY)) - { - if (metadataSchema != null && !metadataSchema.getName().equals(schema)) - { + if (!schema.equals(Item.ANY)) { + if (metadataSchema != null && !metadataSchema.getName().equals(schema)) { // The namespace doesn't match return false; } @@ -481,8 +468,9 @@ public abstract class DSpaceObjectServiceImpl implements return true; } - protected void getAuthoritiesAndConfidences(String fieldKey, Collection collection, List values, List authorities, List confidences, int i) { - Choices c = choiceAuthorityService.getBestMatch(fieldKey, values.get(i), null, null); + protected void getAuthoritiesAndConfidences(String fieldKey, Collection collection, List values, + List authorities, List confidences, int i) { + Choices c = choiceAuthorityService.getBestMatch(fieldKey, values.get(i), collection, null); authorities.add(c.values.length > 0 ? c.values[0].authority : null); confidences.add(c.confidence); } @@ -494,6 +482,7 @@ public abstract class DSpaceObjectServiceImpl implements * The returned array will always have length greater than or equal to 4 *

    * Values in the returned array can be empty or null. + * * @param fieldName field name * @return array */ @@ -514,6 +503,7 @@ public abstract class DSpaceObjectServiceImpl implements * The returned array will always have length greater than or equal to 4 *

    * When @param fill is true, elements that would be empty or null are replaced by Item.ANY + * * @param fieldName field name * @return array */ @@ -527,91 +517,188 @@ public abstract class DSpaceObjectServiceImpl implements return elements; } - protected String[] getMDValueByField(String field){ + protected String[] getMDValueByField(String field) { StringTokenizer dcf = new StringTokenizer(field, "."); - String[] tokens = { "", "", "" }; + String[] tokens = {"", "", ""}; int i = 0; - while(dcf.hasMoreTokens()){ + while (dcf.hasMoreTokens()) { tokens[i] = dcf.nextToken().trim(); i++; } - if(i!=0){ + if (i != 0) { return tokens; - }else{ + } else { return getMDValueByLegacyField(field); } } @Override - public void update(Context context, T dso) throws SQLException, AuthorizeException - { - if(dso.isMetadataModified()) - { + public void update(Context context, T dso) throws SQLException, AuthorizeException { + if (dso.isMetadataModified()) { /* Update the order of the metadata values */ - // A map created to store the latest place for each metadata field - Map fieldToLastPlace = new HashMap<>(); - List metadataValues = dso.getMetadata(); - for (MetadataValue metadataValue : metadataValues) - { - //Retrieve & store the place for each metadata value - int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); - metadataValue.setPlace(mvPlace); - } + // A map created to store the latest place for each metadata field + Map fieldToLastPlace = new HashMap<>(); + List metadataValues = dso.getMetadata(); + for (MetadataValue metadataValue : metadataValues) { + //Retrieve & store the place for each metadata value + int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); + metadataValue.setPlace(mvPlace); + } } } /** * Retrieve the place of the metadata value + * * @param fieldToLastPlace the map containing the latest place of each metadata field - * @param metadataValue the metadata value that needs to get a place + * @param metadataValue the metadata value that needs to get a place * @return The new place for the metadata valu */ protected int getMetadataValuePlace(Map fieldToLastPlace, MetadataValue metadataValue) { MetadataField metadataField = metadataValue.getMetadataField(); - if(fieldToLastPlace.containsKey(metadataField)) - { + if (fieldToLastPlace.containsKey(metadataField)) { fieldToLastPlace.put(metadataField, fieldToLastPlace.get(metadataField) + 1); - }else{ + } else { // The metadata value place starts at 0 fieldToLastPlace.put(metadataField, 0); } return fieldToLastPlace.get(metadataField); } - protected String[] getMDValueByLegacyField(String field){ + protected String[] getMDValueByLegacyField(String field) { switch (field) { case "introductory_text": - return new String[]{MetadataSchema.DC_SCHEMA, "description", null}; + return new String[] {MetadataSchema.DC_SCHEMA, "description", null}; case "short_description": - return new String[]{MetadataSchema.DC_SCHEMA, "description", "abstract"}; + return new String[] {MetadataSchema.DC_SCHEMA, "description", "abstract"}; case "side_bar_text": - return new String[]{MetadataSchema.DC_SCHEMA, "description", "tableofcontents"}; + return new String[] {MetadataSchema.DC_SCHEMA, "description", "tableofcontents"}; case "copyright_text": - return new String[]{MetadataSchema.DC_SCHEMA, "rights", null}; + return new String[] {MetadataSchema.DC_SCHEMA, "rights", null}; case "name": - return new String[]{MetadataSchema.DC_SCHEMA, "title", null}; + return new String[] {MetadataSchema.DC_SCHEMA, "title", null}; case "provenance_description": - return new String[]{MetadataSchema.DC_SCHEMA,"provenance", null}; + return new String[] {MetadataSchema.DC_SCHEMA, "provenance", null}; case "license": - return new String[]{MetadataSchema.DC_SCHEMA, "rights", "license"}; + return new String[] {MetadataSchema.DC_SCHEMA, "rights", "license"}; case "user_format_description": - return new String[]{MetadataSchema.DC_SCHEMA,"format",null}; + return new String[] {MetadataSchema.DC_SCHEMA, "format", null}; case "source": - return new String[]{MetadataSchema.DC_SCHEMA,"source",null}; + return new String[] {MetadataSchema.DC_SCHEMA, "source", null}; case "firstname": - return new String[]{"eperson","firstname",null}; + return new String[] {"eperson", "firstname", null}; case "lastname": - return new String[]{"eperson","lastname",null}; + return new String[] {"eperson", "lastname", null}; case "phone": - return new String[]{"eperson","phone",null}; + return new String[] {"eperson", "phone", null}; case "language": - return new String[]{"eperson","language",null}; + return new String[] {"eperson", "language", null}; default: - return new String[]{null, null, null}; + return new String[] {null, null, null}; + } + } + + @Override + public void addAndShiftRightMetadata(Context context, T dso, String schema, String element, String qualifier, + String lang, String value, String authority, int confidence, int index) + throws SQLException { + + List list = getMetadata(dso, schema, element, qualifier); + + clearMetadata(context, dso, schema, element, qualifier, Item.ANY); + + int idx = 0; + boolean last = true; + for (MetadataValue rr : list) { + if (idx == index) { + addMetadata(context, dso, schema, element, qualifier, + lang, value, authority, confidence); + last = false; + } + addMetadata(context, dso, schema, element, qualifier, + rr.getLanguage(), rr.getValue(), rr.getAuthority(), rr.getConfidence()); + idx++; + } + if (last) { + addMetadata(context, dso, schema, element, qualifier, + lang, value, authority, confidence); + } + } + + @Override + public void moveMetadata(Context context, T dso, String schema, String element, String qualifier, int from, int to) + throws SQLException, IllegalArgumentException { + + if (from == to) { + throw new IllegalArgumentException("The \"from\" location MUST be different from \"to\" location"); + } + + List list = getMetadata(dso, schema, element, qualifier); + + if (from >= list.size()) { + throw new IllegalArgumentException( + "The \"from\" location MUST exist for the operation to be successful. Idx:" + from); + } + + clearMetadata(context, dso, schema, element, qualifier, Item.ANY); + + int idx = 0; + MetadataValue moved = null; + for (MetadataValue md : list) { + if (idx == from) { + moved = md; + break; + } + idx++; + } + + idx = 0; + boolean last = true; + for (MetadataValue rr : list) { + if (idx == to && to < from) { + addMetadata(context, dso, schema, element, qualifier, moved.getLanguage(), moved.getValue(), + moved.getAuthority(), moved.getConfidence()); + last = false; + } + if (idx != from) { + addMetadata(context, dso, schema, element, qualifier, rr.getLanguage(), rr.getValue(), + rr.getAuthority(), rr.getConfidence()); + } + if (idx == to && to > from) { + addMetadata(context, dso, schema, element, qualifier, moved.getLanguage(), moved.getValue(), + moved.getAuthority(), moved.getConfidence()); + last = false; + } + idx++; + } + if (last) { + addMetadata(context, dso, schema, element, qualifier, moved.getLanguage(), moved.getValue(), + moved.getAuthority(), moved.getConfidence()); + } + } + + @Override + public void replaceMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + String value, String authority, int confidence, int index) throws SQLException { + + List list = getMetadata(dso, schema, element, qualifier); + + clearMetadata(context, dso, schema, element, qualifier, Item.ANY); + + int idx = 0; + for (MetadataValue rr : list) { + if (idx == index) { + addMetadata(context, dso, schema, element, qualifier, + lang, value, authority, confidence); + } else { + addMetadata(context, dso, schema, element, qualifier, + rr.getLanguage(), rr.getValue(), rr.getAuthority(), rr.getConfidence()); + } + idx++; } } } diff --git a/dspace-api/src/main/java/org/dspace/content/InProgressSubmission.java b/dspace-api/src/main/java/org/dspace/content/InProgressSubmission.java index 7af3b1d108..024d769bd0 100644 --- a/dspace-api/src/main/java/org/dspace/content/InProgressSubmission.java +++ b/dspace-api/src/main/java/org/dspace/content/InProgressSubmission.java @@ -7,43 +7,42 @@ */ package org.dspace.content; -import org.dspace.eperson.EPerson; - import java.sql.SQLException; +import org.dspace.eperson.EPerson; + /** * Interface for manipulating in-progress submissions, without having to know at * which stage of submission they are (in workspace or workflow system) - * + * * @author Robert Tansley * @version $Revision$ */ -public interface InProgressSubmission -{ +public interface InProgressSubmission { /** * Get the internal ID of this submission - * + * * @return the internal identifier */ Integer getID(); /** * Get the incomplete item object - * + * * @return the item */ Item getItem(); /** * Get the collection being submitted to - * + * * @return the collection */ Collection getCollection(); /** * Get the submitter - * + * * @return the submitting e-person * @throws SQLException if database error */ @@ -52,41 +51,39 @@ public interface InProgressSubmission /** * Find out if the submission has (or is intended to have) more than one * associated bitstream. - * + * * @return true if there is to be more than one file. */ boolean hasMultipleFiles(); /** * Indicate whether the submission is intended to have more than one file. - * - * @param b - * if true, submission may have more than one - * file. + * + * @param b if true, submission may have more than one + * file. */ void setMultipleFiles(boolean b); /** * Find out if the submission has (or is intended to have) more than one * title. - * + * * @return true if there is to be more than one file. */ boolean hasMultipleTitles(); /** * Indicate whether the submission is intended to have more than one title. - * - * @param b - * if true, submission may have more than one - * title. + * + * @param b if true, submission may have more than one + * title. */ void setMultipleTitles(boolean b); /** * Find out if the submission has been published or publicly distributed * before - * + * * @return true if it has been published before */ boolean isPublishedBefore(); @@ -94,9 +91,8 @@ public interface InProgressSubmission /** * Indicate whether the submission has been published or publicly * distributed before - * - * @param b - * true if it has been published before + * + * @param b true if it has been published before */ void setPublishedBefore(boolean b); } diff --git a/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java index 6a13afd450..59298e4c31 100644 --- a/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java @@ -26,12 +26,11 @@ import org.springframework.beans.factory.annotation.Autowired; /** * Support to install an Item in the archive. - * + * * @author dstuve * @version $Revision$ */ -public class InstallItemServiceImpl implements InstallItemService -{ +public class InstallItemServiceImpl implements InstallItemService { @Autowired(required = true) protected ContentServiceFactory contentServiceFactory; @@ -44,30 +43,26 @@ public class InstallItemServiceImpl implements InstallItemService @Autowired(required = true) protected ItemService itemService; - protected InstallItemServiceImpl() - { + protected InstallItemServiceImpl() { } @Override public Item installItem(Context c, InProgressSubmission is) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { return installItem(c, is, null); } @Override public Item installItem(Context c, InProgressSubmission is, - String suppliedHandle) throws SQLException, - AuthorizeException - { + String suppliedHandle) throws SQLException, + AuthorizeException { Item item = is.getItem(); Collection collection = is.getCollection(); try { - if(suppliedHandle == null) - { + if (suppliedHandle == null) { identifierService.register(c, item); - }else{ + } else { identifierService.register(c, item, suppliedHandle); } } catch (IdentifierException e) { @@ -89,16 +84,14 @@ public class InstallItemServiceImpl implements InstallItemService @Override public Item restoreItem(Context c, InProgressSubmission is, - String suppliedHandle) - throws SQLException, IOException, AuthorizeException - { + String suppliedHandle) + throws SQLException, IOException, AuthorizeException { Item item = is.getItem(); try { - if(suppliedHandle == null) - { + if (suppliedHandle == null) { identifierService.register(c, item); - }else{ + } else { identifierService.register(c, item, suppliedHandle); } } catch (IdentifierException e) { @@ -108,35 +101,32 @@ public class InstallItemServiceImpl implements InstallItemService // Even though we are restoring an item it may not have the proper dates. So let's // double check its associated date(s) DCDate now = DCDate.getCurrent(); - + // If the item doesn't have a date.accessioned, set it to today - List dateAccessioned = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "accessioned", Item.ANY); - if (dateAccessioned.isEmpty()) - { - itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "accessioned", null, now.toString()); + List dateAccessioned = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "accessioned", Item.ANY); + if (dateAccessioned.isEmpty()) { + itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "accessioned", null, now.toString()); } - + // If issue date is set as "today" (literal string), then set it to current date // In the below loop, we temporarily clear all issued dates and re-add, one-by-one, // replacing "today" with today's date. // NOTE: As of DSpace 4.0, DSpace no longer sets an issue date by default - List currentDateIssued = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); + List currentDateIssued = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); itemService.clearMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); - for (MetadataValue dcv : currentDateIssued) - { - if(dcv.getValue()!=null && dcv.getValue().equalsIgnoreCase("today")) - { - DCDate issued = new DCDate(now.getYear(),now.getMonth(),now.getDay(),-1,-1,-1); + for (MetadataValue dcv : currentDateIssued) { + if (dcv.getValue() != null && dcv.getValue().equalsIgnoreCase("today")) { + DCDate issued = new DCDate(now.getYear(), now.getMonth(), now.getDay(), -1, -1, -1); itemService.addMetadata(c, item, dcv.getMetadataField(), dcv.getLanguage(), issued.toString()); - } - else if(dcv.getValue()!=null) - { + } else if (dcv.getValue() != null) { itemService.addMetadata(c, item, dcv.getMetadataField(), dcv.getLanguage(), dcv.getValue()); } } - + // Record that the item was restored - String provDescription = "Restored into DSpace on "+ now + " (GMT)."; + String provDescription = "Restored into DSpace on " + now + " (GMT)."; itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); return finishItem(c, item, is); @@ -144,8 +134,7 @@ public class InstallItemServiceImpl implements InstallItemService protected void populateMetadata(Context c, Item item) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { // create accession date DCDate now = DCDate.getCurrent(); itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "accessioned", null, now.toString()); @@ -154,8 +143,7 @@ public class InstallItemServiceImpl implements InstallItemService // be set when the embargo is lifted. // this will flush out fatal embargo metadata // problems before we set inArchive. - if (embargoService.getEmbargoTermsAsDate(c, item) == null) - { + if (embargoService.getEmbargoTermsAsDate(c, item) == null) { itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "available", null, now.toString()); } @@ -163,34 +151,29 @@ public class InstallItemServiceImpl implements InstallItemService // In the below loop, we temporarily clear all issued dates and re-add, one-by-one, // replacing "today" with today's date. // NOTE: As of DSpace 4.0, DSpace no longer sets an issue date by default - List currentDateIssued = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); + List currentDateIssued = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); itemService.clearMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); - for (MetadataValue dcv : currentDateIssued) - { - if(dcv.getValue()!=null && dcv.getValue().equalsIgnoreCase("today")) - { - DCDate issued = new DCDate(now.getYear(),now.getMonth(),now.getDay(),-1,-1,-1); + for (MetadataValue dcv : currentDateIssued) { + if (dcv.getValue() != null && dcv.getValue().equalsIgnoreCase("today")) { + DCDate issued = new DCDate(now.getYear(), now.getMonth(), now.getDay(), -1, -1, -1); itemService.addMetadata(c, item, dcv.getMetadataField(), dcv.getLanguage(), issued.toString()); - } - else if(dcv.getValue()!=null) - { + } else if (dcv.getValue() != null) { itemService.addMetadata(c, item, dcv.getMetadataField(), dcv.getLanguage(), dcv.getValue()); } } - String provDescription = "Made available in DSpace on " + now - + " (GMT). " + getBitstreamProvenanceMessage(c, item); + String provDescription = "Made available in DSpace on " + now + + " (GMT). " + getBitstreamProvenanceMessage(c, item); // If an issue date was passed in and it wasn't set to "today" (literal string) // then note this previous issue date in provenance message - if (!currentDateIssued.isEmpty()) - { + if (!currentDateIssued.isEmpty()) { String previousDateIssued = currentDateIssued.get(0).getValue(); - if(previousDateIssued!=null && !previousDateIssued.equalsIgnoreCase("today")) - { + if (previousDateIssued != null && !previousDateIssued.equalsIgnoreCase("today")) { DCDate d = new DCDate(previousDateIssued); provDescription = provDescription + " Previous issue date: " - + d.toString(); + + d.toString(); } } @@ -203,16 +186,15 @@ public class InstallItemServiceImpl implements InstallItemService * This method is used by *both* installItem() and restoreItem(), * so all actions here will be run for a newly added item or a restored item. * - * @param c DSpace Context + * @param c DSpace Context * @param item Item in question - * @param is InProgressSubmission object + * @param is InProgressSubmission object * @return final "archived" Item - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ protected Item finishItem(Context c, Item item, InProgressSubmission is) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { // create collection2item mapping collectionService.addItem(c, is.getCollection(), item); @@ -221,13 +203,13 @@ public class InstallItemServiceImpl implements InstallItemService // set in_archive=true item.setArchived(true); - + // save changes ;-) itemService.update(c, item); // Notify interested parties of newly archived Item c.addEvent(new Event(Event.INSTALL, Constants.ITEM, item.getID(), - item.getHandle(), itemService.getIdentifiers(c, item))); + item.getHandle(), itemService.getIdentifiers(c, item))); // remove in-progress submission contentServiceFactory.getInProgressSubmissionService(is).deleteWrapper(c, is); @@ -240,8 +222,7 @@ public class InstallItemServiceImpl implements InstallItemService @Override public String getBitstreamProvenanceMessage(Context context, Item myitem) - throws SQLException - { + throws SQLException { // Get non-internal format bitstreams List bitstreams = itemService.getNonInternalBitstreams(context, myitem); @@ -250,12 +231,11 @@ public class InstallItemServiceImpl implements InstallItemService myMessage.append("No. of bitstreams: ").append(bitstreams.size()).append("\n"); // Add sizes and checksums of bitstreams - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { myMessage.append(bitstream.getName()).append(": ") - .append(bitstream.getSize()).append(" bytes, checksum: ") - .append(bitstream.getChecksum()).append(" (") - .append(bitstream.getChecksumAlgorithm()).append(")\n"); + .append(bitstream.getSizeBytes()).append(" bytes, checksum: ") + .append(bitstream.getChecksum()).append(" (") + .append(bitstream.getChecksumAlgorithm()).append(")\n"); } return myMessage.toString(); diff --git a/dspace-api/src/main/java/org/dspace/content/Item.java b/dspace-api/src/main/java/org/dspace/content/Item.java index 49ab4b8caa..cfe86147f8 100644 --- a/dspace-api/src/main/java/org/dspace/content/Item.java +++ b/dspace-api/src/main/java/org/dspace/content/Item.java @@ -7,19 +7,34 @@ */ package org.dspace.content; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + import org.dspace.content.comparator.NameAscendingComparator; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import org.hibernate.annotations.Sort; -import org.hibernate.annotations.SortType; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.util.*; - /** * Class representing an item in DSpace. *

    @@ -35,49 +50,52 @@ import java.util.*; * @version $Revision$ */ @Entity -@Table(name="item") -public class Item extends DSpaceObject implements DSpaceObjectLegacySupport -{ +@Table(name = "item") +public class Item extends DSpaceObject implements DSpaceObjectLegacySupport { /** * Wild card for Dublin Core metadata qualifiers/languages */ public static final String ANY = "*"; - @Column(name="item_id", insertable = false, updatable = false) + @Column(name = "item_id", insertable = false, updatable = false) private Integer legacyId; - @Column(name= "in_archive") + @Column(name = "in_archive") private boolean inArchive = false; - @Column(name= "discoverable") + @Column(name = "discoverable") private boolean discoverable = false; - @Column(name= "withdrawn") + @Column(name = "withdrawn") private boolean withdrawn = false; - @Column(name= "last_modified", columnDefinition="timestamp with time zone") + @Column(name = "last_modified", columnDefinition = "timestamp with time zone") @Temporal(TemporalType.TIMESTAMP) private Date lastModified = new Date(); - @ManyToOne(fetch = FetchType.LAZY, cascade={CascadeType.PERSIST}) + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) @JoinColumn(name = "owning_collection") private Collection owningCollection; @OneToOne(fetch = FetchType.LAZY, mappedBy = "template") private Collection templateItemOf; - /** The e-person who submitted this item */ + /** + * The e-person who submitted this item + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "submitter_id") private EPerson submitter = null; - /** The bundles in this item - kept in sync with DB */ - @ManyToMany(fetch = FetchType.LAZY, cascade={CascadeType.PERSIST}) + /** + * The bundles in this item - kept in sync with DB + */ + @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) @JoinTable( - name = "collection2item", - joinColumns = {@JoinColumn(name = "item_id") }, - inverseJoinColumns = {@JoinColumn(name = "collection_id") } + name = "collection2item", + joinColumns = {@JoinColumn(name = "item_id")}, + inverseJoinColumns = {@JoinColumn(name = "collection_id")} ) private final Set collections = new HashSet<>(); @@ -90,10 +108,8 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport /** * Protected constructor, create object using: * {@link org.dspace.content.service.ItemService#create(Context, WorkspaceItem)} - * */ - protected Item() - { + protected Item() { } @@ -102,8 +118,7 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * * @return true if the item is in the main archive */ - public boolean isArchived() - { + public boolean isArchived() { return inArchive; } @@ -112,14 +127,14 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * * @return true if the item has been withdrawn */ - public boolean isWithdrawn() - { + public boolean isWithdrawn() { return withdrawn; } /** * Set an item to be withdrawn, do NOT make this method public, use itemService().withdraw() to withdraw an item + * * @param withdrawn */ void setWithdrawn(boolean withdrawn) { @@ -131,8 +146,7 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * * @return true if the item is discoverable */ - public boolean isDiscoverable() - { + public boolean isDiscoverable() { return discoverable; } @@ -141,10 +155,9 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * last_modified is null * * @return the date the item was last modified, or the current date if the - * column is null. + * column is null. */ - public Date getLastModified() - { + public Date getLastModified() { return lastModified; } @@ -156,11 +169,9 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * Set the "is_archived" flag. This is public and only * WorkflowItem.archive() should set this. * - * @param isArchived - * new value for the flag + * @param isArchived new value for the flag */ - public void setArchived(boolean isArchived) - { + public void setArchived(boolean isArchived) { this.inArchive = isArchived; setModified(); } @@ -168,11 +179,9 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport /** * Set the "discoverable" flag. This is public and only * - * @param discoverable - * new value for the flag + * @param discoverable new value for the flag */ - public void setDiscoverable(boolean discoverable) - { + public void setDiscoverable(boolean discoverable) { this.discoverable = discoverable; setModified(); } @@ -180,11 +189,9 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport /** * Set the owning Collection for the item * - * @param c - * Collection + * @param c Collection */ - public void setOwningCollection(Collection c) - { + public void setOwningCollection(Collection c) { this.owningCollection = c; setModified(); } @@ -194,8 +201,7 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * * @return Collection that is the owner of the item */ - public Collection getOwningCollection() - { + public Collection getOwningCollection() { return owningCollection; } @@ -204,8 +210,7 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * * @return the submitter */ - public EPerson getSubmitter() - { + public EPerson getSubmitter() { return submitter; } @@ -215,11 +220,9 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * package. update must be called to write the change to the * database. * - * @param sub - * the submitter + * @param sub the submitter */ - public void setSubmitter(EPerson sub) - { + public void setSubmitter(EPerson sub) { this.submitter = sub; setModified(); } @@ -229,26 +232,23 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * * @return the collections this item is in, if any. */ - public List getCollections() - { + public List getCollections() { // We return a copy because we do not want people to add elements to this collection directly. // We return a list to maintain backwards compatibility - Collection[] output = collections.toArray(new Collection[]{}); + Collection[] output = collections.toArray(new Collection[] {}); Arrays.sort(output, new NameAscendingComparator()); return Arrays.asList(output); } - void addCollection(Collection collection) - { + void addCollection(Collection collection) { collections.add(collection); } - void removeCollection(Collection collection) - { + void removeCollection(Collection collection) { collections.remove(collection); } - public void clearCollections(){ + public void clearCollections() { collections.clear(); } @@ -266,26 +266,45 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * * @return the bundles in an unordered array */ - public List getBundles() - { + public List getBundles() { return bundles; } + /** + * Get the bundles matching a bundle name (name corresponds roughly to type) + * + * @param name + * name of bundle (ORIGINAL/TEXT/THUMBNAIL) + * + * @return the bundles in an unordered array + */ + public List getBundles(String name) { + List matchingBundles = new ArrayList(); + // now only keep bundles with matching names + List bunds = getBundles(); + for (Bundle bundle : bunds) { + if (name.equals(bundle.getName())) { + matchingBundles.add(bundle); + } + } + return matchingBundles; + } + /** * Add a bundle to the item, should not be made public since we don't want to skip business logic + * * @param bundle the bundle to be added */ - void addBundle(Bundle bundle) - { + void addBundle(Bundle bundle) { bundles.add(bundle); } /** * Remove a bundle from item, should not be made public since we don't want to skip business logic + * * @param bundle the bundle to be removed */ - void removeBundle(Bundle bundle) - { + void removeBundle(Bundle bundle) { bundles.remove(bundle); } @@ -293,40 +312,33 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * Return true if other is the same Item as * this object, false otherwise * - * @param obj - * object to compare to + * @param obj object to compare to * @return true if object passed in represents the same item - * as this object + * as this object */ - @Override - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (this.getClass() != objClass) - { - return false; - } - final Item otherItem = (Item) obj; - if (!this.getID().equals(otherItem.getID())) - { - return false; - } + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); + if (this.getClass() != objClass) { + return false; + } + final Item otherItem = (Item) obj; + if (!this.getID().equals(otherItem.getID())) { + return false; + } + return true; + } - return true; - } - - @Override - public int hashCode() - { - int hash = 5; - hash += 71 * hash + getType(); - hash += 71 * hash + getID().hashCode(); - return hash; - } + @Override + public int hashCode() { + int hash = 5; + hash += 71 * hash + getType(); + hash += 71 * hash + getID().hashCode(); + return hash; + } /** * return type found in Constants @@ -334,14 +346,12 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport * @return int Constants.ITEM */ @Override - public int getType() - { + public int getType() { return Constants.ITEM; } @Override - public String getName() - { + public String getName() { return getItemService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); } @@ -350,10 +360,8 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport return legacyId; } - public ItemService getItemService() - { - if(itemService == null) - { + public ItemService getItemService() { + if (itemService == null) { itemService = ContentServiceFactory.getInstance().getItemService(); } return itemService; diff --git a/dspace-api/src/main/java/org/dspace/content/ItemComparator.java b/dspace-api/src/main/java/org/dspace/content/ItemComparator.java index ae55691c3d..27e869d40b 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemComparator.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemComparator.java @@ -8,7 +8,12 @@ package org.dspace.content; import java.io.Serializable; -import java.util.*; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.apache.commons.lang.builder.HashCodeBuilder; import org.dspace.content.factory.ContentServiceFactory; @@ -19,47 +24,49 @@ import org.dspace.sort.OrderFormat; * Compare two Items by their DCValues. * * The DCValues to be compared are specified by the element, qualifier and - language parameters to the constructor. If the Item has more than one - matching Metadatum, then the max parameter to the constructor specifies whether - the maximum or minimum lexicographic value will be used. + * language parameters to the constructor. If the Item has more than one + * matching Metadatum, then the max parameter to the constructor specifies whether + * the maximum or minimum lexicographic value will be used. * * @author Peter Breton * @version $Revision$ */ -public class ItemComparator implements Comparator, Serializable -{ - /** Dublin Core element */ +public class ItemComparator implements Comparator, Serializable { + /** + * Dublin Core element + */ protected String element; - /** Dublin Core qualifier */ + /** + * Dublin Core qualifier + */ protected String qualifier; - /** Language */ + /** + * Language + */ protected String language; - /** Whether maximum or minimum value will be used */ + /** + * Whether maximum or minimum value will be used + */ protected boolean max; protected transient ItemService itemService - = ContentServiceFactory.getInstance().getItemService(); + = ContentServiceFactory.getInstance().getItemService(); /** * Constructor. * - * @param element - * The Dublin Core element - * @param qualifier - * The Dublin Core qualifier - * @param language - * The language for the DCValues - * @param max - * If true, and there is more than one Metadatum for element, - qualifier and language, then use the maximum value - lexicographically; otherwise use the minimum value. + * @param element The Dublin Core element + * @param qualifier The Dublin Core qualifier + * @param language The language for the DCValues + * @param max If true, and there is more than one Metadatum for element, + * qualifier and language, then use the maximum value + * lexicographically; otherwise use the minimum value. */ public ItemComparator(String element, String qualifier, String language, - boolean max) - { + boolean max) { this.element = element; this.qualifier = qualifier; this.language = language; @@ -71,26 +78,22 @@ public class ItemComparator implements Comparator, Serializable * language. * *

    - * Return greater than or equal to 1 if the first is lexicographically greater than the second; + * Return greater than or equal to 1 if the first is lexicographically greater than the second; * less than or equal to -1 if the second is lexicographically greater than the first, and 0 * otherwise. *

    * - * @param first - * The first object to compare. Must be an object of type - * org.dspace.content.Item. - * @param second - * The second object to compare. Must be an object of type - * org.dspace.content.Item. - * @return greater than or equal 1 if the first is lexicographically greater than the second; - * less than or equal -1 if the second is lexicographically greater than the first, and - * 0 otherwise. + * @param first The first object to compare. Must be an object of type + * org.dspace.content.Item. + * @param second The second object to compare. Must be an object of type + * org.dspace.content.Item. + * @return greater than or equal 1 if the first is lexicographically greater than the second; + * less than or equal -1 if the second is lexicographically greater than the first, and + * 0 otherwise. */ @Override - public int compare(Object first, Object second) - { - if ((!(first instanceof Item)) || (!(second instanceof Item))) - { + public int compare(Object first, Object second) { + if ((!(first instanceof Item)) || (!(second instanceof Item))) { throw new IllegalArgumentException("Arguments must be Items"); } @@ -98,18 +101,15 @@ public class ItemComparator implements Comparator, Serializable String firstValue = getValue((Item) first); String secondValue = getValue((Item) second); - if (firstValue == null && secondValue == null) - { + if (firstValue == null && secondValue == null) { return 0; } - if (firstValue == null) - { + if (firstValue == null) { return -1; } - if (secondValue == null) - { + if (secondValue == null) { return 1; } @@ -123,46 +123,39 @@ public class ItemComparator implements Comparator, Serializable * object is equal to this one if it is also an ItemComparator, and has the * same values for element, qualifier, language, and max. * - * @param obj - * The object to compare to. + * @param obj The object to compare to. * @return True if the other object is equal to this one, false otherwise. */ @Override - public boolean equals(Object obj) - { - if (!(obj instanceof ItemComparator)) - { + public boolean equals(Object obj) { + if (!(obj instanceof ItemComparator)) { return false; } ItemComparator other = (ItemComparator) obj; return equalsWithNull(element, other.element) - && equalsWithNull(qualifier, other.qualifier) - && equalsWithNull(language, other.language) && (max == other.max); + && equalsWithNull(qualifier, other.qualifier) + && equalsWithNull(language, other.language) && (max == other.max); } @Override - public int hashCode() - { + public int hashCode() { return new HashCodeBuilder().append(element).append(qualifier).append(language).append(max).toHashCode(); } /** - * @param first first operand + * @param first first operand * @param second second operand * @return true if the first string is equal to the second. Either or both * may be null. */ - protected boolean equalsWithNull(String first, String second) - { - if (first == null && second == null) - { + protected boolean equalsWithNull(String first, String second) { + if (first == null && second == null) { return true; } - if (first == null || second == null) - { + if (first == null || second == null) { return false; } @@ -175,22 +168,19 @@ public class ItemComparator implements Comparator, Serializable * returned. Otherwise, either the maximum or minimum lexicographical value * is returned; the parameter to the constructor says which. * - * @param item - * The item to check + * @param item The item to check * @return The chosen value, or null */ - protected String getValue(Item item) - { + protected String getValue(Item item) { // The overall array and each element are guaranteed non-null - List dcvalues = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, element, qualifier, language); + List dcvalues = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, element, qualifier, language); - if (dcvalues.isEmpty()) - { + if (dcvalues.isEmpty()) { return null; } - if (dcvalues.size() == 1) - { + if (dcvalues.size() == 1) { return normalizeTitle(dcvalues.get(0)); } @@ -198,24 +188,21 @@ public class ItemComparator implements Comparator, Serializable // which Metadatum the value came from. Map values = new HashMap<>(); - for (int i = 0; i < dcvalues.size(); i++) - { + for (int i = 0; i < dcvalues.size(); i++) { String value = dcvalues.get(i).getValue(); - if (value != null) - { + if (value != null) { values.put(value, i); } } - if (values.isEmpty()) - { + if (values.isEmpty()) { return null; } Set valueSet = values.keySet(); String chosen = max ? Collections.max(valueSet) - : Collections.min(valueSet); + : Collections.min(valueSet); int index = values.get(chosen); @@ -224,14 +211,12 @@ public class ItemComparator implements Comparator, Serializable /** * Normalize the title of a Metadatum. - * + * * @param value metadata value * @return normalized title */ - protected String normalizeTitle(MetadataValue value) - { - if (!"title".equals(element)) - { + protected String normalizeTitle(MetadataValue value) { + if (!"title".equals(element)) { return value.getValue(); } diff --git a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java index c13ad27303..41dff1e5a6 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -16,7 +16,7 @@ import java.util.Iterator; import java.util.List; import java.util.UUID; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.util.AuthorizeUtil; @@ -90,19 +90,18 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It protected IdentifierService identifierService; @Autowired(required = true) protected VersioningService versioningService; - @Autowired(required=true) + @Autowired(required = true) protected HarvestedItemService harvestedItemService; - @Autowired(required=true) + @Autowired(required = true) protected ConfigurationService configurationService; - - @Autowired(required=true) - protected WorkspaceItemService workspaceItemService; - @Autowired(required=true) - protected WorkflowItemService workflowItemService; - - protected ItemServiceImpl() - { + @Autowired(required = true) + protected WorkspaceItemService workspaceItemService; + @Autowired(required = true) + protected WorkflowItemService workflowItemService; + + + protected ItemServiceImpl() { super(); } @@ -111,8 +110,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It Bitstream thumbBitstream; List originalBundles = getBundles(item, "ORIGINAL"); Bitstream primaryBitstream = null; - if(CollectionUtils.isNotEmpty(originalBundles)) - { + if (CollectionUtils.isNotEmpty(originalBundles)) { primaryBitstream = originalBundles.get(0).getPrimaryBitstream(); } if (primaryBitstream != null) { @@ -120,7 +118,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It return null; } - thumbBitstream = bitstreamService.getBitstreamByName(item, "THUMBNAIL", primaryBitstream.getName() + ".jpg"); + thumbBitstream = bitstreamService + .getBitstreamByName(item, "THUMBNAIL", primaryBitstream.getName() + ".jpg"); } else { if (requireOriginal) { @@ -143,7 +142,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It if (item == null) { if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_item", - "not_found,item_id=" + id)); + "not_found,item_id=" + id)); } return null; } @@ -151,7 +150,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It // not null, return item if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_item", "item_id=" - + id)); + + id)); } return item; @@ -160,22 +159,22 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It @Override public Item create(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException { if (workspaceItem.getItem() != null) { - throw new IllegalArgumentException("Attempting to create an item for a workspace item that already contains an item"); + throw new IllegalArgumentException( + "Attempting to create an item for a workspace item that already contains an item"); } Item item = createItem(context); workspaceItem.setItem(item); log.info(LogManager.getHeader(context, "create_item", "item_id=" - + item.getID())); + + item.getID())); return item; } @Override public Item createTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException { - if(collection == null || collection.getTemplateItem() != null) - { + if (collection == null || collection.getTemplateItem() != null) { throw new IllegalArgumentException("Collection is null or already contains template item."); } AuthorizeUtil.authorizeManageTemplateItem(context, collection); @@ -186,11 +185,11 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It template.setTemplateItemOf(collection); log.info(LogManager.getHeader(context, "create_template_item", - "collection_id=" + collection.getID() + ",template_item_id=" - + template.getID())); + "collection_id=" + collection.getID() + ",template_item_id=" + + template.getID())); return template; - }else{ + } else { return collection.getTemplateItem(); } } @@ -216,12 +215,14 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It } @Override - public Iterator findBySubmitterDateSorted(Context context, EPerson eperson, Integer limit) throws SQLException { + public Iterator findBySubmitterDateSorted(Context context, EPerson eperson, Integer limit) + throws SQLException { - MetadataField metadataField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "date", "accessioned"); - if(metadataField==null) - { - throw new IllegalArgumentException("Required metadata field '" + MetadataSchema.DC_SCHEMA + ".date.accessioned' doesn't exist!"); + MetadataField metadataField = metadataFieldService + .findByElement(context, MetadataSchema.DC_SCHEMA, "date", "accessioned"); + if (metadataField == null) { + throw new IllegalArgumentException( + "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".date.accessioned' doesn't exist!"); } return itemDAO.findBySubmitter(context, eperson, metadataField, limit); @@ -233,7 +234,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It } @Override - public Iterator findByCollection(Context context, Collection collection, Integer limit, Integer offset) throws SQLException { + public Iterator findByCollection(Context context, Collection collection, Integer limit, Integer offset) + throws SQLException { return itemDAO.findArchivedByCollection(context, collection, limit, offset); } @@ -242,13 +244,24 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It return itemDAO.findAllByCollection(context, collection); } + @Override + public Iterator findAllByCollection(Context context, Collection collection, Integer limit, Integer offset) + throws SQLException { + return itemDAO.findAllByCollection(context, collection, limit, offset); + } + @Override public Iterator findInArchiveOrWithdrawnDiscoverableModifiedSince(Context context, Date since) - throws SQLException - { + throws SQLException { return itemDAO.findAll(context, true, true, true, since); } + @Override + public Iterator findInArchiveOrWithdrawnNonDiscoverableModifiedSince(Context context, Date since) + throws SQLException { + return itemDAO.findAll(context, true, true, false, since); + } + @Override public void updateLastModified(Context context, Item item) throws SQLException, AuthorizeException { item.setLastModified(new Date()); @@ -293,7 +306,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It authorizeService.authorizeAction(context, item, Constants.ADD); log.info(LogManager.getHeader(context, "add_bundle", "item_id=" - + item.getID() + ",bundle_id=" + bundle.getID())); + + item.getID() + ",bundle_id=" + bundle.getID())); // Check it's not already there if (item.getBundles().contains(bundle)) { @@ -310,26 +323,28 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It bundle.addItem(item); context.addEvent(new Event(Event.ADD, Constants.ITEM, item.getID(), - Constants.BUNDLE, bundle.getID(), bundle.getName(), - getIdentifiers(context, item))); + Constants.BUNDLE, bundle.getID(), bundle.getName(), + getIdentifiers(context, item))); } @Override - public void removeBundle(Context context, Item item, Bundle bundle) throws SQLException, AuthorizeException, IOException { + public void removeBundle(Context context, Item item, Bundle bundle) + throws SQLException, AuthorizeException, IOException { // Check authorisation authorizeService.authorizeAction(context, item, Constants.REMOVE); log.info(LogManager.getHeader(context, "remove_bundle", "item_id=" - + item.getID() + ",bundle_id=" + bundle.getID())); + + item.getID() + ",bundle_id=" + bundle.getID())); context.addEvent(new Event(Event.REMOVE, Constants.ITEM, item.getID(), - Constants.BUNDLE, bundle.getID(), bundle.getName(), getIdentifiers(context, item))); + Constants.BUNDLE, bundle.getID(), bundle.getName(), getIdentifiers(context, item))); - bundleService.delete(context, bundle); + bundleService.delete(context, bundle); } @Override - public Bitstream createSingleBitstream(Context context, InputStream is, Item item, String name) throws AuthorizeException, IOException, SQLException { + public Bitstream createSingleBitstream(Context context, InputStream is, Item item, String name) + throws AuthorizeException, IOException, SQLException { // Authorisation is checked by methods below // Create a bundle Bundle bnd = bundleService.create(context, item, name); @@ -341,7 +356,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It } @Override - public Bitstream createSingleBitstream(Context context, InputStream is, Item item) throws AuthorizeException, IOException, SQLException { + public Bitstream createSingleBitstream(Context context, InputStream is, Item item) + throws AuthorizeException, IOException, SQLException { return createSingleBitstream(context, is, item, "ORIGINAL"); } @@ -379,7 +395,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It context.restoreAuthSystemState(); context.addEvent(new Event(Event.CREATE, Constants.ITEM, item.getID(), - null, getIdentifiers(context, item))); + null, getIdentifiers(context, item))); log.info(LogManager.getHeader(context, "create_item", "item_id=" + item.getID())); @@ -435,13 +451,12 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It public void update(Context context, Item item) throws SQLException, AuthorizeException { // Check authorisation // only do write authorization if user is not an editor - if (!canEdit(context, item)) - { + if (!canEdit(context, item)) { authorizeService.authorizeAction(context, item, Constants.WRITE); } log.info(LogManager.getHeader(context, "update_item", "item_id=" - + item.getID())); + + item.getID())); super.update(context, item); @@ -477,19 +492,19 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It } } - if (item.isMetadataModified() || item.isModified()) - { + if (item.isMetadataModified() || item.isModified()) { // Set the last modified date item.setLastModified(new Date()); itemDAO.save(context, item); - if(item.isMetadataModified()){ - context.addEvent(new Event(Event.MODIFY_METADATA, item.getType(), item.getID(), item.getDetails(), getIdentifiers(context, item))); + if (item.isMetadataModified()) { + context.addEvent(new Event(Event.MODIFY_METADATA, item.getType(), item.getID(), item.getDetails(), + getIdentifiers(context, item))); } context.addEvent(new Event(Event.MODIFY, Constants.ITEM, item.getID(), - null, getIdentifiers(context, item))); + null, getIdentifiers(context, item))); item.clearModified(); item.clearDetails(); } @@ -497,7 +512,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It @Override public void withdraw(Context context, Item item) throws SQLException, AuthorizeException { - // Check permission. User either has to have REMOVE on owning collection + // Check permission. User either has to have REMOVE on owning collection // or be COLLECTION_EDITOR of owning collection AuthorizeUtil.authorizeWithdrawItem(context, item); @@ -511,8 +526,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It StringBuilder prov = new StringBuilder(); prov.append("Item withdrawn by ").append(e.getFullName()).append(" (") - .append(e.getEmail()).append(") on ").append(timestamp).append("\n") - .append("Item was in collections:\n"); + .append(e.getEmail()).append(") on ").append(timestamp).append("\n") + .append("Item was in collections:\n"); List colls = item.getCollections(); @@ -534,7 +549,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It update(context, item); context.addEvent(new Event(Event.MODIFY, Constants.ITEM, item.getID(), - "WITHDRAW", getIdentifiers(context, item))); + "WITHDRAW", getIdentifiers(context, item))); // switch all READ authorization policies to WITHDRAWN_READ authorizeService.switchPoliciesAction(context, item, Constants.READ, Constants.WITHDRAWN_READ); @@ -547,12 +562,12 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It // Write log log.info(LogManager.getHeader(context, "withdraw_item", "user=" - + e.getEmail() + ",item_id=" + item.getID())); + + e.getEmail() + ",item_id=" + item.getID())); } @Override public void reinstate(Context context, Item item) throws SQLException, AuthorizeException { - // check authorization + // check authorization AuthorizeUtil.authorizeReinstateItem(context, item); String timestamp = DCDate.getCurrent().toString(); @@ -566,8 +581,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It EPerson e = context.getCurrentUser(); StringBuilder prov = new StringBuilder(); prov.append("Item reinstated by ").append(e.getFullName()).append(" (") - .append(e.getEmail()).append(") on ").append(timestamp).append("\n") - .append("Item was in collections:\n"); + .append(e.getEmail()).append(") on ").append(timestamp).append("\n") + .append("Item was in collections:\n"); for (Collection coll : colls) { prov.append(coll.getName()).append(" (ID: ").append(coll.getID()).append(")\n"); @@ -589,7 +604,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It update(context, item); context.addEvent(new Event(Event.MODIFY, Constants.ITEM, item.getID(), - "REINSTATE", getIdentifiers(context, item))); + "REINSTATE", getIdentifiers(context, item))); // restore all WITHDRAWN_READ authorization policies back to READ for (Bundle bnd : item.getBundles()) { @@ -602,26 +617,24 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It // check if the item was withdrawn before the fix DS-3097 if (authorizeService.getPoliciesActionFilter(context, item, Constants.WITHDRAWN_READ).size() != 0) { authorizeService.switchPoliciesAction(context, item, Constants.WITHDRAWN_READ, Constants.READ); - } - else { + } else { // authorization policies - if (colls.size() > 0) - { + if (colls.size() > 0) { // remove the item's policies and replace them with // the defaults from the collection adjustItemPolicies(context, item, item.getOwningCollection()); } } - + // Write log log.info(LogManager.getHeader(context, "reinstate_item", "user=" - + e.getEmail() + ",item_id=" + item.getID())); + + e.getEmail() + ",item_id=" + item.getID())); } @Override public void delete(Context context, Item item) throws SQLException, AuthorizeException, IOException { authorizeService.authorizeAction(context, item, Constants.DELETE); - rawDelete(context, item); + rawDelete(context, item); } @Override @@ -633,25 +646,24 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It authorizeService.authorizeAction(context, item, Constants.REMOVE); context.addEvent(new Event(Event.DELETE, Constants.ITEM, item.getID(), - item.getHandle(), getIdentifiers(context, item))); + item.getHandle(), getIdentifiers(context, item))); log.info(LogManager.getHeader(context, "delete_item", "item_id=" - + item.getID())); + + item.getID())); // Remove bundles removeAllBundles(context, item); // Remove any Handle handleService.unbindHandle(context, item); - + // remove version attached to the item removeVersion(context, item); // Also delete the item if it appears in a harvested collection. HarvestedItem hi = harvestedItemService.find(context, item); - if(hi!=null) - { + if (hi != null) { harvestedItemService.delete(context, hi); } @@ -666,31 +678,30 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It @Override public void removeAllBundles(Context context, Item item) throws AuthorizeException, SQLException, IOException { Iterator bundles = item.getBundles().iterator(); - while(bundles.hasNext()) - { + while (bundles.hasNext()) { Bundle bundle = bundles.next(); bundles.remove(); deleteBundle(context, item, bundle); } } - protected void deleteBundle(Context context, Item item, Bundle b) throws AuthorizeException, SQLException, IOException { - // Check authorisation - authorizeService.authorizeAction(context, item, Constants.REMOVE); + protected void deleteBundle(Context context, Item item, Bundle b) + throws AuthorizeException, SQLException, IOException { + // Check authorisation + authorizeService.authorizeAction(context, item, Constants.REMOVE); - bundleService.delete(context, b); + bundleService.delete(context, b); - log.info(LogManager.getHeader(context, "remove_bundle", "item_id=" - + item.getID() + ",bundle_id=" + b.getID())); - context.addEvent(new Event(Event.REMOVE, Constants.ITEM, item.getID(), Constants.BUNDLE, b.getID(), b.getName())); - } + log.info(LogManager.getHeader(context, "remove_bundle", "item_id=" + + item.getID() + ",bundle_id=" + b.getID())); + context + .addEvent(new Event(Event.REMOVE, Constants.ITEM, item.getID(), Constants.BUNDLE, b.getID(), b.getName())); + } - protected void removeVersion(Context context, Item item) throws AuthorizeException, SQLException - { - if(versioningService.getVersion(context, item)!=null) - { + protected void removeVersion(Context context, Item item) throws AuthorizeException, SQLException { + if (versioningService.getVersion(context, item) != null) { versioningService.removeVersion(context, item); - }else{ + } else { try { identifierService.delete(context, item); } catch (IdentifierException e) { @@ -707,14 +718,16 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It } @Override - public void replaceAllItemPolicies(Context context, Item item, List newpolicies) throws SQLException, AuthorizeException { + public void replaceAllItemPolicies(Context context, Item item, List newpolicies) + throws SQLException, AuthorizeException { // remove all our policies, add new ones authorizeService.removeAllPolicies(context, item); authorizeService.addPolicies(context, newpolicies, item); } @Override - public void replaceAllBitstreamPolicies(Context context, Item item, List newpolicies) throws SQLException, AuthorizeException { + public void replaceAllBitstreamPolicies(Context context, Item item, List newpolicies) + throws SQLException, AuthorizeException { // remove all policies from bundles, add new ones List bunds = item.getBundles(); @@ -745,22 +758,25 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It } @Override - public void inheritCollectionDefaultPolicies(Context context, Item item, Collection collection) throws SQLException, AuthorizeException { + public void inheritCollectionDefaultPolicies(Context context, Item item, Collection collection) + throws SQLException, AuthorizeException { adjustItemPolicies(context, item, collection); adjustBundleBitstreamPolicies(context, item, collection); log.debug(LogManager.getHeader(context, "item_inheritCollectionDefaultPolicies", - "item_id=" + item.getID())); + "item_id=" + item.getID())); } @Override - public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection) throws SQLException, AuthorizeException { - List defaultCollectionPolicies = authorizeService.getPoliciesActionFilter(context, collection, Constants.DEFAULT_BITSTREAM_READ); + public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection) + throws SQLException, AuthorizeException { + List defaultCollectionPolicies = authorizeService + .getPoliciesActionFilter(context, collection, Constants.DEFAULT_BITSTREAM_READ); - if (defaultCollectionPolicies.size() < 1){ + if (defaultCollectionPolicies.size() < 1) { throw new SQLException("Collection " + collection.getID() - + " (" + collection.getHandle() + ")" - + " has no default bitstream READ policies"); + + " (" + collection.getHandle() + ")" + + " has no default bitstream READ policies"); } // remove all policies from bundles, add new ones @@ -773,8 +789,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It authorizeService.removeAllPoliciesByDSOAndType(context, mybundle, ResourcePolicy.TYPE_WORKFLOW); addDefaultPoliciesNotInPlace(context, mybundle, defaultCollectionPolicies); - for(Bitstream bitstream : mybundle.getBitstreams()) - { + for (Bitstream bitstream : mybundle.getBitstreams()) { // if come from InstallItem: remove all submission/workflow policies authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_SUBMISSION); authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_WORKFLOW); @@ -784,16 +799,17 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It } @Override - public void adjustItemPolicies(Context context, Item item, Collection collection) throws SQLException, AuthorizeException { - // read collection's default READ policies - List defaultCollectionPolicies = authorizeService.getPoliciesActionFilter(context, collection, Constants.DEFAULT_ITEM_READ); + public void adjustItemPolicies(Context context, Item item, Collection collection) + throws SQLException, AuthorizeException { + // read collection's default READ policies + List defaultCollectionPolicies = authorizeService + .getPoliciesActionFilter(context, collection, Constants.DEFAULT_ITEM_READ); // MUST have default policies - if (defaultCollectionPolicies.size() < 1) - { + if (defaultCollectionPolicies.size() < 1) { throw new SQLException("Collection " + collection.getID() - + " (" + collection.getHandle() + ")" - + " has no default item READ policies"); + + " (" + collection.getHandle() + ")" + + " has no default item READ policies"); } try { @@ -806,26 +822,25 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It // add default policies only if not already in place addDefaultPoliciesNotInPlace(context, item, defaultCollectionPolicies); - } - finally - { + } finally { context.restoreAuthSystemState(); } } @Override - public void move(Context context, Item item, Collection from, Collection to) throws SQLException, AuthorizeException, IOException { + public void move(Context context, Item item, Collection from, Collection to) + throws SQLException, AuthorizeException, IOException { // Use the normal move method, and default to not inherit permissions this.move(context, item, from, to, false); } @Override - public void move(Context context, Item item, Collection from, Collection to, boolean inheritDefaultPolicies) throws SQLException, AuthorizeException, IOException { - // Check authorisation on the item before that the move occur + public void move(Context context, Item item, Collection from, Collection to, boolean inheritDefaultPolicies) + throws SQLException, AuthorizeException, IOException { + // Check authorisation on the item before that the move occur // otherwise we will need edit permission on the "target collection" to archive our goal // only do write authorization if user is not an editor - if (!canEdit(context, item)) - { + if (!canEdit(context, item)) { authorizeService.authorizeAction(context, item, Constants.WRITE); } @@ -834,20 +849,18 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It collectionService.removeItem(context, from, item); // If we are moving from the owning collection, update that too - if (isOwningCollection(item, from)) - { + if (isOwningCollection(item, from)) { // Update the owning collection log.info(LogManager.getHeader(context, "move_item", "item_id=" + item.getID() + ", from " + - "collection_id=" + from.getID() + " to " + - "collection_id=" + to.getID())); + "collection_id=" + from.getID() + " to " + + "collection_id=" + to.getID())); item.setOwningCollection(to); // If applicable, update the item policies - if (inheritDefaultPolicies) - { + if (inheritDefaultPolicies) { log.info(LogManager.getHeader(context, "move_item", - "Updating item with inherited policies")); + "Updating item with inherited policies")); inheritCollectionDefaultPolicies(context, item, to); } @@ -855,9 +868,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It context.turnOffAuthorisationSystem(); update(context, item); context.restoreAuthSystemState(); - } - else - { + } else { // Although we haven't actually updated anything within the item // we'll tell the event system that it has, so that any consumers that // care about the structure of the repository can take account of the move @@ -866,7 +877,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It // so we only do this here if the owning collection hasn't changed. context.addEvent(new Event(Event.MODIFY, Constants.ITEM, item.getID(), - null, getIdentifiers(context, item))); + null, getIdentifiers(context, item))); } } @@ -887,26 +898,21 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It List linkedCollections = item.getCollections(); List notLinkedCollections = new ArrayList<>(allCollections.size() - linkedCollections.size()); - if ((allCollections.size() - linkedCollections.size()) == 0) - { + if ((allCollections.size() - linkedCollections.size()) == 0) { return notLinkedCollections; } - for (Collection collection : allCollections) - { - boolean alreadyLinked = false; - for (Collection linkedCommunity : linkedCollections) - { - if (collection.getID().equals(linkedCommunity.getID())) - { - alreadyLinked = true; - break; - } - } + for (Collection collection : allCollections) { + boolean alreadyLinked = false; + for (Collection linkedCommunity : linkedCollections) { + if (collection.getID().equals(linkedCommunity.getID())) { + alreadyLinked = true; + break; + } + } - if (!alreadyLinked) - { - notLinkedCollections.add(collection); - } + if (!alreadyLinked) { + notLinkedCollections.add(collection); + } } return notLinkedCollections; @@ -916,18 +922,15 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It public boolean canEdit(Context context, Item item) throws SQLException { // can this person write to the item? if (authorizeService.authorizeActionBoolean(context, item, - Constants.WRITE)) - { + Constants.WRITE)) { return true; } // is this collection not yet created, and an item template is created - if (item.getOwningCollection() == null) - { + if (item.getOwningCollection() == null) { if (!isInProgressSubmission(context, item)) { return true; - } - else { + } else { return false; } } @@ -937,106 +940,97 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It /** * Check if the item is an inprogress submission - * - * @param context - * The relevant DSpace Context. - * @param item item to check + * + * @param context The relevant DSpace Context. + * @param item item to check * @return true if the item is an inprogress submission, i.e. a WorkspaceItem or WorkflowItem - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean isInProgressSubmission(Context context, Item item) throws SQLException { return workspaceItemService.findByItem(context, item) != null - || workflowItemService.findByItem(context, item) != null; + || workflowItemService.findByItem(context, item) != null; } - + /* - With every finished submission a bunch of resource policy entries which have null value for the dspace_object column are generated in the database. + With every finished submission a bunch of resource policy entries which have null value for the dspace_object + column are generated in the database. prevent the generation of resource policy entry values with null dspace_object as value */ /** * Add the default policies, which have not been already added to the given DSpace object - * - * @param context - * The relevant DSpace Context. - * @param dso - * The DSpace Object to add policies to - * @param defaultCollectionPolicies - * list of policies - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * + * @param context The relevant DSpace Context. + * @param dso The DSpace Object to add policies to + * @param defaultCollectionPolicies list of policies + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ - protected void addDefaultPoliciesNotInPlace(Context context, DSpaceObject dso, List defaultCollectionPolicies) throws SQLException, AuthorizeException - { - for (ResourcePolicy defaultPolicy : defaultCollectionPolicies) - { - if (!authorizeService.isAnIdenticalPolicyAlreadyInPlace(context, dso, defaultPolicy.getGroup(), Constants.READ, defaultPolicy.getID())) - { - ResourcePolicy newPolicy = resourcePolicyService.clone(context, defaultPolicy); - newPolicy.setdSpaceObject(dso); - newPolicy.setAction(Constants.READ); - newPolicy.setRpType(ResourcePolicy.TYPE_INHERITED); - resourcePolicyService.update(context, newPolicy); - } + protected void addDefaultPoliciesNotInPlace(Context context, DSpaceObject dso, + List defaultCollectionPolicies) + throws SQLException, AuthorizeException { + for (ResourcePolicy defaultPolicy : defaultCollectionPolicies) { + if (!authorizeService + .isAnIdenticalPolicyAlreadyInPlace(context, dso, defaultPolicy.getGroup(), Constants.READ, + defaultPolicy.getID())) { + ResourcePolicy newPolicy = resourcePolicyService.clone(context, defaultPolicy); + newPolicy.setdSpaceObject(dso); + newPolicy.setAction(Constants.READ); + newPolicy.setRpType(ResourcePolicy.TYPE_INHERITED); + resourcePolicyService.update(context, newPolicy); } + } } /** * Returns an iterator of Items possessing the passed metadata field, or only * those matching the passed value, if value is not Item.ANY * - * @param context DSpace context object - * @param schema metadata field schema - * @param element metadata field element + * @param context DSpace context object + * @param schema metadata field schema + * @param element metadata field element * @param qualifier metadata field qualifier - * @param value field value or Item.ANY to match any value + * @param value field value or Item.ANY to match any value * @return an iterator over the items matching that authority value - * @throws SQLException if database error - * An exception that provides information on a database access error or other errors. + * @throws SQLException if database error + * An exception that provides information on a database access error or other errors. * @throws AuthorizeException if authorization error - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws IOException if IO error - * A general class of exceptions produced by failed or interrupted I/O operations. - * + * Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws IOException if IO error + * A general class of exceptions produced by failed or interrupted I/O operations. */ @Override public Iterator findByMetadataField(Context context, - String schema, String element, String qualifier, String value) - throws SQLException, AuthorizeException, IOException - { + String schema, String element, String qualifier, String value) + throws SQLException, AuthorizeException, IOException { MetadataSchema mds = metadataSchemaService.find(context, schema); - if (mds == null) - { + if (mds == null) { throw new IllegalArgumentException("No such metadata schema: " + schema); } MetadataField mdf = metadataFieldService.findByElement(context, mds, element, qualifier); - if (mdf == null) - { + if (mdf == null) { throw new IllegalArgumentException( - "No such metadata field: schema=" + schema + ", element=" + element + ", qualifier=" + qualifier); + "No such metadata field: schema=" + schema + ", element=" + element + ", qualifier=" + qualifier); } - if (Item.ANY.equals(value)) - { + if (Item.ANY.equals(value)) { return itemDAO.findByMetadataField(context, mdf, null, true); - } - else - { + } else { return itemDAO.findByMetadataField(context, mdf, value, true); } } @Override - public Iterator findByMetadataQuery(Context context, List> listFieldList, List query_op, List query_val, List collectionUuids, String regexClause, int offset, int limit) - throws SQLException, AuthorizeException, IOException - { - return itemDAO.findByMetadataQuery(context, listFieldList, query_op, query_val, collectionUuids, regexClause, offset, limit); + public Iterator findByMetadataQuery(Context context, List> listFieldList, + List query_op, List query_val, List collectionUuids, + String regexClause, int offset, int limit) + throws SQLException, AuthorizeException, IOException { + return itemDAO + .findByMetadataQuery(context, listFieldList, query_op, query_val, collectionUuids, regexClause, offset, + limit); } @Override @@ -1045,68 +1039,46 @@ prevent the generation of resource policy entry values with null dspace_object a //Items are always owned by collections Collection collection = (Collection) getParentObject(context, item); Community community = null; - if (collection != null) - { - if(CollectionUtils.isNotEmpty(collection.getCommunities())) - { + if (collection != null) { + if (CollectionUtils.isNotEmpty(collection.getCommunities())) { community = collection.getCommunities().get(0); } } - switch (action) - { + switch (action) { case Constants.ADD: // ADD a cc license is less general than add a bitstream but we can't/won't // add complex logic here to know if the ADD action on the item is required by a cc or // a generic bitstream so simply we ignore it.. UI need to enforce the requirements. - if (AuthorizeConfiguration.canItemAdminPerformBitstreamCreation()) - { + if (AuthorizeConfiguration.canItemAdminPerformBitstreamCreation()) { adminObject = item; - } - else if (AuthorizeConfiguration.canCollectionAdminPerformBitstreamCreation()) - { + } else if (AuthorizeConfiguration.canCollectionAdminPerformBitstreamCreation()) { adminObject = collection; - } - else if (AuthorizeConfiguration.canCommunityAdminPerformBitstreamCreation()) - { + } else if (AuthorizeConfiguration.canCommunityAdminPerformBitstreamCreation()) { adminObject = community; } break; case Constants.REMOVE: // see comments on ADD action, same things... - if (AuthorizeConfiguration.canItemAdminPerformBitstreamDeletion()) - { + if (AuthorizeConfiguration.canItemAdminPerformBitstreamDeletion()) { adminObject = item; - } - else if (AuthorizeConfiguration.canCollectionAdminPerformBitstreamDeletion()) - { + } else if (AuthorizeConfiguration.canCollectionAdminPerformBitstreamDeletion()) { adminObject = collection; - } - else if (AuthorizeConfiguration.canCommunityAdminPerformBitstreamDeletion()) - { + } else if (AuthorizeConfiguration.canCommunityAdminPerformBitstreamDeletion()) { adminObject = community; } break; case Constants.DELETE: - if (item.getOwningCollection() != null) - { - if (AuthorizeConfiguration.canCollectionAdminPerformItemDeletion()) - { + if (item.getOwningCollection() != null) { + if (AuthorizeConfiguration.canCollectionAdminPerformItemDeletion()) { adminObject = collection; - } - else if (AuthorizeConfiguration.canCommunityAdminPerformItemDeletion()) - { + } else if (AuthorizeConfiguration.canCommunityAdminPerformItemDeletion()) { adminObject = community; } - } - else - { - if (AuthorizeConfiguration.canCollectionAdminManageTemplateItem()) - { + } else { + if (AuthorizeConfiguration.canCollectionAdminManageTemplateItem()) { adminObject = collection; - } - else if (AuthorizeConfiguration.canCommunityAdminManageCollectionTemplateItem()) - { + } else if (AuthorizeConfiguration.canCommunityAdminManageCollectionTemplateItem()) { adminObject = community; } } @@ -1114,63 +1086,37 @@ prevent the generation of resource policy entry values with null dspace_object a case Constants.WRITE: // if it is a template item we need to check the // collection/community admin configuration - if (item.getOwningCollection() == null) - { - if (AuthorizeConfiguration.canCollectionAdminManageTemplateItem()) - { + if (item.getOwningCollection() == null) { + if (AuthorizeConfiguration.canCollectionAdminManageTemplateItem()) { adminObject = collection; - } - else if (AuthorizeConfiguration.canCommunityAdminManageCollectionTemplateItem()) - { + } else if (AuthorizeConfiguration.canCommunityAdminManageCollectionTemplateItem()) { adminObject = community; } - } - else - { + } else { adminObject = item; } break; default: adminObject = item; break; - } + } return adminObject; } @Override public DSpaceObject getParentObject(Context context, Item item) throws SQLException { Collection ownCollection = item.getOwningCollection(); - if (ownCollection != null) - { + if (ownCollection != null) { return ownCollection; - } - else - { + } else { // is a template item? return item.getTemplateItemOf(); } } @Override - public Iterator findByAuthorityValue(Context context, String schema, String element, String qualifier, String value) throws SQLException, AuthorizeException { - MetadataSchema mds = metadataSchemaService.find(context, schema); - if (mds == null) - { - throw new IllegalArgumentException("No such metadata schema: " + schema); - } - MetadataField mdf = metadataFieldService.findByElement(context, mds, element, qualifier); - if (mdf == null) - { - throw new IllegalArgumentException("No such metadata field: schema=" + schema + ", element=" + element + ", qualifier=" + qualifier); - } - - return itemDAO.findByAuthorityValue(context, mdf, value, true); - } - - @Override - public Iterator findByMetadataFieldAuthority(Context context, String mdString, String authority) throws SQLException, AuthorizeException { - String[] elements = getElementsFilled(mdString); - String schema = elements[0], element = elements[1], qualifier = elements[2]; + public Iterator findByAuthorityValue(Context context, String schema, String element, String qualifier, + String value) throws SQLException, AuthorizeException { MetadataSchema mds = metadataSchemaService.find(context, schema); if (mds == null) { throw new IllegalArgumentException("No such metadata schema: " + schema); @@ -1178,7 +1124,27 @@ prevent the generation of resource policy entry values with null dspace_object a MetadataField mdf = metadataFieldService.findByElement(context, mds, element, qualifier); if (mdf == null) { throw new IllegalArgumentException( - "No such metadata field: schema=" + schema + ", element=" + element + ", qualifier=" + qualifier); + "No such metadata field: schema=" + schema + ", element=" + element + ", qualifier=" + qualifier); + } + + return itemDAO.findByAuthorityValue(context, mdf, value, true); + } + + @Override + public Iterator findByMetadataFieldAuthority(Context context, String mdString, String authority) + throws SQLException, AuthorizeException { + String[] elements = getElementsFilled(mdString); + String schema = elements[0]; + String element = elements[1]; + String qualifier = elements[2]; + MetadataSchema mds = metadataSchemaService.find(context, schema); + if (mds == null) { + throw new IllegalArgumentException("No such metadata schema: " + schema); + } + MetadataField mdf = metadataFieldService.findByElement(context, mds, element, qualifier); + if (mdf == null) { + throw new IllegalArgumentException( + "No such metadata field: schema=" + schema + ", element=" + element + ", qualifier=" + qualifier); } return findByAuthorityValue(context, mds.getName(), mdf.getElement(), mdf.getQualifier(), authority); } @@ -1190,7 +1156,7 @@ prevent the generation of resource policy entry values with null dspace_object a return true; } if (authorizeService.authorizeActionBoolean(context, item, org.dspace.core.Constants.READ)) { - if(item.isDiscoverable()) { + if (item.isDiscoverable()) { return true; } } @@ -1207,30 +1173,44 @@ prevent the generation of resource policy entry values with null dspace_object a return itemDAO.countItems(context, collection, true, false); } + @Override + public int countAllItems(Context context, Collection collection) throws SQLException { + return itemDAO.countItems(context, collection, true, false) + itemDAO.countItems(context, collection, + false, true); + } + @Override public int countItems(Context context, Community community) throws SQLException { // First we need a list of all collections under this community in the hierarchy List collections = communityService.getAllCollections(context, community); - + // Now, lets count unique items across that list of collections return itemDAO.countItems(context, collections, true, false); } @Override - protected void getAuthoritiesAndConfidences(String fieldKey, Collection collection, List values, List authorities, List confidences, int i) { + public int countAllItems(Context context, Community community) throws SQLException { + // First we need a list of all collections under this community in the hierarchy + List collections = communityService.getAllCollections(context, community); + + // Now, lets count unique items across that list of collections + return itemDAO.countItems(context, collections, true, false) + itemDAO.countItems(context, collections, + false, true); + } + + @Override + protected void getAuthoritiesAndConfidences(String fieldKey, Collection collection, List values, + List authorities, List confidences, int i) { Choices c = choiceAuthorityService.getBestMatch(fieldKey, values.get(i), collection, null); - authorities.add(c.values.length > 0 ? c.values[0].authority : null); + authorities.add(c.values.length > 0 && c.values[0] != null ? c.values[0].authority : null); confidences.add(c.confidence); } @Override public Item findByIdOrLegacyId(Context context, String id) throws SQLException { - if(StringUtils.isNumeric(id)) - { + if (StringUtils.isNumeric(id)) { return findByLegacyId(context, Integer.parseInt(id)); - } - else - { + } else { return find(context, UUID.fromString(id)); } } @@ -1242,8 +1222,7 @@ prevent the generation of resource policy entry values with null dspace_object a @Override public Iterator findByLastModifiedSince(Context context, Date last) - throws SQLException - { + throws SQLException { return itemDAO.findByLastModifiedSince(context, last); } @@ -1260,22 +1239,20 @@ prevent the generation of resource policy entry values with null dspace_object a @Override public int countWithdrawnItems(Context context) throws SQLException { - // return count of items that are not in archive and withdrawn - return itemDAO.countItems(context, false, true); + // return count of items that are not in archive and withdrawn + return itemDAO.countItems(context, false, true); } @Override - public boolean canCreateNewVersion(Context context, Item item) throws SQLException{ - if (authorizeService.isAdmin(context, item)) - { + public boolean canCreateNewVersion(Context context, Item item) throws SQLException { + if (authorizeService.isAdmin(context, item)) { return true; } if (context.getCurrentUser() != null - && context.getCurrentUser().equals(item.getSubmitter())) - { + && context.getCurrentUser().equals(item.getSubmitter())) { return configurationService.getPropertyAsType( - "versioning.submitterCanCreateNewVersion", false); + "versioning.submitterCanCreateNewVersion", false); } return false; diff --git a/dspace-api/src/main/java/org/dspace/content/LicenseUtils.java b/dspace-api/src/main/java/org/dspace/content/LicenseUtils.java index 813d92481e..be804a9bbb 100644 --- a/dspace-api/src/main/java/org/dspace/content/LicenseUtils.java +++ b/dspace-api/src/main/java/org/dspace/content/LicenseUtils.java @@ -27,17 +27,22 @@ import org.dspace.eperson.EPerson; /** * Utility class to manage generation and storing of the license text that the * submitter has to grant/granted for archiving the item - * + * * @author bollini - * */ -public class LicenseUtils -{ +public class LicenseUtils { private static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - private static final BitstreamFormatService bitstreamFormat = ContentServiceFactory.getInstance().getBitstreamFormatService(); - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final BitstreamFormatService bitstreamFormat = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); + private static final CollectionService collectionService = ContentServiceFactory.getInstance() + .getCollectionService(); private static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); + /** + * Default constructor + */ + private LicenseUtils() { } + /** * Return the text of the license that the user has granted/must grant * before for submit the item. The license text is build using the template @@ -55,23 +60,17 @@ public class LicenseUtils * LicenseArgumentFormatter plugin (if defined)
    * {x} any addition argument supplied wrapped in the * LicenseArgumentFormatter based on his type (map key) - * - * @param locale - * Formatter locale - * @param collection - * collection to get license from - * @param item - * the item object of the license - * @param eperson - * EPerson to get firstname, lastname and email from - * @param additionalInfo - * additional template arguments beyond 0-6 + * + * @param locale Formatter locale + * @param collection collection to get license from + * @param item the item object of the license + * @param eperson EPerson to get firstname, lastname and email from + * @param additionalInfo additional template arguments beyond 0-6 * @return the license text obtained substituting the provided argument in - * the license template + * the license template */ public static String getLicenseText(Locale locale, Collection collection, - Item item, EPerson eperson, Map additionalInfo) - { + Item item, EPerson eperson, Map additionalInfo) { Formatter formatter = new Formatter(locale); // EPerson firstname, lastname, email and the current date @@ -88,11 +87,9 @@ public class LicenseUtils args[5] = new FormattableArgument("item", item); args[6] = new FormattableArgument("eperson", eperson); - if (additionalInfo != null) - { + if (additionalInfo != null) { int i = 7; // Start is next index after previous args - for (Map.Entry info : additionalInfo.entrySet()) - { + for (Map.Entry info : additionalInfo.entrySet()) { args[i] = new FormattableArgument(info.getKey(), info.getValue()); i++; } @@ -108,39 +105,31 @@ public class LicenseUtils * license template. (equivalent to calling the full getLicenseText * supplying {@code null} for the additionalInfo argument) * - * @param locale - * Formatter locale - * @param collection - * collection to get license from - * @param item - * the item object of the license - * @param eperson - * EPerson to get firstname, lastname and email from + * @param locale Formatter locale + * @param collection collection to get license from + * @param item the item object of the license + * @param eperson EPerson to get firstname, lastname and email from * @return the license text, with no custom substitutions. */ public static String getLicenseText(Locale locale, Collection collection, - Item item, EPerson eperson) - { + Item item, EPerson eperson) { return getLicenseText(locale, collection, item, eperson, null); } /** * Store a copy of the license a user granted in the item. - * - * @param context - * the dspace context - * @param item - * the item object of the license - * @param licenseText - * the license the user granted - * @throws SQLException if database error - * @throws IOException if IO error + * + * @param context the dspace context + * @param item the item object of the license + * @param licenseText the license the user granted + * @param acceptanceDate TODO + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ public static void grantLicense(Context context, Item item, - String licenseText) throws SQLException, IOException, - AuthorizeException - { + String licenseText, String acceptanceDate) throws SQLException, IOException, + AuthorizeException { // Put together text to store // String licenseText = "License granted by " + eperson.getFullName() // + " (" + eperson.getEmail() + ") on " @@ -155,9 +144,14 @@ public class LicenseUtils b.setName(context, "license.txt"); b.setSource(context, "Written by org.dspace.content.LicenseUtils"); + DCDate acceptanceDCDate = DCDate.getCurrent(); + if (acceptanceDate != null) { + acceptanceDCDate = new DCDate(acceptanceDate); + } + b.setAcceptanceDate(context, acceptanceDCDate); // Find the License format BitstreamFormat bf = bitstreamFormat.findByShortDescription(context, - "License"); + "License"); b.setFormat(bf); bitstreamService.update(context, b); diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataField.java b/dspace-api/src/main/java/org/dspace/content/MetadataField.java index 329537f31e..3f574dab0e 100644 --- a/dspace-api/src/main/java/org/dspace/content/MetadataField.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataField.java @@ -7,14 +7,24 @@ */ package org.dspace.content; +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; - /** * DSpace object that represents a metadata field, which is @@ -29,17 +39,18 @@ import javax.persistence.*; @Entity @Cacheable @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@Table(name="metadatafieldregistry") +@Table(name = "metadatafieldregistry") public class MetadataField implements ReloadableEntity { @Id - @Column(name="metadata_field_id", nullable = false, unique = true) - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="metadatafieldregistry_seq") - @SequenceGenerator(name="metadatafieldregistry_seq", sequenceName="metadatafieldregistry_seq", allocationSize = 1, initialValue = 1) + @Column(name = "metadata_field_id", nullable = false, unique = true) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "metadatafieldregistry_seq") + @SequenceGenerator(name = "metadatafieldregistry_seq", sequenceName = "metadatafieldregistry_seq", allocationSize + = 1, initialValue = 1) private Integer id; @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "metadata_schema_id",nullable = false) + @JoinColumn(name = "metadata_schema_id", nullable = false) private MetadataSchema metadataSchema; @Column(name = "element", length = 64) @@ -48,18 +59,16 @@ public class MetadataField implements ReloadableEntity { @Column(name = "qualifier", length = 64) private String qualifier = null; -// @Column(name = "scope_note") + // @Column(name = "scope_note") // @Lob - @Column(name="scope_note", columnDefinition = "text") + @Column(name = "scope_note", columnDefinition = "text") private String scopeNote; /** * Protected constructor, create object using: * {@link org.dspace.content.service.MetadataFieldService#create(Context, MetadataSchema, String, String, String)} - * */ - protected MetadataField() - { + protected MetadataField() { } @@ -68,8 +77,7 @@ public class MetadataField implements ReloadableEntity { * * @return metadata field id */ - public Integer getID() - { + public Integer getID() { return id; } @@ -78,8 +86,7 @@ public class MetadataField implements ReloadableEntity { * * @return element name */ - public String getElement() - { + public String getElement() { return element; } @@ -88,8 +95,7 @@ public class MetadataField implements ReloadableEntity { * * @param element new value for element */ - public void setElement(String element) - { + public void setElement(String element) { this.element = element; } @@ -98,8 +104,7 @@ public class MetadataField implements ReloadableEntity { * * @return qualifier */ - public String getQualifier() - { + public String getQualifier() { return qualifier; } @@ -108,8 +113,7 @@ public class MetadataField implements ReloadableEntity { * * @param qualifier new value for qualifier */ - public void setQualifier(String qualifier) - { + public void setQualifier(String qualifier) { this.qualifier = qualifier; } @@ -118,8 +122,7 @@ public class MetadataField implements ReloadableEntity { * * @return scope note */ - public String getScopeNote() - { + public String getScopeNote() { return scopeNote; } @@ -128,8 +131,7 @@ public class MetadataField implements ReloadableEntity { * * @param scopeNote new value for scope note */ - public void setScopeNote(String scopeNote) - { + public void setScopeNote(String scopeNote) { this.scopeNote = scopeNote; } @@ -152,44 +154,35 @@ public class MetadataField implements ReloadableEntity { } - /** * Return true if other is the same MetadataField * as this object, false otherwise * - * @param obj - * object to compare to - * + * @param obj object to compare to * @return true if object passed in represents the same - * MetadataField as this object + * MetadataField as this object */ @Override - public boolean equals(Object obj) - { - if (obj == null) - { + public boolean equals(Object obj) { + if (obj == null) { return false; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } final MetadataField other = (MetadataField) obj; - if (this.getID() != other.getID()) - { + if (this.getID() != other.getID()) { return false; } - if (!getMetadataSchema().equals(other.getMetadataSchema())) - { + if (!getMetadataSchema().equals(other.getMetadataSchema())) { return false; } return true; } @Override - public int hashCode() - { + public int hashCode() { int hash = 7; hash = 47 * hash + getID(); hash = 47 * hash + getMetadataSchema().getID(); @@ -197,12 +190,9 @@ public class MetadataField implements ReloadableEntity { } public String toString(char separator) { - if (qualifier == null) - { + if (qualifier == null) { return getMetadataSchema().getName() + separator + element; - } - else - { + } else { return getMetadataSchema().getName() + separator + element + separator + qualifier; } } diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataFieldServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/MetadataFieldServiceImpl.java index 490ab7fef8..c48ff015e4 100644 --- a/dspace-api/src/main/java/org/dspace/content/MetadataFieldServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataFieldServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.content; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; @@ -17,11 +22,6 @@ import org.dspace.core.Context; import org.dspace.core.LogManager; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import org.apache.commons.collections.CollectionUtils; - /** * Service implementation for the MetadataField object. * This class is responsible for all business logic calls for the MetadataField object and is autowired by spring. @@ -30,7 +30,9 @@ import org.apache.commons.collections.CollectionUtils; * @author kevinvandevelde at atmire.com */ public class MetadataFieldServiceImpl implements MetadataFieldService { - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(MetadataFieldServiceImpl.class); @Autowired(required = true) @@ -41,25 +43,23 @@ public class MetadataFieldServiceImpl implements MetadataFieldService { @Autowired(required = true) protected MetadataValueService metadataValueService; - protected MetadataFieldServiceImpl() - { + protected MetadataFieldServiceImpl() { } @Override - public MetadataField create(Context context, MetadataSchema metadataSchema, String element, String qualifier, String scopeNote) throws AuthorizeException, SQLException, NonUniqueMetadataException { + public MetadataField create(Context context, MetadataSchema metadataSchema, String element, String qualifier, + String scopeNote) throws AuthorizeException, SQLException, NonUniqueMetadataException { // Check authorisation: Only admins may create DC types - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators may modify the metadata registry"); + "Only administrators may modify the metadata registry"); } // Ensure the element and qualifier are unique within a given schema. - if (hasElement(context, -1, metadataSchema, element, qualifier)) - { + if (hasElement(context, -1, metadataSchema, element, qualifier)) { throw new NonUniqueMetadataException("Please make " + element + "." - + qualifier + " unique within schema #" + metadataSchema.getID()); + + qualifier + " unique within schema #" + metadataSchema.getID()); } // Create a table row and update it with the values @@ -72,35 +72,36 @@ public class MetadataFieldServiceImpl implements MetadataFieldService { metadataFieldDAO.save(context, metadataField); log.info(LogManager.getHeader(context, "create_metadata_field", - "metadata_field_id=" + metadataField.getID())); + "metadata_field_id=" + metadataField.getID())); return metadataField; } @Override - public MetadataField find(Context context, int id) throws SQLException - { + public MetadataField find(Context context, int id) throws SQLException { return metadataFieldDAO.findByID(context, MetadataField.class, id); } @Override - public MetadataField findByElement(Context context, MetadataSchema metadataSchema, String element, String qualifier) throws SQLException { + public MetadataField findByElement(Context context, MetadataSchema metadataSchema, String element, String qualifier) + throws SQLException { return metadataFieldDAO.findByElement(context, metadataSchema, element, qualifier); } @Override - public MetadataField findByElement(Context context, String metadataSchemaName, String element, String qualifier) throws SQLException { + public MetadataField findByElement(Context context, String metadataSchemaName, String element, String qualifier) + throws SQLException { return metadataFieldDAO.findByElement(context, metadataSchemaName, element, qualifier); } @Override - public List findFieldsByElementNameUnqualified(Context context, String metadataSchemaName, String element) throws SQLException { + public List findFieldsByElementNameUnqualified(Context context, String metadataSchemaName, + String element) throws SQLException { return metadataFieldDAO.findFieldsByElementNameUnqualified(context, metadataSchemaName, element); } @Override - public List findAll(Context context) throws SQLException - { + public List findAll(Context context) throws SQLException { return metadataFieldDAO.findAll(context, MetadataField.class); } @@ -110,60 +111,56 @@ public class MetadataFieldServiceImpl implements MetadataFieldService { } @Override - public void update(Context context, MetadataField metadataField) throws SQLException, AuthorizeException, NonUniqueMetadataException, IOException { - // Check authorisation: Only admins may update the metadata registry - if (!authorizeService.isAdmin(context)) - { + public void update(Context context, MetadataField metadataField) + throws SQLException, AuthorizeException, NonUniqueMetadataException, IOException { + // Check authorisation: Only admins may update the metadata registry + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators may modiffy the Dublin Core registry"); + "Only administrators may modiffy the Dublin Core registry"); } // Ensure the element and qualifier are unique within a given schema. - if (hasElement(context, metadataField.getID(), metadataField.getMetadataSchema(), metadataField.getElement(), metadataField.getQualifier())) - { - throw new NonUniqueMetadataException("Please make " + metadataField.getMetadataSchema().getName() + "." + metadataField.getElement() + "." + if (hasElement(context, metadataField.getID(), metadataField.getMetadataSchema(), metadataField.getElement(), + metadataField.getQualifier())) { + throw new NonUniqueMetadataException( + "Please make " + metadataField.getMetadataSchema().getName() + "." + metadataField.getElement() + "." + metadataField.getQualifier()); } metadataFieldDAO.save(context, metadataField); log.info(LogManager.getHeader(context, "update_metadatafieldregistry", - "metadata_field_id=" + metadataField.getID() + "element=" + metadataField.getElement() - + "qualifier=" + metadataField.getQualifier())); + "metadata_field_id=" + metadataField.getID() + "element=" + metadataField + .getElement() + + "qualifier=" + metadataField.getQualifier())); } @Override public void delete(Context context, MetadataField metadataField) throws SQLException, AuthorizeException { // Check authorisation: Only admins may create DC types - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators may modify the metadata registry"); + "Only administrators may modify the metadata registry"); } // Check for existing usages of this field List values = null; - try - { - values = metadataValueService.findByField(context, metadataField); - } - catch(IOException io) - { + try { + values = metadataValueService.findByField(context, metadataField); + } catch (IOException io) { // ignore } // Only remove this field if it is NOT in use (as we don't want to bulk delete metadata values) - if(CollectionUtils.isEmpty(values)) - { + if (CollectionUtils.isEmpty(values)) { metadataFieldDAO.delete(context, metadataField); - } - else - { - throw new IllegalStateException("Metadata field " + metadataField.toString() + " cannot be deleted as it is currently used by one or more objects."); + } else { + throw new IllegalStateException("Metadata field " + metadataField + .toString() + " cannot be deleted as it is currently used by one or more objects."); } log.info(LogManager.getHeader(context, "delete_metadata_field", - "metadata_field_id=" + metadataField.getID())); + "metadata_field_id=" + metadataField.getID())); } /** @@ -171,16 +168,16 @@ public class MetadataFieldServiceImpl implements MetadataFieldService { * within a given schema. The check happens in code as we cannot use a * database constraint. * - * @param context dspace context - * @param fieldId field id + * @param context dspace context + * @param fieldId field id * @param metadataSchema metadataSchema - * @param element element - * @param qualifier qualifier + * @param element element + * @param qualifier qualifier * @return true if unique * @throws SQLException if database error */ - protected boolean hasElement(Context context, int fieldId, MetadataSchema metadataSchema, String element, String qualifier) throws SQLException - { + protected boolean hasElement(Context context, int fieldId, MetadataSchema metadataSchema, String element, + String qualifier) throws SQLException { return metadataFieldDAO.find(context, fieldId, metadataSchema, element, qualifier) != null; } diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataSchema.java b/dspace-api/src/main/java/org/dspace/content/MetadataSchema.java index e877261c15..511cda3f7b 100644 --- a/dspace-api/src/main/java/org/dspace/content/MetadataSchema.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataSchema.java @@ -7,13 +7,20 @@ */ package org.dspace.content; +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; - /** * Class representing a schema in DSpace. *

    @@ -30,16 +37,18 @@ import javax.persistence.*; @Entity @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@Table(name="metadataschemaregistry") -public class MetadataSchema implements ReloadableEntity -{ - /** Short Name of built-in Dublin Core schema. */ +@Table(name = "metadataschemaregistry") +public class MetadataSchema implements ReloadableEntity { + /** + * Short Name of built-in Dublin Core schema. + */ public static final String DC_SCHEMA = "dc"; @Id - @Column(name="metadata_schema_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="metadataschemaregistry_seq") - @SequenceGenerator(name="metadataschemaregistry_seq", sequenceName="metadataschemaregistry_seq", allocationSize = 1) + @Column(name = "metadata_schema_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "metadataschemaregistry_seq") + @SequenceGenerator(name = "metadataschemaregistry_seq", sequenceName = "metadataschemaregistry_seq", + allocationSize = 1) private Integer id; @Column(name = "namespace", unique = true, length = 256) @@ -51,40 +60,32 @@ public class MetadataSchema implements ReloadableEntity /** * Protected constructor, create object using: * {@link org.dspace.content.service.MetadataSchemaService#create(Context, String, String)} - * */ - protected MetadataSchema() - { + protected MetadataSchema() { } @Override - public boolean equals(Object obj) - { - if (obj == null) - { + public boolean equals(Object obj) { + if (obj == null) { return false; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } final MetadataSchema other = (MetadataSchema) obj; - if (this.id != other.id) - { + if (this.id != other.id) { return false; } - if ((this.namespace == null) ? (other.namespace != null) : !this.namespace.equals(other.namespace)) - { + if ((this.namespace == null) ? (other.namespace != null) : !this.namespace.equals(other.namespace)) { return false; } return true; } @Override - public int hashCode() - { + public int hashCode() { int hash = 5; hash = 67 * hash + this.id; hash = 67 * hash + (this.namespace != null ? this.namespace.hashCode() : 0); @@ -96,18 +97,16 @@ public class MetadataSchema implements ReloadableEntity * * @return namespace String */ - public String getNamespace() - { + public String getNamespace() { return namespace; } /** * Set the schema namespace. * - * @param namespace XML namespace URI + * @param namespace XML namespace URI */ - public void setNamespace(String namespace) - { + public void setNamespace(String namespace) { this.namespace = namespace; } @@ -116,18 +115,16 @@ public class MetadataSchema implements ReloadableEntity * * @return name String */ - public String getName() - { + public String getName() { return name; } /** * Set the schema name. * - * @param name short name of schema + * @param name short name of schema */ - public void setName(String name) - { + public void setName(String name) { this.name = name; } @@ -136,8 +133,7 @@ public class MetadataSchema implements ReloadableEntity * * @return schema record key */ - public Integer getID() - { + public Integer getID() { return id; } } diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataSchemaServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/MetadataSchemaServiceImpl.java index 601a90a976..f2b13fb8ea 100644 --- a/dspace-api/src/main/java/org/dspace/content/MetadataSchemaServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataSchemaServiceImpl.java @@ -7,6 +7,9 @@ */ package org.dspace.content; +import java.sql.SQLException; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; @@ -16,9 +19,6 @@ import org.dspace.core.Context; import org.dspace.core.LogManager; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.List; - /** * Service implementation for the MetadataSchema object. * This class is responsible for all business logic calls for the MetadataSchema object and is autowired by spring. @@ -28,7 +28,9 @@ import java.util.List; */ public class MetadataSchemaServiceImpl implements MetadataSchemaService { - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(MetadataSchemaServiceImpl.class); @Autowired(required = true) @@ -37,32 +39,29 @@ public class MetadataSchemaServiceImpl implements MetadataSchemaService { @Autowired(required = true) protected MetadataSchemaDAO metadataSchemaDAO; - protected MetadataSchemaServiceImpl() - { + protected MetadataSchemaServiceImpl() { } @Override - public MetadataSchema create(Context context, String name, String namespace) throws SQLException, AuthorizeException, NonUniqueMetadataException { - // Check authorisation: Only admins may create metadata schemas - if (!authorizeService.isAdmin(context)) - { + public MetadataSchema create(Context context, String name, String namespace) + throws SQLException, AuthorizeException, NonUniqueMetadataException { + // Check authorisation: Only admins may create metadata schemas + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators may modify the metadata registry"); + "Only administrators may modify the metadata registry"); } // Ensure the schema name is unique - if (!uniqueShortName(context,-1, name)) - { + if (!uniqueShortName(context, -1, name)) { throw new NonUniqueMetadataException("Please make the name " + name - + " unique"); + + " unique"); } // Ensure the schema namespace is unique - if (!uniqueNamespace(context,-1, namespace)) - { + if (!uniqueNamespace(context, -1, namespace)) { throw new NonUniqueMetadataException("Please make the namespace " + namespace - + " unique"); + + " unique"); } @@ -72,8 +71,8 @@ public class MetadataSchemaServiceImpl implements MetadataSchemaService { metadataSchema.setName(name); metadataSchemaDAO.save(context, metadataSchema); log.info(LogManager.getHeader(context, "create_metadata_schema", - "metadata_schema_id=" - + metadataSchema.getID())); + "metadata_schema_id=" + + metadataSchema.getID())); return metadataSchema; } @@ -83,44 +82,41 @@ public class MetadataSchemaServiceImpl implements MetadataSchemaService { } @Override - public void update(Context context, MetadataSchema metadataSchema) throws SQLException, AuthorizeException, NonUniqueMetadataException { + public void update(Context context, MetadataSchema metadataSchema) + throws SQLException, AuthorizeException, NonUniqueMetadataException { // Check authorisation: Only admins may update the metadata registry - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators may modify the metadata registry"); + "Only administrators may modify the metadata registry"); } // Ensure the schema name is unique - if (!uniqueShortName(context, metadataSchema.getID(), metadataSchema.getName())) - { + if (!uniqueShortName(context, metadataSchema.getID(), metadataSchema.getName())) { throw new NonUniqueMetadataException("Please make the name " + metadataSchema.getName() - + " unique"); + + " unique"); } // Ensure the schema namespace is unique - if (!uniqueNamespace(context, metadataSchema.getID(), metadataSchema.getNamespace())) - { + if (!uniqueNamespace(context, metadataSchema.getID(), metadataSchema.getNamespace())) { throw new NonUniqueMetadataException("Please make the namespace " + metadataSchema.getNamespace() - + " unique"); + + " unique"); } metadataSchemaDAO.save(context, metadataSchema); log.info(LogManager.getHeader(context, "update_metadata_schema", - "metadata_schema_id=" + metadataSchema.getID() + "namespace=" - + metadataSchema.getNamespace() + "name=" + metadataSchema.getName())); + "metadata_schema_id=" + metadataSchema.getID() + "namespace=" + + metadataSchema.getNamespace() + "name=" + metadataSchema.getName())); } @Override public void delete(Context context, MetadataSchema metadataSchema) throws SQLException, AuthorizeException { - // Check authorisation: Only admins may create DC types - if (!authorizeService.isAdmin(context)) - { + // Check authorisation: Only admins may create DC types + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "Only administrators may modify the metadata registry"); + "Only administrators may modify the metadata registry"); } log.info(LogManager.getHeader(context, "delete_metadata_schema", - "metadata_schema_id=" + metadataSchema.getID())); + "metadata_schema_id=" + metadataSchema.getID())); metadataSchemaDAO.delete(context, metadataSchema); } @@ -132,14 +128,13 @@ public class MetadataSchemaServiceImpl implements MetadataSchemaService { @Override public MetadataSchema find(Context context, int id) throws SQLException { - return metadataSchemaDAO.findByID(context, MetadataSchema.class, id); + return metadataSchemaDAO.findByID(context, MetadataSchema.class, id); } @Override public MetadataSchema find(Context context, String shortName) throws SQLException { // If we are not passed a valid schema name then return - if (shortName == null) - { + if (shortName == null) { return null; } return metadataSchemaDAO.find(context, shortName); @@ -150,30 +145,28 @@ public class MetadataSchemaServiceImpl implements MetadataSchemaService { * Return true if and only if the passed name appears within the allowed * number of times in the current schema. * - * @param context DSpace context + * @param context DSpace context * @param metadataSchemaId metadata schema id - * @param namespace namespace URI to match + * @param namespace namespace URI to match * @return true of false * @throws SQLException if database error */ protected boolean uniqueNamespace(Context context, int metadataSchemaId, String namespace) - throws SQLException - { + throws SQLException { return metadataSchemaDAO.uniqueNamespace(context, metadataSchemaId, namespace); } /** * Return true if and only if the passed name is unique. * - * @param context DSpace context + * @param context DSpace context * @param metadataSchemaId metadata schema id - * @param name short name of schema + * @param name short name of schema * @return true of false * @throws SQLException if database error */ protected boolean uniqueShortName(Context context, int metadataSchemaId, String name) - throws SQLException - { + throws SQLException { return metadataSchemaDAO.uniqueShortName(context, metadataSchemaId, name); } } diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataValue.java b/dspace-api/src/main/java/org/dspace/content/MetadataValue.java index 8a0344e01b..4ce0c291f7 100644 --- a/dspace-api/src/main/java/org/dspace/content/MetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataValue.java @@ -7,13 +7,24 @@ */ package org.dspace.content; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.hibernate.annotations.Type; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; - /** * Database access class representing a Dublin Core metadata value. * It represents a value of a given MetadataField on an Item. @@ -26,54 +37,65 @@ import javax.persistence.*; * @see org.dspace.content.MetadataField */ @Entity -@Table(name="metadatavalue") -public class MetadataValue implements ReloadableEntity -{ - /** The reference to the metadata field */ +@Table(name = "metadatavalue") +public class MetadataValue implements ReloadableEntity { + /** + * The reference to the metadata field + */ @Id - @Column(name="metadata_value_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="metadatavalue_seq") - @SequenceGenerator(name="metadatavalue_seq", sequenceName="metadatavalue_seq", allocationSize = 1) + @Column(name = "metadata_value_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "metadatavalue_seq") + @SequenceGenerator(name = "metadatavalue_seq", sequenceName = "metadatavalue_seq", allocationSize = 1) private Integer id; - /** The primary key for the metadata value */ + /** + * The primary key for the metadata value + */ @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "metadata_field_id") private MetadataField metadataField = null; - /** The value of the field */ + /** + * The value of the field + */ @Lob - @Type(type="org.hibernate.type.MaterializedClobType") - @Column(name="text_value") + @Type(type = "org.hibernate.type.MaterializedClobType") + @Column(name = "text_value") private String value; - /** The language of the field, may be null */ + /** + * The language of the field, may be null + */ @Column(name = "text_lang", length = 24) private String language; - /** The position of the record. */ + /** + * The position of the record. + */ @Column(name = "place") private int place = 1; - /** Authority key, if any */ + /** + * Authority key, if any + */ @Column(name = "authority", length = 100) private String authority = null; - /** Authority confidence value -- see Choices class for values */ + /** + * Authority confidence value -- see Choices class for values + */ @Column(name = "confidence") private int confidence = -1; - @ManyToOne(fetch = FetchType.LAZY, cascade={CascadeType.PERSIST}) - @JoinColumn(name="dspace_object_id") + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) + @JoinColumn(name = "dspace_object_id") protected DSpaceObject dSpaceObject; /** * Protected constructor, create object using: * {@link org.dspace.content.service.MetadataValueService#create(Context, DSpaceObject, MetadataField)} - * */ - protected MetadataValue() - { + protected MetadataValue() { id = 0; } @@ -82,8 +104,7 @@ public class MetadataValue implements ReloadableEntity * * @return metadata value ID */ - public Integer getID() - { + public Integer getID() { return id; } @@ -92,8 +113,7 @@ public class MetadataValue implements ReloadableEntity * * @return dspaceObject */ - public DSpaceObject getDSpaceObject() - { + public DSpaceObject getDSpaceObject() { return dSpaceObject; } @@ -102,8 +122,7 @@ public class MetadataValue implements ReloadableEntity * * @param dso new dspaceObject ID */ - public void setDSpaceObject(DSpaceObject dso) - { + public void setDSpaceObject(DSpaceObject dso) { this.dSpaceObject = dso; } @@ -112,8 +131,7 @@ public class MetadataValue implements ReloadableEntity * * @return language */ - public String getLanguage() - { + public String getLanguage() { return language; } @@ -122,8 +140,7 @@ public class MetadataValue implements ReloadableEntity * * @param language new language */ - public void setLanguage(String language) - { + public void setLanguage(String language) { this.language = language; } @@ -132,8 +149,7 @@ public class MetadataValue implements ReloadableEntity * * @return place ordering */ - public int getPlace() - { + public int getPlace() { return place; } @@ -142,8 +158,7 @@ public class MetadataValue implements ReloadableEntity * * @param place new place (relative order in series of values) */ - public void setPlace(int place) - { + public void setPlace(int place) { this.place = place; } @@ -160,8 +175,7 @@ public class MetadataValue implements ReloadableEntity * * @return metadata value */ - public String getValue() - { + public String getValue() { return value; } @@ -170,8 +184,7 @@ public class MetadataValue implements ReloadableEntity * * @param value new metadata value */ - public void setValue(String value) - { + public void setValue(String value) { this.value = value; } @@ -180,9 +193,8 @@ public class MetadataValue implements ReloadableEntity * * @return metadata authority */ - public String getAuthority () - { - return authority ; + public String getAuthority() { + return authority; } /** @@ -190,9 +202,8 @@ public class MetadataValue implements ReloadableEntity * * @param value new metadata authority */ - public void setAuthority (String value) - { - this.authority = value; + public void setAuthority(String value) { + this.authority = value; } /** @@ -200,8 +211,7 @@ public class MetadataValue implements ReloadableEntity * * @return metadata confidence */ - public int getConfidence() - { + public int getConfidence() { return confidence; } @@ -210,8 +220,7 @@ public class MetadataValue implements ReloadableEntity * * @param value new metadata confidence */ - public void setConfidence(int value) - { + public void setConfidence(int value) { this.confidence = value; } @@ -220,43 +229,34 @@ public class MetadataValue implements ReloadableEntity * Return true if other is the same MetadataValue * as this object, false otherwise * - * @param obj - * object to compare to - * + * @param obj object to compare to * @return true if object passed in represents the same - * MetadataValue as this object + * MetadataValue as this object */ @Override - public boolean equals(Object obj) - { - if (obj == null) - { + public boolean equals(Object obj) { + if (obj == null) { return false; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } final MetadataValue other = (MetadataValue) obj; - if (this.id != other.id) - { + if (this.id != other.id) { return false; } - if (this.getID() != other.getID()) - { + if (this.getID() != other.getID()) { return false; } - if (this.getDSpaceObject().getID() != other.getDSpaceObject().getID()) - { + if (this.getDSpaceObject().getID() != other.getDSpaceObject().getID()) { return false; } return true; } @Override - public int hashCode() - { + public int hashCode() { int hash = 7; hash = 47 * hash + this.id; hash = 47 * hash + this.getID(); @@ -265,4 +265,4 @@ public class MetadataValue implements ReloadableEntity } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataValueServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/MetadataValueServiceImpl.java index 4da67aeaf2..396265467b 100644 --- a/dspace-api/src/main/java/org/dspace/content/MetadataValueServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataValueServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.content; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; @@ -19,11 +24,6 @@ import org.dspace.core.Context; import org.dspace.core.LogManager; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Service implementation for the MetadataValue object. * This class is responsible for all business logic calls for the MetadataValue object and is autowired by spring. @@ -66,7 +66,8 @@ public class MetadataValueServiceImpl implements MetadataValueService { } @Override - public List findByField(Context context, MetadataField metadataField) throws IOException, SQLException { + public List findByField(Context context, MetadataField metadataField) + throws IOException, SQLException { return metadataValueDAO.findByField(context, metadataField); } @@ -74,16 +75,18 @@ public class MetadataValueServiceImpl implements MetadataValueService { public void update(Context context, MetadataValue metadataValue) throws SQLException { metadataValueDAO.save(context, metadataValue); log.info(LogManager.getHeader(context, "update_metadatavalue", - "metadata_value_id=" + metadataValue.getID())); + "metadata_value_id=" + metadataValue.getID())); } @Override - public void update(Context context, MetadataValue metadataValue, boolean updateLastModified) throws SQLException, AuthorizeException { - if(updateLastModified){ + public void update(Context context, MetadataValue metadataValue, boolean updateLastModified) + throws SQLException, AuthorizeException { + if (updateLastModified) { authorizeService.authorizeAction(context, metadataValue.getDSpaceObject(), Constants.WRITE); - DSpaceObjectService dSpaceObjectService = contentServiceFactory.getDSpaceObjectService(metadataValue.getDSpaceObject()); - // get the right class for our dspaceobject not the DSpaceObject lazy proxy + DSpaceObjectService dSpaceObjectService = contentServiceFactory + .getDSpaceObjectService(metadataValue.getDSpaceObject()); + // get the right class for our dspaceobject not the DSpaceObject lazy proxy DSpaceObject dso = dSpaceObjectService.find(context, metadataValue.getDSpaceObject().getID()); dSpaceObjectService.updateLastModified(context, dso); } @@ -94,7 +97,7 @@ public class MetadataValueServiceImpl implements MetadataValueService { @Override public void delete(Context context, MetadataValue metadataValue) throws SQLException { log.info(LogManager.getHeader(context, "delete_metadata_value", - " metadata_value_id=" + metadataValue.getID())); + " metadata_value_id=" + metadataValue.getID())); metadataValueDAO.delete(context, metadataValue); } @@ -110,10 +113,9 @@ public class MetadataValueServiceImpl implements MetadataValueService { @Override public MetadataValue getMinimum(Context context, int metadataFieldId) - throws SQLException - { + throws SQLException { return metadataValueDAO.getMinimum(context, - metadataFieldId); + metadataFieldId); } @Override diff --git a/dspace-api/src/main/java/org/dspace/content/NonUniqueMetadataException.java b/dspace-api/src/main/java/org/dspace/content/NonUniqueMetadataException.java index 9d55a2aea3..a45c43b9e7 100644 --- a/dspace-api/src/main/java/org/dspace/content/NonUniqueMetadataException.java +++ b/dspace-api/src/main/java/org/dspace/content/NonUniqueMetadataException.java @@ -10,27 +10,23 @@ package org.dspace.content; /** * An exception that gets thrown when a metadata field cannot be created or * saved due to an existing field with an identical element and qualifier. - * + * * @author Martin Hald */ -public class NonUniqueMetadataException extends Exception -{ +public class NonUniqueMetadataException extends Exception { /** * Create an empty authorize exception */ - public NonUniqueMetadataException() - { + public NonUniqueMetadataException() { super(); } /** * Create an exception with only a message - * - * @param message - * message string + * + * @param message message string */ - public NonUniqueMetadataException(String message) - { + public NonUniqueMetadataException(String message) { super(message); } } diff --git a/dspace-api/src/main/java/org/dspace/content/Site.java b/dspace-api/src/main/java/org/dspace/content/Site.java index 8d3106a700..ade0f62408 100644 --- a/dspace-api/src/main/java/org/dspace/content/Site.java +++ b/dspace-api/src/main/java/org/dspace/content/Site.java @@ -7,6 +7,11 @@ */ package org.dspace.content; +import javax.persistence.Cacheable; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.Transient; + import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.SiteService; import org.dspace.core.ConfigurationManager; @@ -14,11 +19,6 @@ import org.dspace.core.Constants; import org.dspace.core.Context; import org.hibernate.annotations.CacheConcurrencyStrategy; -import javax.persistence.Cacheable; -import javax.persistence.Entity; -import javax.persistence.Table; -import javax.persistence.Transient; - /** * Represents the root of the DSpace Archive. * By default, the handle suffix "0" represents the Site, e.g. "1721.1/0" @@ -27,8 +27,7 @@ import javax.persistence.Transient; @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @Table(name = "site") -public class Site extends DSpaceObject -{ +public class Site extends DSpaceObject { @Transient private transient SiteService siteService; @@ -36,10 +35,8 @@ public class Site extends DSpaceObject /** * Protected constructor, create object using: * {@link org.dspace.content.service.SiteService#createSite(Context)} - * */ - protected Site() - { + protected Site() { } @@ -49,25 +46,21 @@ public class Site extends DSpaceObject * @return type of the object */ @Override - public int getType() - { + public int getType() { return Constants.SITE; } @Override - public String getName() - { + public String getName() { return getSiteService().getName(this); } - public String getURL() - { + public String getURL() { return ConfigurationManager.getProperty("dspace.url"); } private SiteService getSiteService() { - if(siteService == null) - { + if (siteService == null) { siteService = ContentServiceFactory.getInstance().getSiteService(); } return siteService; diff --git a/dspace-api/src/main/java/org/dspace/content/SiteServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/SiteServiceImpl.java index 7bf764c8ca..44077c491c 100644 --- a/dspace-api/src/main/java/org/dspace/content/SiteServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/SiteServiceImpl.java @@ -7,6 +7,10 @@ */ package org.dspace.content; +import java.io.IOException; +import java.sql.SQLException; +import java.util.UUID; + import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.dao.SiteDAO; @@ -18,10 +22,6 @@ import org.dspace.event.Event; import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.UUID; - /** * Service implementation for the Site object. * This class is responsible for all business logic calls for the Site object and is autowired by spring. @@ -40,16 +40,14 @@ public class SiteServiceImpl extends DSpaceObjectServiceImpl implements Si @Autowired(required = true) protected SiteDAO siteDAO; - protected SiteServiceImpl() - { + protected SiteServiceImpl() { super(); } @Override public Site createSite(Context context) throws SQLException { Site site = findSite(context); - if(site == null) - { + if (site == null) { //Only one site can be created at any point in time site = siteDAO.create(context, new Site()); handleService.createHandle(context, site, configurationService.getProperty("handle.prefix") + "/0"); @@ -74,18 +72,19 @@ public class SiteServiceImpl extends DSpaceObjectServiceImpl implements Si @Override public void update(Context context, Site site) throws SQLException, AuthorizeException { - if(!authorizeService.isAdmin(context)){ + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException(); } super.update(context, site); - if(site.isMetadataModified()) - { - context.addEvent(new Event(Event.MODIFY_METADATA, site.getType(), site.getID(), site.getDetails(), getIdentifiers(context, site))); + if (site.isMetadataModified()) { + context.addEvent(new Event(Event.MODIFY_METADATA, site.getType(), site.getID(), site.getDetails(), + getIdentifiers(context, site))); } - if(site.isModified()) { - context.addEvent(new Event(Event.MODIFY, site.getType(), site.getID(), site.getDetails(), getIdentifiers(context, site))); + if (site.isModified()) { + context.addEvent(new Event(Event.MODIFY, site.getType(), site.getID(), site.getDetails(), + getIdentifiers(context, site))); } site.clearModified(); site.clearDetails(); @@ -94,8 +93,7 @@ public class SiteServiceImpl extends DSpaceObjectServiceImpl implements Si } @Override - public String getName(Site dso) - { + public String getName(Site dso) { return ConfigurationManager.getProperty("dspace.name"); } diff --git a/dspace-api/src/main/java/org/dspace/content/SupervisedItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/SupervisedItemServiceImpl.java index 6fd022f7f0..b0eb77ec2a 100644 --- a/dspace-api/src/main/java/org/dspace/content/SupervisedItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/SupervisedItemServiceImpl.java @@ -16,29 +16,25 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.springframework.beans.factory.annotation.Autowired; -public class SupervisedItemServiceImpl implements SupervisedItemService -{ +public class SupervisedItemServiceImpl implements SupervisedItemService { @Autowired(required = true) protected WorkspaceItemService workspaceItemService; - protected SupervisedItemServiceImpl() - { + protected SupervisedItemServiceImpl() { } @Override public List getAll(Context context) - throws SQLException - { + throws SQLException { return workspaceItemService.findAllSupervisedItems(context); } @Override public List findbyEPerson(Context context, EPerson ep) - throws SQLException - { + throws SQLException { return workspaceItemService.findSupervisedItemsByEPerson(context, ep); } - + } diff --git a/dspace-api/src/main/java/org/dspace/content/Thumbnail.java b/dspace-api/src/main/java/org/dspace/content/Thumbnail.java index 833a9b3fbc..589a8ddca4 100644 --- a/dspace-api/src/main/java/org/dspace/content/Thumbnail.java +++ b/dspace-api/src/main/java/org/dspace/content/Thumbnail.java @@ -7,66 +7,61 @@ */ package org.dspace.content; -import org.dspace.content.Bitstream; - /** * Wrapper class for bitstreams with Thumbnails associated with them for * convenience in the browse system - * - * @author Richard Jones * + * @author Richard Jones */ -public class Thumbnail -{ - /** the bitstream that is actually the thumbnail */ - private Bitstream thumb; - - /** the original bitstream for which this is the thumbnail */ - private Bitstream original; - - /** - * Construct a new thumbnail using the two bitstreams - * - * @param thumb the thumbnail bitstream - * @param original the original bitstream - */ - public Thumbnail(Bitstream thumb, Bitstream original) - { - this.thumb = thumb; - this.original = original; - } +public class Thumbnail { + /** + * the bitstream that is actually the thumbnail + */ + private Bitstream thumb; - /** - * @return Returns the original. - */ - public Bitstream getOriginal() - { - return original; - } + /** + * the original bitstream for which this is the thumbnail + */ + private Bitstream original; - /** - * @param original The original to set. - */ - public void setOriginal(Bitstream original) - { - this.original = original; - } + /** + * Construct a new thumbnail using the two bitstreams + * + * @param thumb the thumbnail bitstream + * @param original the original bitstream + */ + public Thumbnail(Bitstream thumb, Bitstream original) { + this.thumb = thumb; + this.original = original; + } - /** - * @return Returns the thumb. - */ - public Bitstream getThumb() - { - return thumb; - } + /** + * @return Returns the original. + */ + public Bitstream getOriginal() { + return original; + } - /** - * @param thumb The thumb to set. - */ - public void setThumb(Bitstream thumb) - { - this.thumb = thumb; - } + /** + * @param original The original to set. + */ + public void setOriginal(Bitstream original) { + this.original = original; + } + + /** + * @return Returns the thumb. + */ + public Bitstream getThumb() { + return thumb; + } + + /** + * @param thumb The thumb to set. + */ + public void setThumb(Bitstream thumb) { + this.thumb = thumb; + } } diff --git a/dspace-api/src/main/java/org/dspace/content/WorkspaceItem.java b/dspace-api/src/main/java/org/dspace/content/WorkspaceItem.java index 367d99e9ca..42ecce9403 100644 --- a/dspace-api/src/main/java/org/dspace/content/WorkspaceItem.java +++ b/dspace-api/src/main/java/org/dspace/content/WorkspaceItem.java @@ -7,6 +7,24 @@ */ package org.dspace.content; +import java.io.Serializable; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.apache.commons.lang.builder.HashCodeBuilder; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; @@ -15,36 +33,33 @@ import org.dspace.eperson.Group; import org.dspace.workflow.WorkflowItem; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.io.Serializable; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /** * Class representing an item in the process of being submitted by a user - * + * * @author Robert Tansley * @version $Revision$ */ @Entity @Table(name = "workspaceitem") -public class WorkspaceItem implements InProgressSubmission, Serializable, ReloadableEntity -{ +public class WorkspaceItem implements InProgressSubmission, Serializable, ReloadableEntity { @Id @Column(name = "workspace_item_id", unique = true, nullable = false) - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="workspaceitem_seq") - @SequenceGenerator(name="workspaceitem_seq", sequenceName="workspaceitem_seq", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "workspaceitem_seq") + @SequenceGenerator(name = "workspaceitem_seq", sequenceName = "workspaceitem_seq", allocationSize = 1) private Integer workspaceItemId; - /** The item this workspace object pertains to */ + /** + * The item this workspace object pertains to + */ @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "item_id") private Item item; - /** The collection the item is being submitted to */ + /** + * The collection the item is being submitted to + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "collection_id") private Collection collection; @@ -66,9 +81,9 @@ public class WorkspaceItem implements InProgressSubmission, Serializable, Reload @ManyToMany(fetch = FetchType.LAZY) @JoinTable( - name = "epersongroup2workspaceitem", - joinColumns = {@JoinColumn(name = "workspace_item_id") }, - inverseJoinColumns = {@JoinColumn(name = "eperson_group_id") } + name = "epersongroup2workspaceitem", + joinColumns = {@JoinColumn(name = "workspace_item_id")}, + inverseJoinColumns = {@JoinColumn(name = "eperson_group_id")} ) private final List supervisorGroups = new ArrayList<>(); @@ -77,65 +92,56 @@ public class WorkspaceItem implements InProgressSubmission, Serializable, Reload * {@link org.dspace.content.service.WorkspaceItemService#create(Context, Collection, boolean)} * or * {@link org.dspace.content.service.WorkspaceItemService#create(Context, WorkflowItem)} - * */ - protected WorkspaceItem() - { + protected WorkspaceItem() { } /** * Get the internal ID of this workspace item - * + * * @return the internal identifier */ @Override - public Integer getID() - { + public Integer getID() { return workspaceItemId; } /** * Get the value of the stage reached column - * + * * @return the value of the stage reached column */ - public int getStageReached() - { + public int getStageReached() { return stageReached; } /** * Set the value of the stage reached column - * - * @param v - * the value of the stage reached column + * + * @param v the value of the stage reached column */ - public void setStageReached(int v) - { + public void setStageReached(int v) { stageReached = v; } /** * Get the value of the page reached column (which represents the page * reached within a stage/step) - * + * * @return the value of the page reached column */ - public int getPageReached() - { + public int getPageReached() { return pageReached; } /** * Set the value of the page reached column (which represents the page * reached within a stage/step) - * - * @param v - * the value of the page reached column + * + * @param v the value of the page reached column */ - public void setPageReached(int v) - { + public void setPageReached(int v) { pageReached = v; } @@ -147,18 +153,15 @@ public class WorkspaceItem implements InProgressSubmission, Serializable, Reload */ @Override public boolean equals(Object o) { - if (this == o) - { + if (this == o) { return true; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(o); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } - final WorkspaceItem that = (WorkspaceItem)o; - if (this.getID() != that.getID()) - { + final WorkspaceItem that = (WorkspaceItem) o; + if (this.getID() != that.getID()) { return false; } @@ -166,15 +169,13 @@ public class WorkspaceItem implements InProgressSubmission, Serializable, Reload } @Override - public int hashCode() - { + public int hashCode() { return new HashCodeBuilder().append(getID()).toHashCode(); } // InProgressSubmission methods @Override - public Item getItem() - { + public Item getItem() { return item; } @@ -183,8 +184,7 @@ public class WorkspaceItem implements InProgressSubmission, Serializable, Reload } @Override - public Collection getCollection() - { + public Collection getCollection() { return collection; } @@ -193,44 +193,37 @@ public class WorkspaceItem implements InProgressSubmission, Serializable, Reload } @Override - public EPerson getSubmitter() throws SQLException - { + public EPerson getSubmitter() throws SQLException { return item.getSubmitter(); } @Override - public boolean hasMultipleFiles() - { + public boolean hasMultipleFiles() { return multipleFiles; } @Override - public void setMultipleFiles(boolean b) - { + public void setMultipleFiles(boolean b) { multipleFiles = b; } @Override - public boolean hasMultipleTitles() - { + public boolean hasMultipleTitles() { return multipleTitles; } @Override - public void setMultipleTitles(boolean b) - { + public void setMultipleTitles(boolean b) { multipleTitles = b; } @Override - public boolean isPublishedBefore() - { + public boolean isPublishedBefore() { return publishedBefore; } @Override - public void setPublishedBefore(boolean b) - { + public void setPublishedBefore(boolean b) { publishedBefore = b; } @@ -238,13 +231,11 @@ public class WorkspaceItem implements InProgressSubmission, Serializable, Reload return supervisorGroups; } - void removeSupervisorGroup(Group group) - { + void removeSupervisorGroup(Group group) { supervisorGroups.remove(group); } - void addSupervisorGroup(Group group) - { + void addSupervisorGroup(Group group) { supervisorGroups.add(group); } } diff --git a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java index 8239f6a4f2..d378ecdb27 100644 --- a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java @@ -7,7 +7,15 @@ */ package org.dspace.content; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.apache.log4j.Logger; +import org.dspace.app.util.DCInputsReaderException; +import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.service.AuthorizeService; @@ -23,11 +31,6 @@ import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.WorkflowService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; - /** * Service implementation for the WorkspaceItem object. * This class is responsible for all business logic calls for the WorkspaceItem object and is autowired by spring. @@ -52,8 +55,7 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { protected WorkflowService workflowService; - protected WorkspaceItemServiceImpl() - { + protected WorkspaceItemServiceImpl() { } @@ -61,27 +63,23 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { public WorkspaceItem find(Context context, int id) throws SQLException { WorkspaceItem workspaceItem = workspaceItemDAO.findByID(context, WorkspaceItem.class, id); - if (workspaceItem == null) - { - if (log.isDebugEnabled()) - { + if (workspaceItem == null) { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_workspace_item", - "not_found,workspace_item_id=" + id)); + "not_found,workspace_item_id=" + id)); } - } - else - { - if (log.isDebugEnabled()) - { + } else { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_workspace_item", - "workspace_item_id=" + id)); + "workspace_item_id=" + id)); } } return workspaceItem; } @Override - public WorkspaceItem create(Context context, Collection collection, boolean template) throws AuthorizeException, SQLException { + public WorkspaceItem create(Context context, Collection collection, boolean template) + throws AuthorizeException, SQLException { // Check the user has permission to ADD to the collection authorizeService.authorizeAction(context, collection, Constants.ADD); @@ -102,23 +100,25 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { // add permission authorizeService.addPolicy(context, item, Constants.ADD, item.getSubmitter(), ResourcePolicy.TYPE_SUBMISSION); // remove contents permission - authorizeService.addPolicy(context, item, Constants.REMOVE, item.getSubmitter(), ResourcePolicy.TYPE_SUBMISSION); + authorizeService + .addPolicy(context, item, Constants.REMOVE, item.getSubmitter(), ResourcePolicy.TYPE_SUBMISSION); // delete permission - authorizeService.addPolicy(context, item, Constants.DELETE, item.getSubmitter(), ResourcePolicy.TYPE_SUBMISSION); + authorizeService + .addPolicy(context, item, Constants.DELETE, item.getSubmitter(), ResourcePolicy.TYPE_SUBMISSION); // Copy template if appropriate Item templateItem = collection.getTemplateItem(); - if (template && (templateItem != null)) - { + if (template && (templateItem != null)) { List md = itemService.getMetadata(templateItem, Item.ANY, Item.ANY, Item.ANY, Item.ANY); for (MetadataValue aMd : md) { MetadataField metadataField = aMd.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); - itemService.addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(), metadataField.getQualifier(), aMd.getLanguage(), - aMd.getValue()); + itemService.addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(), + metadataField.getQualifier(), aMd.getLanguage(), + aMd.getValue()); } } @@ -126,9 +126,9 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { workspaceItem.setItem(item); log.info(LogManager.getHeader(context, "create_workspace_item", - "workspace_item_id=" + workspaceItem.getID() - + "item_id=" + item.getID() + "collection_id=" - + collection.getID())); + "workspace_item_id=" + workspaceItem.getID() + + "item_id=" + item.getID() + "collection_id=" + + collection.getID())); return workspaceItem; } @@ -147,6 +147,12 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { return workspaceItemDAO.findByEPerson(context, ep); } + @Override + public List findByEPerson(Context context, EPerson ep, Integer limit, Integer offset) + throws SQLException { + return workspaceItemDAO.findByEPerson(context, ep, limit, offset); + } + @Override public List findByCollection(Context context, Collection collection) throws SQLException { return workspaceItemDAO.findByCollection(context, collection); @@ -172,12 +178,17 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { return workspaceItemDAO.findAll(context); } + @Override + public List findAll(Context context, Integer limit, Integer offset) throws SQLException { + return workspaceItemDAO.findAll(context, limit, offset); + } + @Override public void update(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException { - // Authorisation is checked by the item.update() method below + // Authorisation is checked by the item.update() method below log.info(LogManager.getHeader(context, "update_workspace_item", - "workspace_item_id=" + workspaceItem.getID())); + "workspace_item_id=" + workspaceItem.getID())); // Update the item itemService.update(context, workspaceItem.getItem()); @@ -187,7 +198,8 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { } @Override - public void deleteAll(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException, IOException { + public void deleteAll(Context context, WorkspaceItem workspaceItem) + throws SQLException, AuthorizeException, IOException { /* * Authorisation is a special case. The submitter won't have REMOVE * permission on the collection, so our policy is this: Only the @@ -196,18 +208,17 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { */ Item item = workspaceItem.getItem(); if (!authorizeService.isAdmin(context) - && ((context.getCurrentUser() == null) || (context - .getCurrentUser().getID() != item.getSubmitter() - .getID()))) - { + && ((context.getCurrentUser() == null) || (context + .getCurrentUser().getID() != item.getSubmitter() + .getID()))) { // Not an admit, not the submitter throw new AuthorizeException("Must be an administrator or the " - + "original submitter to delete a workspace item"); + + "original submitter to delete a workspace item"); } log.info(LogManager.getHeader(context, "delete_workspace_item", - "workspace_item_id=" + workspaceItem.getID() + "item_id=" + item.getID() - + "collection_id=" + workspaceItem.getCollection().getID())); + "workspace_item_id=" + workspaceItem.getID() + "item_id=" + item.getID() + + "collection_id=" + workspaceItem.getCollection().getID())); // Need to delete the epersongroup2workspaceitem row first since it refers // to workspaceitem ID @@ -226,6 +237,11 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { return workspaceItemDAO.countRows(context); } + @Override + public int countByEPerson(Context context, EPerson ep) throws SQLException { + return workspaceItemDAO.countRows(context, ep); + } + @Override public List> getStageReachedCounts(Context context) throws SQLException { return workspaceItemDAO.getStageReachedCounts(context); @@ -238,8 +254,8 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { authorizeService.authorizeAction(context, item, Constants.WRITE); log.info(LogManager.getHeader(context, "delete_workspace_item", - "workspace_item_id=" + workspaceItem.getID() + "item_id=" + item.getID() - + "collection_id=" + workspaceItem.getCollection().getID())); + "workspace_item_id=" + workspaceItem.getID() + "item_id=" + item.getID() + + "collection_id=" + workspaceItem.getCollection().getID())); // deleteSubmitPermissions(); @@ -249,4 +265,24 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { workspaceItemDAO.delete(context, workspaceItem); } + + @Override + public void move(Context context, WorkspaceItem source, Collection fromCollection, Collection toCollection) + throws DCInputsReaderException { + source.setCollection(toCollection); + + List remove = new ArrayList<>(); + List diff = Util.differenceInSubmissionFields(fromCollection, toCollection); + for (String toRemove : diff) { + for (MetadataValue value : source.getItem().getMetadata()) { + if (value.getMetadataField().toString('.').equals(toRemove)) { + remove.add(value); + } + } + } + + source.getItem().removeMetadata(remove); + + } + } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/AuthorityVariantsSupport.java b/dspace-api/src/main/java/org/dspace/content/authority/AuthorityVariantsSupport.java index 434cb15bd0..d4aa2dc0ff 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/AuthorityVariantsSupport.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/AuthorityVariantsSupport.java @@ -15,7 +15,6 @@ package org.dspace.content.authority; import java.util.List; /** - * * @author bollini */ public interface AuthorityVariantsSupport { diff --git a/dspace-api/src/main/java/org/dspace/content/authority/Choice.java b/dspace-api/src/main/java/org/dspace/content/authority/Choice.java index cbf2304470..9b68c75d28 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/Choice.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/Choice.java @@ -7,6 +7,7 @@ */ package org.dspace.content.authority; +import java.util.HashMap; import java.util.Map; /** @@ -16,25 +17,28 @@ import java.util.Map; * @author Larry Stone * @see Choices */ -public class Choice -{ - /** Authority key for this value */ +public class Choice { + /** + * Authority key for this value + */ public String authority = null; - /** Label to display for this value (e.g. to present in UI menu) */ + /** + * Label to display for this value (e.g. to present in UI menu) + */ public String label = null; - /** The canonical text value to insert into MetadataValue's text field */ + /** + * The canonical text value to insert into MetadataValue's text field + */ public String value = null; - public Map extras = null; + public Map extras = new HashMap(); - public Choice() - { + public Choice() { } - public Choice(String authority, String value, String label) - { + public Choice(String authority, String value, String label) { this.authority = authority; this.value = value; this.label = label; diff --git a/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthority.java index 907a93fbda..d2d06fe983 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthority.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthority.java @@ -17,8 +17,7 @@ import org.dspace.content.Collection; * @see ChoiceAuthorityServiceImpl * @see MetadataAuthorityServiceImpl */ -public interface ChoiceAuthority -{ +public interface ChoiceAuthority { /** * Get all values from the authority that match the preferred value. * Note that the offering was entered by the user and may contain @@ -33,12 +32,12 @@ public interface ChoiceAuthority * defaultSelected index in the Choices instance to the choice, if any, * that matches the value. * - * @param field being matched for - * @param text user's value to match + * @param field being matched for + * @param text user's value to match * @param collection database ID of Collection for context (owner of Item) - * @param start choice at which to start, 0 is first. - * @param limit maximum number of choices to return, 0 for no limit. - * @param locale explicit localization key if available, or null + * @param start choice at which to start, 0 is first. + * @param limit maximum number of choices to return, 0 for no limit. + * @param locale explicit localization key if available, or null * @return a Choices object (never null). */ public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale); @@ -52,10 +51,10 @@ public interface ChoiceAuthority * This call is typically used in non-interactive metadata ingest * where there is no interactive agent to choose from among options. * - * @param field being matched for - * @param text user's value to match + * @param field being matched for + * @param text user's value to match * @param collection database ID of Collection for context (owner of Item) - * @param locale explicit localization key if available, or null + * @param locale explicit localization key if available, or null * @return a Choices object (never null) with 1 or 0 values. */ public Choices getBestMatch(String field, String text, Collection collection, String locale); @@ -68,10 +67,31 @@ public interface ChoiceAuthority * This may get called many times while populating a Web page so it should * be implemented as efficiently as possible. * - * @param field being matched for - * @param key authority key known to this authority. + * @param field being matched for + * @param key authority key known to this authority. * @param locale explicit localization key if available, or null * @return descriptive label - should always return something, never null. */ public String getLabel(String field, String key, String locale); + + default boolean isHierarchical() { + return false; + } + + default boolean isScrollable() { + return false; + } + + default boolean hasIdentifier() { + return true; + } + + default public Choice getChoice(String fieldKey, String authKey, String locale) { + Choice result = new Choice(); + result.authority = authKey; + result.label = getLabel(fieldKey, authKey, locale); + result.value = getLabel(fieldKey, authKey, locale); + return result; + } + } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java index 0484c0a768..94d5696f5e 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java @@ -7,16 +7,22 @@ */ package org.dspace.content.authority; -import java.util.List; -import java.util.Map; import java.util.HashMap; import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; - +import org.dspace.app.util.DCInput; +import org.dspace.app.util.DCInputSet; +import org.dspace.app.util.DCInputsReader; +import org.dspace.app.util.DCInputsReaderException; import org.dspace.content.Collection; import org.dspace.content.MetadataValue; import org.dspace.content.authority.service.ChoiceAuthorityService; +import org.dspace.core.Utils; import org.dspace.core.service.PluginService; import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; @@ -28,31 +34,34 @@ import org.springframework.beans.factory.annotation.Autowired; * Configuration keys, per metadata field (e.g. "dc.contributer.author") * * {@code - * # names the ChoiceAuthority plugin called for this field - * choices.plugin. = name-of-plugin + * # names the ChoiceAuthority plugin called for this field + * choices.plugin. = name-of-plugin * - * # mode of UI presentation desired in submission UI: - * # "select" is dropdown menu, "lookup" is popup with selector, "suggest" is autocomplete/suggest - * choices.presentation. = "select" | "suggest" + * # mode of UI presentation desired in submission UI: + * # "select" is dropdown menu, "lookup" is popup with selector, "suggest" is autocomplete/suggest + * choices.presentation. = "select" | "suggest" * - * # is value "closed" to the set of these choices or are non-authority values permitted? - * choices.closed. = true | false + * # is value "closed" to the set of these choices or are non-authority values permitted? + * choices.closed. = true | false * } + * * @author Larry Stone * @see ChoiceAuthority */ -public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService -{ +public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService { private Logger log = Logger.getLogger(ChoiceAuthorityServiceImpl.class); // map of field key to authority plugin - protected Map controller = new HashMap(); + protected Map controller = new HashMap(); // map of field key to presentation type - protected Map presentation = new HashMap(); + protected Map presentation = new HashMap(); // map of field key to closed value - protected Map closed = new HashMap(); + protected Map closed = new HashMap(); + + // map of authority name to field key + protected Map authorities = new HashMap(); @Autowired(required = true) protected ConfigurationService configurationService; @@ -68,195 +77,257 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService // translate tail of configuration key (supposed to be schema.element.qual) // into field key - protected String config2fkey(String field) - { + protected String config2fkey(String field) { // field is expected to be "schema.element.qualifier" int dot = field.indexOf('.'); - if (dot < 0) - { + if (dot < 0) { return null; } String schema = field.substring(0, dot); - String element = field.substring(dot+1); + String element = field.substring(dot + 1); String qualifier = null; dot = element.indexOf('.'); - if (dot >= 0) - { - qualifier = element.substring(dot+1); + if (dot >= 0) { + qualifier = element.substring(dot + 1); element = element.substring(0, dot); } return makeFieldKey(schema, element, qualifier); } + @Override + public Set getChoiceAuthoritiesNames() { + if (authorities.keySet().isEmpty()) { + loadChoiceAuthorityConfigurations(); + } + return authorities.keySet(); + } + @Override public Choices getMatches(String schema, String element, String qualifier, - String query, Collection collection, int start, int limit, String locale) - { + String query, Collection collection, int start, int limit, String locale) { return getMatches(makeFieldKey(schema, element, qualifier), query, - collection, start, limit, locale); + collection, start, limit, locale); } @Override public Choices getMatches(String fieldKey, String query, Collection collection, - int start, int limit, String locale) - { + int start, int limit, String locale) { ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey); - if (ma == null) - { + if (ma == null) { throw new IllegalArgumentException( - "No choices plugin was configured for field \"" + fieldKey - + "\"."); + "No choices plugin was configured for field \"" + fieldKey + + "\"."); } return ma.getMatches(fieldKey, query, collection, start, limit, locale); } @Override - public Choices getMatches(String fieldKey, String query, Collection collection, int start, int limit, String locale, boolean externalInput) { + public Choices getMatches(String fieldKey, String query, Collection collection, int start, int limit, String locale, + boolean externalInput) { ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey); if (ma == null) { throw new IllegalArgumentException( - "No choices plugin was configured for field \"" + fieldKey - + "\"."); + "No choices plugin was configured for field \"" + fieldKey + + "\"."); } if (externalInput && ma instanceof SolrAuthority) { - ((SolrAuthority)ma).addExternalResultsInNextMatches(); + ((SolrAuthority) ma).addExternalResultsInNextMatches(); } return ma.getMatches(fieldKey, query, collection, start, limit, locale); } @Override public Choices getBestMatch(String fieldKey, String query, Collection collection, - String locale) - { + String locale) { ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey); - if (ma == null) - { + if (ma == null) { throw new IllegalArgumentException( - "No choices plugin was configured for field \"" + fieldKey - + "\"."); + "No choices plugin was configured for field \"" + fieldKey + + "\"."); } return ma.getBestMatch(fieldKey, query, collection, locale); } @Override - public String getLabel(MetadataValue metadataValue, String locale) - { + public String getLabel(MetadataValue metadataValue, String locale) { return getLabel(metadataValue.getMetadataField().toString(), metadataValue.getAuthority(), locale); } @Override - public String getLabel(String fieldKey, String authKey, String locale) - { + public String getLabel(String fieldKey, String authKey, String locale) { ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey); - if (ma == null) - { + if (ma == null) { throw new IllegalArgumentException("No choices plugin was configured for field \"" + fieldKey + "\"."); } return ma.getLabel(fieldKey, authKey, locale); } @Override - public boolean isChoicesConfigured(String fieldKey) - { + public boolean isChoicesConfigured(String fieldKey) { return getChoiceAuthorityMap().containsKey(fieldKey); } @Override - public String getPresentation(String fieldKey) - { + public String getPresentation(String fieldKey) { return getPresentationMap().get(fieldKey); } @Override - public boolean isClosed(String fieldKey) - { + public boolean isClosed(String fieldKey) { return getClosedMap().containsKey(fieldKey) && getClosedMap().get(fieldKey); } @Override - public List getVariants(MetadataValue metadataValue) - { + public List getVariants(MetadataValue metadataValue) { ChoiceAuthority ma = getChoiceAuthorityMap().get(metadataValue.getMetadataField().toString()); - if (ma instanceof AuthorityVariantsSupport) - { + if (ma instanceof AuthorityVariantsSupport) { AuthorityVariantsSupport avs = (AuthorityVariantsSupport) ma; return avs.getVariants(metadataValue.getAuthority(), metadataValue.getLanguage()); } return null; } - protected String makeFieldKey(String schema, String element, String qualifier) - { - if (qualifier == null) - { - return schema + "_" + element; - } - else - { - return schema + "_" + element + "_" + qualifier; + + @Override + public String getChoiceAuthorityName(String schema, String element, String qualifier) { + String makeFieldKey = makeFieldKey(schema, element, qualifier); + if (getChoiceAuthorityMap().containsKey(makeFieldKey)) { + for (String key : this.authorities.keySet()) { + if (this.authorities.get(key).equals(makeFieldKey)) { + return key; + } + } } + return configurationService.getProperty( + CHOICES_PLUGIN_PREFIX + schema + "." + element + (qualifier != null ? "." + qualifier : "")); + } + + protected String makeFieldKey(String schema, String element, String qualifier) { + return Utils.standardize(schema, element, qualifier, "_"); } /** * Return map of key to ChoiceAuthority plugin + * * @return */ - private Map getChoiceAuthorityMap() - { + private Map getChoiceAuthorityMap() { // If empty, load from configuration - if(controller.isEmpty()) - { - // Get all configuration keys starting with a given prefix - List propKeys = configurationService.getPropertyKeys(CHOICES_PLUGIN_PREFIX); - Iterator keyIterator = propKeys.iterator(); - while(keyIterator.hasNext()) - { - String key = keyIterator.next(); - String fkey = config2fkey(key.substring(CHOICES_PLUGIN_PREFIX.length())); - if (fkey == null) - { - log.warn("Skipping invalid ChoiceAuthority configuration property: "+key+": does not have schema.element.qualifier"); - continue; - } - - // XXX FIXME maybe add sanity check, call - // MetadataField.findByElement to make sure it's a real field. - ChoiceAuthority ma = (ChoiceAuthority) - pluginService.getNamedPlugin(ChoiceAuthority.class, configurationService.getProperty(key)); - if (ma == null) - { - log.warn("Skipping invalid configuration for "+key+" because named plugin not found: "+configurationService.getProperty(key)); - continue; - } - controller.put(fkey, ma); - - log.debug("Choice Control: For field="+fkey+", Plugin="+ma); - } + if (controller.isEmpty()) { + loadChoiceAuthorityConfigurations(); } return controller; } + private void loadChoiceAuthorityConfigurations() { + // Get all configuration keys starting with a given prefix + List propKeys = configurationService.getPropertyKeys(CHOICES_PLUGIN_PREFIX); + Iterator keyIterator = propKeys.iterator(); + while (keyIterator.hasNext()) { + String key = keyIterator.next(); + String fkey = config2fkey(key.substring(CHOICES_PLUGIN_PREFIX.length())); + if (fkey == null) { + log.warn( + "Skipping invalid ChoiceAuthority configuration property: " + key + ": does not have schema" + + ".element.qualifier"); + continue; + } + + // XXX FIXME maybe add sanity check, call + // MetadataField.findByElement to make sure it's a real field. + String authorityName = configurationService.getProperty(key); + ChoiceAuthority ma = (ChoiceAuthority) + pluginService.getNamedPlugin(ChoiceAuthority.class, authorityName); + if (ma == null) { + log.warn( + "Skipping invalid configuration for " + key + " because named plugin not found: " + authorityName); + continue; + } + if (!authorities.containsKey(authorityName)) { + controller.put(fkey, ma); + authorities.put(authorityName, fkey); + } else { + log.warn( + "Skipping invalid configuration for " + key + " because plugin is alredy in use: " + + authorityName + " used by " + authorities + .get(authorityName)); + continue; + } + + log.debug("Choice Control: For field=" + fkey + ", Plugin=" + ma); + } + autoRegisterChoiceAuthorityFromInputReader(); + } + + private void autoRegisterChoiceAuthorityFromInputReader() { + try { + DCInputsReader dcInputsReader = new DCInputsReader(); + for (DCInputSet dcinputSet : dcInputsReader.getAllInputs(Integer.MAX_VALUE, 0)) { + DCInput[][] dcinputs = dcinputSet.getFields(); + for (DCInput[] dcrows : dcinputs) { + for (DCInput dcinput : dcrows) { + if (StringUtils.isNotBlank(dcinput.getPairsType()) + || StringUtils.isNotBlank(dcinput.getVocabulary())) { + String authorityName = dcinput.getPairsType(); + if (StringUtils.isBlank(authorityName)) { + authorityName = dcinput.getVocabulary(); + } + if (!StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) { + String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(), + dcinput.getQualifier()); + ChoiceAuthority ca = controller.get(authorityName); + if (ca == null) { + InputFormSelfRegisterWrapperAuthority ifa = new + InputFormSelfRegisterWrapperAuthority(); + if (controller.containsKey(fieldKey)) { + ifa = (InputFormSelfRegisterWrapperAuthority) controller.get(fieldKey); + } + + ChoiceAuthority ma = (ChoiceAuthority) pluginService + .getNamedPlugin(ChoiceAuthority.class, authorityName); + if (ma == null) { + log.warn("Skipping invalid configuration for " + fieldKey + + " because named plugin not found: " + authorityName); + continue; + } + ifa.getDelegates().put(dcinputSet.getFormName(), ma); + controller.put(fieldKey, ifa); + } + + if (!authorities.containsKey(authorityName)) { + authorities.put(authorityName, fieldKey); + } + + } + } + } + } + } + } catch (DCInputsReaderException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + /** * Return map of key to presentation + * * @return */ - private Map getPresentationMap() - { + private Map getPresentationMap() { // If empty, load from configuration - if(presentation.isEmpty()) - { + if (presentation.isEmpty()) { // Get all configuration keys starting with a given prefix List propKeys = configurationService.getPropertyKeys(CHOICES_PRESENTATION_PREFIX); Iterator keyIterator = propKeys.iterator(); - while(keyIterator.hasNext()) - { + while (keyIterator.hasNext()) { String key = keyIterator.next(); String fkey = config2fkey(key.substring(CHOICES_PRESENTATION_PREFIX.length())); - if (fkey == null) - { - log.warn("Skipping invalid ChoiceAuthority configuration property: "+key+": does not have schema.element.qualifier"); + if (fkey == null) { + log.warn( + "Skipping invalid ChoiceAuthority configuration property: " + key + ": does not have schema" + + ".element.qualifier"); continue; } presentation.put(fkey, configurationService.getProperty(key)); @@ -268,24 +339,23 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService /** * Return map of key to closed setting + * * @return */ - private Map getClosedMap() - { + private Map getClosedMap() { // If empty, load from configuration - if(closed.isEmpty()) - { + if (closed.isEmpty()) { // Get all configuration keys starting with a given prefix List propKeys = configurationService.getPropertyKeys(CHOICES_CLOSED_PREFIX); Iterator keyIterator = propKeys.iterator(); - while(keyIterator.hasNext()) - { + while (keyIterator.hasNext()) { String key = keyIterator.next(); String fkey = config2fkey(key.substring(CHOICES_CLOSED_PREFIX.length())); - if (fkey == null) - { - log.warn("Skipping invalid ChoiceAuthority configuration property: "+key+": does not have schema.element.qualifier"); + if (fkey == null) { + log.warn( + "Skipping invalid ChoiceAuthority configuration property: " + key + ": does not have schema" + + ".element.qualifier"); continue; } closed.put(fkey, configurationService.getBooleanProperty(key)); @@ -295,4 +365,35 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService return closed; } + @Override + public String getChoiceMetadatabyAuthorityName(String name) { + if (authorities.isEmpty()) { + loadChoiceAuthorityConfigurations(); + } + if (authorities.containsKey(name)) { + return authorities.get(name); + } + return null; + } + + @Override + public Choice getChoice(String fieldKey, String authKey, String locale) { + ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey); + if (ma == null) { + throw new IllegalArgumentException("No choices plugin was configured for field \"" + fieldKey + "\"."); + } + return ma.getChoice(fieldKey, authKey, locale); + } + + @Override + public ChoiceAuthority getChoiceAuthorityByAuthorityName(String authorityName) { + ChoiceAuthority ma = (ChoiceAuthority) + pluginService.getNamedPlugin(ChoiceAuthority.class, authorityName); + if (ma == null) { + throw new IllegalArgumentException( + "No choices plugin was configured for authorityName \"" + authorityName + + "\"."); + } + return ma; + } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/Choices.java b/dspace-api/src/main/java/org/dspace/content/authority/Choices.java index 5780f6c1b1..ab5fa162cd 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/Choices.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/Choices.java @@ -16,41 +16,58 @@ import org.apache.commons.lang.ArrayUtils; * @author Larry Stone * @see Choice */ -public class Choices -{ +public class Choices { /** -------------- Class fields ----------------- **/ /** Canonical values of the confidence metric. Higher is better. */ - /** This authority value has been confirmed as accurate by an - interactive user or authoritative policy */ + /** + * This authority value has been confirmed as accurate by an + * interactive user or authoritative policy + */ public static final int CF_ACCEPTED = 600; - /** Value is singular and valid but has not been seen and accepted - by a human, so its provenance is uncertain. */ + /** + * Value is singular and valid but has not been seen and accepted + * by a human, so its provenance is uncertain. + */ public static final int CF_UNCERTAIN = 500; - /** There are multiple matching authority values of equal validity. */ + /** + * There are multiple matching authority values of equal validity. + */ public static final int CF_AMBIGUOUS = 400; - /** There are no matching answers from the authority. */ + /** + * There are no matching answers from the authority. + */ public static final int CF_NOTFOUND = 300; - /** The authority encountered an internal failure - this preserves a - record in the metadata of why there is no value. */ + /** + * The authority encountered an internal failure - this preserves a + * record in the metadata of why there is no value. + */ public static final int CF_FAILED = 200; - /** The authority recommends this submission be rejected. */ + /** + * The authority recommends this submission be rejected. + */ public static final int CF_REJECTED = 100; - /** No reasonable confidence value is available */ + /** + * No reasonable confidence value is available + */ public static final int CF_NOVALUE = 0; - /** Value has not been set (DB default). */ + /** + * Value has not been set (DB default). + */ public static final int CF_UNSET = -1; - /** descriptive labels for confidence values */ + /** + * descriptive labels for confidence values + */ private static final int confidenceValue[] = { CF_UNSET, CF_NOVALUE, @@ -74,37 +91,49 @@ public class Choices /** -------------- Instance fields ----------------- **/ - /** The set of values returned by the authority */ + /** + * The set of values returned by the authority + */ public Choice values[] = null; - /** The confidence level that applies to all values in this result set */ + /** + * The confidence level that applies to all values in this result set + */ public int confidence = CF_NOVALUE; - /** Index of start of this result wrt. all results; 0 is start of - complete result. Note that length is implicit in values.length. */ + /** + * Index of start of this result wrt. all results; 0 is start of + * complete result. Note that length is implicit in values.length. + */ public int start = 0; - /** Count of total results available */ + /** + * Count of total results available + */ public int total = 0; - /** Index of value to be selected by default, if any. -1 means none selected. */ + /** + * Index of value to be selected by default, if any. -1 means none selected. + */ public int defaultSelected = -1; - /** true when there are more values to be sent after this result. */ + /** + * true when there are more values to be sent after this result. + */ public boolean more = false; /** -------------- Methods ----------------- **/ /** * Constructor for general purpose - * @param values values array - * @param start start number - * @param total total results + * + * @param values values array + * @param start start number + * @param total total results * @param confidence confidence level - * @param more whether more values + * @param more whether more values */ - public Choices(Choice values[], int start, int total, int confidence, boolean more) - { + public Choices(Choice values[], int start, int total, int confidence, boolean more) { super(); this.values = (Choice[]) ArrayUtils.clone(values); this.start = start; @@ -115,15 +144,15 @@ public class Choices /** * Constructor for general purpose - * @param values values array - * @param start start number - * @param total total results - * @param confidence confidence level - * @param more whether more values + * + * @param values values array + * @param start start number + * @param total total results + * @param confidence confidence level + * @param more whether more values * @param defaultSelected default selected value */ - public Choices(Choice values[], int start, int total, int confidence, boolean more, int defaultSelected) - { + public Choices(Choice values[], int start, int total, int confidence, boolean more, int defaultSelected) { super(); this.values = (Choice[]) ArrayUtils.clone(values); this.start = start; @@ -135,30 +164,30 @@ public class Choices /** * Constructor for error results + * * @param confidence confidence level */ - public Choices(int confidence) - { + public Choices(int confidence) { this.values = new Choice[0]; this.confidence = confidence; } /** * Constructor for simple empty or error results + * * @param isError whether error */ - public Choices(boolean isError) - { + public Choices(boolean isError) { this.values = new Choice[0]; this.confidence = isError ? CF_FAILED : CF_NOVALUE; } /** * Predicate, did this result encounter an error? + * * @return true if this Choices result encountered an error */ - public boolean isError() - { + public boolean isError() { return confidence == CF_FAILED || confidence == CF_REJECTED; } @@ -169,17 +198,12 @@ public class Choices * @param cv confidence value * @return String with symbolic name corresponding to value (never null) */ - public static String getConfidenceText(int cv) - { + public static String getConfidenceText(int cv) { String novalue = null; - for (int i = 0; i < confidenceValue.length; ++i) - { - if (confidenceValue[i] == cv) - { + for (int i = 0; i < confidenceValue.length; ++i) { + if (confidenceValue[i] == cv) { return confidenceText[i]; - } - else if (confidenceValue[i] == CF_NOVALUE) - { + } else if (confidenceValue[i] == CF_NOVALUE) { novalue = confidenceText[i]; } } @@ -193,8 +217,7 @@ public class Choices * @param ct symbolic name in String * @return corresponding value or CF_NOVALUE if not found */ - public static int getConfidenceValue(String ct) - { + public static int getConfidenceValue(String ct) { return getConfidenceValue(ct, CF_NOVALUE); } @@ -203,16 +226,13 @@ public class Choices * value, or the given default if the symbol is unknown. This * lets an application detect invalid data, e.g. in a configuration file. * - * @param ct symbolic name in String + * @param ct symbolic name in String * @param dflt the default value to return * @return corresponding value or CF_NOVALUE if not found */ - public static int getConfidenceValue(String ct, int dflt) - { - for (int i = 0; i < confidenceText.length; ++i) - { - if (confidenceText[i].equalsIgnoreCase(ct)) - { + public static int getConfidenceValue(String ct, int dflt) { + for (int i = 0; i < confidenceText.length; ++i) { + if (confidenceText[i].equalsIgnoreCase(ct)) { return confidenceValue[i]; } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/ChoicesXMLGenerator.java b/dspace-api/src/main/java/org/dspace/content/authority/ChoicesXMLGenerator.java index 2e0746f8bf..8e8bd60559 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/ChoicesXMLGenerator.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/ChoicesXMLGenerator.java @@ -19,22 +19,23 @@ import org.xml.sax.helpers.AttributesImpl; * @author Larry Stone * @see Choice */ -public class ChoicesXMLGenerator -{ +public class ChoicesXMLGenerator { // use the XHTML NS, even though this is a fragment. protected static final String NS_URI = "http://www.w3.org/1999/xhtml"; protected static final String NS_NAME = ""; + /** + * Default constructor + */ + private ChoicesXMLGenerator() { } + public static void generate(Choices result, String format, ContentHandler contentHandler) - throws SAXException - { + throws SAXException { AttributesImpl resultAtts = new AttributesImpl(); - if (result.more) - { + if (result.more) { resultAtts.addAttribute("", "more", "more", "boolean", "true"); } - if (result.isError()) - { + if (result.isError()) { resultAtts.addAttribute("", "error", "error", "boolean", "true"); } resultAtts.addAttribute("", "start", "start", "int", String.valueOf(result.start)); @@ -43,77 +44,64 @@ public class ChoicesXMLGenerator contentHandler.startDocument(); // "select" HTML format for DSpace popup - if (format != null && format.equalsIgnoreCase("select")) - { + if (format != null && format.equalsIgnoreCase("select")) { contentHandler.startElement(NS_URI, NS_NAME, "select", resultAtts); - for (int i = 0; i < result.values.length; ++i) - { + for (int i = 0; i < result.values.length; ++i) { Choice mdav = result.values[i]; AttributesImpl va = new AttributesImpl(); - va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "":mdav.authority); + va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "" : mdav.authority); va.addAttribute("", "value", "value", "string", mdav.value); - if (result.defaultSelected == i) - { + if (result.defaultSelected == i) { va.addAttribute("", "selected", "selected", "boolean", ""); } contentHandler.startElement(NS_URI, NS_NAME, "option", va); - contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length()); + contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length()); contentHandler.endElement(NS_URI, NS_NAME, "option"); } contentHandler.endElement(NS_URI, NS_NAME, "select"); - } - - // "ul" HTML format (required by Scriptactulous autocomplete) - else if (format != null && format.equalsIgnoreCase("ul")) - { + } else if (format != null && format.equalsIgnoreCase("ul")) { + // "ul" HTML format (required by Scriptactulous autocomplete) AttributesImpl classLabel = new AttributesImpl(); classLabel.addAttribute("", "class", "class", "string", "label"); AttributesImpl classValue = new AttributesImpl(); classValue.addAttribute("", "class", "class", "string", "value"); contentHandler.startElement(NS_URI, NS_NAME, "ul", resultAtts); - for (int i = 0; i < result.values.length; ++i) - { + for (int i = 0; i < result.values.length; ++i) { Choice mdav = result.values[i]; AttributesImpl va = new AttributesImpl(); - va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "":mdav.authority); - if (result.defaultSelected == i) - { + va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "" : mdav.authority); + if (result.defaultSelected == i) { va.addAttribute("", "selected", "selected", "boolean", ""); } contentHandler.startElement(NS_URI, NS_NAME, "li", va); - contentHandler.startElement(NS_URI, NS_NAME, "span", classLabel); - contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length()); - contentHandler.endElement(NS_URI, NS_NAME, "span"); - contentHandler.startElement(NS_URI, NS_NAME, "span", classValue); - contentHandler.characters(mdav.value.toCharArray(), 0, mdav.value.length()); - contentHandler.endElement(NS_URI, NS_NAME, "span"); + contentHandler.startElement(NS_URI, NS_NAME, "span", classLabel); + contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length()); + contentHandler.endElement(NS_URI, NS_NAME, "span"); + contentHandler.startElement(NS_URI, NS_NAME, "span", classValue); + contentHandler.characters(mdav.value.toCharArray(), 0, mdav.value.length()); + contentHandler.endElement(NS_URI, NS_NAME, "span"); contentHandler.endElement(NS_URI, NS_NAME, "li"); } contentHandler.endElement(NS_URI, NS_NAME, "ul"); - } - - // default is XML format, Choices/Choice - else - { + } else { + // default is XML format, Choices/Choice contentHandler.startElement(NS_URI, NS_NAME, "Choices", resultAtts); - for (int i = 0; i < result.values.length; ++i) - { + for (int i = 0; i < result.values.length; ++i) { Choice mdav = result.values[i]; AttributesImpl va = new AttributesImpl(); - va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "":mdav.authority); + va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "" : mdav.authority); va.addAttribute("", "value", "value", "string", mdav.value); - if(mdav.extras != null){ - for(String extraLabel : mdav.extras.keySet()){ + if (mdav.extras != null) { + for (String extraLabel : mdav.extras.keySet()) { va.addAttribute("", extraLabel, extraLabel, "string", mdav.extras.get(extraLabel)); } } - if (result.defaultSelected == i) - { + if (result.defaultSelected == i) { va.addAttribute("", "selected", "selected", "boolean", ""); } contentHandler.startElement(NS_URI, NS_NAME, "Choice", va); - contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length()); + contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length()); contentHandler.endElement(NS_URI, NS_NAME, "Choice"); } contentHandler.endElement(NS_URI, NS_NAME, "Choices"); diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java index 42da4664db..bf01f37f02 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java @@ -7,32 +7,31 @@ */ package org.dspace.content.authority; -import java.util.Iterator; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; import org.apache.commons.lang.ArrayUtils; import org.apache.log4j.Logger; - import org.dspace.app.util.DCInputsReader; import org.dspace.app.util.DCInputsReaderException; import org.dspace.content.Collection; import org.dspace.core.SelfNamedPlugin; /** - * ChoiceAuthority source that reads the same input-forms which drive + * ChoiceAuthority source that reads the same submission-forms which drive * configurable submission. * * Configuration: - * This MUST be configured aas a self-named plugin, e.g.: - * {@code - * plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \ - * org.dspace.content.authority.DCInputAuthority - * } + * This MUST be configured aas a self-named plugin, e.g.: + * {@code + * plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \ + * org.dspace.content.authority.DCInputAuthority + * } * * It AUTOMATICALLY configures a plugin instance for each {@code } - * element (within {@code }) of the input-forms.xml. The name + * element (within {@code }) of the submission-forms.xml. The name * of the instance is the "value-pairs-name" attribute, e.g. * the element: {@code } * defines a plugin instance "common_types". @@ -42,8 +41,7 @@ import org.dspace.core.SelfNamedPlugin; * So you should not use them as the choice source for authority-controlled * fields. */ -public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority -{ +public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority { private static Logger log = Logger.getLogger(DCInputAuthority.class); private String values[] = null; @@ -52,68 +50,52 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority private static DCInputsReader dci = null; private static String pluginNames[] = null; - public DCInputAuthority() - { + public DCInputAuthority() { super(); } - public static String[] getPluginNames() - { - if (pluginNames == null) - { + public static String[] getPluginNames() { + if (pluginNames == null) { initPluginNames(); } - + return (String[]) ArrayUtils.clone(pluginNames); } - private static synchronized void initPluginNames() - { - if (pluginNames == null) - { - try - { - if (dci == null) - { + private static synchronized void initPluginNames() { + if (pluginNames == null) { + try { + if (dci == null) { dci = new DCInputsReader(); } - } - catch (DCInputsReaderException e) - { - log.error("Failed reading DCInputs initialization: ",e); + } catch (DCInputsReaderException e) { + log.error("Failed reading DCInputs initialization: ", e); } List names = new ArrayList(); Iterator pi = dci.getPairsNameIterator(); - while (pi.hasNext()) - { - names.add((String)pi.next()); + while (pi.hasNext()) { + names.add((String) pi.next()); } pluginNames = names.toArray(new String[names.size()]); - log.debug("Got plugin names = "+Arrays.deepToString(pluginNames)); + log.debug("Got plugin names = " + Arrays.deepToString(pluginNames)); } } // once-only load of values and labels - private void init() - { - if (values == null) - { + private void init() { + if (values == null) { String pname = this.getPluginInstanceName(); List pairs = dci.getPairs(pname); - if (pairs != null) - { - values = new String[pairs.size()/2]; - labels = new String[pairs.size()/2]; - for (int i = 0; i < pairs.size(); i += 2) - { - labels[i/2] = pairs.get(i); - values[i/2] = pairs.get(i+1); + if (pairs != null) { + values = new String[pairs.size() / 2]; + labels = new String[pairs.size() / 2]; + for (int i = 0; i < pairs.size(); i += 2) { + labels[i / 2] = pairs.get(i); + values[i / 2] = pairs.get(i + 1); } - log.debug("Found pairs for name="+pname); - } - else - { + log.debug("Found pairs for name=" + pname); + } else { log.error("Failed to find any pairs for name=" + pname, new IllegalStateException()); } } @@ -121,17 +103,14 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority @Override - public Choices getMatches(String field, String query, Collection collection, int start, int limit, String locale) - { + public Choices getMatches(String field, String query, Collection collection, int start, int limit, String locale) { init(); int dflt = -1; Choice v[] = new Choice[values.length]; - for (int i = 0; i < values.length; ++i) - { + for (int i = 0; i < values.length; ++i) { v[i] = new Choice(values[i], values[i], labels[i]); - if (values[i].equalsIgnoreCase(query)) - { + if (values[i].equalsIgnoreCase(query)) { dflt = i; } } @@ -139,13 +118,10 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority } @Override - public Choices getBestMatch(String field, String text, Collection collection, String locale) - { + public Choices getBestMatch(String field, String text, Collection collection, String locale) { init(); - for (int i = 0; i < values.length; ++i) - { - if (text.equalsIgnoreCase(values[i])) - { + for (int i = 0; i < values.length; ++i) { + if (text.equalsIgnoreCase(values[i])) { Choice v[] = new Choice[1]; v[0] = new Choice(String.valueOf(i), values[i], labels[i]); return new Choices(v, 0, v.length, Choices.CF_UNCERTAIN, false, 0); @@ -155,19 +131,19 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority } @Override - public String getLabel(String field, String key, String locale) - { - init(); - int pos=-1; + public String getLabel(String field, String key, String locale) { + init(); + int pos = -1; for (int i = 0; i < values.length; i++) { - if (values[i].equals(key)){ - pos = i; - break; + if (values[i].equals(key)) { + pos = i; + break; } } - if (pos != -1) + if (pos != -1) { return labels[pos]; - else - return "UNKNOWN KEY "+key; + } else { + return "UNKNOWN KEY " + key; + } } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java index 91e0a53fdd..70159c89dd 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java @@ -7,62 +7,60 @@ */ package org.dspace.content.authority; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.io.File; - -import org.apache.commons.lang.ArrayUtils; -import org.dspace.content.Collection; -import org.dspace.services.factory.DSpaceServicesFactory; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import org.xml.sax.InputSource; - +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; - +import org.dspace.content.Collection; import org.dspace.core.SelfNamedPlugin; import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; /** * ChoiceAuthority source that reads the JSPUI-style hierarchical vocabularies - * from {@code ${dspace.dir}/config/controlled-vocabularies/*.xml} and turns them into - * autocompleting authorities. + * from {@code ${dspace.dir}/config/controlled-vocabularies/*.xml} and turns + * them into autocompleting authorities. * - * Configuration: - * This MUST be configured as a self-named plugin, e.g.: - * {@code - * plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \ - * org.dspace.content.authority.DSpaceControlledVocabulary - * } + * Configuration: This MUST be configured as a self-named plugin, e.g.: {@code + * plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \ + * org.dspace.content.authority.DSpaceControlledVocabulary + * } * * It AUTOMATICALLY configures a plugin instance for each XML file in the - * controlled vocabularies directory. The name of the plugin is the basename - * of the file; e.g., {@code ${dspace.dir}/config/controlled-vocabularies/nsi.xml} + * controlled vocabularies directory. The name of the plugin is the basename of + * the file; e.g., {@code ${dspace.dir}/config/controlled-vocabularies/nsi.xml} * would generate a plugin called "nsi". * - * Each configured plugin comes with three configuration options: - * {@code - * vocabulary.plugin._plugin_.hierarchy.store = # Store entire hierarchy along with selected value. Default: TRUE - * vocabulary.plugin._plugin_.hierarchy.suggest = # Display entire hierarchy in the suggestion list. Default: TRUE - * vocabulary.plugin._plugin_.delimiter = "" # Delimiter to use when building hierarchy strings. Default: "::" - * } + * Each configured plugin comes with three configuration options: {@code + * vocabulary.plugin._plugin_.hierarchy.store = + * # Store entire hierarchy along with selected value. Default: TRUE + * vocabulary.plugin._plugin_.hierarchy.suggest = + * # Display entire hierarchy in the suggestion list. Default: TRUE + * vocabulary.plugin._plugin_.delimiter = "" + * # Delimiter to use when building hierarchy strings. Default: "::" + * } * * @author Michael B. Klein - * */ -public class DSpaceControlledVocabulary extends SelfNamedPlugin implements ChoiceAuthority -{ +public class DSpaceControlledVocabulary extends SelfNamedPlugin implements ChoiceAuthority { private static Logger log = Logger.getLogger(DSpaceControlledVocabulary.class); - protected static String xpathTemplate = "//node[contains(translate(@label,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'),'%s')]"; + protected static String xpathTemplate = "//node[contains(translate(@label,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'," + + "'abcdefghijklmnopqrstuvwxyz'),'%s')]"; protected static String idTemplate = "//node[@id = '%s']"; + protected static String idParentTemplate = "//node[@id = '%s']/parent::isComposedBy"; protected static String pluginNames[] = null; protected String vocabularyName = null; @@ -71,39 +69,32 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic protected Boolean storeHierarchy = true; protected String hierarchyDelimiter = "::"; - public DSpaceControlledVocabulary() - { - super(); + public DSpaceControlledVocabulary() { + super(); } - public static String[] getPluginNames() - { - if (pluginNames == null) - { + public static String[] getPluginNames() { + if (pluginNames == null) { initPluginNames(); } - + return (String[]) ArrayUtils.clone(pluginNames); } - private static synchronized void initPluginNames() - { - if (pluginNames == null) - { - class xmlFilter implements java.io.FilenameFilter - { + private static synchronized void initPluginNames() { + if (pluginNames == null) { + class xmlFilter implements java.io.FilenameFilter { @Override - public boolean accept(File dir, String name) - { + public boolean accept(File dir, String name) { return name.endsWith(".xml"); } } - String vocabulariesPath = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") - + "/config/controlled-vocabularies/"; + String vocabulariesPath = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty( + "dspace.dir") + "/config/controlled-vocabularies/"; String[] xmlFiles = (new File(vocabulariesPath)).list(new xmlFilter()); List names = new ArrayList(); - for (String filename : xmlFiles) - { + for (String filename : xmlFiles) { names.add((new File(filename)).getName().replace(".xml", "")); } pluginNames = names.toArray(new String[names.size()]); @@ -111,133 +102,191 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic } } - protected void init() - { - if (vocabulary == null) - { + protected void init() { + if (vocabulary == null) { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); - log.info("Initializing " + this.getClass().getName()); - vocabularyName = this.getPluginInstanceName(); + log.info("Initializing " + this.getClass().getName()); + vocabularyName = this.getPluginInstanceName(); String vocabulariesPath = config.getProperty("dspace.dir") + "/config/controlled-vocabularies/"; String configurationPrefix = "vocabulary.plugin." + vocabularyName; storeHierarchy = config.getBooleanProperty(configurationPrefix + ".hierarchy.store", storeHierarchy); suggestHierarchy = config.getBooleanProperty(configurationPrefix + ".hierarchy.suggest", suggestHierarchy); String configuredDelimiter = config.getProperty(configurationPrefix + ".delimiter"); - if (configuredDelimiter != null) - { - hierarchyDelimiter = configuredDelimiter.replaceAll("(^\"|\"$)",""); + if (configuredDelimiter != null) { + hierarchyDelimiter = configuredDelimiter.replaceAll("(^\"|\"$)", ""); } - String filename = vocabulariesPath + vocabularyName + ".xml"; - log.info("Loading " + filename); + String filename = vocabulariesPath + vocabularyName + ".xml"; + log.info("Loading " + filename); vocabulary = new InputSource(filename); - } + } } - protected String buildString(Node node) - { - if (node.getNodeType() == Node.DOCUMENT_NODE) - { - return(""); - } - else - { - String parentValue = buildString(node.getParentNode()); - Node currentLabel = node.getAttributes().getNamedItem("label"); - if (currentLabel != null) - { - String currentValue = currentLabel.getNodeValue(); - if (parentValue.equals("")) - { - return currentValue; - } - else - { - return(parentValue + this.hierarchyDelimiter + currentValue); - } - } - else - { - return(parentValue); - } - } + protected String buildString(Node node) { + if (node.getNodeType() == Node.DOCUMENT_NODE) { + return (""); + } else { + String parentValue = buildString(node.getParentNode()); + Node currentLabel = node.getAttributes().getNamedItem("label"); + if (currentLabel != null) { + String currentValue = currentLabel.getNodeValue(); + if (parentValue.equals("")) { + return currentValue; + } else { + return (parentValue + this.hierarchyDelimiter + currentValue); + } + } else { + return (parentValue); + } + } } @Override - public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) - { - init(); - log.debug("Getting matches for '" + text + "'"); - String xpathExpression = String.format(xpathTemplate, text.replaceAll("'", "'").toLowerCase()); - XPath xpath = XPathFactory.newInstance().newXPath(); - Choice[] choices; - try { - NodeList results = (NodeList) xpath.evaluate(xpathExpression, - vocabulary, XPathConstants.NODESET); + public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) { + init(); + log.debug("Getting matches for '" + text + "'"); + String xpathExpression = ""; + String[] textHierarchy = text.split(hierarchyDelimiter, -1); + for (int i = 0; i < textHierarchy.length; i++) { + xpathExpression += String.format(xpathTemplate, textHierarchy[i].replaceAll("'", "'").toLowerCase()); + } + XPath xpath = XPathFactory.newInstance().newXPath(); + Choice[] choices; + try { + NodeList results = (NodeList) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODESET); String[] authorities = new String[results.getLength()]; String[] values = new String[results.getLength()]; String[] labels = new String[results.getLength()]; - for (int i = 0; i < results.getLength(); i++) - { + String[] parent = new String[results.getLength()]; + String[] notes = new String[results.getLength()]; + for (int i = 0; i < results.getLength(); i++) { Node node = results.item(i); - String hierarchy = this.buildString(node); - if (this.suggestHierarchy) - { - labels[i] = hierarchy; - } - else - { - labels[i] = node.getAttributes().getNamedItem("label").getNodeValue(); - } - if (this.storeHierarchy) - { - values[i] = hierarchy; - } - else - { - values[i] = node.getAttributes().getNamedItem("label").getNodeValue(); - } - Node idAttr = node.getAttributes().getNamedItem("id"); - if (null != idAttr) // 'id' is optional - authorities[i] = idAttr.getNodeValue(); + readNode(authorities, values, labels, parent, notes, i, node); } int resultCount = labels.length - start; - if ((limit > 0) && (resultCount > limit)) // limit = 0 means no limit + // limit = 0 means no limit + if ((limit > 0) && (resultCount > limit)) { resultCount = limit; + } choices = new Choice[resultCount]; - if (resultCount > 0) - { - for (int i = 0; i < resultCount; i++) - { - choices[i] = new Choice(authorities[start + i], values[start - + i], labels[start + i]); + if (resultCount > 0) { + for (int i = 0; i < resultCount; i++) { + choices[i] = new Choice(authorities[start + i], values[start + i], labels[start + i]); + if (StringUtils.isNotBlank(parent[i])) { + choices[i].extras.put("parent", parent[i]); + } + if (StringUtils.isNotBlank(notes[i])) { + choices[i].extras.put("note", notes[i]); + } } } - } catch(XPathExpressionException e) { - choices = new Choice[0]; - } - return new Choices(choices, 0, choices.length, Choices.CF_AMBIGUOUS, false); + } catch (XPathExpressionException e) { + choices = new Choice[0]; + } + return new Choices(choices, 0, choices.length, Choices.CF_AMBIGUOUS, false); } @Override - public Choices getBestMatch(String field, String text, Collection collection, String locale) - { - init(); - log.debug("Getting best match for '" + text + "'"); + public Choices getBestMatch(String field, String text, Collection collection, String locale) { + init(); + log.debug("Getting best match for '" + text + "'"); return getMatches(field, text, collection, 0, 2, locale); } @Override - public String getLabel(String field, String key, String locale) - { - init(); - String xpathExpression = String.format(idTemplate, key); - XPath xpath = XPathFactory.newInstance().newXPath(); - try { - Node node = (Node)xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODE); - return node.getAttributes().getNamedItem("label").getNodeValue(); - } catch(XPathExpressionException e) { - return(""); - } + public String getLabel(String field, String key, String locale) { + init(); + String xpathExpression = String.format(idTemplate, key); + XPath xpath = XPathFactory.newInstance().newXPath(); + try { + Node node = (Node) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODE); + return node.getAttributes().getNamedItem("label").getNodeValue(); + } catch (XPathExpressionException e) { + return (""); + } } + + @Override + public boolean isHierarchical() { + return true; + } + + @Override + public Choice getChoice(String fieldKey, String authKey, String locale) { + init(); + log.debug("Getting matches for '" + authKey + "'"); + String xpathExpression = String.format(idTemplate, authKey); + XPath xpath = XPathFactory.newInstance().newXPath(); + try { + Node node = (Node) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODE); + if (node != null) { + String[] authorities = new String[1]; + String[] values = new String[1]; + String[] labels = new String[1]; + String[] parent = new String[1]; + String[] note = new String[1]; + readNode(authorities, values, labels, parent, note, 0, node); + + if (values.length > 0) { + Choice choice = new Choice(authorities[0], values[0], labels[0]); + if (StringUtils.isNotBlank(parent[0])) { + choice.extras.put("parent", parent[0]); + } + if (StringUtils.isNotBlank(note[0])) { + choice.extras.put("note", note[0]); + } + return choice; + } + } + } catch (XPathExpressionException e) { + log.warn(e.getMessage(), e); + } + return new Choice("", "", ""); + } + + private void readNode(String[] authorities, String[] values, String[] labels, String[] parent, String[] notes, + int i, Node node) { + String hierarchy = this.buildString(node); + if (this.suggestHierarchy) { + labels[i] = hierarchy; + } else { + labels[i] = node.getAttributes().getNamedItem("label").getNodeValue(); + } + if (this.storeHierarchy) { + values[i] = hierarchy; + } else { + values[i] = node.getAttributes().getNamedItem("label").getNodeValue(); + } + + NodeList childNodes = node.getChildNodes(); + for (int ci = 0; ci < childNodes.getLength(); ci++) { + Node firstChild = childNodes.item(ci); + if (firstChild != null && "hasNote".equals(firstChild.getNodeName())) { + String nodeValue = firstChild.getTextContent(); + if (StringUtils.isNotBlank(nodeValue)) { + notes[i] = nodeValue; + } + } + } + Node idAttr = node.getAttributes().getNamedItem("id"); + if (null != idAttr) { // 'id' is optional + authorities[i] = idAttr.getNodeValue(); + if (isHierarchical()) { + Node parentN = node.getParentNode(); + if (parentN != null) { + parentN = parentN.getParentNode(); + if (parentN != null) { + Node parentIdAttr = parentN.getAttributes().getNamedItem("id"); + if (null != parentIdAttr) { + parent[i] = parentIdAttr.getNodeValue(); + } + } + } + } + } else { + authorities[i] = null; + parent[i] = null; + } + } + } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/InputFormSelfRegisterWrapperAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/InputFormSelfRegisterWrapperAuthority.java new file mode 100644 index 0000000000..acfe4292f6 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/authority/InputFormSelfRegisterWrapperAuthority.java @@ -0,0 +1,165 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.content.authority; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.dspace.app.util.DCInputsReader; +import org.dspace.app.util.DCInputsReaderException; +import org.dspace.content.Collection; + +/** + * This authority is registered automatically by the ChoiceAuthorityService for + * all the metadata that use a value-pair or a vocabulary in the submission-form.xml + * + * It keeps a map of form-name vs ChoiceAuthority to delegate the execution of + * the method to the specific ChoiceAuthority configured for the collection when + * the same metadata have different vocabulary or value-pair on a collection + * basis + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + */ +public class InputFormSelfRegisterWrapperAuthority implements ChoiceAuthority { + + private static Logger log = Logger.getLogger(InputFormSelfRegisterWrapperAuthority.class); + + private Map delegates = new HashMap(); + + private static DCInputsReader dci = null; + + private void init() { + try { + if (dci == null) { + dci = new DCInputsReader(); + } + } catch (DCInputsReaderException e) { + log.error("Failed reading DCInputs initialization: ", e); + } + } + + @Override + public Choices getMatches(String field, String query, Collection collection, int start, int limit, String locale) { + String formName; + try { + init(); + if (collection == null) { + Set choices = new HashSet(); + //workaround search in all authority configured + for (ChoiceAuthority ca : delegates.values()) { + Choices tmp = ca.getMatches(field, query, null, start, limit, locale); + if (tmp.total > 0) { + Set mySet = new HashSet(Arrays.asList(tmp.values)); + choices.addAll(mySet); + } + } + if (!choices.isEmpty()) { + Choice[] results = new Choice[choices.size() - 1]; + choices.toArray(results); + return new Choices(results, 0, choices.size(), Choices.CF_AMBIGUOUS, false); + } + } else { + formName = dci.getInputFormNameByCollectionAndField(collection, field); + return delegates.get(formName).getMatches(field, query, collection, start, limit, locale); + } + } catch (DCInputsReaderException e) { + log.error(e.getMessage(), e); + } + return new Choices(Choices.CF_NOTFOUND); + } + + @Override + public Choices getBestMatch(String field, String text, Collection collection, String locale) { + String formName; + try { + init(); + if (collection == null) { + Set choices = new HashSet(); + //workaround search in all authority configured + for (ChoiceAuthority ca : delegates.values()) { + Choices tmp = ca.getBestMatch(field, text, null, locale); + if (tmp.total > 0) { + Set mySet = new HashSet(Arrays.asList(tmp.values)); + choices.addAll(mySet); + } + } + if (!choices.isEmpty()) { + Choice[] results = new Choice[choices.size() - 1]; + choices.toArray(results); + return new Choices(results, 0, choices.size(), Choices.CF_UNCERTAIN, false); + } + } else { + formName = dci.getInputFormNameByCollectionAndField(collection, field); + return delegates.get(formName).getBestMatch(field, text, collection, locale); + } + } catch (DCInputsReaderException e) { + log.error(e.getMessage(), e); + } + return new Choices(Choices.CF_NOTFOUND); + } + + @Override + public String getLabel(String field, String key, String locale) { + // TODO we need to manage REALLY the authority + // WRONG BEHAVIOUR: now in each delegates can exists the same key with + // different value + for (ChoiceAuthority delegate : delegates.values()) { + String label = delegate.getLabel(field, key, locale); + if (StringUtils.isNotBlank(label)) { + return label; + } + } + return "UNKNOWN KEY " + key; + } + + @Override + public boolean isHierarchical() { + // TODO we need to manage REALLY the authority + // WRONG BEHAVIOUR: now in each delegates can exists the same key with + // different value + for (ChoiceAuthority delegate : delegates.values()) { + return delegate.isHierarchical(); + } + return false; + } + + @Override + public boolean isScrollable() { + // TODO we need to manage REALLY the authority + // WRONG BEHAVIOUR: now in each delegates can exists the same key with + // different value + for (ChoiceAuthority delegate : delegates.values()) { + return delegate.isScrollable(); + } + return false; + } + + @Override + public boolean hasIdentifier() { + // TODO we need to manage REALLY the authority + // WRONG BEHAVIOUR: now in each delegates can exists the same key with + // different value + for (ChoiceAuthority delegate : delegates.values()) { + return delegate.hasIdentifier(); + } + return false; + } + + public Map getDelegates() { + return delegates; + } + + public void setDelegates(Map delegates) { + this.delegates = delegates; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/authority/LCNameAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/LCNameAuthority.java index 8c008b10b5..77da8400ea 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/LCNameAuthority.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/LCNameAuthority.java @@ -10,24 +10,11 @@ package org.dspace.content.authority; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.util.List; import java.util.ArrayList; -import javax.xml.parsers.SAXParserFactory; -import javax.xml.parsers.SAXParser; +import java.util.List; import javax.xml.parsers.ParserConfigurationException; - -import org.dspace.content.Collection; -import org.xml.sax.XMLReader; -import org.xml.sax.InputSource; -import org.xml.sax.helpers.DefaultHandler; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import org.apache.log4j.Logger; - -import org.dspace.core.ConfigurationManager; -import org.dspace.content.DCPersonName; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -35,6 +22,16 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.log4j.Logger; +import org.dspace.content.Collection; +import org.dspace.content.DCPersonName; +import org.dspace.core.ConfigurationManager; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; /** * Sample personal name authority based on Library of Congress Name Authority @@ -52,15 +49,14 @@ import org.apache.http.impl.client.DefaultHttpClient; * * Reads these DSpace Config properties: * - * lcname.url = http://alcme.oclc.org/srw/search/lcnaf + * lcname.url = http://alcme.oclc.org/srw/search/lcnaf * - * TODO: make # of results to ask for (and return) configurable. + * TODO: make # of results to ask for (and return) configurable. * * @author Larry Stone * @version $Revision $ */ -public class LCNameAuthority implements ChoiceAuthority -{ +public class LCNameAuthority implements ChoiceAuthority { private static final Logger log = Logger.getLogger(LCNameAuthority.class); // get these from configuration @@ -73,15 +69,12 @@ public class LCNameAuthority implements ChoiceAuthority protected static final String NS_MX = "http://www.loc.gov/MARC21/slim"; // constructor does static init too.. - public LCNameAuthority() - { - if (url == null) - { + public LCNameAuthority() { + if (url == null) { url = ConfigurationManager.getProperty("lcname.url"); // sanity check - if (url == null) - { + if (url == null) { throw new IllegalStateException("Missing DSpace configuration keys for LCName Query"); } } @@ -89,8 +82,7 @@ public class LCNameAuthority implements ChoiceAuthority // punt! this is a poor implementation.. @Override - public Choices getBestMatch(String field, String text, Collection collection, String locale) - { + public Choices getBestMatch(String field, String text, Collection collection, String locale) { return getMatches(field, text, collection, 0, 2, locale); } @@ -99,22 +91,19 @@ public class LCNameAuthority implements ChoiceAuthority * Value is assumed to be in "Lastname, Firstname" format. */ @Override - public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) - { + public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) { Choices result = queryPerson(text, start, limit); - if (result == null) - { + if (result == null) { result = new Choices(true); } - + return result; } // punt; supposed to get the canonical display form of a metadata authority key // XXX FIXME implement this with a query on the authority key, cache results @Override - public String getLabel(String field, String key, String locale) - { + public String getLabel(String field, String key, String locale) { return key; } @@ -122,11 +111,9 @@ public class LCNameAuthority implements ChoiceAuthority * Guts of the implementation, returns a complete Choices result, or * null for a failure. */ - private Choices queryPerson(String text, int start, int limit) - { + private Choices queryPerson(String text, int start, int limit) { // punt if there is no query text - if (text == null || text.trim().length() == 0) - { + if (text == null || text.trim().length() == 0) { return new Choices(true); } @@ -134,12 +121,11 @@ public class LCNameAuthority implements ChoiceAuthority DCPersonName pn = new DCPersonName(text); StringBuilder query = new StringBuilder(); query.append("local.FirstName = \"").append(pn.getFirstNames()). - append("\" and local.FamilyName = \"").append(pn.getLastName()). - append("\""); + append("\" and local.FamilyName = \"").append(pn.getLastName()). + append("\""); // XXX arbitrary default limit - should be configurable? - if (limit == 0) - { + if (limit == 0) { limit = 50; } @@ -151,7 +137,7 @@ public class LCNameAuthority implements ChoiceAuthority builder.addParameter("recordSchema", "info:srw/schema/1/marcxml-v1.1"); builder.addParameter("query", query.toString()); builder.addParameter("maximumRecords", String.valueOf(limit)); - builder.addParameter("startRecord", String.valueOf(start+1)); + builder.addParameter("startRecord", String.valueOf(start + 1)); sruUri = builder.build(); } catch (URISyntaxException e) { log.error("SRU query failed: ", e); @@ -162,12 +148,10 @@ public class LCNameAuthority implements ChoiceAuthority log.debug("Trying SRU query, URL=" + sruUri); // 2. web request - try - { + try { HttpClient hc = new DefaultHttpClient(); HttpResponse response = hc.execute(get); - if (response.getStatusLine().getStatusCode() == 200) - { + if (response.getStatusLine().getStatusCode() == 200) { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); @@ -182,52 +166,38 @@ public class LCNameAuthority implements ChoiceAuthority xr.parse(new InputSource(responseBody.getContent())); // this probably just means more results available.. - if (handler.hits != handler.result.size()) - { + if (handler.hits != handler.result.size()) { log.warn("Discrepency in results, result.length=" + handler.result.size() + - ", yet expected results=" + handler.hits); + ", yet expected results=" + handler.hits); } boolean more = handler.hits > (start + handler.result.size()); // XXX add non-auth option; perhaps the UI should do this? // XXX it's really a policy matter if they allow unauth result. - // XXX good, stop it. + // XXX good, stop it. // handler.result.add(new Choice("", text, "Non-Authority: \""+text+"\"")); int confidence; - if (handler.hits == 0) - { + if (handler.hits == 0) { confidence = Choices.CF_NOTFOUND; - } - else if (handler.hits == 1) - { + } else if (handler.hits == 1) { confidence = Choices.CF_UNCERTAIN; - } - else - { + } else { confidence = Choices.CF_AMBIGUOUS; } return new Choices(handler.result.toArray(new Choice[handler.result.size()]), start, handler.hits, confidence, more); } - } - catch (IOException e) - { + } catch (IOException e) { log.error("SRU query failed: ", e); return new Choices(true); - } - catch (ParserConfigurationException e) - { + } catch (ParserConfigurationException e) { log.warn("Failed parsing SRU result: ", e); return new Choices(true); - } - catch (SAXException e) - { + } catch (SAXException e) { log.warn("Failed parsing SRU result: ", e); return new Choices(true); - } - finally - { + } finally { get.releaseConnection(); } return new Choices(true); @@ -241,8 +211,7 @@ public class LCNameAuthority implements ChoiceAuthority * Should probably read other 100 subfields to build a more detailed label. */ private static class SRUHandler - extends DefaultHandler - { + extends DefaultHandler { private List result = new ArrayList(); private int hits = -1; private String textValue = null; @@ -258,17 +227,12 @@ public class LCNameAuthority implements ChoiceAuthority // options of a real object system like CLOS?) @Override public void characters(char[] ch, int start, int length) - throws SAXException - { + throws SAXException { String newValue = new String(ch, start, length); - if (newValue.length() > 0) - { - if (textValue == null) - { + if (newValue.length() > 0) { + if (textValue == null) { textValue = newValue; - } - else - { + } else { textValue += newValue; } } @@ -276,62 +240,44 @@ public class LCNameAuthority implements ChoiceAuthority @Override public void endElement(String namespaceURI, String localName, - String qName) - throws SAXException - { + String qName) + throws SAXException { if (localName.equals("numberOfRecords") && - namespaceURI.equals(NS_SRU)) - { + namespaceURI.equals(NS_SRU)) { hits = Integer.parseInt(textValue.trim()); - if (hits > 0) - { + if (hits > 0) { name = null; lccn = null; - log.debug("Expecting "+hits+" records in results."); + log.debug("Expecting " + hits + " records in results."); } - } - - // after record get next hit ready - else if (localName.equals("record") && - namespaceURI.equals(NS_SRU)) - { - if (name != null && lccn != null) - { + } else if (localName.equals("record") && + namespaceURI.equals(NS_SRU)) { + // after record get next hit ready + if (name != null && lccn != null) { // HACK: many LC name entries end with ',' ...trim it. - if (name.endsWith(",")) - { + if (name.endsWith(",")) { name = name.substring(0, name.length() - 1); } // XXX DEBUG // log.debug("Got result, name="+name+", lccn="+lccn); result.add(new Choice(lccn, name, name)); - } - else - { + } else { log.warn("Got anomalous result, at least one of these null: lccn=" + lccn + ", name=" + name); } name = null; lccn = null; - } - - else if (localName.equals("subfield") && namespaceURI.equals(NS_MX)) - { - if (lastTag != null && lastCode != null) - { - if (lastTag.equals("010") && lastCode.equals("a")) - { + } else if (localName.equals("subfield") && namespaceURI.equals(NS_MX)) { + if (lastTag != null && lastCode != null) { + if (lastTag.equals("010") && lastCode.equals("a")) { // 010.a is lccn, "authority code" lccn = textValue; - } - else if (lastTag.equals("100") && lastCode.equals("a")) - { + } else if (lastTag.equals("100") && lastCode.equals("a")) { // 100.a is the personal name name = textValue; } - if (lastTag.equals("100") && lastCode.equals("d") && (name != null)) - { + if (lastTag.equals("100") && lastCode.equals("d") && (name != null)) { name = name + " " + textValue; } } @@ -342,25 +288,19 @@ public class LCNameAuthority implements ChoiceAuthority @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) - throws SAXException - { + throws SAXException { textValue = null; if (localName.equals("datafield") && - namespaceURI.equals(NS_MX)) - { + namespaceURI.equals(NS_MX)) { lastTag = atts.getValue("tag"); - if (lastTag == null) - { + if (lastTag == null) { log.warn("MARC datafield without tag attribute!"); } - } - else if (localName.equals("subfield") && - namespaceURI.equals(NS_MX)) - { + } else if (localName.equals("subfield") && + namespaceURI.equals(NS_MX)) { lastCode = atts.getValue("code"); - if (lastCode == null) - { + if (lastCode == null) { log.warn("MARC subfield without code attribute!"); } } @@ -368,15 +308,13 @@ public class LCNameAuthority implements ChoiceAuthority @Override public void error(SAXParseException exception) - throws SAXException - { + throws SAXException { throw new SAXException(exception); } @Override public void fatalError(SAXParseException exception) - throws SAXException - { + throws SAXException { throw new SAXException(exception); } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/MetadataAuthorityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/authority/MetadataAuthorityServiceImpl.java index 21ec172d2d..dc9797598f 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/MetadataAuthorityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/MetadataAuthorityServiceImpl.java @@ -9,14 +9,17 @@ package org.dspace.content.authority; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.HashMap; -import java.util.Enumeration; - +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; - +import org.dspace.app.util.DCInput; +import org.dspace.app.util.DCInputSet; +import org.dspace.app.util.DCInputsReader; +import org.dspace.app.util.DCInputsReaderException; import org.dspace.content.MetadataField; import org.dspace.content.authority.service.MetadataAuthorityService; import org.dspace.content.service.MetadataFieldService; @@ -29,42 +32,41 @@ import org.springframework.beans.factory.annotation.Autowired; * * Configuration keys, per metadata field (e.g. "dc.contributer.author") * - * {@code - * # is field authority controlled (i.e. store authority, confidence values)? - * authority.controlled. = true + * {@code + * # is field authority controlled (i.e. store authority, confidence values)? + * authority.controlled. = true * - * # is field required to have an authority value, or may it be empty? - * # default is false. - * authority.required. = true | false + * # is field required to have an authority value, or may it be empty? + * # default is false. + * authority.required. = true | false * - * # default value of minimum confidence level for ALL fields - must be - * # symbolic confidence level, see org.dspace.content.authority.Choices - * authority.minconfidence = uncertain + * # default value of minimum confidence level for ALL fields - must be + * # symbolic confidence level, see org.dspace.content.authority.Choices + * authority.minconfidence = uncertain * - * # minimum confidence level for this field - * authority.minconfidence.SCHEMA.ELEMENT.QUALIFIER = SYMBOL - * e.g. - * authority.minconfidence.dc.contributor.author = accepted - * } + * # minimum confidence level for this field + * authority.minconfidence.SCHEMA.ELEMENT.QUALIFIER = SYMBOL + * e.g. + * authority.minconfidence.dc.contributor.author = accepted + * } * NOTE: There is *expected* to be a "choices" (see ChoiceAuthorityManager) * configuration for each authority-controlled field. * + * @author Larry Stone * @see ChoiceAuthorityServiceImpl * @see Choices - * @author Larry Stone */ -public class MetadataAuthorityServiceImpl implements MetadataAuthorityService -{ +public class MetadataAuthorityServiceImpl implements MetadataAuthorityService { private static Logger log = Logger.getLogger(MetadataAuthorityServiceImpl.class); @Autowired(required = true) protected MetadataFieldService metadataFieldService; // map of field key to authority plugin - protected Map controlled = new HashMap(); + protected Map controlled = new HashMap(); // map of field key to answer of whether field is required to be controlled - protected Map isAuthorityRequired = null; + protected Map isAuthorityRequired = null; /** * map of field key to answer of which is the min acceptable confidence @@ -72,64 +74,65 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService */ protected Map minConfidence = new HashMap(); - /** fallback default value unless authority.minconfidence = X is configured. */ + /** + * fallback default value unless authority.minconfidence = X is configured. + */ protected int defaultMinConfidence = Choices.CF_ACCEPTED; - protected MetadataAuthorityServiceImpl() - { + protected MetadataAuthorityServiceImpl() { } public void init() { - if(isAuthorityRequired == null) - { - isAuthorityRequired = new HashMap(); + if (isAuthorityRequired == null) { + isAuthorityRequired = new HashMap(); Enumeration pn = ConfigurationManager.propertyNames(); final String authPrefix = "authority.controlled."; Context context = new Context(); try { - while (pn.hasMoreElements()) - { - String key = (String)pn.nextElement(); - if (key.startsWith(authPrefix)) - { + while (pn.hasMoreElements()) { + String key = (String) pn.nextElement(); + if (key.startsWith(authPrefix)) { // field is expected to be "schema.element.qualifier" String field = key.substring(authPrefix.length()); int dot = field.indexOf('.'); - if (dot < 0) - { - log.warn("Skipping invalid MetadataAuthority configuration property: "+key+": does not have schema.element.qualifier"); + if (dot < 0) { + log.warn( + "Skipping invalid MetadataAuthority configuration property: " + key + ": does not " + + "have schema.element.qualifier"); continue; } String schema = field.substring(0, dot); - String element = field.substring(dot+1); + String element = field.substring(dot + 1); String qualifier = null; dot = element.indexOf('.'); - if (dot >= 0) - { - qualifier = element.substring(dot+1); + if (dot >= 0) { + qualifier = element.substring(dot + 1); element = element.substring(0, dot); } - MetadataField metadataField = metadataFieldService.findByElement(context, schema, element, qualifier); - if(metadataField == null) - { - throw new IllegalStateException("Error while configuring authority control, metadata field: " + field + " could not be found"); + MetadataField metadataField = metadataFieldService + .findByElement(context, schema, element, qualifier); + if (metadataField == null) { + throw new IllegalStateException( + "Error while configuring authority control, metadata field: " + field + " could not " + + "be found"); } boolean ctl = ConfigurationManager.getBooleanProperty(key, true); - boolean req = ConfigurationManager.getBooleanProperty("authority.required."+field, false); + boolean req = ConfigurationManager.getBooleanProperty("authority.required." + field, false); controlled.put(metadataField.toString(), ctl); isAuthorityRequired.put(metadataField.toString(), req); // get minConfidence level for this field if any - int mci = readConfidence("authority.minconfidence."+field); - if (mci >= Choices.CF_UNSET) - { + int mci = readConfidence("authority.minconfidence." + field); + if (mci >= Choices.CF_UNSET) { minConfidence.put(metadataField.toString(), mci); } - log.debug("Authority Control: For schema="+schema+", elt="+element+", qual="+qualifier+", controlled="+ctl+", required="+req); + log.debug( + "Authority Control: For schema=" + schema + ", elt=" + element + ", qual=" + qualifier + + ", controlled=" + ctl + ", required=" + req); } } } catch (SQLException e) { @@ -138,63 +141,56 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService // get default min confidence if any: int dmc = readConfidence("authority.minconfidence"); - if (dmc >= Choices.CF_UNSET) - { + if (dmc >= Choices.CF_UNSET) { defaultMinConfidence = dmc; } + + autoRegisterAuthorityFromInputReader(); } } - private int readConfidence(String key) - { + private int readConfidence(String key) { String mc = ConfigurationManager.getProperty(key); - if (mc != null) - { - int mci = Choices.getConfidenceValue(mc.trim(), Choices.CF_UNSET-1); - if (mci == Choices.CF_UNSET-1) - { - log.warn("IGNORING bad value in DSpace Configuration, key="+key+", value="+mc+", must be a valid Authority Confidence keyword."); - } - else - { + if (mc != null) { + int mci = Choices.getConfidenceValue(mc.trim(), Choices.CF_UNSET - 1); + if (mci == Choices.CF_UNSET - 1) { + log.warn( + "IGNORING bad value in DSpace Configuration, key=" + key + ", value=" + mc + ", must be a valid " + + "Authority Confidence keyword."); + } else { return mci; } } - return Choices.CF_UNSET-1; + return Choices.CF_UNSET - 1; } @Override - public boolean isAuthorityControlled(MetadataField metadataField) - { + public boolean isAuthorityControlled(MetadataField metadataField) { init(); return isAuthorityControlled(makeFieldKey(metadataField)); } @Override - public boolean isAuthorityControlled(String fieldKey) - { + public boolean isAuthorityControlled(String fieldKey) { init(); return controlled.containsKey(fieldKey) && controlled.get(fieldKey); } @Override - public boolean isAuthorityRequired(MetadataField metadataField) - { + public boolean isAuthorityRequired(MetadataField metadataField) { init(); return isAuthorityRequired(makeFieldKey(metadataField)); } @Override - public boolean isAuthorityRequired(String fieldKey) - { + public boolean isAuthorityRequired(String fieldKey) { init(); Boolean result = isAuthorityRequired.get(fieldKey); return (result != null) && result; } @Override - public String makeFieldKey(MetadataField metadataField) - { + public String makeFieldKey(MetadataField metadataField) { init(); return metadataField.toString(); } @@ -202,12 +198,9 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService @Override public String makeFieldKey(String schema, String element, String qualifier) { init(); - if (qualifier == null) - { + if (qualifier == null) { return schema + "_" + element; - } - else - { + } else { return schema + "_" + element + "_" + qualifier; } } @@ -216,12 +209,12 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService /** * Give the minimal level of confidence required to consider valid an authority value * for the given metadata. + * * @param metadataField metadata field * @return the minimal valid level of confidence for the given metadata */ @Override - public int getMinConfidence(MetadataField metadataField) - { + public int getMinConfidence(MetadataField metadataField) { init(); Integer result = minConfidence.get(makeFieldKey(metadataField)); return result == null ? defaultMinConfidence : result; @@ -231,10 +224,40 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService public List getAuthorityMetadata() { init(); List copy = new ArrayList<>(); - for (String s : controlled.keySet()) - { - copy.add(s.replaceAll("_",".")); + for (String s : controlled.keySet()) { + copy.add(s.replaceAll("_", ".")); } return copy; } + + + private void autoRegisterAuthorityFromInputReader() { + try { + DCInputsReader dcInputsReader = new DCInputsReader(); + for (DCInputSet dcinputSet : dcInputsReader.getAllInputs(Integer.MAX_VALUE, 0)) { + DCInput[][] dcinputs = dcinputSet.getFields(); + for (DCInput[] dcrows : dcinputs) { + for (DCInput dcinput : dcrows) { + if (StringUtils.isNotBlank(dcinput.getPairsType()) + || StringUtils.isNotBlank(dcinput.getVocabulary())) { + String authorityName = dcinput.getPairsType(); + if (StringUtils.isBlank(authorityName)) { + authorityName = dcinput.getVocabulary(); + } + if (!StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) { + String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(), + dcinput.getQualifier()); + boolean req = ConfigurationManager + .getBooleanProperty("authority.required." + fieldKey, false); + controlled.put(fieldKey, true); + isAuthorityRequired.put(fieldKey, req); + } + } + } + } + } + } catch (DCInputsReaderException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOJournalTitle.java b/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOJournalTitle.java index ed7335ece4..8677a0be44 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOJournalTitle.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOJournalTitle.java @@ -9,6 +9,7 @@ package org.dspace.content.authority; import java.util.ArrayList; import java.util.List; + import org.apache.http.message.BasicNameValuePair; import org.dspace.content.Collection; @@ -16,42 +17,37 @@ import org.dspace.content.Collection; * Sample Journal-name authority based on SHERPA/RoMEO * * WARNING: This is a very crude and incomplete implementation, done mainly - * as a proof-of-concept. Any site that actually wants to use it will - * probably have to refine it (and give patches back to dspace.org). + * as a proof-of-concept. Any site that actually wants to use it will + * probably have to refine it (and give patches back to dspace.org). * - * @see SHERPARoMEOProtocol * @author Larry Stone * @version $Revision $ + * @see SHERPARoMEOProtocol */ -public class SHERPARoMEOJournalTitle extends SHERPARoMEOProtocol -{ +public class SHERPARoMEOJournalTitle extends SHERPARoMEOProtocol { private static final String RESULT = "journal"; private static final String LABEL = "jtitle"; private static final String AUTHORITY = "issn"; - public SHERPARoMEOJournalTitle() - { + public SHERPARoMEOJournalTitle() { super(); } @Override - public Choices getMatches(String text, Collection collection, int start, int limit, String locale) - { + public Choices getMatches(String text, Collection collection, int start, int limit, String locale) { // punt if there is no query text - if (text == null || text.trim().length() == 0) - { + if (text == null || text.trim().length() == 0) { return new Choices(true); } // query args to add to SHERPA/RoMEO request URL List args = new ArrayList(); args.add(new BasicNameValuePair("jtitle", text)); - args.add(new BasicNameValuePair("qtype","contains")); // OR: starts, exact + args.add(new BasicNameValuePair("qtype", "contains")); // OR: starts, exact Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit); - if (result == null) - { - result = new Choices(true); + if (result == null) { + result = new Choices(true); } return result; } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOProtocol.java b/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOProtocol.java index fcfcf355e6..5bc94bf06a 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOProtocol.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOProtocol.java @@ -9,21 +9,9 @@ package org.dspace.content.authority; import java.io.IOException; import java.util.List; -import javax.xml.parsers.SAXParserFactory; -import javax.xml.parsers.SAXParser; import javax.xml.parsers.ParserConfigurationException; - -import org.dspace.content.Collection; -import org.xml.sax.XMLReader; -import org.xml.sax.InputSource; -import org.xml.sax.helpers.DefaultHandler; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import org.apache.log4j.Logger; - -import org.dspace.core.ConfigurationManager; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; @@ -31,6 +19,15 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; +import org.apache.log4j.Logger; +import org.dspace.content.Collection; +import org.dspace.core.ConfigurationManager; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; /** * Choice Authority based on SHERPA/RoMEO - for Publishers and Journals @@ -40,34 +37,30 @@ import org.apache.http.message.BasicNameValuePair; * * Reads these DSpace Config properties: * - * # contact URL for server - * sherpa.romeo.url = http://www.sherpa.ac.uk/romeoapi11.php + * # contact URL for server + * sherpa.romeo.url = http://www.sherpa.ac.uk/romeoapi11.php * * WARNING: This is a very crude and incomplete implementation, done mainly - * as a proof-of-concept. Any site that actually wants to use it will - * probably have to refine it (and give patches back to dspace.org). + * as a proof-of-concept. Any site that actually wants to use it will + * probably have to refine it (and give patches back to dspace.org). * - * @see SHERPARoMEOPublisher - * @see SHERPARoMEOJournalTitle * @author Larry Stone * @version $Revision $ + * @see SHERPARoMEOPublisher + * @see SHERPARoMEOJournalTitle */ -public abstract class SHERPARoMEOProtocol implements ChoiceAuthority -{ +public abstract class SHERPARoMEOProtocol implements ChoiceAuthority { private static final Logger log = Logger.getLogger(SHERPARoMEOProtocol.class); // contact URL from configuration private static String url = null; - public SHERPARoMEOProtocol() - { - if (url == null) - { + public SHERPARoMEOProtocol() { + if (url == null) { url = ConfigurationManager.getProperty("sherpa.romeo.url"); // sanity check - if (url == null) - { + if (url == null) { throw new IllegalStateException("Missing DSpace configuration keys for SHERPA/RoMEO Query"); } } @@ -77,34 +70,29 @@ public abstract class SHERPARoMEOProtocol implements ChoiceAuthority public abstract Choices getMatches(String text, Collection collection, int start, int limit, String locale); @Override - public Choices getBestMatch(String field, String text, Collection collection, String locale) - { + public Choices getBestMatch(String field, String text, Collection collection, String locale) { return getMatches(field, text, collection, 0, 2, locale); } // XXX FIXME just punt, returning value, never got around to // implementing a reverse query. @Override - public String getLabel(String field, String key, String locale) - { + public String getLabel(String field, String key, String locale) { return key; } // NOTE - ignore limit and start for now protected Choices query(String result, String label, String authority, - List args, int start, int limit) - { + List args, int start, int limit) { HttpClient hc = new DefaultHttpClient(); String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8"); HttpGet get = new HttpGet(srUrl); log.debug("Trying SHERPA/RoMEO Query, URL=" + srUrl); - try - { + try { HttpResponse response = hc.execute(get); - if (response.getStatusLine().getStatusCode() == 200) - { + if (response.getStatusLine().getStatusCode() == 200) { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); @@ -117,38 +105,25 @@ public abstract class SHERPARoMEOProtocol implements ChoiceAuthority xr.setErrorHandler(handler); xr.parse(new InputSource(response.getEntity().getContent())); int confidence; - if (handler.total == 0) - { + if (handler.total == 0) { confidence = Choices.CF_NOTFOUND; - } - else if (handler.total == 1) - { + } else if (handler.total == 1) { confidence = Choices.CF_UNCERTAIN; - } - else - { + } else { confidence = Choices.CF_AMBIGUOUS; } return new Choices(handler.result, start, handler.total, confidence, false); } - } - catch (IOException e) - { + } catch (IOException e) { log.error("SHERPA/RoMEO query failed: ", e); return null; - } - catch (ParserConfigurationException e) - { + } catch (ParserConfigurationException e) { log.warn("Failed parsing SHERPA/RoMEO result: ", e); return null; - } - catch (SAXException e) - { + } catch (SAXException e) { log.warn("Failed parsing SHERPA/RoMEO result: ", e); return null; - } - finally - { + } finally { get.releaseConnection(); } return null; @@ -156,8 +131,7 @@ public abstract class SHERPARoMEOProtocol implements ChoiceAuthority // SAX handler to grab SHERPA/RoMEO (and eventually other details) from result private static class SRHandler - extends DefaultHandler - { + extends DefaultHandler { private Choice result[] = null; int rindex = 0; // result index int total = 0; @@ -173,8 +147,7 @@ public abstract class SHERPARoMEOProtocol implements ChoiceAuthority protected String textValue = null; - public SRHandler(String result, String label, String authority) - { + public SRHandler(String result, String label, String authority) { super(); resultElement = result; labelElement = label; @@ -188,17 +161,12 @@ public abstract class SHERPARoMEOProtocol implements ChoiceAuthority // options of a real object system like CLOS?) @Override public void characters(char[] ch, int start, int length) - throws SAXException - { + throws SAXException { String newValue = new String(ch, start, length); - if (newValue.length() > 0) - { - if (textValue == null) - { + if (newValue.length() > 0) { + if (textValue == null) { textValue = newValue; - } - else - { + } else { textValue += newValue; } } @@ -207,44 +175,31 @@ public abstract class SHERPARoMEOProtocol implements ChoiceAuthority // if this was the FIRST "numhits" element, it's size of results: @Override public void endElement(String namespaceURI, String localName, - String qName) - throws SAXException - { - if (localName.equals("numhits")) - { + String qName) + throws SAXException { + if (localName.equals("numhits")) { String stotal = textValue.trim(); - if (stotal.length() > 0) - { + if (stotal.length() > 0) { total = Integer.parseInt(stotal); result = new Choice[total]; - if (total > 0) - { + if (total > 0) { result[0] = new Choice(); - log.debug("Got "+total+" records in results."); + log.debug("Got " + total + " records in results."); } } - } - else if (localName.equals(resultElement)) - { + } else if (localName.equals(resultElement)) { // after start of result element, get next hit ready - if (++rindex < result.length) - { + if (++rindex < result.length) { result[rindex] = new Choice(); } - } - else if (localName.equals(labelElement) && textValue != null) - { + } else if (localName.equals(labelElement) && textValue != null) { // plug in label value result[rindex].value = textValue.trim(); - result[rindex].label = result[rindex].value; - } - else if (authorityElement != null && localName.equals(authorityElement) && textValue != null) - { + result[rindex].label = result[rindex].value; + } else if (authorityElement != null && localName.equals(authorityElement) && textValue != null) { // plug in authority value result[rindex].authority = textValue.trim(); - } - else if (localName.equals("message") && textValue != null) - { + } else if (localName.equals("message") && textValue != null) { // error message log.warn("SHERPA/RoMEO response error message: " + textValue.trim()); } @@ -254,22 +209,19 @@ public abstract class SHERPARoMEOProtocol implements ChoiceAuthority @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) - throws SAXException - { + throws SAXException { textValue = null; } @Override public void error(SAXParseException exception) - throws SAXException - { + throws SAXException { throw new SAXException(exception); } @Override public void fatalError(SAXParseException exception) - throws SAXException - { + throws SAXException { throw new SAXException(exception); } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOPublisher.java b/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOPublisher.java index 770fcd7ed7..d16ccf4022 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOPublisher.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/SHERPARoMEOPublisher.java @@ -9,6 +9,7 @@ package org.dspace.content.authority; import java.util.ArrayList; import java.util.List; + import org.apache.http.message.BasicNameValuePair; import org.dspace.content.Collection; @@ -17,43 +18,38 @@ import org.dspace.content.Collection; * * * WARNING: This is a very crude and incomplete implementation, done mainly - * as a proof-of-concept. Any site that actually wants to use it will - * probably have to refine it (and give patches back to dspace.org). + * as a proof-of-concept. Any site that actually wants to use it will + * probably have to refine it (and give patches back to dspace.org). * - * @see SHERPARoMEOProtocol * @author Larry Stone * @version $Revision $ + * @see SHERPARoMEOProtocol */ -public class SHERPARoMEOPublisher extends SHERPARoMEOProtocol -{ +public class SHERPARoMEOPublisher extends SHERPARoMEOProtocol { protected static final String RESULT = "publisher"; protected static final String LABEL = "name"; // note: the publisher records have nothing we can use as authority code. protected static final String AUTHORITY = null; - public SHERPARoMEOPublisher() - { + public SHERPARoMEOPublisher() { super(); } @Override - public Choices getMatches(String text, Collection collection, int start, int limit, String locale) - { + public Choices getMatches(String text, Collection collection, int start, int limit, String locale) { // punt if there is no query text - if (text == null || text.trim().length() == 0) - { + if (text == null || text.trim().length() == 0) { return new Choices(true); } // query args to add to SHERPA/RoMEO request URL List args = new ArrayList(); args.add(new BasicNameValuePair("pub", text)); - args.add(new BasicNameValuePair("qtype","all")); // OR: starts, exact + args.add(new BasicNameValuePair("qtype", "all")); // OR: starts, exact Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit); - if (result == null) - { - result = new Choices(true); + if (result == null) { + result = new Choices(true); } return result; } @@ -61,5 +57,5 @@ public class SHERPARoMEOPublisher extends SHERPARoMEOProtocol @Override public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) { return getMatches(text, collection, start, limit, locale); - } + } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/SampleAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/SampleAuthority.java index 6601b070c5..8197f180af 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/SampleAuthority.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/SampleAuthority.java @@ -13,8 +13,7 @@ import org.dspace.content.Collection; * This is a *very* stupid test fixture for authority control, and also * serves as a trivial example of an authority plugin implementation. */ -public class SampleAuthority implements ChoiceAuthority -{ +public class SampleAuthority implements ChoiceAuthority { protected static String values[] = { "sun", "mon", @@ -36,15 +35,12 @@ public class SampleAuthority implements ChoiceAuthority }; @Override - public Choices getMatches(String field, String query, Collection collection, int start, int limit, String locale) - { + public Choices getMatches(String field, String query, Collection collection, int start, int limit, String locale) { int dflt = -1; Choice v[] = new Choice[values.length]; - for (int i = 0; i < values.length; ++i) - { + for (int i = 0; i < values.length; ++i) { v[i] = new Choice(String.valueOf(i), values[i], labels[i]); - if (values[i].equalsIgnoreCase(query)) - { + if (values[i].equalsIgnoreCase(query)) { dflt = i; } } @@ -52,12 +48,9 @@ public class SampleAuthority implements ChoiceAuthority } @Override - public Choices getBestMatch(String field, String text, Collection collection, String locale) - { - for (int i = 0; i < values.length; ++i) - { - if (text.equalsIgnoreCase(values[i])) - { + public Choices getBestMatch(String field, String text, Collection collection, String locale) { + for (int i = 0; i < values.length; ++i) { + if (text.equalsIgnoreCase(values[i])) { Choice v[] = new Choice[1]; v[0] = new Choice(String.valueOf(i), values[i], labels[i]); return new Choices(v, 0, v.length, Choices.CF_UNCERTAIN, false, 0); @@ -67,8 +60,7 @@ public class SampleAuthority implements ChoiceAuthority } @Override - public String getLabel(String field, String key, String locale) - { + public String getLabel(String field, String key, String locale) { return labels[Integer.parseInt(key)]; } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/SolrAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/SolrAuthority.java index 692a149571..e6dbe45cc0 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/SolrAuthority.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/SolrAuthority.java @@ -7,10 +7,11 @@ */ package org.dspace.content.authority; -import org.dspace.authority.AuthoritySearchService; -import org.dspace.authority.AuthorityValue; -import org.dspace.authority.factory.AuthorityServiceFactory; -import org.dspace.authority.rest.RestSource; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.solr.client.solrj.SolrQuery; @@ -18,18 +19,16 @@ import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.params.CommonParams; +import org.dspace.authority.AuthoritySearchService; +import org.dspace.authority.AuthorityValue; +import org.dspace.authority.SolrAuthorityInterface; +import org.dspace.authority.factory.AuthorityServiceFactory; import org.dspace.authority.service.AuthorityValueService; import org.dspace.content.Collection; import org.dspace.core.ConfigurationManager; import org.dspace.services.factory.DSpaceServicesFactory; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - /** - * * @author Antoine Snyers (antoine at atmire.com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -38,13 +37,18 @@ import java.util.Map; public class SolrAuthority implements ChoiceAuthority { private static final Logger log = Logger.getLogger(SolrAuthority.class); - protected RestSource source = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("AuthoritySource", RestSource.class); + protected SolrAuthorityInterface source = + DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("AuthoritySource", SolrAuthorityInterface.class); protected boolean externalResults = false; - protected final AuthorityValueService authorityValueService = AuthorityServiceFactory.getInstance().getAuthorityValueService(); + protected final AuthorityValueService authorityValueService = AuthorityServiceFactory.getInstance() + .getAuthorityValueService(); - public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale, boolean bestMatch) { - if(limit == 0) + public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale, + boolean bestMatch) { + if (limit == 0) { limit = 10; + } SolrQuery queryArgs = new SolrQuery(); if (text == null || text.trim().equals("")) { @@ -74,7 +78,7 @@ public class SolrAuthority implements ChoiceAuthority { queryArgs.set(CommonParams.START, start); //We add one to our facet limit so that we know if there are more matches int maxNumberOfSolrResults = limit + 1; - if(externalResults){ + if (externalResults) { maxNumberOfSolrResults = ConfigurationManager.getIntProperty("xmlui.lookup.select.size", 12); } queryArgs.set(CommonParams.ROWS, maxNumberOfSolrResults); @@ -98,8 +102,9 @@ public class SolrAuthority implements ChoiceAuthority { if (authDocs != null) { max = (int) searchResponse.getResults().getNumFound(); int maxDocs = authDocs.size(); - if (limit < maxDocs) + if (limit < maxDocs) { maxDocs = limit; + } List alreadyPresent = new ArrayList(); for (int i = 0; i < maxDocs; i++) { SolrDocument solrDocument = authDocs.get(i); @@ -115,7 +120,8 @@ public class SolrAuthority implements ChoiceAuthority { if (externalResults && StringUtils.isNotBlank(text)) { int sizeFromSolr = alreadyPresent.size(); - int maxExternalResults = limit <= 10 ? Math.max(limit - sizeFromSolr, 2) : Math.max(limit - 10 - sizeFromSolr, 2) + limit - 10; + int maxExternalResults = limit <= 10 ? Math.max(limit - sizeFromSolr, 2) : Math + .max(limit - 10 - sizeFromSolr, 2) + limit - 10; addExternalResults(text, choices, alreadyPresent, maxExternalResults); } @@ -126,14 +132,16 @@ public class SolrAuthority implements ChoiceAuthority { int confidence; - if (choices.size() == 0) + if (choices.size() == 0) { confidence = Choices.CF_NOTFOUND; - else if (choices.size() == 1) + } else if (choices.size() == 1) { confidence = Choices.CF_UNCERTAIN; - else + } else { confidence = Choices.CF_AMBIGUOUS; + } - result = new Choices(choices.toArray(new Choice[choices.size()]), start, hasMore ? max : choices.size() + start, confidence, hasMore); + result = new Choices(choices.toArray(new Choice[choices.size()]), start, + hasMore ? max : choices.size() + start, confidence, hasMore); } catch (Exception e) { log.error("Error while retrieving authority values {field: " + field + ", prefix:" + text + "}", e); result = new Choices(true); @@ -142,10 +150,12 @@ public class SolrAuthority implements ChoiceAuthority { return result; //To change body of implemented methods use File | Settings | File Templates. } - protected void addExternalResults(String text, ArrayList choices, List alreadyPresent, int max) { - if(source != null){ + protected void addExternalResults(String text, ArrayList choices, List alreadyPresent, + int max) { + if (source != null) { try { - List values = source.queryAuthorities(text, max * 2); // max*2 because results get filtered + List values = source + .queryAuthorities(text, max * 2); // max*2 because results get filtered // filtering loop Iterator iterator = values.iterator(); @@ -176,7 +186,8 @@ public class SolrAuthority implements ChoiceAuthority { } private String toQuery(String searchField, String text) { - return searchField + ":\"" + text.toLowerCase().replaceAll(":", "\\:") + "*\" or " + searchField + ":\"" + text.toLowerCase().replaceAll(":", "\\:")+"\""; + return searchField + ":\"" + text.toLowerCase().replaceAll(":", "\\:") + "*\" or " + searchField + ":\"" + text + .toLowerCase().replaceAll(":", "\\:") + "\""; } @Override @@ -187,7 +198,7 @@ public class SolrAuthority implements ChoiceAuthority { @Override public Choices getBestMatch(String field, String text, Collection collection, String locale) { Choices matches = getMatches(field, text, collection, 0, 1, locale, false); - if (matches.values.length !=0 && !matches.values[0].value.equalsIgnoreCase(text)) { + if (matches.values.length != 0 && !matches.values[0].value.equalsIgnoreCase(text)) { matches = new Choices(false); } return matches; @@ -213,35 +224,41 @@ public class SolrAuthority implements ChoiceAuthority { } if (label != null) { if (log.isDebugEnabled()) { - log.debug("returning label " + label + " for key " + key + " using locale " + locale + " and fieldvalue " + "value_" + locale); + log.debug( + "returning label " + label + " for key " + key + " using locale " + locale + " and " + + "fieldvalue " + "value_" + locale); } return label; } try { label = (String) docs.get(0).getFieldValue("value"); } catch (Exception e) { - log.error("couldn't get field value for key " + key,e); + log.error("couldn't get field value for key " + key, e); } if (label != null) { if (log.isDebugEnabled()) { - log.debug("returning label " + label + " for key " + key + " using locale " + locale + " and fieldvalue " + "value"); + log.debug( + "returning label " + label + " for key " + key + " using locale " + locale + " and " + + "fieldvalue " + "value"); } return label; } try { label = (String) docs.get(0).getFieldValue("value_en"); } catch (Exception e) { - log.error("couldn't get field value for key " + key,e); + log.error("couldn't get field value for key " + key, e); } if (label != null) { if (log.isDebugEnabled()) { - log.debug("returning label " + label + " for key " + key + " using locale " + locale + " and fieldvalue " + "value_en"); + log.debug( + "returning label " + label + " for key " + key + " using locale " + locale + " and " + + "fieldvalue " + "value_en"); } return label; } } } catch (Exception e) { - log.error("error occurred while trying to get label for key " + key,e); + log.error("error occurred while trying to get label for key " + key, e); } return key; diff --git a/dspace-api/src/main/java/org/dspace/content/authority/TestAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/TestAuthority.java index 3dfaa44fc0..8c3c94e5f1 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/TestAuthority.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/TestAuthority.java @@ -15,21 +15,17 @@ import org.dspace.content.Collection; /** * This is a *very* stupid test fixture for authority control with AuthorityVariantsSupport. - * + * * @author Andrea Bollini (CILEA) */ -public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport -{ +public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport { @Override - public List getVariants(String key, String locale) - { - if (StringUtils.isNotBlank(key)) - { + public List getVariants(String key, String locale) { + if (StringUtils.isNotBlank(key)) { List variants = new ArrayList(); - for (int i = 0; i < 3; i++) - { - variants.add(key+"_variant#"+i); + for (int i = 0; i < 3; i++) { + variants.add(key + "_variant#" + i); } return variants; } @@ -38,51 +34,44 @@ public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport @Override public Choices getMatches(String field, String text, Collection collection, - int start, int limit, String locale) - { + int start, int limit, String locale) { Choices choices = new Choices(false); - if (StringUtils.isNotBlank(text)) - { - + if (StringUtils.isNotBlank(text)) { + List choiceValues = new ArrayList(); - for (int i = 0; i < 3; i++) - { + for (int i = 0; i < 3; i++) { choiceValues.add(new Choice(text + "_authority#" + i, text - + "_value#" + i, text + "_label#" + i)); + + "_value#" + i, text + "_label#" + i)); } choices = new Choices( - (Choice[]) choiceValues.toArray(new Choice[choiceValues - .size()]), 0, 3, Choices.CF_AMBIGUOUS, false); + (Choice[]) choiceValues.toArray(new Choice[choiceValues + .size()]), 0, 3, Choices.CF_AMBIGUOUS, false); } - + return choices; } @Override public Choices getBestMatch(String field, String text, Collection collection, - String locale) - { + String locale) { Choices choices = new Choices(false); - if (StringUtils.isNotBlank(text)) - { - + if (StringUtils.isNotBlank(text)) { + List choiceValues = new ArrayList(); - - choiceValues.add(new Choice(text + "_authoritybest", text - + "_valuebest", text + "_labelbest")); - + + choiceValues.add(new Choice(text + "_authoritybest", text + + "_valuebest", text + "_labelbest")); + choices = new Choices( - (Choice[]) choiceValues.toArray(new Choice[choiceValues - .size()]), 0, 3, Choices.CF_UNCERTAIN, false); + (Choice[]) choiceValues.toArray(new Choice[choiceValues + .size()]), 0, 3, Choices.CF_UNCERTAIN, false); } return choices; } @Override - public String getLabel(String field, String key, String locale) - { - if (StringUtils.isNotBlank(key)) - { + public String getLabel(String field, String key, String locale) { + if (StringUtils.isNotBlank(key)) { return key.replaceAll("authority", "label"); } return "Unknown"; diff --git a/dspace-api/src/main/java/org/dspace/content/authority/factory/ContentAuthorityServiceFactory.java b/dspace-api/src/main/java/org/dspace/content/authority/factory/ContentAuthorityServiceFactory.java index b28f1da1ba..45c8840cc3 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/factory/ContentAuthorityServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/factory/ContentAuthorityServiceFactory.java @@ -12,7 +12,8 @@ import org.dspace.content.authority.service.MetadataAuthorityService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the content.authority package, use ContentAuthorityServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the content.authority package, use ContentAuthorityServiceFactory.getInstance + * () to retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -22,7 +23,9 @@ public abstract class ContentAuthorityServiceFactory { public abstract MetadataAuthorityService getMetadataAuthorityService(); - public static ContentAuthorityServiceFactory getInstance(){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("contentAuthorityServiceFactory", ContentAuthorityServiceFactory.class); + public static ContentAuthorityServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("contentAuthorityServiceFactory", + ContentAuthorityServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/factory/ContentAuthorityServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/content/authority/factory/ContentAuthorityServiceFactoryImpl.java index d69a48912e..eb68ec8497 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/factory/ContentAuthorityServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/factory/ContentAuthorityServiceFactoryImpl.java @@ -12,7 +12,8 @@ import org.dspace.content.authority.service.MetadataAuthorityService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the content.authority package, use ContentAuthorityServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the content.authority package, use ContentAuthorityServiceFactory + * .getInstance() to retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -26,14 +27,12 @@ public class ContentAuthorityServiceFactoryImpl extends ContentAuthorityServiceF @Override - public ChoiceAuthorityService getChoiceAuthorityService() - { + public ChoiceAuthorityService getChoiceAuthorityService() { return choiceAuthorityService; } @Override - public MetadataAuthorityService getMetadataAuthorityService() - { + public MetadataAuthorityService getMetadataAuthorityService() { return metadataAuthorityService; } } diff --git a/dspace-api/src/main/java/org/dspace/content/authority/service/ChoiceAuthorityService.java b/dspace-api/src/main/java/org/dspace/content/authority/service/ChoiceAuthorityService.java index 0b2381b944..b29d8a329a 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/service/ChoiceAuthorityService.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/service/ChoiceAuthorityService.java @@ -7,99 +7,123 @@ */ package org.dspace.content.authority.service; +import java.util.List; +import java.util.Set; + import org.dspace.content.Collection; import org.dspace.content.MetadataValue; +import org.dspace.content.authority.Choice; import org.dspace.content.authority.ChoiceAuthority; import org.dspace.content.authority.Choices; -import java.util.List; - /** * Broker for ChoiceAuthority plugins, and for other information configured * about the choice aspect of authority control for a metadata field. * * Configuration keys, per metadata field (e.g. "dc.contributer.author") - * {@code - * # names the ChoiceAuthority plugin called for this field - * choices.plugin. = name-of-plugin + * {@code + * # names the ChoiceAuthority plugin called for this field + * choices.plugin. = name-of-plugin * - * # mode of UI presentation desired in submission UI: - * # "select" is dropdown menu, "lookup" is popup with selector, "suggest" is autocomplete/suggest - * choices.presentation. = "select" | "suggest" + * # mode of UI presentation desired in submission UI: + * # "select" is dropdown menu, "lookup" is popup with selector, "suggest" is autocomplete/suggest + * choices.presentation. = "select" | "suggest" + * + * # is value "closed" to the set of these choices or are non-authority values permitted? + * choices.closed. = true | false + * } * - * # is value "closed" to the set of these choices or are non-authority values permitted? - * choices.closed. = true | false - * } * @author Larry Stone * @see ChoiceAuthority */ -public interface ChoiceAuthorityService -{ +public interface ChoiceAuthorityService { /** - * Wrapper that calls getMatches method of the plugin corresponding to - * the metadata field defined by schema,element,qualifier. - * - * @see org.dspace.content.authority.ChoiceAuthority#getMatches(java.lang.String, java.lang.String, org.dspace.content.Collection, int, int, java.lang.String) - * @param schema schema of metadata field - * @param element element of metadata field + * @return the names of all the defined choice authorities + */ + public Set getChoiceAuthoritiesNames(); + + /** + * @param schema schema of metadata field + * @param element element of metadata field * @param qualifier qualifier of metadata field - * @param query user's value to match + * @return the name of the choice authority associated with the specified + * metadata. Throw IllegalArgumentException if the supplied metadat + * is not associated with an authority choice + */ + public String getChoiceAuthorityName(String schema, String element, String qualifier); + + /** + * Wrapper that calls getMatches method of the plugin corresponding to + * the metadata field defined by schema,element,qualifier. + * + * @param schema schema of metadata field + * @param element element of metadata field + * @param qualifier qualifier of metadata field + * @param query user's value to match * @param collection database ID of Collection for context (owner of Item) - * @param start choice at which to start, 0 is first. - * @param limit maximum number of choices to return, 0 for no limit. - * @param locale explicit localization key if available, or null + * @param start choice at which to start, 0 is first. + * @param limit maximum number of choices to return, 0 for no limit. + * @param locale explicit localization key if available, or null * @return a Choices object (never null). + * @see org.dspace.content.authority.ChoiceAuthority#getMatches(java.lang.String, java.lang.String, org.dspace + * .content.Collection, int, int, java.lang.String) */ public Choices getMatches(String schema, String element, String qualifier, String query, Collection collection, int start, int limit, String locale); + /** - * Wrapper calls getMatches method of the plugin corresponding to - * the metadata field defined by single field key. + * Wrapper calls getMatches method of the plugin corresponding to + * the metadata field defined by single field key. * - * @see org.dspace.content.authority.ChoiceAuthority#getMatches(java.lang.String, java.lang.String, org.dspace.content.Collection, int, int, java.lang.String) - * @param fieldKey single string identifying metadata field - * @param query user's value to match + * @param fieldKey single string identifying metadata field + * @param query user's value to match * @param collection database ID of Collection for context (owner of Item) - * @param start choice at which to start, 0 is first. - * @param limit maximum number of choices to return, 0 for no limit. - * @param locale explicit localization key if available, or null + * @param start choice at which to start, 0 is first. + * @param limit maximum number of choices to return, 0 for no limit. + * @param locale explicit localization key if available, or null * @return a Choices object (never null). + * @see org.dspace.content.authority.ChoiceAuthority#getMatches(java.lang.String, java.lang.String, org.dspace + * .content.Collection, int, int, java.lang.String) */ public Choices getMatches(String fieldKey, String query, Collection collection, int start, int limit, String locale); - public Choices getMatches(String fieldKey, String query, Collection collection, int start, int limit, String locale, boolean externalInput); + public Choices getMatches(String fieldKey, String query, Collection collection, int start, int limit, String locale, + boolean externalInput); /** - * Wrapper that calls getBestMatch method of the plugin corresponding to - * the metadata field defined by single field key. + * Wrapper that calls getBestMatch method of the plugin corresponding to + * the metadata field defined by single field key. * - * @see org.dspace.content.authority.ChoiceAuthority#getBestMatch(java.lang.String, java.lang.String, org.dspace.content.Collection, java.lang.String) - * @param fieldKey single string identifying metadata field - * @param query user's value to match + * @param fieldKey single string identifying metadata field + * @param query user's value to match * @param collection database ID of Collection for context (owner of Item) - * @param locale explicit localization key if available, or null + * @param locale explicit localization key if available, or null * @return a Choices object (never null) with 1 or 0 values. + * @see org.dspace.content.authority.ChoiceAuthority#getBestMatch(java.lang.String, java.lang.String, org.dspace + * .content.Collection, java.lang.String) */ public Choices getBestMatch(String fieldKey, String query, Collection collection, String locale); /** - * Wrapper that calls getLabel method of the plugin corresponding to - * the metadata field defined by schema,element,qualifier. + * Wrapper that calls getLabel method of the plugin corresponding to + * the metadata field defined by schema,element,qualifier. + * * @param metadataValue metadata value - * @param locale explicit localization key if available + * @param locale explicit localization key if available * @return label */ public String getLabel(MetadataValue metadataValue, String locale); /** - * Wrapper that calls getLabel method of the plugin corresponding to - * the metadata field defined by single field key. + * Wrapper that calls getLabel method of the plugin corresponding to + * the metadata field defined by single field key. + * * @param fieldKey single string identifying metadata field - * @param locale explicit localization key if available - * @param authKey authority key + * @param locale explicit localization key if available + * @param authKey authority key * @return label */ public String getLabel(String fieldKey, String authKey, String locale); @@ -107,6 +131,7 @@ public interface ChoiceAuthorityService /** * Predicate, is there a Choices configuration of any kind for the * given metadata field? + * * @param fieldKey single string identifying metadata field * @return true if choices are configured for this field. */ @@ -131,8 +156,16 @@ public interface ChoiceAuthorityService /** * Wrapper to call plugin's getVariants(). + * * @param metadataValue metadata value * @return List of variants */ public List getVariants(MetadataValue metadataValue); -} \ No newline at end of file + + public String getChoiceMetadatabyAuthorityName(String name); + + public Choice getChoice(String fieldKey, String authKey, String locale); + + public ChoiceAuthority getChoiceAuthorityByAuthorityName(String authorityName); + +} diff --git a/dspace-api/src/main/java/org/dspace/content/authority/service/MetadataAuthorityService.java b/dspace-api/src/main/java/org/dspace/content/authority/service/MetadataAuthorityService.java index 66436be6de..3cf16b35c9 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/service/MetadataAuthorityService.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/service/MetadataAuthorityService.java @@ -7,65 +7,69 @@ */ package org.dspace.content.authority.service; -import org.dspace.content.MetadataField; - import java.util.List; +import org.dspace.content.MetadataField; + /** * Broker for metadata authority settings configured for each metadata field. * * Configuration keys, per metadata field (e.g. "dc.contributer.author") * - * # is field authority controlled (i.e. store authority, confidence values)? - * {@code authority.controlled. = true} + * # is field authority controlled (i.e. store authority, confidence values)? + * {@code authority.controlled. = true} * - * # is field required to have an authority value, or may it be empty? - * # default is false. - * {@code authority.required. = true | false} + * # is field required to have an authority value, or may it be empty? + * # default is false. + * {@code authority.required. = true | false} * - * # default value of minimum confidence level for ALL fields - must be - * # symbolic confidence level, see org.dspace.content.authority.Choices - * {@code authority.minconfidence = uncertain} + * # default value of minimum confidence level for ALL fields - must be + * # symbolic confidence level, see org.dspace.content.authority.Choices + * {@code authority.minconfidence = uncertain} * - * # minimum confidence level for this field - * {@code authority.minconfidence.SCHEMA.ELEMENT.QUALIFIER = SYMBOL} - * e.g. - * {@code authority.minconfidence.dc.contributor.author = accepted} + * # minimum confidence level for this field + * {@code authority.minconfidence.SCHEMA.ELEMENT.QUALIFIER = SYMBOL} + * e.g. + * {@code authority.minconfidence.dc.contributor.author = accepted} * * NOTE: There is *expected* to be a "choices" (see ChoiceAuthorityManager) * configuration for each authority-controlled field. * + * @author Larry Stone * @see org.dspace.content.authority.ChoiceAuthorityServiceImpl * @see org.dspace.content.authority.Choices - * @author Larry Stone */ public interface MetadataAuthorityService { - /** + /** * Predicate - is field authority-controlled? + * * @param metadataField metadata field * @return true/false */ public boolean isAuthorityControlled(MetadataField metadataField); - /** + /** * Predicate - is field authority-controlled? + * * @param fieldKey field key * @return true/false */ public boolean isAuthorityControlled(String fieldKey); - /** + /** * Predicate - is authority value required for field? + * * @param metadataField metadata field - * @return true/false + * @return true/false */ public boolean isAuthorityRequired(MetadataField metadataField); - /** + /** * Predicate - is authority value required for field? + * * @param fieldKey field key - * @return true/false + * @return true/false */ public boolean isAuthorityRequired(String fieldKey); @@ -74,6 +78,7 @@ public interface MetadataAuthorityService { * Construct a single key from the tuple of schema/element/qualifier * that describes a metadata field. Punt to the function we use for * submission UI input forms, for now. + * * @param metadataField metadata field * @return field key */ @@ -83,8 +88,9 @@ public interface MetadataAuthorityService { * Construct a single key from the tuple of schema/element/qualifier * that describes a metadata field. Punt to the function we use for * submission UI input forms, for now. - * @param schema schema - * @param element element + * + * @param schema schema + * @param element element * @param qualifier qualifier * @return field key */ @@ -93,6 +99,7 @@ public interface MetadataAuthorityService { /** * Give the minimal level of confidence required to consider valid an authority value * for the given metadata. + * * @param metadataField metadata field * @return the minimal valid level of confidence for the given metadata */ diff --git a/dspace-api/src/main/java/org/dspace/content/comparator/NameAscendingComparator.java b/dspace-api/src/main/java/org/dspace/content/comparator/NameAscendingComparator.java index bb78300e55..980554228b 100644 --- a/dspace-api/src/main/java/org/dspace/content/comparator/NameAscendingComparator.java +++ b/dspace-api/src/main/java/org/dspace/content/comparator/NameAscendingComparator.java @@ -7,28 +7,28 @@ */ package org.dspace.content.comparator; +import java.util.Comparator; + import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.dspace.content.DSpaceObject; -import java.util.Comparator; - -public class NameAscendingComparator implements Comparator{ +public class NameAscendingComparator implements Comparator { @Override public int compare(DSpaceObject dso1, DSpaceObject dso2) { - if (dso1 == dso2){ + if (dso1 == dso2) { return 0; - }else if (dso1 == null){ + } else if (dso1 == null) { return -1; - }else if (dso2 == null){ + } else if (dso2 == null) { return 1; - }else { + } else { String name1 = StringUtils.trimToEmpty(dso1.getName()); String name2 = StringUtils.trimToEmpty(dso2.getName()); //When two DSO's have the same name, use their UUID to put them in an order - if(name1.equals(name2)) { + if (name1.equals(name2)) { return ObjectUtils.compare(dso1.getID(), dso2.getID()); } else { return name1.compareToIgnoreCase(name2); @@ -36,4 +36,4 @@ public class NameAscendingComparator implements Comparator{ } } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/AIPDIMCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/AIPDIMCrosswalk.java index a5d29247d7..2d919baa9d 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/AIPDIMCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/AIPDIMCrosswalk.java @@ -8,14 +8,12 @@ package org.dspace.content.crosswalk; import java.io.IOException; +import java.sql.SQLException; import java.util.List; -import java.sql.SQLException; - -import org.dspace.core.Context; -import org.dspace.content.DSpaceObject; import org.dspace.authorize.AuthorizeException; - +import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; import org.jdom.Element; import org.jdom.Namespace; @@ -39,8 +37,7 @@ import org.jdom.Namespace; * @version $Revision: 1.2 $ */ public class AIPDIMCrosswalk - implements DisseminationCrosswalk, IngestionCrosswalk -{ + implements DisseminationCrosswalk, IngestionCrosswalk { /** * Get XML namespaces of the elements this crosswalk may return. * Returns the XML namespaces (as JDOM objects) of the root element. @@ -48,8 +45,7 @@ public class AIPDIMCrosswalk * @return array of namespaces, which may be empty. */ @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { Namespace result[] = new Namespace[1]; result[0] = XSLTCrosswalk.DIM_NS; return result; @@ -59,16 +55,16 @@ public class AIPDIMCrosswalk * Get the XML Schema location(s) of the target metadata format. * Returns the string value of the xsi:schemaLocation * attribute that should be applied to the generated XML. - *

    + *

    * It may return the empty string if no schema is known, but crosswalk * authors are strongly encouraged to implement this call so their output * XML can be validated correctly. + * * @return SchemaLocation string, including URI namespace, followed by - * whitespace and URI of XML schema document, or empty string if unknown. + * whitespace and URI of XML schema document, or empty string if unknown. */ @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return ""; } @@ -76,12 +72,11 @@ public class AIPDIMCrosswalk * Predicate: Can this disseminator crosswalk the given object. * Needed by OAI-PMH server implementation. * - * @param dso dspace object, e.g. an Item. + * @param dso dspace object, e.g. an Item. * @return true when disseminator is capable of producing metadata. */ @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { return true; } @@ -100,8 +95,7 @@ public class AIPDIMCrosswalk * @return true when disseminator prefers you call disseminateList(). */ @Override - public boolean preferList() - { + public boolean preferList() { return false; } @@ -116,20 +110,19 @@ public class AIPDIMCrosswalk * empty list is returned, but never null. * * @param context context - * @param dso the DSpace Object whose metadata to export. + * @param dso the DSpace Object whose metadata to export. * @return results of crosswalk as list of XML elements. - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, - AuthorizeException - { + AuthorizeException { Element dim = disseminateElement(context, dso); return dim.getChildren(); } @@ -141,20 +134,19 @@ public class AIPDIMCrosswalk *

    * * @param context context - * @param dso the DSpace Object whose metadata to export. + * @param dso the DSpace Object whose metadata to export. * @return root Element of the target metadata, never null - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, - AuthorizeException - { + AuthorizeException { return XSLTDisseminationCrosswalk.createDIM(dso); } @@ -162,34 +154,34 @@ public class AIPDIMCrosswalk * Ingest a whole document. Build Document object around root element, * and feed that to the transformation, since it may get handled * differently than a List of metadata elements. + * * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { ingest(context, dso, root.getChildren(), createMissingMetadataFields); } /** * Fields correspond directly to Item.addMetadata() calls so * they are simply executed. + * * @param createMissingMetadataFields whether to create missing fields - * @param dimList List of elements + * @param dimList List of elements * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, List dimList, boolean createMissingMetadataFields) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { XSLTIngestionCrosswalk.ingestDIM(context, dso, dimList, createMissingMetadataFields); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/AIPTechMDCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/AIPTechMDCrosswalk.java index 1856615edd..3f109d9a1e 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/AIPTechMDCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/AIPTechMDCrosswalk.java @@ -8,34 +8,34 @@ package org.dspace.content.crosswalk; import java.io.IOException; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import java.sql.SQLException; - -import org.apache.commons.collections.CollectionUtils; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.dspace.core.Constants; -import org.dspace.core.Context; -import org.dspace.core.ConfigurationManager; -import org.dspace.content.Item; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.Site; -import org.dspace.content.packager.PackageUtils; -import org.dspace.eperson.EPerson; -import org.dspace.authorize.AuthorizeException; - -import org.apache.log4j.Logger; +import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.packager.DSpaceAIPIngester; import org.dspace.content.packager.METSManifest; +import org.dspace.content.packager.PackageUtils; +import org.dspace.content.service.BitstreamFormatService; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.SiteService; +import org.dspace.core.ConfigurationManager; +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 org.jdom.Element; @@ -52,26 +52,29 @@ import org.jdom.Namespace; * * It encodes the following common properties of all archival objects: * - * identifier.uri -- persistent identifier of object in URI form (e.g. Handle URN) - * relation.isPartOf -- persistent identifier of object's parent in URI form (e.g. Handle URN) - * relation.isReferencedBy -- if relevant, persistent identifier of other objects that map this one as a child. May repeat. + * identifier.uri -- persistent identifier of object in URI form (e.g. Handle URN) + * relation.isPartOf -- persistent identifier of object's parent in URI form (e.g. Handle URN) + * relation.isReferencedBy -- if relevant, persistent identifier of other objects that map this one as a child. May + * repeat. * * There may also be other fields, depending on the type of object, * which encode attributes that are not part of the descriptive metadata and * are not adequately covered by other technical MD formats (i.e. PREMIS). * - * Configuration entries: - * aip.ingest.createEperson -- boolean, create EPerson for Submitter - * automatically, on ingest, if it doesn't exist. + * Configuration entries: + * aip.ingest.createEperson -- boolean, create EPerson for Submitter + * automatically, on ingest, if it doesn't exist. * * @author Larry Stone * @version $Revision: 1.2 $ */ -public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCrosswalk -{ - /** log4j category */ +public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCrosswalk { + /** + * log4j category + */ private static Logger log = Logger.getLogger(AIPTechMDCrosswalk.class); - protected final BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + protected final BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); protected final SiteService siteService = ContentServiceFactory.getInstance().getSiteService(); protected final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); @@ -85,8 +88,7 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros * @return array of namespaces, which may be empty. */ @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { Namespace result[] = new Namespace[1]; result[0] = XSLTCrosswalk.DIM_NS; return result; @@ -96,16 +98,16 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros * Get the XML Schema location(s) of the target metadata format. * Returns the string value of the xsi:schemaLocation * attribute that should be applied to the generated XML. - *

    + *

    * It may return the empty string if no schema is known, but crosswalk * authors are strongly encouraged to implement this call so their output * XML can be validated correctly. + * * @return SchemaLocation string, including URI namespace, followed by - * whitespace and URI of XML schema document, or empty string if unknown. + * whitespace and URI of XML schema document, or empty string if unknown. */ @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return ""; } @@ -113,18 +115,17 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros * Predicate: Can this disseminator crosswalk the given object. * Needed by OAI-PMH server implementation. * - * @param dso dspace object, e.g. an Item. + * @param dso dspace object, e.g. an Item. * @return true when disseminator is capable of producing metadata. */ @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { //can only Disseminate SITE, COMMUNITY, COLLECTION, ITEM, BITSTREAM - return (dso.getType()==Constants.SITE - || dso.getType()==Constants.COMMUNITY - || dso.getType()==Constants.COLLECTION - || dso.getType()==Constants.ITEM - || dso.getType()==Constants.BITSTREAM); + return (dso.getType() == Constants.SITE + || dso.getType() == Constants.COMMUNITY + || dso.getType() == Constants.COLLECTION + || dso.getType() == Constants.ITEM + || dso.getType() == Constants.BITSTREAM); } /** @@ -142,8 +143,7 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros * @return true when disseminator prefers you call disseminateList(). */ @Override - public boolean preferList() - { + public boolean preferList() { return false; } @@ -158,20 +158,19 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros * empty list is returned, but never null. * * @param context context - * @param dso the DSpace Object whose metadata to export. + * @param dso the DSpace Object whose metadata to export. * @return results of crosswalk as list of XML elements. - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, - AuthorizeException - { + AuthorizeException { Element dim = disseminateElement(context, dso); return dim.getChildren(); } @@ -183,74 +182,60 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros *

    * * @param context context - * @param dso the DSpace Object whose metadata to export. + * @param dso the DSpace Object whose metadata to export. * @return root Element of the target metadata, never null - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, - AuthorizeException - { + AuthorizeException { List dc = new ArrayList<>(); - if (dso.getType() == Constants.ITEM) - { - Item item = (Item)dso; + if (dso.getType() == Constants.ITEM) { + Item item = (Item) dso; EPerson is = item.getSubmitter(); - if (is != null) - { + if (is != null) { dc.add(makeDC("creator", null, is.getEmail())); } dc.add(makeDC("identifier", "uri", "hdl:" + item.getHandle())); Collection owningColl = item.getOwningCollection(); String owner = owningColl.getHandle(); - if (owner != null) - { + if (owner != null) { dc.add(makeDC("relation", "isPartOf", "hdl:" + owner)); } List inColl = item.getCollections(); - for (int i = 0; i < inColl.size(); ++i) - { - if (!inColl.get(i).getID().equals(owningColl.getID())) - { + for (int i = 0; i < inColl.size(); ++i) { + if (!inColl.get(i).getID().equals(owningColl.getID())) { String h = inColl.get(i).getHandle(); - if (h != null) - { + if (h != null) { dc.add(makeDC("relation", "isReferencedBy", "hdl:" + h)); } } } - if (item.isWithdrawn()) - { + if (item.isWithdrawn()) { dc.add(makeDC("rights", "accessRights", "WITHDRAWN")); } - } - else if (dso.getType() == Constants.BITSTREAM) - { - Bitstream bitstream = (Bitstream)dso; + } else if (dso.getType() == Constants.BITSTREAM) { + Bitstream bitstream = (Bitstream) dso; String bsName = bitstream.getName(); - if (bsName != null) - { + if (bsName != null) { dc.add(makeDC("title", null, bsName)); } String bsSource = bitstream.getSource(); - if (bsSource != null) - { + if (bsSource != null) { dc.add(makeDC("title", "alternative", bsSource)); } String bsDesc = bitstream.getDescription(); - if (bsDesc != null) - { + if (bsDesc != null) { dc.add(makeDC("description", null, bsDesc)); } String bsUfmt = bitstream.getUserFormatDescription(); - if (bsUfmt != null) - { + if (bsUfmt != null) { dc.add(makeDC("format", null, bsUfmt)); } BitstreamFormat bsf = bitstream.getFormat(context); @@ -258,50 +243,37 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros dc.add(makeDC("format", "mimetype", bsf.getMIMEType())); dc.add(makeDC("format", "supportlevel", bitstreamFormatService.getSupportLevelText(bsf))); dc.add(makeDC("format", "internal", Boolean.toString(bsf.isInternal()))); - } - else if (dso.getType() == Constants.COLLECTION) - { - Collection collection = (Collection)dso; + } else if (dso.getType() == Constants.COLLECTION) { + Collection collection = (Collection) dso; dc.add(makeDC("identifier", "uri", "hdl:" + dso.getHandle())); List owners = collection.getCommunities(); String ownerHdl = owners.get(0).getHandle(); - if (ownerHdl != null) - { + if (ownerHdl != null) { dc.add(makeDC("relation", "isPartOf", "hdl:" + ownerHdl)); } - for (int i = 1; i < owners.size(); ++i) - { + for (int i = 1; i < owners.size(); ++i) { String h = owners.get(i).getHandle(); - if (h != null) - { + if (h != null) { dc.add(makeDC("relation", "isReferencedBy", "hdl:" + h)); } } - } - else if (dso.getType() == Constants.COMMUNITY) - { - Community community = (Community)dso; + } else if (dso.getType() == Constants.COMMUNITY) { + Community community = (Community) dso; dc.add(makeDC("identifier", "uri", "hdl:" + dso.getHandle())); List parentCommunities = community.getParentCommunities(); String ownerHdl = null; - if (CollectionUtils.isEmpty(parentCommunities)) - { + if (CollectionUtils.isEmpty(parentCommunities)) { ownerHdl = siteService.findSite(context).getHandle(); - } - else - { + } else { ownerHdl = parentCommunities.get(0).getHandle(); } - if (ownerHdl != null) - { + if (ownerHdl != null) { dc.add(makeDC("relation", "isPartOf", "hdl:" + ownerHdl)); } - } - else if (dso.getType() == Constants.SITE) - { + } else if (dso.getType() == Constants.SITE) { Site site = (Site) dso; - + //FIXME: adding two URIs for now (site handle and URL), in case site isn't using handles dc.add(makeDC("identifier", "uri", "hdl:" + site.getHandle())); dc.add(makeDC("identifier", "uri", site.getURL())); @@ -310,8 +282,7 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros return XSLTDisseminationCrosswalk.createDIM(dso, dc); } - private static MockMetadataValue makeDC(String element, String qualifier, String value) - { + private static MockMetadataValue makeDC(String element, String qualifier, String value) { MockMetadataValue dcv = new MockMetadataValue(); dcv.setSchema("dc"); dcv.setLanguage(null); @@ -325,16 +296,16 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros * Ingest a whole document. Build Document object around root element, * and feed that to the transformation, since it may get handled * differently than a List of metadata elements. + * * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { ingest(context, dso, root.getChildren(), createMissingMetadataFields); } @@ -343,18 +314,18 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros * Translation produces a list of DIM "field" elements; * these correspond directly to Item.addMetadata() calls so * they are simply executed. + * * @param createMissingMetadataFields whether to create missing fields - * @param dimList List of elements + * @param dimList List of elements * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, List dimList, boolean createMissingMetadataFields) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { int type = dso.getType(); // accumulate values for bitstream format in case we have to make one @@ -363,127 +334,89 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros int bsfSupport = BitstreamFormat.KNOWN; boolean bsfInternal = false; - for (Element field : dimList) - { + for (Element field : dimList) { // if we get in a list, recurse. - if (field.getName().equals("dim") && field.getNamespace().equals(XSLTCrosswalk.DIM_NS)) - { + if (field.getName().equals("dim") && field.getNamespace().equals(XSLTCrosswalk.DIM_NS)) { ingest(context, dso, field.getChildren(), createMissingMetadataFields); - } - else if (field.getName().equals("field") && field.getNamespace().equals(XSLTCrosswalk.DIM_NS)) - { + } else if (field.getName().equals("field") && field.getNamespace().equals(XSLTCrosswalk.DIM_NS)) { String schema = field.getAttributeValue("mdschema"); - if (schema.equals("dc")) - { + if (schema.equals("dc")) { String dcField = field.getAttributeValue("element"); String qualifier = field.getAttributeValue("qualifier"); - if (qualifier != null) - { + if (qualifier != null) { dcField += "." + qualifier; } String value = field.getText(); - if (type == Constants.BITSTREAM) - { - Bitstream bitstream = (Bitstream)dso; - if (dcField.equals("title")) - { + if (type == Constants.BITSTREAM) { + Bitstream bitstream = (Bitstream) dso; + if (dcField.equals("title")) { bitstream.setName(context, value); - } - else if (dcField.equals("title.alternative")) - { + } else if (dcField.equals("title.alternative")) { bitstream.setSource(context, value); - } - else if (dcField.equals("description")) - { + } else if (dcField.equals("description")) { bitstream.setDescription(context, value); - } - else if (dcField.equals("format")) - { + } else if (dcField.equals("format")) { bitstream.setUserFormatDescription(context, value); - } - else if (dcField.equals("format.medium")) - { + } else if (dcField.equals("format.medium")) { bsfShortName = value; - } - else if (dcField.equals("format.mimetype")) - { + } else if (dcField.equals("format.mimetype")) { bsfMIMEType = value; - } - else if (dcField.equals("format.supportlevel")) - { + } else if (dcField.equals("format.supportlevel")) { int sl = bitstreamFormatService.getSupportLevelID(value); - if (sl < 0) - { - throw new MetadataValidationException("Got unrecognized value for bitstream support level: " + value); - } - else - { + if (sl < 0) { + throw new MetadataValidationException( + "Got unrecognized value for bitstream support level: " + value); + } else { bsfSupport = sl; } - } - else if (dcField.equals("format.internal")) - { + } else if (dcField.equals("format.internal")) { bsfInternal = (Boolean.valueOf(value)).booleanValue(); - } - else - { + } else { log.warn("Got unrecognized DC field for Bitstream: " + dcField); } - } - else if (type == Constants.ITEM) - { - Item item = (Item)dso; + } else if (type == Constants.ITEM) { + Item item = (Item) dso; // item submitter - if (dcField.equals("creator")) - { + if (dcField.equals("creator")) { EPerson sub = ePersonService.findByEmail(context, value); // if eperson doesn't exist yet, optionally create it: - if (sub == null) - { - //This class works in conjunction with the DSpaceAIPIngester. + if (sub == null) { + //This class works in conjunction with the DSpaceAIPIngester. // so, we'll use the configuration settings for that ingester String configName = new DSpaceAIPIngester().getConfigurationName(); //Create the EPerson if specified and person doesn't already exit - if (ConfigurationManager.getBooleanProperty(METSManifest.CONFIG_METS_PREFIX + configName + ".ingest.createSubmitter")) - { + if (ConfigurationManager.getBooleanProperty( + METSManifest.CONFIG_METS_PREFIX + configName + ".ingest.createSubmitter")) { sub = ePersonService.create(context); sub.setEmail(value); sub.setCanLogIn(false); ePersonService.update(context, sub); - } - else - { - log.warn("Ignoring unknown Submitter=" + value + " in AIP Tech MD, no matching EPerson and 'mets.dspaceAIP.ingest.createSubmitter' is false in dspace.cfg."); + } else { + log.warn( + "Ignoring unknown Submitter=" + value + " in AIP Tech MD, no matching EPerson" + + " and 'mets.dspaceAIP.ingest.createSubmitter' is false in dspace.cfg."); } } - if (sub != null) - { + if (sub != null) { item.setSubmitter(sub); } - } - else if (dcField.equals("rights.accessRights")) - { + } else if (dcField.equals("rights.accessRights")) { //check if item is withdrawn - if (value.equalsIgnoreCase("WITHDRAWN")) - { + if (value.equalsIgnoreCase("WITHDRAWN")) { itemService.withdraw(context, item); } - } - else if(dcField.equals("identifier.uri") || - dcField.equals("relation.isPartOf")) - { + } else if (dcField.equals("identifier.uri") || + dcField.equals("relation.isPartOf")) { // Ignore identifier.uri (which specifies object handle) // and relation.isPartOf (which specifies primary parent object) // Both of these should already be set on object, as they // are required/generated when a DSpaceObject is created. - } - else if (dcField.equals("relation.isReferencedBy")) - { + } else if (dcField.equals("relation.isReferencedBy")) { // This Item is referenced by other Collections. This means // it has been mapped into one or more additional collections. @@ -494,89 +427,67 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros // we were unable to create now. String parentHandle = value; - if(parentHandle!=null && !parentHandle.isEmpty()) - { + if (parentHandle != null && !parentHandle.isEmpty()) { //Remove 'hdl:' prefix, if it exists - if (parentHandle.startsWith("hdl:")) - { + if (parentHandle.startsWith("hdl:")) { parentHandle = parentHandle.substring(4); } //Get parent object (if it exists) DSpaceObject parentDso = handleService.resolveToObject(context, parentHandle); //For Items, this parent *must* be a Collection - if(parentDso!=null && parentDso.getType()==Constants.COLLECTION) - { + if (parentDso != null && parentDso.getType() == Constants.COLLECTION) { Collection collection = (Collection) parentDso; //If this item is not already mapped into this collection, map it! - if (!itemService.isIn(item, collection)) - { + if (!itemService.isIn(item, collection)) { collectionService.addItem(context, collection, item); } } } - } - else - { + } else { log.warn("Got unrecognized DC field for Item: " + dcField); } - } - else if (type == Constants.COMMUNITY || type == Constants.COLLECTION) - { - if (dcField.equals("identifier.uri") || dcField.equals("relation.isPartOf")) - { + } else if (type == Constants.COMMUNITY || type == Constants.COLLECTION) { + if (dcField.equals("identifier.uri") || dcField.equals("relation.isPartOf")) { // Ignore identifier.uri (which specifies object handle) // and relation.isPartOf (which specifies primary parent object) // Both of these should already be set on object, as they // are required/generated when a DSpaceObject is created. - } - else if (dcField.equals("relation.isReferencedBy")) - { + } else if (dcField.equals("relation.isReferencedBy")) { // Ignore relation.isReferencedBy since it only // lists _extra_ mapped parents, not the primary one. // DSpace currently doesn't fully support mapping of Collections/Communities - } - else - { + } else { log.warn("Got unrecognized DC field for Collection/Community: " + dcField); } - } - } - else - { + } + } else { log.warn("Skipping DIM field with mdschema=\"" + schema + "\"."); } - } - else - { - log.error("Got unexpected element in DIM list: "+field.toString()); - throw new MetadataValidationException("Got unexpected element in DIM list: "+field.toString()); + } else { + log.error("Got unexpected element in DIM list: " + field.toString()); + throw new MetadataValidationException("Got unexpected element in DIM list: " + field.toString()); } } // final step: find or create bitstream format since it // takes the accumulation of a few values: - if (type == Constants.BITSTREAM && bsfShortName != null) - { + if (type == Constants.BITSTREAM && bsfShortName != null) { BitstreamFormat bsf = bitstreamFormatService.findByShortDescription(context, bsfShortName); - if (bsf == null && bsfMIMEType != null) - { + if (bsf == null && bsfMIMEType != null) { bsf = PackageUtils.findOrCreateBitstreamFormat(context, - bsfShortName, - bsfMIMEType, - bsfShortName, - bsfSupport, - bsfInternal); + bsfShortName, + bsfMIMEType, + bsfShortName, + bsfSupport, + bsfInternal); } - if (bsf != null) - { + if (bsf != null) { ((Bitstream) dso).setFormat(context, bsf); - } - else - { + } else { log.warn("Failed to find or create bitstream format named \"" + bsfShortName + "\""); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/AbstractPackagerWrappingCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/AbstractPackagerWrappingCrosswalk.java index fe80019347..84bea05e42 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/AbstractPackagerWrappingCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/AbstractPackagerWrappingCrosswalk.java @@ -30,11 +30,11 @@ import org.dspace.content.packager.PackageParameters; * @see org.dspace.content.packager.PackageDisseminator * @see org.dspace.content.packager.PackageParameters */ -public abstract class AbstractPackagerWrappingCrosswalk -{ - // Crosswalk's PackageParameters, which can be used when calling/initializing a Packager during ingestion/dissemination +public abstract class AbstractPackagerWrappingCrosswalk { + // Crosswalk's PackageParameters, which can be used when calling/initializing a Packager during + // ingestion/dissemination private PackageParameters packageParameters = null; - + // Crosswalk's Ingestion License, which can be used when calling a Packager during ingestion private String ingestionLicense = null; @@ -52,8 +52,7 @@ public abstract class AbstractPackagerWrappingCrosswalk * * @param pparams PackageParameters to make available to the Crosswalk */ - public void setPackagingParameters(PackageParameters pparams) - { + public void setPackagingParameters(PackageParameters pparams) { this.packageParameters = pparams; } @@ -71,36 +70,33 @@ public abstract class AbstractPackagerWrappingCrosswalk * * @return PackageParameters previously made available to the Crosswalk or null */ - public PackageParameters getPackagingParameters() - { + public PackageParameters getPackagingParameters() { return this.packageParameters; } - - + + /** * Set custom ingestion license for this Crosswalk. *

    * This license can be used by the crosswalk when calling a PackageIngester - * + * * @param license the full text of the ingestion license * @see org.dspace.content.packager.PackageIngester */ - public void setIngestionLicense(String license) - { + public void setIngestionLicense(String license) { this.ingestionLicense = license; } - + /** * Get custom ingestion license for this Crosswalk. *

    * This license can be used by the crosswalk when calling a PackageIngester - * + * * @return the full text of the ingestion license as a String * @see org.dspace.content.packager.PackageIngester */ - public String getIngestionLicense() - { + public String getIngestionLicense() { return this.ingestionLicense; } - + } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java index 629daa3d2c..d530f55905 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java @@ -7,15 +7,14 @@ */ package org.dspace.content.crosswalk; -import java.io.OutputStream; import java.io.IOException; +import java.io.OutputStream; import java.sql.SQLException; import org.apache.log4j.Logger; - import org.dspace.authorize.AuthorizeException; -import org.dspace.content.DSpaceObject; import org.dspace.content.Bitstream; +import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; @@ -28,41 +27,36 @@ import org.dspace.license.service.CreativeCommonsService; /** * Export the item's Creative Commons license, RDF form. * - * @author Larry Stone + * @author Larry Stone * @version $Revision: 1.0 $ */ public class CreativeCommonsRDFStreamDisseminationCrosswalk - implements StreamDisseminationCrosswalk -{ - /** log4j logger */ + implements StreamDisseminationCrosswalk { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(CreativeCommonsRDFStreamDisseminationCrosswalk.class); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance().getCreativeCommonsService(); + protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance() + .getCreativeCommonsService(); @Override - public boolean canDisseminate(Context context, DSpaceObject dso) - { - try - { + public boolean canDisseminate(Context context, DSpaceObject dso) { + try { return dso.getType() == Constants.ITEM && - creativeCommonsService.getLicenseRdfBitstream((Item) dso) != null; - } - catch (Exception e) - { + creativeCommonsService.getLicenseRdfBitstream((Item) dso) != null; + } catch (Exception e) { log.error("Failed getting CC license", e); - return false; + return false; } } @Override public void disseminate(Context context, DSpaceObject dso, OutputStream out) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { - if (dso.getType() == Constants.ITEM) - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { + if (dso.getType() == Constants.ITEM) { Bitstream cc = creativeCommonsService.getLicenseRdfBitstream((Item) dso); - if (cc != null) - { + if (cc != null) { Utils.copy(bitstreamService.retrieve(context, cc), out); out.close(); } @@ -70,8 +64,7 @@ public class CreativeCommonsRDFStreamDisseminationCrosswalk } @Override - public String getMIMEType() - { + public String getMIMEType() { return "text/xml"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamIngestionCrosswalk.java index 5d2d7ecc4d..d011202921 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamIngestionCrosswalk.java @@ -7,12 +7,11 @@ */ package org.dspace.content.crosswalk; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.sql.SQLException; import org.apache.log4j.Logger; - import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; @@ -31,27 +30,26 @@ import org.dspace.license.service.CreativeCommonsService; *

    * This crosswalk should only be used when ingesting other kinds of SIPs. * - * @author Larry Stone + * @author Larry Stone * @version $Revision: 1.0 $ */ public class CreativeCommonsRDFStreamIngestionCrosswalk - implements StreamIngestionCrosswalk -{ - /** log4j logger */ + implements StreamIngestionCrosswalk { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(CreativeCommonsRDFStreamIngestionCrosswalk.class); - protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance().getCreativeCommonsService(); + protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance() + .getCreativeCommonsService(); @Override public void ingest(Context context, DSpaceObject dso, InputStream in, String MIMEType) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { // If package includes a Creative Commons license, add that: - if (dso.getType() == Constants.ITEM) - { - if (log.isDebugEnabled()) - { + if (dso.getType() == Constants.ITEM) { + if (log.isDebugEnabled()) { log.debug("Reading a Creative Commons license, MIMEtype=" + MIMEType); } @@ -60,8 +58,7 @@ public class CreativeCommonsRDFStreamIngestionCrosswalk } - public String getMIMEType() - { + public String getMIMEType() { return "text/rdf"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java index 7304366f50..bf6d97fbea 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java @@ -7,16 +7,15 @@ */ package org.dspace.content.crosswalk; -import java.io.OutputStream; import java.io.IOException; +import java.io.OutputStream; import java.sql.SQLException; import org.apache.log4j.Logger; - import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; -import org.dspace.content.Bitstream; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.core.Constants; @@ -28,45 +27,40 @@ import org.dspace.license.service.CreativeCommonsService; /** * Export the object's Creative Commons license, text form. * - * @author Larry Stone + * @author Larry Stone * @version $Revision: 1.0 $ - * - * @deprecated to make uniform JSPUI and XMLUI approach the bitstream with the license in the textual format it is no longer stored (see https://jira.duraspace.org/browse/DS-2604) + * @deprecated to make uniform JSPUI and XMLUI approach the bitstream with the license in the textual format it is no + * longer stored (see https://jira.duraspace.org/browse/DS-2604) */ public class CreativeCommonsTextStreamDisseminationCrosswalk - implements StreamDisseminationCrosswalk -{ + implements StreamDisseminationCrosswalk { protected final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - protected final CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance().getCreativeCommonsService(); + protected final CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance() + .getCreativeCommonsService(); - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(CreativeCommonsTextStreamDisseminationCrosswalk.class); @Override - public boolean canDisseminate(Context context, DSpaceObject dso) - { - try - { + public boolean canDisseminate(Context context, DSpaceObject dso) { + try { return dso.getType() == Constants.ITEM && - creativeCommonsService.getLicenseTextBitstream((Item) dso) != null; - } - catch (Exception e) - { + creativeCommonsService.getLicenseTextBitstream((Item) dso) != null; + } catch (Exception e) { log.error("Failed getting CC license", e); - return false; + return false; } } @Override public void disseminate(Context context, DSpaceObject dso, OutputStream out) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { - if (dso.getType() == Constants.ITEM) - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { + if (dso.getType() == Constants.ITEM) { Bitstream cc = creativeCommonsService.getLicenseTextBitstream((Item) dso); - if (cc != null) - { + if (cc != null) { Utils.copy(bitstreamService.retrieve(context, cc), out); out.close(); } @@ -74,8 +68,7 @@ public class CreativeCommonsTextStreamDisseminationCrosswalk } @Override - public String getMIMEType() - { + public String getMIMEType() { return "text/plain"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkException.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkException.java index aaf5c239d4..c2a7a287fd 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkException.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkException.java @@ -15,25 +15,20 @@ package org.dspace.content.crosswalk; * @author Larry Stone * @version $Revision$ */ -public class CrosswalkException extends Exception -{ - public CrosswalkException() - { +public class CrosswalkException extends Exception { + public CrosswalkException() { super(); } - public CrosswalkException(String s, Throwable t) - { + public CrosswalkException(String s, Throwable t) { super(s, t); } - public CrosswalkException(String s) - { + public CrosswalkException(String s) { super(s); } - public CrosswalkException(Throwable t) - { + public CrosswalkException(Throwable t) { super(t); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkInternalException.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkInternalException.java index 7bbaf211b1..9f4ee81164 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkInternalException.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkInternalException.java @@ -18,20 +18,16 @@ package org.dspace.content.crosswalk; * @author Larry Stone * @version $Revision$ */ -public class CrosswalkInternalException extends CrosswalkException -{ - public CrosswalkInternalException(String s) - { +public class CrosswalkInternalException extends CrosswalkException { + public CrosswalkInternalException(String s) { super(s); } - public CrosswalkInternalException(String arg0, Throwable arg1) - { + public CrosswalkInternalException(String arg0, Throwable arg1) { super(arg0, arg1); } - public CrosswalkInternalException(Throwable arg0) - { + public CrosswalkInternalException(Throwable arg0) { super(arg0); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkMetadataValidator.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkMetadataValidator.java index e6625dc2c0..d68eff3df7 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkMetadataValidator.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkMetadataValidator.java @@ -7,6 +7,11 @@ */ package org.dspace.content.crosswalk; +import java.sql.SQLException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.commons.lang3.tuple.Triple; import org.dspace.authorize.AuthorizeException; @@ -19,11 +24,6 @@ import org.dspace.content.service.MetadataSchemaService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; -import java.sql.SQLException; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - public class CrosswalkMetadataValidator { protected MetadataSchemaService metadataSchemaService; @@ -42,14 +42,12 @@ public class CrosswalkMetadataValidator { // The two options, with three possibilities each: add, ignore, fail schemaChoice = ConfigurationManager.getProperty("oai", "harvester.unknownSchema"); - if (schemaChoice == null) - { + if (schemaChoice == null) { schemaChoice = "fail"; } fieldChoice = ConfigurationManager.getProperty("oai", "harvester.unknownField"); - if (fieldChoice == null) - { + if (fieldChoice == null) { fieldChoice = "fail"; } } @@ -58,22 +56,20 @@ public class CrosswalkMetadataValidator { * Scans metadata for elements not defined in this DSpace instance. It then takes action based * on a configurable parameter (fail, ignore, add). * - * @param context - * The relevant DSpace Context. - * @param schema metadata field schema - * @param element metadata field element - * @param qualifier metadata field qualifier + * @param context The relevant DSpace Context. + * @param schema metadata field schema + * @param element metadata field element + * @param qualifier metadata field qualifier * @param forceCreate if true, force addinga schema or metadata field * @return metadata field - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws CrosswalkException - * Superclass for more-specific crosswalk exceptions. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws CrosswalkException Superclass for more-specific crosswalk exceptions. */ - public MetadataField checkMetadata(Context context, String schema, String element, String qualifier, boolean forceCreate) throws SQLException, AuthorizeException, CrosswalkException { + public MetadataField checkMetadata(Context context, String schema, String element, String qualifier, + boolean forceCreate) + throws SQLException, AuthorizeException, CrosswalkException { if (!validatedBefore(schema, element, qualifier)) { // Verify that the schema exists MetadataSchema mdSchema = metadataSchemaService.find(context, schema); @@ -90,10 +86,9 @@ public class CrosswalkMetadataValidator { // This case should not be possible e.printStackTrace(); } - } - // ignore the offending schema, quietly dropping all of its metadata elements before they clog our gears - else if (!schemaChoice.equals("ignore")) { - throw new CrosswalkException("The '" + schema + "' schema has not been defined in this DSpace instance. "); + } else if (!schemaChoice.equals("ignore")) { + throw new CrosswalkException( + "The '" + schema + "' schema has not been defined in this DSpace instance. "); } } @@ -109,7 +104,9 @@ public class CrosswalkMetadataValidator { e.printStackTrace(); } } else if (!fieldChoice.equals("ignore")) { - throw new CrosswalkException("The '" + element + "." + qualifier + "' element has not been defined in this DSpace instance. "); + throw new CrosswalkException( + "The '" + element + "." + qualifier + "' element has not been defined in this DSpace " + + "instance. "); } } } @@ -124,7 +121,8 @@ public class CrosswalkMetadataValidator { return validatedMetadataFields.containsKey(createKey(schema, element, qualifier)); } - private ImmutableTriple createKey(final String schema, final String element, final String qualifier) { + private ImmutableTriple createKey(final String schema, final String element, + final String qualifier) { return new ImmutableTriple(schema, element, qualifier); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkObjectNotSupported.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkObjectNotSupported.java index 28d09d5012..2361e98d4b 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkObjectNotSupported.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CrosswalkObjectNotSupported.java @@ -18,20 +18,16 @@ package org.dspace.content.crosswalk; * @author Larry Stone * @version $Revision$ */ -public class CrosswalkObjectNotSupported extends CrosswalkException -{ - public CrosswalkObjectNotSupported(String s) - { +public class CrosswalkObjectNotSupported extends CrosswalkException { + public CrosswalkObjectNotSupported(String s) { super(s); } - public CrosswalkObjectNotSupported(String arg0, Throwable arg1) - { + public CrosswalkObjectNotSupported(String arg0, Throwable arg1) { super(arg0, arg1); } - public CrosswalkObjectNotSupported(Throwable arg0) - { + public CrosswalkObjectNotSupported(Throwable arg0) { super(arg0); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/DIMDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/DIMDisseminationCrosswalk.java index d6c79e98bc..05560f0b32 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/DIMDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/DIMDisseminationCrosswalk.java @@ -14,7 +14,11 @@ import java.util.List; import org.apache.commons.lang.ArrayUtils; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; +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.Constants; @@ -31,46 +35,41 @@ import org.jdom.Namespace; * @version $Revision: 1 $ */ public class DIMDisseminationCrosswalk - implements DisseminationCrosswalk -{ + implements DisseminationCrosswalk { // Non-existant XSD schema public static final String DIM_XSD = "null"; - - // Namespaces + + // Namespaces public static final Namespace DIM_NS = Namespace.getNamespace("dim", "http://www.dspace.org/xmlns/dspace/dim"); protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - private static final Namespace namespaces[] = { DIM_NS }; + private static final Namespace namespaces[] = {DIM_NS}; @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { return (Namespace[]) ArrayUtils.clone(namespaces); } - /* No schema for DIM */ + /* No schema for DIM */ @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return DIM_NS.getURI() + " " + DIM_XSD; } - + @Override - public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException - { - if (dso.getType() != Constants.ITEM) - { + public Element disseminateElement(Context context, DSpaceObject dso) + throws CrosswalkException, IOException, SQLException, AuthorizeException { + if (dso.getType() != Constants.ITEM) { throw new CrosswalkObjectNotSupported("DIMDisseminationCrosswalk can only crosswalk an Item."); } - Item item = (Item)dso; - - List dc = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + Item item = (Item) dso; + + List dc = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); Element dim = new Element("dim", DIM_NS); - for (MetadataValue aDc : dc) - { + for (MetadataValue aDc : dc) { MetadataField metadataField = aDc.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); Element field = new Element("field", DIM_NS); @@ -88,27 +87,25 @@ public class DIMDisseminationCrosswalk dim.addContent(field); } return dim; - } - + } + @Override - public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException - { - List result = new ArrayList(1); - result.add(disseminateElement(context, dso)); - return result; - } + public List disseminateList(Context context, DSpaceObject dso) + throws CrosswalkException, IOException, SQLException, AuthorizeException { + List result = new ArrayList(1); + result.add(disseminateElement(context, dso)); + return result; + } /* Only interested in disseminating items at this time */ @Override - public boolean canDisseminate(DSpaceObject dso) - { - return (dso.getType() == Constants.ITEM); + public boolean canDisseminate(DSpaceObject dso) { + return (dso.getType() == Constants.ITEM); } @Override - public boolean preferList() - { + public boolean preferList() { return false; } - + } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/DIMIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/DIMIngestionCrosswalk.java index b108d90805..ad922a65f2 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/DIMIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/DIMIngestionCrosswalk.java @@ -7,6 +7,10 @@ */ package org.dspace.content.crosswalk; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; @@ -18,10 +22,6 @@ import org.dspace.core.Context; import org.jdom.Element; import org.jdom.Namespace; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * DIM ingestion crosswalk *

    @@ -30,51 +30,50 @@ import java.util.List; * @author Alexey Maslov * @version $Revision: 1 $ */ -public class DIMIngestionCrosswalk implements IngestionCrosswalk -{ +public class DIMIngestionCrosswalk implements IngestionCrosswalk { private static final Namespace DIM_NS = Namespace.getNamespace("http://www.dspace.org/xmlns/dspace/dim"); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); private CrosswalkMetadataValidator metadataValidator = new CrosswalkMetadataValidator(); - @Override - public void ingest(Context context, DSpaceObject dso, List metadata, boolean createMissingMetadataFields) throws CrosswalkException, IOException, SQLException, AuthorizeException { + @Override + public void ingest(Context context, DSpaceObject dso, List metadata, boolean createMissingMetadataFields) + throws CrosswalkException, IOException, SQLException, AuthorizeException { Element first = metadata.get(0); - if (first.getName().equals("dim") && metadata.size() == 1) { - ingest(context,dso,first, createMissingMetadataFields); - } - else if (first.getName().equals("field") && first.getParentElement() != null) { - ingest(context,dso,first.getParentElement(), createMissingMetadataFields); - } - else { + if (first.getName().equals("dim") && metadata.size() == 1) { + ingest(context, dso, first, createMissingMetadataFields); + } else if (first.getName().equals("field") && first.getParentElement() != null) { + ingest(context, dso, first.getParentElement(), createMissingMetadataFields); + } else { Element wrapper = new Element("wrap", metadata.get(0).getNamespace()); wrapper.addContent(metadata); - ingest(context,dso,wrapper, createMissingMetadataFields); - } - } + ingest(context, dso, wrapper, createMissingMetadataFields); + } + } - @Override - public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) throws CrosswalkException, IOException, SQLException, AuthorizeException { - if (dso.getType() != Constants.ITEM) - { + @Override + public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) + throws CrosswalkException, IOException, SQLException, AuthorizeException { + if (dso.getType() != Constants.ITEM) { throw new CrosswalkObjectNotSupported("DIMIngestionCrosswalk can only crosswalk an Item."); } - Item item = (Item)dso; - + Item item = (Item) dso; + if (root == null) { - System.err.println("The element received by ingest was null"); - return; + System.err.println("The element received by ingest was null"); + return; } - - List metadata = root.getChildren("field",DIM_NS); + + List metadata = root.getChildren("field", DIM_NS); for (Element field : metadata) { String schema = field.getAttributeValue("mdschema"); String element = field.getAttributeValue("element"); String qualifier = field.getAttributeValue("qualifier"); - MetadataField metadataField = metadataValidator.checkMetadata(context, schema, element, qualifier, createMissingMetadataFields); + MetadataField metadataField = metadataValidator + .checkMetadata(context, schema, element, qualifier, createMissingMetadataFields); itemService.addMetadata(context, item, metadataField, - field.getAttributeValue("lang"), field.getText()); + field.getAttributeValue("lang"), field.getText()); } - - } - + + } + } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/DisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/DisseminationCrosswalk.java index bcc73bc80c..23e1965d7b 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/DisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/DisseminationCrosswalk.java @@ -29,9 +29,10 @@ import org.jdom.Namespace; * @author Larry Stone * @version $Revision$ */ -public interface DisseminationCrosswalk -{ - /** XSI namespace, required for xsi:schemalocation attributes */ +public interface DisseminationCrosswalk { + /** + * XSI namespace, required for xsi:schemalocation attributes + */ static final Namespace XSI_NS = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); @@ -47,12 +48,13 @@ public interface DisseminationCrosswalk * Get the XML Schema location(s) of the target metadata format. * Returns the string value of the xsi:schemaLocation * attribute that should be applied to the generated XML. - *

    + *

    * It may return the empty string if no schema is known, but crosswalk * authors are strongly encouraged to implement this call so their output * XML can be validated correctly. + * * @return SchemaLocation string, including URI namespace, followed by - * whitespace and URI of XML schema document, or empty string if unknown. + * whitespace and URI of XML schema document, or empty string if unknown. */ public String getSchemaLocation(); @@ -60,7 +62,7 @@ public interface DisseminationCrosswalk * Predicate: Can this disseminator crosswalk the given object. * Needed by OAI-PMH server implementation. * - * @param dso dspace object, e.g. an Item. + * @param dso dspace object, e.g. an Item. * @return true when disseminator is capable of producing metadata. */ public boolean canDisseminate(DSpaceObject dso); @@ -92,18 +94,18 @@ public interface DisseminationCrosswalk * empty list is returned, but never null. * * @param context context - * @param dso the DSpace Object whose metadata to export. + * @param dso the DSpace Object whose metadata to export. * @return results of crosswalk as list of XML elements. - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, - AuthorizeException; + AuthorizeException; /** * Execute crosswalk, returning one XML root element as @@ -112,16 +114,16 @@ public interface DisseminationCrosswalk *

    * * @param context context - * @param dso the DSpace Object whose metadata to export. + * @param dso the DSpace Object whose metadata to export. * @return root Element of the target metadata, never null - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, - AuthorizeException; + AuthorizeException; } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/IConverter.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/IConverter.java index e31eb307a2..38098012bb 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/IConverter.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/IConverter.java @@ -7,15 +7,13 @@ */ package org.dspace.content.crosswalk; -public interface IConverter -{ +public interface IConverter { /** * Get an alternative format for the input string. Useful examples are * conversion from a metadata language value in ISO-639-3 to ISO-639-1, etc. - * - * @param value - * the input string to convert - * @return the converted string returned by the "conversion algorithm" + * + * @param value the input string to convert + * @return the converted string returned by the "conversion algorithm" */ public String makeConversion(String value); } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/IngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/IngestionCrosswalk.java index 3151c2ec67..7edfb6f79f 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/IngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/IngestionCrosswalk.java @@ -31,8 +31,7 @@ import org.jdom.Element; * @author Larry Stone * @version $Revision$ */ -public interface IngestionCrosswalk -{ +public interface IngestionCrosswalk { /** * Crosswalk metadata from external XML representation to DSpace * internal representations. This version accepts metadata as a @@ -60,19 +59,22 @@ public interface IngestionCrosswalk * capable of) choosing whether the list or element version should * be called. *

    - * @param context DSpace context. - * @param dso DSpace Object (Item, Bitstream, etc) to which new metadata gets attached. - * @param metadata List of XML Elements of metadata - * @param createMissingMetadataFields whether to create missing fields * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk into this kind of DSpace object. - * @throws MetadataValidationException (CrosswalkException) metadata format was not acceptable or missing required elements. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @param context DSpace context. + * @param dso DSpace Object (Item, Bitstream, etc) to which new metadata gets attached. + * @param metadata List of XML Elements of metadata + * @param createMissingMetadataFields whether to create missing fields + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk into this kind of + * DSpace object. + * @throws MetadataValidationException (CrosswalkException) metadata format was not acceptable or + * missing required elements. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ - public abstract void ingest(Context context, DSpaceObject dso, List metadata, boolean createMissingMetadataFields) + public abstract void ingest(Context context, DSpaceObject dso, List metadata, + boolean createMissingMetadataFields) throws CrosswalkException, IOException, SQLException, AuthorizeException; /** @@ -83,17 +85,19 @@ public interface IngestionCrosswalk * It is otherwise just like the List form of * ingest() above. *

    - * @param context DSpace context. - * @param dso DSpace Object (usually an Item) to which new metadata gets attached. - * @param root root Element of metadata document. - * @param createMissingMetadataFields whether to create missing fields * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk into this kind of DSpace object. - * @throws MetadataValidationException (CrosswalkException) metadata format was not acceptable or missing required elements. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @param context DSpace context. + * @param dso DSpace Object (usually an Item) to which new metadata gets attached. + * @param root root Element of metadata document. + * @param createMissingMetadataFields whether to create missing fields + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk into this kind of + * DSpace object. + * @throws MetadataValidationException (CrosswalkException) metadata format was not acceptable or + * missing required elements. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ public abstract void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) throws CrosswalkException, IOException, SQLException, AuthorizeException; diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java index 689a2003dd..da10a212ec 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java @@ -7,15 +7,14 @@ */ package org.dspace.content.crosswalk; -import java.io.OutputStream; import java.io.IOException; +import java.io.OutputStream; import java.sql.SQLException; import org.apache.log4j.Logger; - import org.dspace.authorize.AuthorizeException; -import org.dspace.content.DSpaceObject; import org.dspace.content.Bitstream; +import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.packager.PackageUtils; @@ -27,41 +26,35 @@ import org.dspace.core.Utils; /** * Export the object's DSpace deposit license. * - * @author Larry Stone + * @author Larry Stone * @version $Revision: 1.0 $ */ public class LicenseStreamDisseminationCrosswalk - implements StreamDisseminationCrosswalk -{ - /** log4j logger */ + implements StreamDisseminationCrosswalk { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(LicenseStreamDisseminationCrosswalk.class); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); @Override - public boolean canDisseminate(Context context, DSpaceObject dso) - { - try - { + public boolean canDisseminate(Context context, DSpaceObject dso) { + try { return dso.getType() == Constants.ITEM && - PackageUtils.findDepositLicense(context, (Item)dso) != null; - } - catch (Exception e) - { + PackageUtils.findDepositLicense(context, (Item) dso) != null; + } catch (Exception e) { log.error("Failed getting Deposit license", e); - return false; + return false; } } @Override public void disseminate(Context context, DSpaceObject dso, OutputStream out) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { - if (dso.getType() == Constants.ITEM) - { - Bitstream licenseBs = PackageUtils.findDepositLicense(context, (Item)dso); - - if (licenseBs != null) - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { + if (dso.getType() == Constants.ITEM) { + Bitstream licenseBs = PackageUtils.findDepositLicense(context, (Item) dso); + + if (licenseBs != null) { Utils.copy(bitstreamService.retrieve(context, licenseBs), out); out.close(); } @@ -69,8 +62,7 @@ public class LicenseStreamDisseminationCrosswalk } @Override - public String getMIMEType() - { + public String getMIMEType() { return "text/plain"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamIngestionCrosswalk.java index 7007fdcccf..fb3653b4db 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamIngestionCrosswalk.java @@ -8,12 +8,11 @@ package org.dspace.content.crosswalk; import java.io.ByteArrayOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.sql.SQLException; import org.apache.log4j.Logger; - import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; @@ -32,36 +31,33 @@ import org.dspace.core.Utils; *

    * This crosswalk should only be used when ingesting other kinds of SIPs. * - * @author Larry Stone + * @author Larry Stone * @version $Revision: 1.0 $ */ public class LicenseStreamIngestionCrosswalk - implements StreamIngestionCrosswalk -{ - /** log4j logger */ + implements StreamIngestionCrosswalk { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(LicenseStreamIngestionCrosswalk.class); @Override public void ingest(Context context, DSpaceObject dso, InputStream in, String MIMEType) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { // If package includes a Creative Commons license, add that: - if (dso.getType() == Constants.ITEM) - { - if (log.isDebugEnabled()) - { + if (dso.getType() == Constants.ITEM) { + if (log.isDebugEnabled()) { log.debug("Reading a DSpace Deposit license, MIMEtype=" + MIMEType); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); Utils.copy(in, baos); PackageUtils.addDepositLicense(context, baos.toString(), - (Item)dso, null); + (Item) dso, null); } } - public String getMIMEType() - { + public String getMIMEType() { return "text/plain"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/METSDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/METSDisseminationCrosswalk.java index 826e71eb56..efe24b63d5 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/METSDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/METSDisseminationCrosswalk.java @@ -40,8 +40,7 @@ import org.jdom.input.SAXBuilder; * @version $Revision$ */ public class METSDisseminationCrosswalk - implements DisseminationCrosswalk -{ + implements DisseminationCrosswalk { // Plugin Name of METS packager to use for manifest; // maybe make this configurable. private static final String METS_PACKAGER_PLUGIN = "METS"; @@ -56,35 +55,36 @@ public class METSDisseminationCrosswalk Namespace.getNamespace("xlink", "http://www.w3.org/TR/xlink"); - /** METS namespace -- includes "mets" prefix for use in XPaths */ + /** + * METS namespace -- includes "mets" prefix for use in XPaths + */ private static final Namespace METS_NS = Namespace - .getNamespace("mets", "http://www.loc.gov/METS/"); + .getNamespace("mets", "http://www.loc.gov/METS/"); - private static final Namespace namespaces[] = { METS_NS, MODS_NS, XLINK_NS }; + private static final Namespace namespaces[] = {METS_NS, MODS_NS, XLINK_NS}; - /** URL of METS XML Schema */ + /** + * URL of METS XML Schema + */ private static final String METS_XSD = "http://www.loc.gov/standards/mets/mets.xsd"; private static final String schemaLocation = - METS_NS.getURI()+" "+METS_XSD; + METS_NS.getURI() + " " + METS_XSD; @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { return (Namespace[]) ArrayUtils.clone(namespaces); } @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return schemaLocation; } @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { List result = new ArrayList(1); result.add(disseminateElement(context, dso)); return result; @@ -93,29 +93,29 @@ public class METSDisseminationCrosswalk @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { - if (!canDisseminate(dso)) - { - throw new CrosswalkObjectNotSupported("METSDisseminationCrosswalk cannot disseminate a DSpaceObject of type: " + Constants.typeText[dso.getType()]); - } - - PackageDisseminator dip = (PackageDisseminator) - CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(PackageDisseminator.class, METS_PACKAGER_PLUGIN); - if (dip == null) - { - throw new CrosswalkInternalException("Cannot find a disseminate plugin for package=" + METS_PACKAGER_PLUGIN); + IOException, SQLException, AuthorizeException { + if (!canDisseminate(dso)) { + throw new CrosswalkObjectNotSupported( + "METSDisseminationCrosswalk cannot disseminate a DSpaceObject of type: " + Constants.typeText[dso + .getType()]); } - try - { + PackageDisseminator dip = (PackageDisseminator) + CoreServiceFactory.getInstance().getPluginService() + .getNamedPlugin(PackageDisseminator.class, METS_PACKAGER_PLUGIN); + if (dip == null) { + throw new CrosswalkInternalException( + "Cannot find a disseminate plugin for package=" + METS_PACKAGER_PLUGIN); + } + + try { // Set the manifestOnly=true param so we just get METS document (and not content files, etc) PackageParameters pparams = new PackageParameters(); pparams.put("manifestOnly", "true"); // Create a temporary file to disseminate into String tempDirectory = (ConfigurationManager.getProperty("upload.temp.dir") != null) - ? ConfigurationManager.getProperty("upload.temp.dir") : System.getProperty("java.io.tmpdir"); + ? ConfigurationManager.getProperty("upload.temp.dir") : System.getProperty("java.io.tmpdir"); File tempFile = File.createTempFile("METSDissemination" + dso.hashCode(), null, new File(tempDirectory)); tempFile.deleteOnExit(); @@ -123,42 +123,36 @@ public class METSDisseminationCrosswalk // Disseminate METS to temp file dip.disseminate(context, dso, pparams, tempFile); - try - { + try { //Return just the root Element of the METS file SAXBuilder builder = new SAXBuilder(); Document metsDocument = builder.build(tempFile); return metsDocument.getRootElement(); + } catch (JDOMException je) { + throw new MetadataValidationException( + "Error parsing METS (see wrapped error message for more details) ", je); } - catch (JDOMException je) - { - throw new MetadataValidationException("Error parsing METS (see wrapped error message for more details) ",je); - } - } - catch (PackageException pe) - { - throw new CrosswalkInternalException("Failed making METS manifest in packager (see wrapped error message for more details) ",pe); + } catch (PackageException pe) { + throw new CrosswalkInternalException( + "Failed making METS manifest in packager (see wrapped error message for more details) ", pe); } } @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { //can disseminate most types of DSpaceObjects (Site, Community, Collection, Item) - if(dso.getType()==Constants.SITE || - dso.getType()==Constants.COMMUNITY || - dso.getType()==Constants.COLLECTION || - dso.getType()==Constants.ITEM) - { + if (dso.getType() == Constants.SITE || + dso.getType() == Constants.COMMUNITY || + dso.getType() == Constants.COLLECTION || + dso.getType() == Constants.ITEM) { return true; - } - else + } else { return false; + } } @Override - public boolean preferList() - { + public boolean preferList() { return false; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java index 702495bf73..4b76afd90b 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java @@ -10,13 +10,13 @@ package org.dspace.content.crosswalk; import java.io.IOException; import java.sql.SQLException; import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Date; -import java.text.SimpleDateFormat; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -56,10 +56,11 @@ import org.jdom.Namespace; * @author Tim Donohue * @version $Revision: 2108 $ */ -public class METSRightsCrosswalk - implements IngestionCrosswalk, DisseminationCrosswalk -{ - /** log4j category */ +public class METSRightsCrosswalk + implements IngestionCrosswalk, DisseminationCrosswalk { + /** + * log4j category + */ private static Logger log = Logger.getLogger(METSRightsCrosswalk.class); private static final Namespace METSRights_NS = @@ -67,13 +68,13 @@ public class METSRightsCrosswalk // XML schemaLocation fragment for this crosswalk, from config. private String schemaLocation = - METSRights_NS.getURI()+" http://cosimo.stanford.edu/sdr/metsrights.xsd"; + METSRights_NS.getURI() + " http://cosimo.stanford.edu/sdr/metsrights.xsd"; - private static final Namespace namespaces[] = { METSRights_NS }; + private static final Namespace namespaces[] = {METSRights_NS}; - private static final Map otherTypesMapping = new HashMap(); - static - { + private static final Map otherTypesMapping = new HashMap(); + + static { //Mapping of DSpace Policy Actions to METSRights PermissionType values // (These are the values stored in the @OTHERPERMITTYPE attribute in METSRights) // NOTE: READ, WRITE, DELETE are not included here as they map directly to existing METSRights PermissionTypes @@ -100,28 +101,26 @@ public class METSRightsCrosswalk protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); + protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance() + .getResourcePolicyService(); /*----------- Dissemination functions -------------------*/ @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { return (Namespace[]) ArrayUtils.clone(namespaces); } @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return schemaLocation; } @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { //can disseminate all types of DSpace Objects, except for SITE - return (dso.getType()!=Constants.SITE); + return (dso.getType() != Constants.SITE); } /** @@ -130,25 +129,21 @@ public class METSRightsCrosswalk * METSRights PermissionTypes. * * @param context context - * @param dso DSpace Object + * @param dso DSpace Object * @return XML Element corresponding to the new {@code } translation * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { - if(dso==null) - { + IOException, SQLException, AuthorizeException { + if (dso == null) { return null; - } - // we don't have a way to provide METSRights for a SITE object - else if(dso.getType() == Constants.SITE) - { + } else if (dso.getType() == Constants.SITE) { + // we don't have a way to provide METSRights for a SITE object throw new CrosswalkObjectNotSupported("The METSRightsCrosswalk cannot crosswalk a SITE object"); } @@ -170,127 +165,115 @@ public class METSRightsCrosswalk List policies = authorizeService.getPolicies(context, dso); //For each DSpace policy - for(ResourcePolicy policy : policies) - { - // DSpace Policies can either reference a Group or an Individual, but not both! - Group group = policy.getGroup(); - EPerson person = policy.getEPerson(); + for (ResourcePolicy policy : policies) { + // DSpace Policies can either reference a Group or an Individual, but not both! + Group group = policy.getGroup(); + EPerson person = policy.getEPerson(); - // Create our node for this policy - Element rightsContext = new Element("Context", METSRights_NS); + // Create our node for this policy + Element rightsContext = new Element("Context", METSRights_NS); - String rpName = policy.getRpName(); - if (rpName != null) - { - rightsContext.setAttribute("rpName",rpName); - } + String rpName = policy.getRpName(); + if (rpName != null) { + rightsContext.setAttribute("rpName", rpName); + } - // As of DSpace 3.0, policies may have an effective date range, check if a policy is effective - rightsContext.setAttribute("in-effect","true"); - Date now = new Date(); - SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd"); - if (policy.getStartDate() != null) - { - rightsContext.setAttribute("start-date", iso8601.format(policy.getStartDate())); - if (policy.getStartDate().after(now)) - { - rightsContext.setAttribute("in-effect","false"); - } - } - - if (policy.getEndDate() != null) - { - rightsContext.setAttribute("end-date", iso8601.format(policy.getEndDate())); - if (policy.getEndDate().before(now)) - { - rightsContext.setAttribute("in-effect","false"); - } - } - - //First, handle Group-based policies - // For Group policies we need to setup a - // [group-name]... - if(group != null) - { - //Default all DSpace groups to have "MANAGED GRP" as the type - String contextClass=GROUP_CONTEXTCLASS; + // As of DSpace 3.0, policies may have an effective date range, check if a policy is effective + rightsContext.setAttribute("in-effect", "true"); + Date now = new Date(); + SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd"); + if (policy.getStartDate() != null) { + rightsContext.setAttribute("start-date", iso8601.format(policy.getStartDate())); + if (policy.getStartDate().after(now)) { + rightsContext.setAttribute("in-effect", "false"); + } + } - if(StringUtils.equals(group.getName(), Group.ANONYMOUS)) //DSpace Anonymous Group = 'GENERAL PUBLIC' type - { - contextClass = ANONYMOUS_CONTEXTCLASS; - } - else if(StringUtils.equals(group.getName(), Group.ADMIN)) //DSpace Administrator Group = 'REPOSITORY MGR' type - { - contextClass = ADMIN_CONTEXTCLASS; - } + if (policy.getEndDate() != null) { + rightsContext.setAttribute("end-date", iso8601.format(policy.getEndDate())); + if (policy.getEndDate().before(now)) { + rightsContext.setAttribute("in-effect", "false"); + } + } - rightsContext.setAttribute("CONTEXTCLASS", contextClass); + //First, handle Group-based policies + // For Group policies we need to setup a + // [group-name]... + if (group != null) { + //Default all DSpace groups to have "MANAGED GRP" as the type + String contextClass = GROUP_CONTEXTCLASS; - //If this is a "MANAGED GRP", then create a child - //to specify the group Name, and set @USERTYPE='GROUP' - if(contextClass.equals(GROUP_CONTEXTCLASS)) - { - try - { - //Translate the Group name for export. This ensures that groups with Internal IDs in their names - // (e.g. COLLECTION_1_ADMIN) are properly translated using the corresponding Handle or external identifier. - String exportGroupName = PackageUtils.translateGroupNameForExport(context, group.getName()); + if (StringUtils.equals(group.getName(), Group.ANONYMOUS)) { + //DSpace Anonymous Group = 'GENERAL PUBLIC' type + contextClass = ANONYMOUS_CONTEXTCLASS; + } else if (StringUtils.equals(group.getName(), Group.ADMIN)) { + //DSpace Administrator Group = 'REPOSITORY MGR' type + contextClass = ADMIN_CONTEXTCLASS; + } - //If translated group name is returned as "null", this means the Group name - // had an Internal Collection/Community ID embedded, which could not be - // translated properly to a Handle. We will NOT export these groups, - // as they could cause conflicts or data integrity problems if they are - // imported into another DSpace system. - if(exportGroupName!=null && !exportGroupName.isEmpty()) - { - //Create element. Add the Group's name to that element - Element rightsUser = new Element("UserName", METSRights_NS); - rightsUser.setAttribute("USERTYPE",GROUP_USERTYPE); - rightsUser.addContent(exportGroupName); - rightsContext.addContent(rightsUser); - } - else - //Skip over this Group, as we couldn't translate it for export. - //The Group seems to refer to a Community or Collection which no longer exists - continue; - } - catch(PackageException pe) - { - //A PackageException will only be thrown if translateGroupNameForExport() fails - //We'll just wrap it as a CrosswalkException and throw it upwards - throw new CrosswalkException(pe); - } - } + rightsContext.setAttribute("CONTEXTCLASS", contextClass); - rightsMD.addContent(rightsContext); + //If this is a "MANAGED GRP", then create a child + //to specify the group Name, and set @USERTYPE='GROUP' + if (contextClass.equals(GROUP_CONTEXTCLASS)) { + try { + //Translate the Group name for export. This ensures that groups with Internal IDs in their + // names + // (e.g. COLLECTION_1_ADMIN) are properly translated using the corresponding Handle or + // external identifier. + String exportGroupName = PackageUtils.translateGroupNameForExport(context, group.getName()); - }//end if group - //Next, handle User-based policies - // For User policies we need to setup a - // [group-name]... - else if(person!=null) - { - // All EPeople are considered 'Academic Users' - rightsContext.setAttribute("CONTEXTCLASS", PERSON_CONTEXTCLASS); + //If translated group name is returned as "null", this means the Group name + // had an Internal Collection/Community ID embedded, which could not be + // translated properly to a Handle. We will NOT export these groups, + // as they could cause conflicts or data integrity problems if they are + // imported into another DSpace system. + if (exportGroupName != null && !exportGroupName.isEmpty()) { + //Create element. Add the Group's name to that element + Element rightsUser = new Element("UserName", METSRights_NS); + rightsUser.setAttribute("USERTYPE", GROUP_USERTYPE); + rightsUser.addContent(exportGroupName); + rightsContext.addContent(rightsUser); + } else { + //Skip over this Group, as we couldn't translate it for export. + //The Group seems to refer to a Community or Collection which no longer exists + continue; + } + } catch (PackageException pe) { + //A PackageException will only be thrown if translateGroupNameForExport() fails + //We'll just wrap it as a CrosswalkException and throw it upwards + throw new CrosswalkException(pe); + } + } - //Create a node corresponding to person's email, set @USERTYPE='INDIVIDUAL' - Element rightsUser = new Element("UserName", METSRights_NS); - rightsUser.setAttribute("USERTYPE",PERSON_USERTYPE); - rightsUser.addContent(person.getEmail()); - rightsContext.addContent(rightsUser); + rightsMD.addContent(rightsContext); - rightsMD.addContent(rightsContext); - }//end if person - else - log.error("Policy " + String.valueOf(policy.getID()) - + " is neither user nor group! Omitted from package."); + } else if (person != null) { + //Next, handle User-based policies + // For User policies we need to setup a + // [group-name]... + + // All EPeople are considered 'Academic Users' + rightsContext.setAttribute("CONTEXTCLASS", PERSON_CONTEXTCLASS); + + //Create a node corresponding to person's email, set @USERTYPE='INDIVIDUAL' + Element rightsUser = new Element("UserName", METSRights_NS); + rightsUser.setAttribute("USERTYPE", PERSON_USERTYPE); + rightsUser.addContent(person.getEmail()); + rightsContext.addContent(rightsUser); + + rightsMD.addContent(rightsContext); + } else { + log.error("Policy " + String.valueOf(policy.getID()) + + " is neither user nor group! Omitted from package."); + } - //Translate the DSpace ResourcePolicy into a element - Element rightsPerm = translatePermissions(policy); - rightsContext.addContent(rightsPerm); - - }//end for each policy + //Translate the DSpace ResourcePolicy into a element + Element rightsPerm = translatePermissions(policy); + rightsContext.addContent(rightsPerm); + + } //end for each policy return rightsMD; } @@ -298,16 +281,14 @@ public class METSRightsCrosswalk @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { List result = new ArrayList(1); result.add(disseminateElement(context, dso)); return result; } @Override - public boolean preferList() - { + public boolean preferList() { return false; } @@ -318,52 +299,42 @@ public class METSRightsCrosswalk * Permissions element. This element may be empty if * there was an issue translating the ResourcePolicy. * - * @param policy The DSpace ResourcePolicy + * @param policy The DSpace ResourcePolicy * @return the Element representing the METSRIghts Permissions or null. */ - private Element translatePermissions(ResourcePolicy policy) - { + private Element translatePermissions(ResourcePolicy policy) { //Create our node to store all permissions in this context Element rightsPerm = new Element("Permissions", METSRights_NS); //Determine the 'actions' permitted by this DSpace policy, and translate to METSRights PermissionTypes int action = policy.getAction(); //All READ-based actions = cannot modify or delete object - if(action==Constants.READ - || action==Constants.DEFAULT_BITSTREAM_READ - || action==Constants.DEFAULT_ITEM_READ) - { - // For DSpace, READ = Discover and Display - rightsPerm.setAttribute("DISCOVER", "true"); - rightsPerm.setAttribute("DISPLAY", "true"); - //Read = cannot modify or delete - rightsPerm.setAttribute("MODIFY", "false"); - rightsPerm.setAttribute("DELETE", "false"); - } - //All WRITE-based actions = can modify, but cannot delete - else if(action == Constants.WRITE - || action==Constants.ADD) - { + if (action == Constants.READ + || action == Constants.DEFAULT_BITSTREAM_READ + || action == Constants.DEFAULT_ITEM_READ) { + // For DSpace, READ = Discover and Display + rightsPerm.setAttribute("DISCOVER", "true"); + rightsPerm.setAttribute("DISPLAY", "true"); + //Read = cannot modify or delete + rightsPerm.setAttribute("MODIFY", "false"); + rightsPerm.setAttribute("DELETE", "false"); + } else if (action == Constants.WRITE || action == Constants.ADD) { + //All WRITE-based actions = can modify, but cannot delete rightsPerm.setAttribute("DISCOVER", "true"); rightsPerm.setAttribute("DISPLAY", "true"); //Write = can modify, but cannot delete rightsPerm.setAttribute("MODIFY", "true"); rightsPerm.setAttribute("DELETE", "false"); - } - //All DELETE-based actions = can modify & can delete - //(NOTE: Although Constants.DELETE is marked as "obsolete", it is still used in dspace-api) - else if(action == Constants.DELETE - || action==Constants.REMOVE) - { + } else if (action == Constants.DELETE || action == Constants.REMOVE) { + //All DELETE-based actions = can modify & can delete + //(NOTE: Although Constants.DELETE is marked as "obsolete", it is still used in dspace-api) rightsPerm.setAttribute("DISCOVER", "true"); rightsPerm.setAttribute("DISPLAY", "true"); //Delete = can both modify and delete rightsPerm.setAttribute("MODIFY", "true"); rightsPerm.setAttribute("DELETE", "true"); - } - //ADMIN action = full permissions - else if(action == Constants.ADMIN) - { + } else if (action == Constants.ADMIN) { + //ADMIN action = full permissions rightsPerm.setAttribute("DISCOVER", "true"); rightsPerm.setAttribute("DISPLAY", "true"); rightsPerm.setAttribute("COPY", "true"); @@ -371,9 +342,7 @@ public class METSRightsCrosswalk rightsPerm.setAttribute("MODIFY", "true"); rightsPerm.setAttribute("DELETE", "true"); rightsPerm.setAttribute("PRINT", "true"); - } - else - { + } else { //Unknown action -- don't enable any rights by default //NOTE: ALL WORKFLOW RELATED ACTIONS ARE NOT INCLUDED IN METSRIGHTS //DSpace API no longer assigns nor checks any of the following 'action' types: @@ -381,13 +350,13 @@ public class METSRightsCrosswalk // * Constants.WORKFLOW_STEP_2 // * Constants.WORKFLOW_STEP_3 // * Constants.WORKFLOW_ABORT - }//end if + } //end if //Also add in OTHER permissionTypes, as necessary (see 'otherTypesMapping' above) // (These OTHER permissionTypes are used to tell apart similar DSpace permissions during Ingestion) - if(otherTypesMapping.containsKey(action)) - { - //if found in our 'otherTypesMapping', enable @OTHER attribute and add in the appropriate value to @OTHERPERMITTYPE attribute + if (otherTypesMapping.containsKey(action)) { + //if found in our 'otherTypesMapping', enable @OTHER attribute and add in the appropriate value to + // @OTHERPERMITTYPE attribute rightsPerm.setAttribute("OTHER", "true"); rightsPerm.setAttribute("OTHERPERMITTYPE", otherTypesMapping.get(action)); } @@ -401,25 +370,19 @@ public class METSRightsCrosswalk /** * Ingest a whole XML document, starting at specified root. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to ingest - * @param root - * root element - * @param createMissingMetadataFields - * whether to create missing fields + * @param context The relevant DSpace Context. + * @param dso DSpace object to ingest + * @param root root element + * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { - if (!(root.getName().equals("RightsDeclarationMD"))) - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { + if (!(root.getName().equals("RightsDeclarationMD"))) { throw new MetadataValidationException("Wrong root element for METSRights: " + root.toString()); } ingest(context, dso, root.getChildren(), createMissingMetadataFields); @@ -437,100 +400,89 @@ public class METSRightsCrosswalk * conjunction with another Crosswalk which can create/restore missing * Groups or EPeople (e.g. RoleCrosswalk). * - * @param context context - * @param dso Dspace object - * @param ml list of elements + * @param context context + * @param dso Dspace object + * @param ml list of elements * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error * @see RoleCrosswalk */ @Override public void ingest(Context context, DSpaceObject dso, List ml, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { // SITE objects are not supported by the METSRightsCrosswalk - if (dso.getType() == Constants.SITE) - { - throw new CrosswalkObjectNotSupported("Wrong target object type, METSRightsCrosswalk cannot crosswalk a SITE object."); + if (dso.getType() == Constants.SITE) { + throw new CrosswalkObjectNotSupported( + "Wrong target object type, METSRightsCrosswalk cannot crosswalk a SITE object."); } // If we're fed the top-level wrapper element, recurse into its guts. // What we need to analyze are the elements underneath it. - if(!ml.isEmpty() && ml.get(0).getName().equals("RightsDeclarationMD")) - { + if (!ml.isEmpty() && ml.get(0).getName().equals("RightsDeclarationMD")) { ingest(context, dso, ml.get(0).getChildren(), createMissingMetadataFields); - } - else - { + } else { // Loop through each Element in the passed in List, creating a ResourcePolicy for each List policies = new ArrayList<>(); - for (Element element : ml) - { + for (Element element : ml) { // Must be a "Context" section (where permissions are stored) - if (element.getName().equals("Context")) - { + if (element.getName().equals("Context")) { //get what class of context this is String contextClass = element.getAttributeValue("CONTEXTCLASS"); ResourcePolicy rp = resourcePolicyService.create(context); - SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd" ); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // get reference to the element // Note: we are assuming here that there will only ever be ONE // element. Currently there are no known use cases for multiple. Element permsElement = element.getChild("Permissions", METSRights_NS); - if(permsElement == null) { - log.error("No element was found. Skipping this element."); - continue; + if (permsElement == null) { + log.error("No element was found. Skipping this element."); + continue; } - if (element.getAttributeValue("rpName") != null) - { + if (element.getAttributeValue("rpName") != null) { rp.setRpName(element.getAttributeValue("rpName")); } try { - if (element.getAttributeValue("start-date") != null) - { + if (element.getAttributeValue("start-date") != null) { rp.setStartDate(sdf.parse(element.getAttributeValue("start-date"))); } - if (element.getAttributeValue("end-date") != null) - { + if (element.getAttributeValue("end-date") != null) { rp.setEndDate(sdf.parse(element.getAttributeValue("end-date"))); } - }catch (ParseException ex) { + } catch (ParseException ex) { log.error("Failed to parse embargo date. The date needs to be in the format 'yyyy-MM-dd'.", ex); } //Check if this permission pertains to Anonymous users - if(ANONYMOUS_CONTEXTCLASS.equals(contextClass)) - { + if (ANONYMOUS_CONTEXTCLASS.equals(contextClass)) { //get DSpace Anonymous group, ID=0 Group anonGroup = groupService.findByName(context, Group.ANONYMOUS); - if(anonGroup==null) - { - throw new CrosswalkInternalException("The DSpace database has not been properly initialized. The Anonymous Group is missing from the database."); + if (anonGroup == null) { + throw new CrosswalkInternalException( + "The DSpace database has not been properly initialized. The Anonymous Group is " + + "missing from the database."); } rp.setGroup(anonGroup); - } // else if this permission declaration pertains to Administrators - else if(ADMIN_CONTEXTCLASS.equals(contextClass)) - { - //get DSpace Administrator group, ID=1 + } else if (ADMIN_CONTEXTCLASS.equals(contextClass)) { + // else if this permission declaration pertains to Administrators + // get DSpace Administrator group Group adminGroup = groupService.findByName(context, Group.ADMIN); - if(adminGroup==null) - { - throw new CrosswalkInternalException("The DSpace database has not been properly initialized. The Administrator Group is missing from the database."); + if (adminGroup == null) { + throw new CrosswalkInternalException( + "The DSpace database has not been properly initialized. The Administrator Group is " + + "missing from the database."); } rp.setGroup(adminGroup); - } // else if this permission pertains to another DSpace group - else if(GROUP_CONTEXTCLASS.equals(contextClass)) - { - try - { + } else if (GROUP_CONTEXTCLASS.equals(contextClass)) { + // else if this permission pertains to another DSpace group + try { //we need to find the name of DSpace group it pertains to //Get the text within the child element, // this is the group's name @@ -544,29 +496,29 @@ public class METSRightsCrosswalk Group group = groupService.findByName(context, groupName); //if not found, throw an error -- user should restore group from the SITE AIP - if(group==null) - { + if (group == null) { throw new CrosswalkInternalException("Cannot restore Group permissions on object (" - + "type=" + Constants.typeText[dso.getType()] + ", " - + "handle=" + dso.getHandle() + ", " - + "ID=" + dso.getID() - + "). The Group named '" + groupName + "' is missing from DSpace. " - + "Please restore this group using the SITE AIP, or recreate it."); + + "type=" + Constants.typeText[dso + .getType()] + ", " + + "handle=" + dso.getHandle() + ", " + + "ID=" + dso.getID() + + "). The Group named '" + groupName + "' is" + + " missing from DSpace. " + + "Please restore this group using the SITE " + + "AIP, or recreate it."); } //assign group to policy rp.setGroup(group); - } - catch(PackageException pe) - { + } catch (PackageException pe) { //A PackageException will only be thrown if translateDefaultGroupName() fails //We'll just wrap it as a CrosswalkException and throw it upwards throw new CrosswalkException(pe); } - }// else if this permission pertains to a DSpace person - else if(PERSON_CONTEXTCLASS.equals(contextClass)) - { - //we need to find the person it pertains to + } else if (PERSON_CONTEXTCLASS.equals(contextClass)) { + // else if this permission pertains to a DSpace person + + // we need to find the person it pertains to // Get the text within the child element, // this is the person's email address String personEmail = element.getChildTextTrim("UserName", METSRights_NS); @@ -576,26 +528,26 @@ public class METSRightsCrosswalk //If cannot find by email, try by netID //(though METSRights should contain email if it was exported by DSpace) - if(person==null) - { + if (person == null) { person = ePersonService.findByNetid(context, personEmail); } //if not found, throw an error -- user should restore person from the SITE AIP - if(person==null) - { + if (person == null) { throw new CrosswalkInternalException("Cannot restore Person permissions on object (" - + "type=" + Constants.typeText[dso.getType()] + ", " - + "handle=" + dso.getHandle() + ", " - + "ID=" + dso.getID() - + "). The Person with email/netid '" + personEmail + "' is missing from DSpace. " - + "Please restore this Person object using the SITE AIP, or recreate it."); + + "type=" + Constants.typeText[dso + .getType()] + ", " + + "handle=" + dso.getHandle() + ", " + + "ID=" + dso.getID() + + "). The Person with email/netid '" + + personEmail + "' is missing from DSpace. " + + "Please restore this Person object using the " + + "SITE AIP, or recreate it."); } //assign person to the policy rp.setEPerson(person); - }//end if Person - else { + } else { log.error("Unrecognized CONTEXTCLASS: " + contextClass); } @@ -603,7 +555,7 @@ public class METSRightsCrosswalk rp.setAction(parsePermissions(permsElement)); policies.add(rp); } //end if "Context" element - }//end for loop + } //end for loop // Finally, we need to remove any existing policies from the current object, // and replace them with the policies provided via METSRights. NOTE: @@ -625,35 +577,27 @@ public class METSRightsCrosswalk * @param permsElement The METSRights Permissions element * @return A DSpace Action ID from org.dspace.core.Constants */ - private int parsePermissions(Element permsElement) - { + private int parsePermissions(Element permsElement) { //First, check if the @OTHERPERMITTYPE attribute is specified String otherPermitType = permsElement.getAttributeValue("OTHERPERMITTYPE"); //if @OTHERPERMITTYPE attribute exists, it will map directly to a DSpace Action type - if(otherPermitType!=null && !otherPermitType.isEmpty()) - { - if(otherTypesMapping.containsValue(otherPermitType)) - { + if (otherPermitType != null && !otherPermitType.isEmpty()) { + if (otherTypesMapping.containsValue(otherPermitType)) { //find the Action ID this value maps to - for(int actionType: otherTypesMapping.keySet()) - { + for (int actionType : otherTypesMapping.keySet()) { //if found, this is the Action ID corresponding to this permission - if(otherTypesMapping.get(actionType).equals(otherPermitType)) - { + if (otherTypesMapping.get(actionType).equals(otherPermitType)) { return actionType; } } - } - else - { + } else { log.warn("Unrecognized @OTHERPERMITTYPE attribute value (" - + otherPermitType - + ") found in METSRights section of METS Manifest."); + + otherPermitType + + ") found in METSRights section of METS Manifest."); } - } - else // Otherwise, a closer analysis of all Permission element attributes is necessary - { + } else { + // Otherwise, a closer analysis of all Permission element attributes is necessary boolean discoverPermit = Boolean.parseBoolean(permsElement.getAttributeValue("DISCOVER")); boolean displayPermit = Boolean.parseBoolean(permsElement.getAttributeValue("DISPLAY")); boolean modifyPermit = Boolean.parseBoolean(permsElement.getAttributeValue("MODIFY")); @@ -661,20 +605,15 @@ public class METSRightsCrosswalk boolean otherPermit = Boolean.parseBoolean(permsElement.getAttributeValue("OTHER")); //if DELETE='true' - if(deletePermit && !otherPermit) - { + if (deletePermit && !otherPermit) { //This must refer to the DELETE action type //(note REMOVE & ADMIN action type have @OTHERPERMITTYPE values specified) return Constants.DELETE; - }//if MODIFY='true' - else if(modifyPermit && !otherPermit) - { + } else if (modifyPermit && !otherPermit) { //This must refer to the WRITE action type //(note ADD action type has an @OTHERPERMITTYPE value specified) return Constants.WRITE; - } - else if(discoverPermit && displayPermit && !otherPermit) - { + } else if (discoverPermit && displayPermit && !otherPermit) { //This must refer to the READ action type return Constants.READ; } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/MODSDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/MODSDisseminationCrosswalk.java index bab81f6411..1258408493 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/MODSDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/MODSDisseminationCrosswalk.java @@ -23,7 +23,12 @@ import java.util.Properties; import org.apache.commons.lang.ArrayUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.Site; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; @@ -32,6 +37,8 @@ import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.SelfNamedPlugin; +import org.dspace.handle.factory.HandleServiceFactory; +import org.dspace.handle.service.HandleService; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; @@ -48,7 +55,7 @@ import org.jdom.xpath.XPath; *

    * This class supports multiple dissemination crosswalks from DSpace * internal data to the MODS XML format - * (see http://www.loc.gov/standards/mods/.) + * (see http://www.loc.gov/standards/mods/.) *

    * It registers multiple Plugin names, which it reads from * the DSpace configuration as follows: @@ -79,9 +86,10 @@ import org.jdom.xpath.XPath; * @version $Revision$ */ public class MODSDisseminationCrosswalk extends SelfNamedPlugin - implements DisseminationCrosswalk -{ - /** log4j category */ + implements DisseminationCrosswalk { + /** + * log4j category + */ private static Logger log = Logger.getLogger(MODSDisseminationCrosswalk.class); private static final String CONFIG_PREFIX = "crosswalk.mods.properties."; @@ -89,29 +97,27 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin protected final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); + protected final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); /** * Fill in the plugin alias table from DSpace configuration entries * for configuration files for flavors of MODS crosswalk: */ private static String aliases[] = null; - static - { + + static { List aliasList = new ArrayList(); - Enumeration pe = (Enumeration)ConfigurationManager.propertyNames(); - while (pe.hasMoreElements()) - { + Enumeration pe = (Enumeration) ConfigurationManager.propertyNames(); + while (pe.hasMoreElements()) { String key = pe.nextElement(); - if (key.startsWith(CONFIG_PREFIX)) - { + if (key.startsWith(CONFIG_PREFIX)) { aliasList.add(key.substring(CONFIG_PREFIX.length())); } } - aliases = (String[])aliasList.toArray(new String[aliasList.size()]); + aliases = (String[]) aliasList.toArray(new String[aliasList.size()]); } - public static String[] getPluginNames() - { + public static String[] getPluginNames() { return (String[]) ArrayUtils.clone(aliases); } @@ -124,14 +130,16 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin private static final Namespace XLINK_NS = Namespace.getNamespace("xlink", "http://www.w3.org/1999/xlink"); - private static final Namespace namespaces[] = { MODS_NS, XLINK_NS }; + private static final Namespace namespaces[] = {MODS_NS, XLINK_NS}; - /** URL of MODS XML Schema */ + /** + * URL of MODS XML Schema + */ public static final String MODS_XSD = "http://www.loc.gov/standards/mods/v3/mods-3-1.xsd"; private static final String schemaLocation = - MODS_NS.getURI()+" "+MODS_XSD; + MODS_NS.getURI() + " " + MODS_XSD; private static XMLOutputter outputUgly = new XMLOutputter(); private static SAXBuilder builder = new SAXBuilder(); @@ -144,8 +152,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin * 2. XML subtree to add to MODS record. * 3. XPath expression showing places to plug in the value. */ - static class modsTriple - { + static class modsTriple { public String qdc = null; public Element xml = null; public XPath xpath = null; @@ -155,30 +162,26 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin * The DC stays a string; parse the XML with appropriate * namespaces; "compile" the XPath. */ - public static modsTriple create(String qdc, String xml, String xpath) - { + public static modsTriple create(String qdc, String xml, String xpath) { modsTriple result = new modsTriple(); - final String prolog = ""; + final String prolog = ""; final String postlog = ""; - try - { + try { result.qdc = qdc; result.xpath = XPath.newInstance(xpath); result.xpath.addNamespace(MODS_NS.getPrefix(), MODS_NS.getURI()); result.xpath.addNamespace(XLINK_NS); - Document d = builder.build(new StringReader(prolog+xml+postlog)); - result.xml = (Element)d.getRootElement().getContent(0); - } - catch (JDOMException je) - { - log.error("Error initializing modsTriple(\""+qdc+"\",\""+xml+"\",\""+xpath+"\"): got "+je.toString()); + Document d = builder.build(new StringReader(prolog + xml + postlog)); + result.xml = (Element) d.getRootElement().getContent(0); + } catch (JDOMException je) { + log.error("Error initializing modsTriple(\"" + qdc + "\",\"" + xml + "\",\"" + xpath + "\"): got " + je + .toString()); return null; - } - catch (IOException je) - { - log.error("Error initializing modsTriple(\""+qdc+"\",\""+xml+"\",\""+xpath+"\"): got "+je.toString()); + } catch (IOException je) { + log.error("Error initializing modsTriple(\"" + qdc + "\",\"" + xml + "\",\"" + xpath + "\"): got " + je + .toString()); return null; } return result; @@ -193,96 +196,77 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin * * The MODS crosswalk configuration properties follow the format: * - * {field-name} = {XML-fragment} | {XPath} + * {field-name} = {XML-fragment} | {XPath} * - * 1. qualified DC field name is of the form - * {MDschema}.{element}.{qualifier} + * 1. qualified DC field name is of the form + * {MDschema}.{element}.{qualifier} * - * e.g. dc.contributor.author + * e.g. dc.contributor.author * - * 2. XML fragment is prototype of metadata element, with empty or "%s" - * placeholders for value(s). NOTE: Leave the %s's in becaue - * it's much easier then to see if something is broken. + * 2. XML fragment is prototype of metadata element, with empty or "%s" + * placeholders for value(s). NOTE: Leave the %s's in becaue + * it's much easier then to see if something is broken. * - * 3. XPath expression listing point(s) in the above XML where - * the value is to be inserted. Context is the element itself. + * 3. XPath expression listing point(s) in the above XML where + * the value is to be inserted. Context is the element itself. * * Example properties line: * - * dc.description.abstract = %s | text() - * + * dc.description.abstract = %s | text() */ private void initMap() - throws CrosswalkInternalException - { - if (modsMap != null) - { + throws CrosswalkInternalException { + if (modsMap != null) { return; } String myAlias = getPluginInstanceName(); - if (myAlias == null) - { + if (myAlias == null) { log.error("Must use PluginService to instantiate MODSDisseminationCrosswalk so the class knows its name."); return; } - String cmPropName = CONFIG_PREFIX+myAlias; + String cmPropName = CONFIG_PREFIX + myAlias; String propsFilename = ConfigurationManager.getProperty(cmPropName); - if (propsFilename == null) - { - String msg = "MODS crosswalk missing "+ - "configuration file for crosswalk named \""+myAlias+"\""; + if (propsFilename == null) { + String msg = "MODS crosswalk missing " + + "configuration file for crosswalk named \"" + myAlias + "\""; log.error(msg); throw new CrosswalkInternalException(msg); - } - else - { + } else { String parent = ConfigurationManager.getProperty("dspace.dir") + File.separator + "config" + File.separator; File propsFile = new File(parent, propsFilename); Properties modsConfig = new Properties(); FileInputStream pfs = null; - try - { + try { pfs = new FileInputStream(propsFile); modsConfig.load(pfs); - } - catch (IOException e) - { - log.error("Error opening or reading MODS properties file: "+propsFile.toString()+": "+e.toString()); - throw new CrosswalkInternalException("MODS crosswalk cannot "+ - "open config file: "+e.toString(), e); - } - finally - { - if (pfs != null) - { - try - { + } catch (IOException e) { + log.error( + "Error opening or reading MODS properties file: " + propsFile.toString() + ": " + e.toString()); + throw new CrosswalkInternalException("MODS crosswalk cannot " + + "open config file: " + e.toString(), e); + } finally { + if (pfs != null) { + try { pfs.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } modsMap = new HashMap(); - Enumeration pe = (Enumeration)modsConfig.propertyNames(); - while (pe.hasMoreElements()) - { + Enumeration pe = (Enumeration) modsConfig.propertyNames(); + while (pe.hasMoreElements()) { String qdc = pe.nextElement(); String val = modsConfig.getProperty(qdc); String pair[] = val.split("\\s+\\|\\s+", 2); - if (pair.length < 2) - { + if (pair.length < 2) { log.warn("Illegal MODS mapping in " + propsFile.toString() + ", line = " + - qdc + " = " + val); - } - else - { + qdc + " = " + val); + } else { modsTriple trip = modsTriple.create(qdc, pair[0], pair[1]); - if (trip != null) - { + if (trip != null) { modsMap.put(qdc, trip); } } @@ -291,11 +275,10 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin } /** - * Return the MODS namespace + * Return the MODS namespace */ @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { return (Namespace[]) ArrayUtils.clone(namespaces); } @@ -303,80 +286,67 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin * Return the MODS schema */ @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return schemaLocation; } /** * Returns object's metadata in MODS format, as List of XML structure nodes. + * * @param context context * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { return disseminateListInternal(dso, true); } /** * Disseminate an Item, Collection, or Community to MODS. + * * @param context context * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { Element root = new Element("mods", MODS_NS); root.setAttribute("schemaLocation", schemaLocation, XSI_NS); - root.addContent(disseminateListInternal(dso,false)); + root.addContent(disseminateListInternal(dso, false)); return root; } private List disseminateListInternal(DSpaceObject dso, boolean addSchema) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { List dcvs = null; - if (dso.getType() == Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { dcvs = item2Metadata((Item) dso); - } - else if (dso.getType() == Constants.COLLECTION) - { + } else if (dso.getType() == Constants.COLLECTION) { dcvs = collection2Metadata((Collection) dso); - } - else if (dso.getType() == Constants.COMMUNITY) - { + } else if (dso.getType() == Constants.COMMUNITY) { dcvs = community2Metadata((Community) dso); - } - else if (dso.getType() == Constants.SITE) - { + } else if (dso.getType() == Constants.SITE) { dcvs = site2Metadata((Site) dso); - } - else - { + } else { throw new CrosswalkObjectNotSupported( - "MODSDisseminationCrosswalk can only crosswalk Items, Collections, or Communities"); + "MODSDisseminationCrosswalk can only crosswalk Items, Collections, or Communities"); } initMap(); List result = new ArrayList(dcvs.size()); - for (MockMetadataValue dcv : dcvs) - { + for (MockMetadataValue dcv : dcvs) { String qdc = dcv.getSchema() + "." + dcv.getElement(); - if (dcv.getQualifier() != null) - { + if (dcv.getQualifier() != null) { qdc += "." + dcv.getQualifier(); } String value = dcv.getValue(); @@ -393,9 +363,9 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin Iterator ni = trip.xpath.selectNodes(me).iterator(); if (!ni.hasNext()) { log.warn("XPath \"" + trip.xpath.getXPath() + - "\" found no elements in \"" + - outputUgly.outputString(me) + - "\", qdc=" + qdc); + "\" found no elements in \"" + + outputUgly.outputString(me) + + "\", qdc=" + qdc); } while (ni.hasNext()) { Object what = ni.next(); @@ -412,9 +382,9 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin result.add(me); } catch (JDOMException je) { log.error("Error following XPath in modsTriple: context=" + - outputUgly.outputString(trip.xml) + - ", xpath=" + trip.xpath.getXPath() + ", exception=" + - je.toString()); + outputUgly.outputString(trip.xml) + + ", xpath=" + trip.xpath.getXPath() + ", exception=" + + je.toString()); } } } @@ -425,8 +395,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin * ModsCrosswalk can disseminate: Items, Collections, Communities, and Site. */ @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { return (dso.getType() == Constants.ITEM || dso.getType() == Constants.COLLECTION || dso.getType() == Constants.COMMUNITY || @@ -437,8 +406,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin * ModsCrosswalk prefer's element form over list. */ @Override - public boolean preferList() - { + public boolean preferList() { return false; } @@ -447,81 +415,70 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin * Generate a list of metadata elements for the given DSpace * site. * - * @param site - * The site to derive metadata from + * @param site The site to derive metadata from * @return list of metadata */ - protected List site2Metadata(Site site) - { + protected List site2Metadata(Site site) { List metadata = new ArrayList<>(); - String identifier_uri = "http://hdl.handle.net/" - + site.getHandle(); + String identifier_uri = handleService.getCanonicalPrefix() + + site.getHandle(); String title = site.getName(); String url = site.getURL(); - if (identifier_uri != null) - { + if (identifier_uri != null) { metadata.add(createDCValue("identifier.uri", null, identifier_uri)); } //FIXME: adding two URIs for now (site handle and URL), in case site isn't using handles - if (url != null) - { + if (url != null) { metadata.add(createDCValue("identifier.uri", null, url)); } - if (title != null) - { + if (title != null) { metadata.add(createDCValue("title", null, title)); } return metadata; } + /** * Generate a list of metadata elements for the given DSpace * community. * - * @param community - * The community to derive metadata from + * @param community The community to derive metadata from * @return list of metadata */ - protected List community2Metadata(Community community) - { + protected List community2Metadata(Community community) { List metadata = new ArrayList<>(); String description = communityService.getMetadata(community, "introductory_text"); String description_abstract = communityService.getMetadata(community, "short_description"); - String description_table = communityService.getMetadata(community,"side_bar_text"); - String identifier_uri = "http://hdl.handle.net/" - + community.getHandle(); - String rights = communityService.getMetadata(community,"copyright_text"); - String title = communityService.getMetadata(community,"name"); + String description_table = communityService.getMetadata(community, "side_bar_text"); + String identifier_uri = handleService.getCanonicalPrefix() + + community.getHandle(); + String rights = communityService.getMetadata(community, "copyright_text"); + String title = communityService.getMetadata(community, "name"); metadata.add(createDCValue("description", null, description)); - if (description_abstract != null) - { + if (description_abstract != null) { metadata.add(createDCValue("description", "abstract", description_abstract)); } - if (description_table != null) - { + if (description_table != null) { metadata.add(createDCValue("description", "tableofcontents", description_table)); } - if (identifier_uri != null) - { + if (identifier_uri != null) { metadata.add(createDCValue("identifier.uri", null, identifier_uri)); } - if (rights != null) - { + if (rights != null) { metadata.add(createDCValue("rights", null, rights)); } - if (title != null) - { + if (title != null) { metadata.add(createDCValue("title", null, title)); } @@ -532,61 +489,51 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin * Generate a list of metadata elements for the given DSpace * collection. * - * @param collection - * The collection to derive metadata from + * @param collection The collection to derive metadata from * @return list of metadata */ - protected List collection2Metadata(Collection collection) - { + protected List collection2Metadata(Collection collection) { List metadata = new ArrayList<>(); String description = collectionService.getMetadata(collection, "introductory_text"); String description_abstract = collectionService.getMetadata(collection, "short_description"); String description_table = collectionService.getMetadata(collection, "side_bar_text"); - String identifier_uri = "http://hdl.handle.net/" - + collection.getHandle(); + String identifier_uri = handleService.getCanonicalPrefix() + + collection.getHandle(); String provenance = collectionService.getMetadata(collection, "provenance_description"); String rights = collectionService.getMetadata(collection, "copyright_text"); String rights_license = collectionService.getMetadata(collection, "license"); String title = collectionService.getMetadata(collection, "name"); - if (description != null) - { + if (description != null) { metadata.add(createDCValue("description", null, description)); } - if (description_abstract != null) - { + if (description_abstract != null) { metadata.add(createDCValue("description", "abstract", description_abstract)); } - if (description_table != null) - { + if (description_table != null) { metadata.add(createDCValue("description", "tableofcontents", description_table)); } - if (identifier_uri != null) - { + if (identifier_uri != null) { metadata.add(createDCValue("identifier", "uri", identifier_uri)); } - if (provenance != null) - { + if (provenance != null) { metadata.add(createDCValue("provenance", null, provenance)); } - if (rights != null) - { + if (rights != null) { metadata.add(createDCValue("rights", null, rights)); } - if (rights_license != null) - { + if (rights_license != null) { metadata.add(createDCValue("rights.license", null, rights_license)); } - if (title != null) - { + if (title != null) { metadata.add(createDCValue("title", null, title)); } @@ -596,14 +543,12 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin /** * Generate a list of metadata elements for the given DSpace item. * - * @param item - * The item to derive metadata from + * @param item The item to derive metadata from * @return list of metadata */ - protected List item2Metadata(Item item) - { + protected List item2Metadata(Item item) { List dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, - Item.ANY); + Item.ANY); List result = new ArrayList<>(); for (MetadataValue metadataValue : dcvs) { result.add(new MockMetadataValue(metadataValue)); @@ -622,29 +567,21 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin } // check for non-XML characters - private String checkedString(String value) - { - if (value == null) - { + private String checkedString(String value) { + if (value == null) { return null; } String reason = Verifier.checkCharacterData(value); - if (reason == null) - { + if (reason == null) { return value; - } - else - { - if (log.isDebugEnabled()) - { + } else { + if (log.isDebugEnabled()) { log.debug("Filtering out non-XML characters in string, reason=" + reason); } StringBuffer result = new StringBuffer(value.length()); - for (int i = 0; i < value.length(); ++i) - { + for (int i = 0; i < value.length(); ++i) { char c = value.charAt(i); - if (Verifier.isXMLCharacter((int)c)) - { + if (Verifier.isXMLCharacter((int) c)) { result.append(c); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/MetadataValidationException.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/MetadataValidationException.java index 23973f7779..5ba9f4555f 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/MetadataValidationException.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/MetadataValidationException.java @@ -8,7 +8,6 @@ package org.dspace.content.crosswalk; /** - * * This indicates a problem with the input metadata (for submission) or * item state (dissemination). It is invalid or incomplete, or simply * unsuitable to be crosswalked. @@ -16,25 +15,20 @@ package org.dspace.content.crosswalk; * @author Larry Stone * @version $Revision$ */ -public class MetadataValidationException extends CrosswalkException -{ - public MetadataValidationException() - { +public class MetadataValidationException extends CrosswalkException { + public MetadataValidationException() { super(); } - public MetadataValidationException(String arg0, Throwable arg1) - { + public MetadataValidationException(String arg0, Throwable arg1) { super(arg0, arg1); } - public MetadataValidationException(String arg0) - { + public MetadataValidationException(String arg0) { super(arg0); } - public MetadataValidationException(Throwable arg0) - { + public MetadataValidationException(Throwable arg0) { super(arg0); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/MockMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/MockMetadataValue.java index 5bb4bb0e49..e7e9b922be 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/MockMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/MockMetadataValue.java @@ -28,8 +28,7 @@ public class MockMetadataValue { private String authority; private int confidence; - public MockMetadataValue(MetadataValue metadataValue) - { + public MockMetadataValue(MetadataValue metadataValue) { MetadataField metadataField = metadataValue.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); schema = metadataSchema.getName(); diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/NullIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/NullIngestionCrosswalk.java index e3cd553281..f5cffdba15 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/NullIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/NullIngestionCrosswalk.java @@ -34,37 +34,36 @@ import org.jdom.output.XMLOutputter; * plugin.named.org.dspace.content.crosswalk.SubmissionCrosswalk = \ * org.dspace.content.crosswalk.NullIngestionCrosswalk = NULL, LOM * + * * @author Larry Stone * @version $Revision$ */ public class NullIngestionCrosswalk - implements IngestionCrosswalk -{ - /** log4j category */ + implements IngestionCrosswalk { + /** + * log4j category + */ private static Logger log = Logger.getLogger(NullIngestionCrosswalk.class); private static XMLOutputter outputPretty = new XMLOutputter(Format.getPrettyFormat()); @Override public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { // drop xml on the floor but mention what we're missing for debugging: - log.debug("Null crosswalk is ignoring this metadata Element: \n"+ - outputPretty.outputString(root)); + log.debug("Null crosswalk is ignoring this metadata Element: \n" + + outputPretty.outputString(root)); } @Override public void ingest(Context context, DSpaceObject dso, List ml, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { // drop xml on the floor but mention what we're missing for debugging: - log.debug("Null crosswalk is ignoring this List of metadata: \n"+ - outputPretty.outputString(ml)); + log.debug("Null crosswalk is ignoring this List of metadata: \n" + + outputPretty.outputString(ml)); } - public boolean preferList() - { + public boolean preferList() { return false; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/NullStreamIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/NullStreamIngestionCrosswalk.java index adf8ab356e..21d44646c7 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/NullStreamIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/NullStreamIngestionCrosswalk.java @@ -7,8 +7,8 @@ */ package org.dspace.content.crosswalk; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.sql.SQLException; import org.dspace.authorize.AuthorizeException; @@ -24,21 +24,18 @@ import org.dspace.core.Context; * AIP ingester, it is best to ignore the rightsMD fields since they * are already going to be ingested as member bitstreams anyway. * - * @author Larry Stone + * @author Larry Stone * @version $Revision: 1.0 $ */ public class NullStreamIngestionCrosswalk - implements StreamIngestionCrosswalk -{ + implements StreamIngestionCrosswalk { @Override public void ingest(Context context, DSpaceObject dso, InputStream in, String MIMEType) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { in.close(); } - public String getMIMEType() - { + public String getMIMEType() { return "text/plain"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/OAIDCIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/OAIDCIngestionCrosswalk.java index 124e9ce285..98b4df7d8c 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/OAIDCIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/OAIDCIngestionCrosswalk.java @@ -7,6 +7,10 @@ */ package org.dspace.content.crosswalk; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; @@ -19,10 +23,6 @@ import org.dspace.core.Context; import org.jdom.Element; import org.jdom.Namespace; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * DIM ingestion crosswalk *

    @@ -32,44 +32,45 @@ import java.util.List; * @version $Revision: 1 $ */ public class OAIDCIngestionCrosswalk - implements IngestionCrosswalk -{ + implements IngestionCrosswalk { protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - private CrosswalkMetadataValidator metadataValidator = new CrosswalkMetadataValidator(); + private CrosswalkMetadataValidator metadataValidator = new CrosswalkMetadataValidator(); - @Override - public void ingest(Context context, DSpaceObject dso, List metadata, boolean createMissingMetadataFields) throws CrosswalkException, IOException, SQLException, AuthorizeException { + @Override + public void ingest(Context context, DSpaceObject dso, List metadata, boolean createMissingMetadataFields) + throws CrosswalkException, IOException, SQLException, AuthorizeException { Element wrapper = new Element("wrap", metadata.get(0).getNamespace()); - wrapper.addContent(metadata); - - ingest(context,dso,wrapper, createMissingMetadataFields); - } + wrapper.addContent(metadata); - @Override - public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) throws CrosswalkException, IOException, SQLException, AuthorizeException { - - if (dso.getType() != Constants.ITEM) - { + ingest(context, dso, wrapper, createMissingMetadataFields); + } + + @Override + public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) + throws CrosswalkException, IOException, SQLException, AuthorizeException { + + if (dso.getType() != Constants.ITEM) { throw new CrosswalkObjectNotSupported("DIMIngestionCrosswalk can only crosswalk an Item."); } - Item item = (Item)dso; - + Item item = (Item) dso; + if (root == null) { - System.err.println("The element received by ingest was null"); - return; + System.err.println("The element received by ingest was null"); + return; } - + List metadata = root.getChildren(); for (Element element : metadata) { - // get language - prefer xml:lang, accept lang. - String lang = element.getAttributeValue("lang", Namespace.XML_NAMESPACE); - if (lang == null) { - lang = element.getAttributeValue("lang"); - } - MetadataField metadataField = metadataValidator.checkMetadata(context, MetadataSchema.DC_SCHEMA, element.getName(), null, createMissingMetadataFields); - itemService.addMetadata(context, item, metadataField, lang, element.getText()); + // get language - prefer xml:lang, accept lang. + String lang = element.getAttributeValue("lang", Namespace.XML_NAMESPACE); + if (lang == null) { + lang = element.getAttributeValue("lang"); + } + MetadataField metadataField = metadataValidator + .checkMetadata(context, MetadataSchema.DC_SCHEMA, element.getName(), null, createMissingMetadataFields); + itemService.addMetadata(context, item, metadataField, lang, element.getText()); } - - } - + + } + } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/OREDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/OREDisseminationCrosswalk.java index be68791368..aad95da99a 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/OREDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/OREDisseminationCrosswalk.java @@ -18,7 +18,12 @@ import java.util.Set; import org.apache.commons.lang.ArrayUtils; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.Constants; @@ -38,11 +43,10 @@ import org.jdom.Namespace; * @version $Revision: 1 $ */ public class OREDisseminationCrosswalk - implements DisseminationCrosswalk -{ + implements DisseminationCrosswalk { /* Schema for Atom only available in Relax NG format */ public static final String ATOM_RNG = "http://tweety.lanl.gov/public/schemas/2008-06/atom-tron.sch"; - + /* Namespaces */ public static final Namespace ATOM_NS = Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom"); @@ -55,321 +59,327 @@ public class OREDisseminationCrosswalk private static final Namespace DCTERMS_NS = Namespace.getNamespace("dcterms", "http://purl.org/dc/terms/"); private static final Namespace DS_NS = - Namespace.getNamespace("ds","http://www.dspace.org/objectModel/"); + Namespace.getNamespace("ds", "http://www.dspace.org/objectModel/"); protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - protected final ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + protected final ConfigurationService configurationService = DSpaceServicesFactory.getInstance() + .getConfigurationService(); - private static final Namespace namespaces[] = { ATOM_NS, ORE_NS, ORE_ATOM, RDF_NS, DCTERMS_NS, DS_NS }; + private static final Namespace namespaces[] = {ATOM_NS, ORE_NS, ORE_ATOM, RDF_NS, DCTERMS_NS, DS_NS}; + - @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { return (Namespace[]) ArrayUtils.clone(namespaces); } - /* There is (and currently can be) no XSD schema that validates Atom feeds, only RNG */ + /* There is (and currently can be) no XSD schema that validates Atom feeds, only RNG */ @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return ATOM_NS.getURI() + " " + ATOM_RNG; } - + /** * Disseminate an Atom-encoded ORE ReM mapped from a DSpace Item - * @param item + * + * @param item * @return * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - private Element disseminateItem(Context context, Item item) throws CrosswalkException, IOException, SQLException, AuthorizeException - { - String oaiUrl = null; + private Element disseminateItem(Context context, Item item) + throws CrosswalkException, IOException, SQLException, AuthorizeException { + String oaiUrl = null; String dsUrl = configurationService.getProperty("dspace.url"); - + String remSource = configurationService.getProperty("oai.ore.authoritative.source"); - if (remSource == null || remSource.equalsIgnoreCase("oai")) - { + if (remSource == null || remSource.equalsIgnoreCase("oai")) { oaiUrl = configurationService.getProperty("oai.url"); - } - else if (remSource.equalsIgnoreCase("xmlui") || remSource.equalsIgnoreCase("manakin")) - { + } else if (remSource.equalsIgnoreCase("xmlui") || remSource.equalsIgnoreCase("manakin")) { oaiUrl = dsUrl; } - - if (oaiUrl == null) - { - throw new CrosswalkInternalException("Base uri for the ore generator has not been set. Check the ore.authoritative.source setting."); + + if (oaiUrl == null) { + throw new CrosswalkInternalException( + "Base uri for the ore generator has not been set. Check the ore.authoritative.source setting."); } - - String uriA = oaiUrl + "/metadata/handle/" + item.getHandle() + "/ore.xml"; - - // Top level atom feed element - Element aggregation = new Element("entry",ATOM_NS); + + String uriA = oaiUrl + "/metadata/handle/" + item.getHandle() + "/ore.xml"; + + // Top level atom feed element + Element aggregation = new Element("entry", ATOM_NS); aggregation.addNamespaceDeclaration(ATOM_NS); aggregation.addNamespaceDeclaration(ORE_NS); aggregation.addNamespaceDeclaration(ORE_ATOM); aggregation.addNamespaceDeclaration(DCTERMS_NS); // Atom-entry specific info - Element atomId = new Element("id",ATOM_NS); + Element atomId = new Element("id", ATOM_NS); atomId.addContent(uriA); aggregation.addContent(atomId); - + Element aggLink; - List uris = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA,"identifier","uri",Item.ANY); + List uris = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); for (MetadataValue uri : uris) { - aggLink = new Element("link",ATOM_NS); - aggLink.setAttribute("rel", "alternate"); - aggLink.setAttribute("href", uri.getValue()); + aggLink = new Element("link", ATOM_NS); + aggLink.setAttribute("rel", "alternate"); + aggLink.setAttribute("href", uri.getValue()); aggregation.addContent(aggLink); } - + // Information about the resource map, as separate entity from the aggregation it describes - Element uriALink = new Element("link",ATOM_NS); + Element uriALink = new Element("link", ATOM_NS); uriALink.setAttribute("rel", "http://www.openarchives.org/ore/terms/describes"); uriALink.setAttribute("href", uriA); - - Element uriRLink = new Element("link",ATOM_NS); - uriRLink.setAttribute("rel","self"); + + Element uriRLink = new Element("link", ATOM_NS); + uriRLink.setAttribute("rel", "self"); uriRLink.setAttribute("href", uriA + "#atom"); - uriRLink.setAttribute("type","application/atom+xml"); - - Element remPublished = new Element("published",ATOM_NS); + uriRLink.setAttribute("type", "application/atom+xml"); + + Element remPublished = new Element("published", ATOM_NS); remPublished.addContent(Utils.formatISO8601Date(new Date())); - Element remUpdated = new Element("updated",ATOM_NS); + Element remUpdated = new Element("updated", ATOM_NS); remUpdated.addContent(Utils.formatISO8601Date(new Date())); - - Element remCreator = new Element("source",ATOM_NS); - Element remGenerator = new Element("generator",ATOM_NS); + + Element remCreator = new Element("source", ATOM_NS); + Element remGenerator = new Element("generator", ATOM_NS); remGenerator.addContent(configurationService.getProperty("dspace.name")); remGenerator.setAttribute("uri", oaiUrl); remCreator.addContent(remGenerator); - + aggregation.addContent(uriALink); aggregation.addContent(uriRLink); aggregation.addContent(remPublished); aggregation.addContent(remUpdated); aggregation.addContent(remCreator); - - // Information about the aggregation (item) itself - Element aggTitle = new Element("title",ATOM_NS); + + // Information about the aggregation (item) itself + Element aggTitle = new Element("title", ATOM_NS); List titles = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); - if (titles != null && titles.size()>0) - { + if (titles != null && titles.size() > 0) { aggTitle.addContent(titles.get(0).getValue()); - } - else - { + } else { aggTitle.addContent(""); } aggregation.addContent(aggTitle); - + Element aggAuthor; Element aggAuthorName; - List authors = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA,"contributor","author",Item.ANY); + List authors = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "contributor", "author", Item.ANY); for (MetadataValue author : authors) { - aggAuthor = new Element("author",ATOM_NS); - aggAuthorName = new Element("name",ATOM_NS); - aggAuthorName.addContent(author.getValue()); - aggAuthor.addContent(aggAuthorName); - aggregation.addContent(aggAuthor); + aggAuthor = new Element("author", ATOM_NS); + aggAuthorName = new Element("name", ATOM_NS); + aggAuthorName.addContent(author.getValue()); + aggAuthor.addContent(aggAuthorName); + aggregation.addContent(aggAuthor); } - - Element oreCategory = new Element("category",ATOM_NS); + + Element oreCategory = new Element("category", ATOM_NS); oreCategory.setAttribute("scheme", ORE_NS.getURI()); - oreCategory.setAttribute("term", ORE_NS.getURI()+"Aggregation"); - oreCategory.setAttribute("label","Aggregation"); - - Element updateCategory = new Element("category",ATOM_NS); - updateCategory.setAttribute("scheme", ORE_ATOM.getURI()+"modified"); + oreCategory.setAttribute("term", ORE_NS.getURI() + "Aggregation"); + oreCategory.setAttribute("label", "Aggregation"); + + Element updateCategory = new Element("category", ATOM_NS); + updateCategory.setAttribute("scheme", ORE_ATOM.getURI() + "modified"); updateCategory.setAttribute("term", Utils.formatISO8601Date(item.getLastModified())); - - Element dsCategory = new Element("category",ATOM_NS); + + Element dsCategory = new Element("category", ATOM_NS); dsCategory.setAttribute("scheme", DS_NS.getURI()); dsCategory.setAttribute("term", "DSpaceItem"); dsCategory.setAttribute("label", "DSpace Item"); - + aggregation.addContent(oreCategory); aggregation.addContent(updateCategory); aggregation.addContent(dsCategory); - - + + // metadata section Element arLink; - Element rdfDescription, rdfType, dcModified, dcDesc; + Element rdfDescription; + Element rdfType; + Element dcModified; + Element dcDesc; Element triples = new Element("triples", ORE_ATOM); - + // metadata about the item rdfDescription = new Element("Description", RDF_NS); rdfDescription.setAttribute("about", uriA, RDF_NS); - + rdfType = new Element("type", RDF_NS); - rdfType.setAttribute("resource", DS_NS.getURI()+"DSpaceItem", RDF_NS); + rdfType.setAttribute("resource", DS_NS.getURI() + "DSpaceItem", RDF_NS); dcModified = new Element("modified", DCTERMS_NS); dcModified.addContent(Utils.formatISO8601Date(item.getLastModified())); - + rdfDescription.addContent(rdfType); rdfDescription.addContent(dcModified); triples.addContent(rdfDescription); - + // Add a link and an oreatom metadata entry for each bitstream in the item List bundles = item.getBundles(); List bitstreams; - for (Bundle bundle : bundles) - { - // Omit the special "ORE" bitstream - if (bundle.getName().equals("ORE")) - { + for (Bundle bundle : bundles) { + // Omit the special "ORE" bitstream + if (bundle.getName().equals("ORE")) { continue; } - - bitstreams = bundle.getBitstreams(); - for (Bitstream bs : bitstreams) - { - arLink = new Element("link",ATOM_NS); - arLink.setAttribute("rel", ORE_NS.getURI()+"aggregates"); - arLink.setAttribute("href",dsUrl + "/bitstream/handle/" + item.getHandle() + "/" + encodeForURL(bs.getName()) + "?sequence=" + bs.getSequenceID()); - arLink.setAttribute("title",bs.getName()); - arLink.setAttribute("type",bs.getFormat(context).getMIMEType()); - arLink.setAttribute("length",Long.toString(bs.getSize())); - - aggregation.addContent(arLink); - - // metadata about the bitstream + + bitstreams = bundle.getBitstreams(); + for (Bitstream bs : bitstreams) { + arLink = new Element("link", ATOM_NS); + arLink.setAttribute("rel", ORE_NS.getURI() + "aggregates"); + arLink.setAttribute("href", dsUrl + "/bitstream/handle/" + item.getHandle() + "/" + encodeForURL( + bs.getName()) + "?sequence=" + bs.getSequenceID()); + arLink.setAttribute("title", bs.getName()); + arLink.setAttribute("type", bs.getFormat(context).getMIMEType()); + arLink.setAttribute("length", Long.toString(bs.getSizeBytes())); + + aggregation.addContent(arLink); + + // metadata about the bitstream rdfDescription = new Element("Description", RDF_NS); - rdfDescription.setAttribute("about", dsUrl + "/bitstream/handle/" + item.getHandle() + "/" + encodeForURL(bs.getName()) + "?sequence=" + bs.getSequenceID(), RDF_NS); - + rdfDescription.setAttribute("about", + dsUrl + "/bitstream/handle/" + item.getHandle() + "/" + encodeForURL( + bs.getName()) + "?sequence=" + bs.getSequenceID(), RDF_NS); + rdfType = new Element("type", RDF_NS); - rdfType.setAttribute("resource", DS_NS.getURI()+"DSpaceBitstream", RDF_NS); + rdfType.setAttribute("resource", DS_NS.getURI() + "DSpaceBitstream", RDF_NS); dcDesc = new Element("description", DCTERMS_NS); dcDesc.addContent(bundle.getName()); - + rdfDescription.addContent(rdfType); rdfDescription.addContent(dcDesc); triples.addContent(rdfDescription); - } + } } - + aggregation.addContent(triples); - - // Add a link to the OAI-PMH served metadata (oai_dc is always on) + + // Add a link to the OAI-PMH served metadata (oai_dc is always on) /* Element pmhMeta = new Element("entry",ATOM_NS); pUri = new Element("id",ATOM_NS); - String oaiId = new String("oai:" + ConfigurationManager.getProperty("dspace.hostname") + ":" + item.getHandle()); - pUri.addContent(oaiId + "#oai_dc"); - pmhMeta.addContent(pUri); - - Element pmhAuthor = new Element("author",ATOM_NS); - Element pmhAuthorName = new Element("name",ATOM_NS); - Element pmhAuthorUri = new Element("uri",ATOM_NS); - pmhAuthorName.addContent(ConfigurationManager.getProperty("dspace.name")); - pmhAuthorUri.addContent(oaiUrl); - pmhAuthor.addContent(pmhAuthorName); - pmhAuthor.addContent(pmhAuthorUri); - pmhMeta.addContent(pmhAuthor); - - arUri = new Element("link",ATOM_NS); - arUri.setAttribute("rel","alternate"); - arUri.setAttribute("href",oaiUrl + "/request?verb=GetRecord&identifier=" + oaiId + "&metadataprefix=oai_dc"); - pmhMeta.addContent(arUri); - - Element rdfDesc = new Element("Description",RDF_NS); - rdfDesc.setAttribute("about",oaiUrl + "/request?verb=GetRecord&identifier=" + oaiId + "&metadataprefix=oai_dc",RDF_NS); - Element dcTerms = new Element("dcterms",DCTERMS_NS); - dcTerms.setAttribute("resource","http://www.openarchives.org/OAI/2.0/oai_dc/",RDF_NS); - rdfDesc.addContent(dcTerms); - pmhMeta.addContent(rdfDesc); - - arUpdated = new Element("updated",ATOM_NS); - arUpdated.addContent(Utils.formatISO8601Date(item.getLastModified())); - pmhMeta.addContent(arUpdated); - - arTitle = new Element("title",ATOM_NS); - arTitle.addContent(""); - pmhMeta.addContent(arTitle); - - aggregation.addContent(pmhMeta);*/ - + String oaiId = new String("oai:" + ConfigurationManager.getProperty("dspace.hostname") + ":" + item.getHandle + ()); + pUri.addContent(oaiId + "#oai_dc"); + pmhMeta.addContent(pUri); + + Element pmhAuthor = new Element("author",ATOM_NS); + Element pmhAuthorName = new Element("name",ATOM_NS); + Element pmhAuthorUri = new Element("uri",ATOM_NS); + pmhAuthorName.addContent(ConfigurationManager.getProperty("dspace.name")); + pmhAuthorUri.addContent(oaiUrl); + pmhAuthor.addContent(pmhAuthorName); + pmhAuthor.addContent(pmhAuthorUri); + pmhMeta.addContent(pmhAuthor); + + arUri = new Element("link",ATOM_NS); + arUri.setAttribute("rel","alternate"); + arUri.setAttribute("href",oaiUrl + "/request?verb=GetRecord&identifier=" + oaiId + "& + metadataprefix=oai_dc"); + pmhMeta.addContent(arUri); + + Element rdfDesc = new Element("Description",RDF_NS); + rdfDesc.setAttribute("about",oaiUrl + "/request?verb=GetRecord&identifier=" + oaiId + "& + metadataprefix=oai_dc",RDF_NS); + Element dcTerms = new Element("dcterms",DCTERMS_NS); + dcTerms.setAttribute("resource","http://www.openarchives.org/OAI/2.0/oai_dc/",RDF_NS); + rdfDesc.addContent(dcTerms); + pmhMeta.addContent(rdfDesc); + + arUpdated = new Element("updated",ATOM_NS); + arUpdated.addContent(Utils.formatISO8601Date(item.getLastModified())); + pmhMeta.addContent(arUpdated); + + arTitle = new Element("title",ATOM_NS); + arTitle.addContent(""); + pmhMeta.addContent(arTitle); + + aggregation.addContent(pmhMeta);*/ + return aggregation; } - + @Override - public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException - { - switch(dso.getType()) { - case Constants.ITEM: return disseminateItem(context, (Item)dso); - case Constants.COLLECTION: break; - case Constants.COMMUNITY: break; - default: throw new CrosswalkObjectNotSupported("ORE implementation unable to disseminate unknown DSpace object."); - } - - return null; - } - + public Element disseminateElement(Context context, DSpaceObject dso) + throws CrosswalkException, IOException, SQLException, AuthorizeException { + switch (dso.getType()) { + case Constants.ITEM: + return disseminateItem(context, (Item) dso); + case Constants.COLLECTION: + break; + case Constants.COMMUNITY: + break; + default: + throw new CrosswalkObjectNotSupported( + "ORE implementation unable to disseminate unknown DSpace object."); + } + + return null; + } + /** - * Helper method to escape all chaacters that are not part of the canon set + * Helper method to escape all chaacters that are not part of the canon set + * * @param sourceString source unescaped string */ private String encodeForURL(String sourceString) { - Character lowalpha[] = {'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , - 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , - 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z'}; - Character upalpha[] = {'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , - 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , 'P' , 'Q' , 'R' , - 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z'}; - Character digit[] = {'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9'}; - Character mark[] = {'-' , '_' , '.' , '!' , '~' , '*' , '\'' , '/', '(' , ')'}; - - // reserved - //Character reserved[] = {';' , '/' , '?' , ':' , '@' , '&' , '=' , '+' , '$' , ',' ,'%', '#'}; - - Set URLcharsSet = new HashSet(); - URLcharsSet.addAll(Arrays.asList(lowalpha)); - URLcharsSet.addAll(Arrays.asList(upalpha)); - URLcharsSet.addAll(Arrays.asList(digit)); - URLcharsSet.addAll(Arrays.asList(mark)); - //URLcharsSet.addAll(Arrays.asList(reserved)); - + Character lowalpha[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; + Character upalpha[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + Character digit[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + Character mark[] = {'-', '_', '.', '!', '~', '*', '\'', '/', '(', ')'}; + + // reserved + //Character reserved[] = {';' , '/' , '?' , ':' , '@' , '&' , '=' , '+' , '$' , ',' ,'%', '#'}; + + Set URLcharsSet = new HashSet(); + URLcharsSet.addAll(Arrays.asList(lowalpha)); + URLcharsSet.addAll(Arrays.asList(upalpha)); + URLcharsSet.addAll(Arrays.asList(digit)); + URLcharsSet.addAll(Arrays.asList(mark)); + //URLcharsSet.addAll(Arrays.asList(reserved)); + StringBuilder processedString = new StringBuilder(); - for (int i=0; i disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException - { - List result = new ArrayList(1); - result.add(disseminateElement(context, dso)); - return result; - } + public List disseminateList(Context context, DSpaceObject dso) + throws CrosswalkException, IOException, SQLException, AuthorizeException { + List result = new ArrayList(1); + result.add(disseminateElement(context, dso)); + return result; + } /* Only interested in disseminating items at this time */ @Override - public boolean canDisseminate(DSpaceObject dso) - { - return (dso.getType() == Constants.ITEM || dso.getType() == Constants.COLLECTION || dso.getType() == Constants.COMMUNITY); + public boolean canDisseminate(DSpaceObject dso) { + return (dso.getType() == Constants.ITEM || dso.getType() == Constants.COLLECTION || dso + .getType() == Constants.COMMUNITY); } @Override - public boolean preferList() - { + public boolean preferList() { return false; } - + } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/OREIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/OREIngestionCrosswalk.java index 4d7310afbc..98a54ff624 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/OREIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/OREIngestionCrosswalk.java @@ -50,9 +50,10 @@ import org.jdom.xpath.XPath; * @version $Revision: 1 $ */ public class OREIngestionCrosswalk - implements IngestionCrosswalk -{ - /** log4j category */ + implements IngestionCrosswalk { + /** + * log4j category + */ private static Logger log = Logger.getLogger(OREDisseminationCrosswalk.class); /* Namespaces */ @@ -67,199 +68,193 @@ public class OREIngestionCrosswalk private static final Namespace DCTERMS_NS = Namespace.getNamespace("dcterms", "http://purl.org/dc/terms/"); private static final Namespace DS_NS = - Namespace.getNamespace("ds","http://www.dspace.org/objectModel/"); + Namespace.getNamespace("ds", "http://www.dspace.org/objectModel/"); - protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); - protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); - protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); + protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); + protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); + protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); + protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - - @Override - public void ingest(Context context, DSpaceObject dso, List metadata, boolean createMissingMetadataFields) throws CrosswalkException, IOException, SQLException, AuthorizeException { + @Override + public void ingest(Context context, DSpaceObject dso, List metadata, boolean createMissingMetadataFields) + throws CrosswalkException, IOException, SQLException, AuthorizeException { - // If this list contains only the root already, just pass it on + // If this list contains only the root already, just pass it on if (metadata.size() == 1) { - ingest(context, dso, metadata.get(0), createMissingMetadataFields); - } - // Otherwise, wrap them up - else { - Element wrapper = new Element("wrap", metadata.get(0).getNamespace()); - wrapper.addContent(metadata); + ingest(context, dso, metadata.get(0), createMissingMetadataFields); + } else { + // Otherwise, wrap them up + Element wrapper = new Element("wrap", metadata.get(0).getNamespace()); + wrapper.addContent(metadata); - ingest(context,dso,wrapper, createMissingMetadataFields); - } - } + ingest(context, dso, wrapper, createMissingMetadataFields); + } + } - - - @Override - public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) throws CrosswalkException, IOException, SQLException, AuthorizeException { - - Date timeStart = new Date(); - - if (dso.getType() != Constants.ITEM) - { + + @Override + public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) + throws CrosswalkException, IOException, SQLException, AuthorizeException { + + Date timeStart = new Date(); + + if (dso.getType() != Constants.ITEM) { throw new CrosswalkObjectNotSupported("OREIngestionCrosswalk can only crosswalk an Item."); } - Item item = (Item)dso; - + Item item = (Item) dso; + if (root == null) { - System.err.println("The element received by ingest was null"); - return; + System.err.println("The element received by ingest was null"); + return; } - + Document doc = new Document(); doc.addContent(root.detach()); - + XPath xpathLinks; List aggregatedResources; String entryId; - try { - xpathLinks = XPath.newInstance("/atom:entry/atom:link[@rel=\"" + ORE_NS.getURI()+"aggregates" + "\"]"); - xpathLinks.addNamespace(ATOM_NS); - aggregatedResources = xpathLinks.selectNodes(doc); - - xpathLinks = XPath.newInstance("/atom:entry/atom:link[@rel='alternate']/@href"); - xpathLinks.addNamespace(ATOM_NS); - entryId = ((Attribute)xpathLinks.selectSingleNode(doc)).getValue(); - } catch (JDOMException e) { - throw new CrosswalkException("JDOM exception occurred while ingesting the ORE", e); - } + try { + xpathLinks = XPath.newInstance("/atom:entry/atom:link[@rel=\"" + ORE_NS.getURI() + "aggregates" + "\"]"); + xpathLinks.addNamespace(ATOM_NS); + aggregatedResources = xpathLinks.selectNodes(doc); - // Next for each resource, create a bitstream - XPath xpathDesc; - NumberFormat nf=NumberFormat.getInstance(); - nf.setGroupingUsed(false); - nf.setMinimumIntegerDigits(4); - - for (Element resource : aggregatedResources) - { - String href = resource.getAttributeValue("href"); - log.debug("ORE processing: " + href); - - String bundleName; - Element desc = null; - try { - xpathDesc = XPath.newInstance("/atom:entry/oreatom:triples/rdf:Description[@rdf:about=\"" + this.encodeForURL(href) + "\"][1]"); - xpathDesc.addNamespace(ATOM_NS); - xpathDesc.addNamespace(ORE_ATOM); - xpathDesc.addNamespace(RDF_NS); - desc = (Element)xpathDesc.selectSingleNode(doc); - } catch (JDOMException e) { - e.printStackTrace(); - } - - if (desc != null && desc.getChild("type", RDF_NS).getAttributeValue("resource", RDF_NS).equals(DS_NS.getURI() + "DSpaceBitstream")) - { - bundleName = desc.getChildText("description", DCTERMS_NS); - log.debug("Setting bundle name to: " + bundleName); - } - else { - log.info("Could not obtain bundle name; using 'ORIGINAL'"); - bundleName = "ORIGINAL"; - } - - // Bundle names are not unique, so we just pick the first one if there's more than one. - List targetBundles = itemService.getBundles(item, bundleName); - Bundle targetBundle; - - // if null, create the new bundle and add it in - if (targetBundles.size() == 0) { - targetBundle = bundleService.create(context, item, bundleName); - itemService.addBundle(context, item, targetBundle); - } - else { - targetBundle = targetBundles.get(0); - } - - URL ARurl = null; - InputStream in = null; - if (href != null) { - try { - // Make sure the url string escapes all the oddball characters - String processedURL = encodeForURL(href); - // Generate a requeset for the aggregated resource - ARurl = new URL(processedURL); - in = ARurl.openStream(); - } - catch(FileNotFoundException fe) { - log.error("The provided URI failed to return a resource: " + href); - } - catch(ConnectException fe) { - log.error("The provided URI was invalid: " + href); - } - } - else { - throw new CrosswalkException("Entry did not contain link to resource: " + entryId); - } - - // ingest and update - if (in != null) { - Bitstream newBitstream = bitstreamService.create(context, targetBundle, in); - - String bsName = resource.getAttributeValue("title"); - newBitstream.setName(context, bsName); - - // Identify the format - String mimeString = resource.getAttributeValue("type"); - BitstreamFormat bsFormat = bitstreamFormatService.findByMIMEType(context, mimeString); - if (bsFormat == null) { - bsFormat = bitstreamFormatService.guessFormat(context, newBitstream); - } - newBitstream.setFormat(context, bsFormat); - bitstreamService.update(context, newBitstream); - - bundleService.addBitstream(context, targetBundle, newBitstream); - bundleService.update(context, targetBundle); - } - else { - throw new CrosswalkException("Could not retrieve bitstream: " + entryId); - } - + xpathLinks = XPath.newInstance("/atom:entry/atom:link[@rel='alternate']/@href"); + xpathLinks.addNamespace(ATOM_NS); + entryId = ((Attribute) xpathLinks.selectSingleNode(doc)).getValue(); + } catch (JDOMException e) { + throw new CrosswalkException("JDOM exception occurred while ingesting the ORE", e); } - log.info("OREIngest for Item "+ item.getID() + " took: " + (new Date().getTime() - timeStart.getTime()) + "ms."); - } - - - /** + + // Next for each resource, create a bitstream + XPath xpathDesc; + NumberFormat nf = NumberFormat.getInstance(); + nf.setGroupingUsed(false); + nf.setMinimumIntegerDigits(4); + + for (Element resource : aggregatedResources) { + String href = resource.getAttributeValue("href"); + log.debug("ORE processing: " + href); + + String bundleName; + Element desc = null; + try { + xpathDesc = XPath.newInstance( + "/atom:entry/oreatom:triples/rdf:Description[@rdf:about=\"" + this.encodeForURL(href) + "\"][1]"); + xpathDesc.addNamespace(ATOM_NS); + xpathDesc.addNamespace(ORE_ATOM); + xpathDesc.addNamespace(RDF_NS); + desc = (Element) xpathDesc.selectSingleNode(doc); + } catch (JDOMException e) { + e.printStackTrace(); + } + + if (desc != null && desc.getChild("type", RDF_NS).getAttributeValue("resource", RDF_NS) + .equals(DS_NS.getURI() + "DSpaceBitstream")) { + bundleName = desc.getChildText("description", DCTERMS_NS); + log.debug("Setting bundle name to: " + bundleName); + } else { + log.info("Could not obtain bundle name; using 'ORIGINAL'"); + bundleName = "ORIGINAL"; + } + + // Bundle names are not unique, so we just pick the first one if there's more than one. + List targetBundles = itemService.getBundles(item, bundleName); + Bundle targetBundle; + + // if null, create the new bundle and add it in + if (targetBundles.size() == 0) { + targetBundle = bundleService.create(context, item, bundleName); + itemService.addBundle(context, item, targetBundle); + } else { + targetBundle = targetBundles.get(0); + } + + URL ARurl = null; + InputStream in = null; + if (href != null) { + try { + // Make sure the url string escapes all the oddball characters + String processedURL = encodeForURL(href); + // Generate a requeset for the aggregated resource + ARurl = new URL(processedURL); + in = ARurl.openStream(); + } catch (FileNotFoundException fe) { + log.error("The provided URI failed to return a resource: " + href); + } catch (ConnectException fe) { + log.error("The provided URI was invalid: " + href); + } + } else { + throw new CrosswalkException("Entry did not contain link to resource: " + entryId); + } + + // ingest and update + if (in != null) { + Bitstream newBitstream = bitstreamService.create(context, targetBundle, in); + + String bsName = resource.getAttributeValue("title"); + newBitstream.setName(context, bsName); + + // Identify the format + String mimeString = resource.getAttributeValue("type"); + BitstreamFormat bsFormat = bitstreamFormatService.findByMIMEType(context, mimeString); + if (bsFormat == null) { + bsFormat = bitstreamFormatService.guessFormat(context, newBitstream); + } + newBitstream.setFormat(context, bsFormat); + bitstreamService.update(context, newBitstream); + + bundleService.addBitstream(context, targetBundle, newBitstream); + bundleService.update(context, targetBundle); + } else { + throw new CrosswalkException("Could not retrieve bitstream: " + entryId); + } + + } + log.info( + "OREIngest for Item " + item.getID() + " took: " + (new Date().getTime() - timeStart.getTime()) + "ms."); + } + + + /** * Helper method to escape all characters that are not part of the canon set + * * @param sourceString source unescaped string */ private String encodeForURL(String sourceString) { - Character lowalpha[] = {'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , - 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , - 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z'}; - Character upalpha[] = {'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , - 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , 'P' , 'Q' , 'R' , - 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z'}; - Character digit[] = {'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9'}; - Character mark[] = {'-' , '_' , '.' , '!' , '~' , '*' , '\'' , '(' , ')'}; - - // reserved - Character reserved[] = {';' , '/' , '?' , ':' , '@' , '&' , '=' , '+' , '$' , ',' ,'%', '#'}; - - Set URLcharsSet = new HashSet(); - URLcharsSet.addAll(Arrays.asList(lowalpha)); - URLcharsSet.addAll(Arrays.asList(upalpha)); - URLcharsSet.addAll(Arrays.asList(digit)); - URLcharsSet.addAll(Arrays.asList(mark)); - URLcharsSet.addAll(Arrays.asList(reserved)); - + Character lowalpha[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; + Character upalpha[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + Character digit[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + Character mark[] = {'-', '_', '.', '!', '~', '*', '\'', '(', ')'}; + + // reserved + Character reserved[] = {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '%', '#'}; + + Set URLcharsSet = new HashSet(); + URLcharsSet.addAll(Arrays.asList(lowalpha)); + URLcharsSet.addAll(Arrays.asList(upalpha)); + URLcharsSet.addAll(Arrays.asList(digit)); + URLcharsSet.addAll(Arrays.asList(mark)); + URLcharsSet.addAll(Arrays.asList(reserved)); + StringBuilder processedString = new StringBuilder(); - for (int i=0; i ml, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { // we only understand how to crosswalk PREMIS to a Bitstream. - if (dso.getType() != Constants.BITSTREAM) - { - throw new CrosswalkObjectNotSupported("Wrong target object type, PREMISCrosswalk can only crosswalk to a Bitstream."); + if (dso.getType() != Constants.BITSTREAM) { + throw new CrosswalkObjectNotSupported( + "Wrong target object type, PREMISCrosswalk can only crosswalk to a Bitstream."); } - Bitstream bitstream = (Bitstream)dso; + Bitstream bitstream = (Bitstream) dso; String MIMEType = null; String bsName = null; - for (Element me : ml) - { - if (me.getName().equals("premis")) - { + for (Element me : ml) { + if (me.getName().equals("premis")) { // if we're fed a wrapper object, recurse on its guts: ingest(context, dso, me.getChildren(), createMissingMetadataFields); - } - else if (me.getName().equals("object")) - { + } else if (me.getName().equals("object")) { // "object" section: // originalName becomes new bitstream source and (default) name Element on = me.getChild("originalName", PREMIS_NS); - if (on != null) - { + if (on != null) { bsName = on.getTextTrim(); } @@ -105,88 +103,73 @@ public class PREMISCrosswalk // check that length and message digest (checksum) match. // XXX FIXME: wait for Checksum Checker code to add better test. Element oc = me.getChild("objectCharacteristics", PREMIS_NS); - if (oc != null) - { + if (oc != null) { String ssize = oc.getChildTextTrim("size", PREMIS_NS); - if (ssize != null) - { - try - { + if (ssize != null) { + try { int size = Integer.parseInt(ssize); - if (bitstream.getSize() != size) - { + if (bitstream.getSizeBytes() != size) { throw new MetadataValidationException( - "Bitstream size (" + String.valueOf(bitstream.getSize()) + - ") does not match size in PREMIS (" + ssize + "), rejecting it."); + "Bitstream size (" + String.valueOf(bitstream.getSizeBytes()) + + ") does not match size in PREMIS (" + ssize + "), rejecting it."); } - } - catch (NumberFormatException ne) - { - throw new MetadataValidationException("Bad number value in PREMIS object/objectCharacteristics/size: "+ssize, ne); + } catch (NumberFormatException ne) { + throw new MetadataValidationException( + "Bad number value in PREMIS object/objectCharacteristics/size: " + ssize, ne); } } Element fixity = oc.getChild("fixity", PREMIS_NS); - if (fixity != null) - { + if (fixity != null) { String alg = fixity.getChildTextTrim("messageDigestAlgorithm", PREMIS_NS); String md = fixity.getChildTextTrim("messageDigest", PREMIS_NS); String b_alg = bitstream.getChecksumAlgorithm(); String b_md = bitstream.getChecksum(); - if (StringUtils.equals(alg, b_alg)) - { - if (StringUtils.equals(md, b_md)) - { + if (StringUtils.equals(alg, b_alg)) { + if (StringUtils.equals(md, b_md)) { log.debug("Bitstream checksum agrees with PREMIS: " + bitstream.getName()); + } else { + throw new MetadataValidationException( + "Bitstream " + alg + " Checksum does not match value in PREMIS (" + b_md + " != " + + md + "), for bitstream: " + bitstream + .getName()); } - else - { - throw new MetadataValidationException("Bitstream " + alg + " Checksum does not match value in PREMIS (" + b_md + " != " + md + "), for bitstream: " + bitstream.getName()); - } - } - else - { + } else { log.warn("Cannot test checksum on bitstream=" + bitstream.getName() + - ", algorithm in PREMIS is different: " + alg); + ", algorithm in PREMIS is different: " + alg); } } // Look for formatDesignation/formatName, which is // MIME Type. Match with DSpace bitstream format. Element format = oc.getChild("format", PREMIS_NS); - if (format != null) - { + if (format != null) { Element fd = format.getChild("formatDesignation", PREMIS_NS); - if (fd != null) - { + if (fd != null) { MIMEType = fd.getChildTextTrim("formatName", PREMIS_NS); } } } // Apply new bitstream name if we found it. - if (bsName != null) - { + if (bsName != null) { bitstream.setName(context, bsName); - log.debug("Changing bitstream id="+String.valueOf(bitstream.getID())+"name and source to: "+bsName); + log.debug( + "Changing bitstream id=" + String.valueOf(bitstream.getID()) + "name and source to: " + bsName); } // reconcile bitstream format; if there's a MIMEtype, // get it from that, otherwise try to divine from file extension // (guessFormat() looks at bitstream Name, which we just set) BitstreamFormat bf = (MIMEType == null) ? null : - bitstreamFormatService.findByMIMEType(context, MIMEType); - if (bf == null) - { + bitstreamFormatService.findByMIMEType(context, MIMEType); + if (bf == null) { bf = bitstreamFormatService.guessFormat(context, bitstream); } - if (bf != null) - { + if (bf != null) { bitstream.setFormat(context, bf); } - } - else - { + } else { log.debug("Skipping element: " + me.toString()); } } @@ -196,20 +179,17 @@ public class PREMISCrosswalk /*----------- Dissemination functions -------------------*/ @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { return (Namespace[]) ArrayUtils.clone(namespaces); } @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return schemaLocation; } @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { //PREMISCrosswalk can only crosswalk a Bitstream return (dso.getType() == Constants.BITSTREAM); } @@ -217,13 +197,11 @@ public class PREMISCrosswalk @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { - if (dso.getType() != Constants.BITSTREAM) - { + IOException, SQLException, AuthorizeException { + if (dso.getType() != Constants.BITSTREAM) { throw new CrosswalkObjectNotSupported("PREMISCrosswalk can only crosswalk a Bitstream."); } - Bitstream bitstream = (Bitstream)dso; + Bitstream bitstream = (Bitstream) dso; Element premis = new Element("premis", PREMIS_NS); Element object = new Element("object", PREMIS_NS); @@ -245,33 +223,27 @@ public class PREMISCrosswalk String handle = null; // get handle of parent Item of this bitstream, if there is one: List bn = bitstream.getBundles(); - if (bn.size() > 0) - { + if (bn.size() > 0) { List bi = bn.get(0).getItems(); - if (bi.size() > 0) - { + if (bi.size() > 0) { handle = bi.get(0).getHandle(); } } // get or make up name for bitstream: String bsName = bitstream.getName(); - if (bsName == null) - { + if (bsName == null) { List ext = bitstream.getFormat(context).getExtensions(); - bsName = "bitstream_"+sid+ (ext.size() > 0 ? ext.get(0) : ""); + bsName = "bitstream_" + sid + (ext.size() > 0 ? ext.get(0) : ""); } - if (handle != null && baseUrl != null) - { + if (handle != null && baseUrl != null) { oiv.setText(baseUrl - + "/bitstream/" - + URLEncoder.encode(handle, "UTF-8") - + "/" - + sid - + "/" - + URLEncoder.encode(bsName, "UTF-8")); - } - else - { + + "/bitstream/" + + URLEncoder.encode(handle, "UTF-8") + + "/" + + sid + + "/" + + URLEncoder.encode(bsName, "UTF-8")); + } else { oiv.setText(URLEncoder.encode(bsName, "UTF-8")); } @@ -289,8 +261,7 @@ public class PREMISCrosswalk // checksum if available String cks = bitstream.getChecksum(); String cka = bitstream.getChecksumAlgorithm(); - if (cks != null && cka != null) - { + if (cks != null && cka != null) { Element fixity = new Element("fixity", PREMIS_NS); Element mda = new Element("messageDigestAlgorithm", PREMIS_NS); mda.setText(cka); @@ -303,7 +274,7 @@ public class PREMISCrosswalk // size Element size = new Element("size", PREMIS_NS); - size.setText(String.valueOf(bitstream.getSize())); + size.setText(String.valueOf(bitstream.getSizeBytes())); ochar.addContent(size); // Punt and set formatName to the MIME type; the best we can @@ -321,12 +292,10 @@ public class PREMISCrosswalk // originalName <- name (or source if none) String oname = bitstream.getName(); - if (oname == null) - { + if (oname == null) { oname = bitstream.getSource(); } - if (oname != null) - { + if (oname != null) { Element on = new Element("originalName", PREMIS_NS); on.setText(oname); object.addContent(on); @@ -338,16 +307,14 @@ public class PREMISCrosswalk @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { List result = new ArrayList(1); result.add(disseminateElement(context, dso)); return result; } @Override - public boolean preferList() - { + public boolean preferList() { return false; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/ParameterizedDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/ParameterizedDisseminationCrosswalk.java index 51e4918f67..312aed3543 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/ParameterizedDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/ParameterizedDisseminationCrosswalk.java @@ -10,6 +10,7 @@ package org.dspace.content.crosswalk; import java.io.IOException; import java.sql.SQLException; import java.util.Map; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; @@ -23,28 +24,25 @@ import org.jdom.Element; * @author mhwood */ public interface ParameterizedDisseminationCrosswalk - extends DisseminationCrosswalk -{ + extends DisseminationCrosswalk { /** * Execute crosswalk, returning one XML root element as * a JDOM Element object. * This is typically the root element of a document. *

    * - * @param context - * The relevant DSpace Context. - * @param dso the DSpace Object whose metadata to export. - * @param parameters - * names and values of parameters to be passed into the transform. + * @param context The relevant DSpace Context. + * @param dso the DSpace Object whose metadata to export. + * @param parameters names and values of parameters to be passed into the transform. * @return root Element of the target metadata, never null. - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ public Element disseminateElement(Context context, DSpaceObject dso, - Map parameters) + Map parameters) throws CrosswalkException, IOException, SQLException, AuthorizeException; } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/QDCCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/QDCCrosswalk.java index ff4d026d88..a20699bf1a 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/QDCCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/QDCCrosswalk.java @@ -7,10 +7,26 @@ */ package org.dspace.content.crosswalk; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + import org.apache.commons.lang.ArrayUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; +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; @@ -22,19 +38,12 @@ import org.jdom.Element; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.StringReader; -import java.sql.SQLException; -import java.util.*; - /** * Configurable QDC Crosswalk *

    * This class supports multiple dissemination crosswalks from DSpace * internal data to the Qualified Dublin Core XML format - * (see http://dublincore.org/ + * (see http://dublincore.org/ *

    * It registers multiple Plugin names, which it reads from * the DSpace configuration as follows: @@ -84,9 +93,10 @@ import java.util.*; * @version $Revision$ */ public class QDCCrosswalk extends SelfNamedPlugin - implements DisseminationCrosswalk, IngestionCrosswalk -{ - /** log4j category */ + implements DisseminationCrosswalk, IngestionCrosswalk { + /** + * log4j category + */ private static Logger log = Logger.getLogger(QDCCrosswalk.class); // map of qdc to JDOM Element @@ -124,59 +134,48 @@ public class QDCCrosswalk extends SelfNamedPlugin * for configuration files for flavors of QDC crosswalk: */ private static String aliases[] = null; - static - { + + static { List aliasList = new ArrayList(); - Enumeration pe = (Enumeration)ConfigurationManager.propertyNames(); + Enumeration pe = (Enumeration) ConfigurationManager.propertyNames(); String propname = CONFIG_PREFIX + ".properties."; - while (pe.hasMoreElements()) - { + while (pe.hasMoreElements()) { String key = pe.nextElement(); - if (key.startsWith(propname)) - { + if (key.startsWith(propname)) { aliasList.add(key.substring(propname.length())); } } - aliases = (String[])aliasList.toArray(new String[aliasList.size()]); + aliases = (String[]) aliasList.toArray(new String[aliasList.size()]); } - public static String[] getPluginNames() - { + public static String[] getPluginNames() { return (String[]) ArrayUtils.clone(aliases); } // utility: return "fully qualified" name of XML element, for a // hashtable key to use on ingesting elements. // Format is {prefix:}name where prefix is optional. - private String makeQualifiedTagName(Element element) - { + private String makeQualifiedTagName(Element element) { String prefix = ""; Namespace ns = element.getNamespace(); - if (ns != null) - { + if (ns != null) { prefix = ns.getPrefix() + ":"; } - + String tagName; String nsQualifier = element.getAttributeValue("type", DisseminationCrosswalk.XSI_NS); - - if (nsQualifier == null || nsQualifier.length() < 1) - { + + if (nsQualifier == null || nsQualifier.length() < 1) { String qualifier = element.getAttributeValue("type"); - if (qualifier == null || qualifier.length() < 1) - { - tagName = prefix+element.getName(); - } - else - { - tagName = prefix+element.getName()+qualifier; + if (qualifier == null || qualifier.length() < 1) { + tagName = prefix + element.getName(); + } else { + tagName = prefix + element.getName() + qualifier; } + } else { + tagName = prefix + element.getName() + nsQualifier; } - else - { - tagName = prefix+element.getName()+nsQualifier; - } - + return tagName; } @@ -188,63 +187,59 @@ public class QDCCrosswalk extends SelfNamedPlugin * * The QDC crosswalk configuration properties follow the format: * - * {qdc-element} = {XML-fragment} + * {qdc-element} = {XML-fragment} * - * 1. qualified DC field name is of the form (qualifier is optional) - * {MDschema}.{element}.{qualifier} + * 1. qualified DC field name is of the form (qualifier is optional) + * {MDschema}.{element}.{qualifier} * - * e.g. dc.contributor.author - * dc.title + * e.g. dc.contributor.author + * dc.title * - * 2. XML fragment is prototype of metadata element, with empty - * placeholders for value). + * 2. XML fragment is prototype of metadata element, with empty + * placeholders for value). * * Example properties line: * - * dc.coverage.temporal = + * dc.coverage.temporal = */ private void init() - throws CrosswalkException, IOException - { - if (inited) - { + throws CrosswalkException, IOException { + if (inited) { return; } inited = true; myName = getPluginInstanceName(); - if (myName == null) - { + if (myName == null) { throw new CrosswalkInternalException("Cannot determine plugin name, " + - "You must use PluginService to instantiate QDCCrosswalk so the instance knows its name."); + "You must use PluginService to instantiate QDCCrosswalk so the " + + "instance knows its name."); } // grovel DSpace configuration for namespaces List nsList = new ArrayList(); - Enumeration pe = (Enumeration)ConfigurationManager.propertyNames(); - String propname = CONFIG_PREFIX + ".namespace."+ myName +"."; - while (pe.hasMoreElements()) - { + Enumeration pe = (Enumeration) ConfigurationManager.propertyNames(); + String propname = CONFIG_PREFIX + ".namespace." + myName + "."; + while (pe.hasMoreElements()) { String key = pe.nextElement(); - if (key.startsWith(propname)) - { + if (key.startsWith(propname)) { nsList.add(Namespace.getNamespace(key.substring(propname.length()), - ConfigurationManager.getProperty(key))); + ConfigurationManager.getProperty(key))); } } nsList.add(Namespace.XML_NAMESPACE); - namespaces = (Namespace[])nsList.toArray(new Namespace[nsList.size()]); + namespaces = (Namespace[]) nsList.toArray(new Namespace[nsList.size()]); // get XML schemaLocation fragment from config - schemaLocation = ConfigurationManager.getProperty(CONFIG_PREFIX + ".schemaLocation."+ myName); + schemaLocation = ConfigurationManager.getProperty(CONFIG_PREFIX + ".schemaLocation." + myName); // read properties - String cmPropName = CONFIG_PREFIX+".properties."+myName; + String cmPropName = CONFIG_PREFIX + ".properties." + myName; String propsFilename = ConfigurationManager.getProperty(cmPropName); - if (propsFilename == null) - { + if (propsFilename == null) { throw new CrosswalkInternalException("Configuration error: " + - "No properties file configured for QDC crosswalk named \"" + myName + "\""); + "No properties file configured for QDC crosswalk named \"" + + myName + "\""); } String parent = ConfigurationManager.getProperty("dspace.dir") + @@ -252,21 +247,15 @@ public class QDCCrosswalk extends SelfNamedPlugin File propsFile = new File(parent, propsFilename); Properties qdcProps = new Properties(); FileInputStream pfs = null; - try - { + try { pfs = new FileInputStream(propsFile); qdcProps.load(pfs); - } - finally - { - if (pfs != null) - { - try - { + } finally { + if (pfs != null) { + try { pfs.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } @@ -275,8 +264,7 @@ public class QDCCrosswalk extends SelfNamedPlugin // evaluate the XML fragment with a wrapper including namespaces. String postlog = ""; StringBuffer prologb = new StringBuffer(""); String prolog = prologb.toString(); - pe = (Enumeration)qdcProps.propertyNames(); - while (pe.hasMoreElements()) - { + pe = (Enumeration) qdcProps.propertyNames(); + while (pe.hasMoreElements()) { String qdc = pe.nextElement(); String val = qdcProps.getProperty(qdc); - try - { - Document d = builder.build(new StringReader(prolog+val+postlog)); - Element element = (Element)d.getRootElement().getContent(0); + try { + Document d = builder.build(new StringReader(prolog + val + postlog)); + Element element = (Element) d.getRootElement().getContent(0); qdc2element.put(qdc, element); element2qdc.put(makeQualifiedTagName(element), qdc); - log.debug("Building Maps: qdc=\""+qdc+"\", element=\""+element.toString()+"\""); - } - catch (org.jdom.JDOMException je) - { - throw new CrosswalkInternalException("Failed parsing XML fragment in properties file: \""+prolog+val+postlog+"\": "+je.toString(), je); + log.debug("Building Maps: qdc=\"" + qdc + "\", element=\"" + element.toString() + "\""); + } catch (org.jdom.JDOMException je) { + throw new CrosswalkInternalException( + "Failed parsing XML fragment in properties file: \"" + prolog + val + postlog + "\": " + je + .toString(), je); } } } @Override - public Namespace[] getNamespaces() - { - try - { + public Namespace[] getNamespaces() { + try { init(); - } - catch (Exception e) - { + } catch (Exception e) { + // ignore } return (Namespace[]) ArrayUtils.clone(namespaces); } @Override - public String getSchemaLocation() - { - try - { + public String getSchemaLocation() { + try { init(); - } - catch (Exception e) - { + } catch (Exception e) { + // ignore } return schemaLocation; } /** * Returns object's metadata in MODS format, as XML structure node. + * * @param context context * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { return disseminateListInternal(dso, true); } private List disseminateListInternal(DSpaceObject dso, boolean addSchema) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { - if (dso.getType() != Constants.ITEM) - { + IOException, SQLException, AuthorizeException { + if (dso.getType() != Constants.ITEM) { throw new CrosswalkObjectNotSupported("QDCCrosswalk can only crosswalk an Item."); } - Item item = (Item)dso; + Item item = (Item) dso; init(); List dc = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); List result = new ArrayList(dc.size()); - for (int i = 0; i < dc.size(); i++) - { + for (int i = 0; i < dc.size(); i++) { MetadataValue metadataValue = dc.get(i); MetadataField metadataField = metadataValue.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); // Compose qualified DC name - schema.element[.qualifier] // e.g. "dc.title", "dc.subject.lcc", "lom.Classification.Keyword" - String qdc = metadataSchema.getName()+"."+ - ((metadataField.getQualifier() == null) ? metadataField.getElement() - : (metadataField.getElement() + "." + metadataField.getQualifier())); + String qdc = metadataSchema.getName() + "." + + ((metadataField.getQualifier() == null) ? metadataField.getElement() + : (metadataField.getElement() + "." + metadataField.getQualifier())); Element elt = qdc2element.get(qdc); // only complain about missing elements in the DC schema: - if (elt == null) - { - if (metadataField.getMetadataSchema().getName().equals(MetadataSchema.DC_SCHEMA)) - { + if (elt == null) { + if (metadataField.getMetadataSchema().getName().equals(MetadataSchema.DC_SCHEMA)) { log.warn("WARNING: " + myName + ": No QDC mapping for \"" + qdc + "\""); } - } - else - { - Element qe = (Element)elt.clone(); + } else { + Element qe = (Element) elt.clone(); qe.setText(metadataValue.getValue()); - if (addSchema && schemaLocation != null) - { + if (addSchema && schemaLocation != null) { qe.setAttribute("schemaLocation", schemaLocation, XSI_NS); } - if (metadataValue.getLanguage() != null) - { + if (metadataValue.getLanguage() != null) { qe.setAttribute("lang", metadataValue.getLanguage(), Namespace.XML_NAMESPACE); } result.add(qe); @@ -403,12 +374,10 @@ public class QDCCrosswalk extends SelfNamedPlugin @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { init(); Element root = new Element("qualifieddc", DCTERMS_NS); - if (schemaLocation != null) - { + if (schemaLocation != null) { root.setAttribute("schemaLocation", schemaLocation, XSI_NS); } root.addContent(disseminateListInternal(dso, false)); @@ -416,23 +385,20 @@ public class QDCCrosswalk extends SelfNamedPlugin } @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { return true; } @Override public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { init(); // NOTE: don't bother comparing namespace on root element // because DCMI doesn't specify one, and every app uses its // own.. just give up in the face of this madness and accept // anything with the right name. - if (!(root.getName().equals("qualifieddc"))) - { + if (!(root.getName().equals("qualifieddc"))) { throw new MetadataValidationException("Wrong root element for Qualified DC: " + root.toString()); } ingest(context, dso, root.getChildren(), createMissingMetadataFields); @@ -440,60 +406,54 @@ public class QDCCrosswalk extends SelfNamedPlugin @Override public void ingest(Context context, DSpaceObject dso, List ml, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { init(); // for now, forget about any targets but item. - if (dso.getType() != Constants.ITEM) - { - throw new CrosswalkInternalException("Wrong target object type, QDCCrosswalk can only crosswalk to an Item."); + if (dso.getType() != Constants.ITEM) { + throw new CrosswalkInternalException( + "Wrong target object type, QDCCrosswalk can only crosswalk to an Item."); } - Item item = (Item)dso; + Item item = (Item) dso; - for (Element me : ml) - { + for (Element me : ml) { String key = makeQualifiedTagName(me); // if the root element gets passed here, recurse: - if ("qualifieddc".equals(me.getName())) - { + if ("qualifieddc".equals(me.getName())) { ingest(context, dso, me.getChildren(), createMissingMetadataFields); - } - - else if (element2qdc.containsKey(key)) - { + } else if (element2qdc.containsKey(key)) { String qdc[] = (element2qdc.get(key)).split("\\."); MetadataField metadataField; if (qdc.length == 3) { - metadataField = metadataValidator.checkMetadata(context, qdc[0], qdc[1], qdc[2], createMissingMetadataFields); + metadataField = metadataValidator + .checkMetadata(context, qdc[0], qdc[1], qdc[2], createMissingMetadataFields); } else if (qdc.length == 2) { - metadataField = metadataValidator.checkMetadata(context, qdc[0], qdc[1], null, createMissingMetadataFields); + metadataField = metadataValidator + .checkMetadata(context, qdc[0], qdc[1], null, createMissingMetadataFields); } else { - throw new CrosswalkInternalException("Unrecognized format in QDC element identifier for key=\"" + key + "\", qdc=\"" + element2qdc.get(key) + "\""); + throw new CrosswalkInternalException( + "Unrecognized format in QDC element identifier for key=\"" + key + "\", qdc=\"" + element2qdc + .get(key) + "\""); } // get language - prefer xml:lang, accept lang. String lang = me.getAttributeValue("lang", Namespace.XML_NAMESPACE); - if (lang == null) - { + if (lang == null) { lang = me.getAttributeValue("lang"); } itemService.addMetadata(context, item, metadataField, lang, me.getText()); - } - else - { + } else { log.warn("WARNING: " + myName + ": No mapping for Element=\"" + key + "\" to qdc."); } } } @Override - public boolean preferList() - { + public boolean preferList() { return true; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/RoleCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/RoleCrosswalk.java index ad56dd1d45..072939060a 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/RoleCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/RoleCrosswalk.java @@ -45,7 +45,7 @@ import org.jdom.output.XMLOutputter; *

    * This is just wrappers; the real work is done in RoleDisseminator and * RoleIngester. - * + * * @author mwood * @author Tim Donohue * @see org.dspace.content.packager.RoleDisseminator @@ -55,9 +55,8 @@ import org.jdom.output.XMLOutputter; * @see DisseminationCrosswalk */ public class RoleCrosswalk - extends AbstractPackagerWrappingCrosswalk - implements IngestionCrosswalk, DisseminationCrosswalk -{ + extends AbstractPackagerWrappingCrosswalk + implements IngestionCrosswalk, DisseminationCrosswalk { // Plugin Name of DSPACE-ROLES packager to use for ingest/dissemination // (Whatever plugin is defined with this name in 'dspace.cfg' will be used by this Crosswalk) private static final String ROLE_PACKAGER_PLUGIN = "DSPACE-ROLES"; @@ -71,8 +70,7 @@ public class RoleCrosswalk * @return array of namespaces, which may be empty. */ @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { Namespace result[] = new Namespace[1]; result[0] = RoleDisseminator.DSROLES_NS; return result; @@ -83,33 +81,32 @@ public class RoleCrosswalk * Get the XML Schema location(s) of the target metadata format. * Returns the string value of the xsi:schemaLocation * attribute that should be applied to the generated XML. - *

    + *

    * It may return the empty string if no schema is known, but crosswalk * authors are strongly encouraged to implement this call so their output * XML can be validated correctly. + * * @return SchemaLocation string, including URI namespace, followed by - * whitespace and URI of XML schema document, or empty string if unknown. + * whitespace and URI of XML schema document, or empty string if unknown. */ @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return ""; } /** * Predicate: Can this disseminator crosswalk the given object. * - * @param dso dspace object, e.g. an Item. + * @param dso dspace object, e.g. an Item. * @return true when disseminator is capable of producing metadata. */ @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { //We can only disseminate SITE, COMMUNITY or COLLECTION objects, //as Groups are only associated with those objects. return (dso.getType() == Constants.SITE || - dso.getType() == Constants.COMMUNITY || - dso.getType() == Constants.COLLECTION); + dso.getType() == Constants.COMMUNITY || + dso.getType() == Constants.COLLECTION); } /** @@ -119,8 +116,7 @@ public class RoleCrosswalk * @return true when disseminator prefers you call disseminateList(). */ @Override - public boolean preferList() - { + public boolean preferList() { //We prefer disseminators call 'disseminateElement()' instead of 'disseminateList()' return false; } @@ -136,20 +132,19 @@ public class RoleCrosswalk * empty list is returned, but never null. * * @param context context - * @param dso the DSpace Object whose metadata to export. + * @param dso the DSpace Object whose metadata to export. * @return results of crosswalk as list of XML elements. - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, - AuthorizeException - { + AuthorizeException { Element dim = disseminateElement(context, dso); return dim.getChildren(); } @@ -161,43 +156,40 @@ public class RoleCrosswalk *

    * * @param context context - * @param dso the DSpace Object whose metadata to export. + * @param dso the DSpace Object whose metadata to export. * @return root Element of the target metadata, never null - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, IOException, SQLException, - AuthorizeException - { - try - { + AuthorizeException { + try { PackageDisseminator dip = (PackageDisseminator) - CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(PackageDisseminator.class, ROLE_PACKAGER_PLUGIN); - if (dip == null) - { - throw new CrosswalkInternalException("Cannot find a PackageDisseminator plugin named " + ROLE_PACKAGER_PLUGIN); + CoreServiceFactory.getInstance().getPluginService() + .getNamedPlugin(PackageDisseminator.class, ROLE_PACKAGER_PLUGIN); + if (dip == null) { + throw new CrosswalkInternalException( + "Cannot find a PackageDisseminator plugin named " + ROLE_PACKAGER_PLUGIN); } // Create a temporary file to disseminate into String tempDirectory = (ConfigurationManager.getProperty("upload.temp.dir") != null) - ? ConfigurationManager.getProperty("upload.temp.dir") : System.getProperty("java.io.tmpdir"); - File tempFile = File.createTempFile("RoleCrosswalkDisseminate" + dso.hashCode(), null, new File(tempDirectory)); + ? ConfigurationManager.getProperty("upload.temp.dir") : System.getProperty("java.io.tmpdir"); + File tempFile = File + .createTempFile("RoleCrosswalkDisseminate" + dso.hashCode(), null, new File(tempDirectory)); tempFile.deleteOnExit(); // Initialize our packaging parameters PackageParameters pparams; - if(this.getPackagingParameters()!=null) - { + if (this.getPackagingParameters() != null) { pparams = this.getPackagingParameters(); - } - else - { + } else { pparams = new PackageParameters(); } @@ -206,34 +198,27 @@ public class RoleCrosswalk // if we ended up with a Zero-length output file, // this means dissemination was successful but had no results - if(tempFile.exists() && tempFile.length()==0) - { + if (tempFile.exists() && tempFile.length() == 0) { return null; } - - try - { + + try { //Try to parse our XML results (which were disseminated by the Packager) SAXBuilder builder = new SAXBuilder(); Document xmlDocument = builder.build(tempFile); //If XML parsed successfully, return root element of doc - if(xmlDocument!=null && xmlDocument.hasRootElement()) - { + if (xmlDocument != null && xmlDocument.hasRootElement()) { return xmlDocument.getRootElement(); - } - else - { + } else { return null; } + } catch (JDOMException je) { + throw new MetadataValidationException( + "Error parsing Roles XML (see wrapped error message for more details) ", je); } - catch (JDOMException je) - { - throw new MetadataValidationException("Error parsing Roles XML (see wrapped error message for more details) ",je); - } - } - catch (PackageException pe) - { - throw new CrosswalkInternalException("Failed to export Roles via packager (see wrapped error message for more details) ",pe); + } catch (PackageException pe) { + throw new CrosswalkInternalException( + "Failed to export Roles via packager (see wrapped error message for more details) ", pe); } } @@ -243,21 +228,19 @@ public class RoleCrosswalk /** * Ingest a List of XML elements * - * @param context context - * @param dso DSpaceObject - * @param metadata list of metadata + * @param context context + * @param dso DSpaceObject + * @param metadata list of metadata * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, List metadata, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { - if(!metadata.isEmpty()) - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { + if (!metadata.isEmpty()) { ingest(context, dso, ((Element) metadata.get(0)).getParentElement(), createMissingMetadataFields); } } @@ -268,79 +251,66 @@ public class RoleCrosswalk *

    * This essentially just wraps a call to the configured Role PackageIngester. * - * @param context context - * @param dso DSpaceObject - * @param root root element + * @param context context + * @param dso DSpaceObject + * @param root root element * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { if (dso.getType() != Constants.SITE && dso.getType() != Constants.COMMUNITY && - dso.getType() != Constants.COLLECTION) - { + dso.getType() != Constants.COLLECTION) { throw new CrosswalkObjectNotSupported("Role crosswalk only valid for Site, Community or Collection"); } //locate our "DSPACE-ROLES" PackageIngester plugin PackageIngester sip = (PackageIngester) - CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(PackageIngester.class, ROLE_PACKAGER_PLUGIN); - if (sip == null) - { + CoreServiceFactory.getInstance().getPluginService() + .getNamedPlugin(PackageIngester.class, ROLE_PACKAGER_PLUGIN); + if (sip == null) { throw new CrosswalkInternalException("Cannot find a PackageIngester plugin named " + ROLE_PACKAGER_PLUGIN); } // Initialize our packaging parameters PackageParameters pparams; - if(this.getPackagingParameters()!=null) - { + if (this.getPackagingParameters() != null) { pparams = this.getPackagingParameters(); - } - else - { + } else { pparams = new PackageParameters(); } - + // Initialize our license info String license = null; - if(this.getIngestionLicense()!=null) - { + if (this.getIngestionLicense() != null) { license = this.getIngestionLicense(); } - + // Create a temporary file to ingest from String tempDirectory = (ConfigurationManager.getProperty("upload.temp.dir") != null) - ? ConfigurationManager.getProperty("upload.temp.dir") : System.getProperty("java.io.tmpdir"); + ? ConfigurationManager.getProperty("upload.temp.dir") : System.getProperty("java.io.tmpdir"); File tempFile = File.createTempFile("RoleCrosswalkIngest" + dso.hashCode(), null, new File(tempDirectory)); tempFile.deleteOnExit(); FileOutputStream fileOutStream = null; - try - { + try { fileOutStream = new FileOutputStream(tempFile); XMLOutputter writer = new XMLOutputter(); writer.output(root, fileOutStream); - } - finally - { - if (fileOutStream != null) - { + } finally { + if (fileOutStream != null) { fileOutStream.close(); } } //Actually call the ingester - try - { + try { sip.ingest(context, dso, tempFile, pparams, license); - } - catch (PackageException | WorkflowException e) - { + } catch (PackageException | WorkflowException e) { throw new CrosswalkInternalException(e); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/SimpleDCDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/SimpleDCDisseminationCrosswalk.java index 78ad431049..789fa9d6fb 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/SimpleDCDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/SimpleDCDisseminationCrosswalk.java @@ -14,7 +14,11 @@ import java.util.List; import org.apache.commons.lang.ArrayUtils; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; +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.Constants; @@ -33,8 +37,7 @@ import org.jdom.Namespace; * @version $Revision$ */ public class SimpleDCDisseminationCrosswalk extends SelfNamedPlugin - implements DisseminationCrosswalk -{ + implements DisseminationCrosswalk { // namespaces of interest. // XXX FIXME: may also want http://www.openarchives.org/OAI/2.0/oai_dc/ for OAI @@ -44,29 +47,27 @@ public class SimpleDCDisseminationCrosswalk extends SelfNamedPlugin // simple DC schema for OAI private static final String DC_XSD = - "http://dublincore.org/schemas/xmls/simpledc20021212.xsd"; - //"http://www.openarchives.org/OAI/2.0/oai_dc.xsd"; + "http://dublincore.org/schemas/xmls/simpledc20021212.xsd"; + //"http://www.openarchives.org/OAI/2.0/oai_dc.xsd"; private static final String schemaLocation = - DC_NS.getURI()+" "+DC_XSD; + DC_NS.getURI() + " " + DC_XSD; private static final Namespace namespaces[] = - { DC_NS, XSI_NS }; + {DC_NS, XSI_NS}; - private static final String aliases[] = { "SimpleDC", "DC" }; + private static final String aliases[] = {"SimpleDC", "DC"}; protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - - public static String[] getPluginNames() - { + + public static String[] getPluginNames() { return (String[]) ArrayUtils.clone(aliases); } @Override public Element disseminateElement(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { Element root = new Element("simpledc", DC_NS); root.setAttribute("schemaLocation", schemaLocation, XSI_NS); root.addContent(disseminateListInternal(dso, false)); @@ -77,31 +78,30 @@ public class SimpleDCDisseminationCrosswalk extends SelfNamedPlugin * Returns object's metadata as XML elements. * Simple-minded copying of elements: convert contributor.author to * "creator" but otherwise just grab element name without qualifier. + * * @param context context * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { return disseminateListInternal(dso, true); } public List disseminateListInternal(DSpaceObject dso, boolean addSchema) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { - if (dso.getType() != Constants.ITEM) - { + IOException, SQLException, AuthorizeException { + if (dso.getType() != Constants.ITEM) { throw new CrosswalkObjectNotSupported("SimpleDCDisseminationCrosswalk can only crosswalk an Item."); } - Item item = (Item)dso; - List allDC = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, Item.ANY, Item.ANY, Item.ANY); + Item item = (Item) dso; + List allDC = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, Item.ANY, Item.ANY, Item.ANY); List dcl = new ArrayList(allDC.size()); @@ -109,13 +109,13 @@ public class SimpleDCDisseminationCrosswalk extends SelfNamedPlugin // Do not include description.provenance MetadataField metadataField = metadataValue.getMetadataField(); if (!(metadataField.getElement().equals("description") && - (metadataField.getQualifier() != null && metadataField.getQualifier().equals("provenance")))) { + (metadataField.getQualifier() != null && metadataField.getQualifier().equals("provenance")))) { String element; // contributor.author exposed as 'creator' if (metadataField.getElement().equals("contributor") - && (metadataField.getQualifier() != null) - && metadataField.getQualifier().equals("author")) { + && (metadataField.getQualifier() != null) + && metadataField.getQualifier().equals("author")) { element = "creator"; } else { element = metadataField.getElement(); @@ -132,26 +132,22 @@ public class SimpleDCDisseminationCrosswalk extends SelfNamedPlugin } @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { return (Namespace[]) ArrayUtils.clone(namespaces); } @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return schemaLocation; } @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { return dso.getType() == Constants.ITEM; } @Override - public boolean preferList() - { + public boolean preferList() { return true; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/StreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/StreamDisseminationCrosswalk.java index c4582b0302..878e6349f9 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/StreamDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/StreamDisseminationCrosswalk.java @@ -27,16 +27,15 @@ import org.dspace.core.Context; * are equipped to call these crosswalks as well as the XML-based ones, * just refer to the desired crosswalk by its plugin name. * - * @author Larry Stone + * @author Larry Stone * @version $Revision$ */ -public interface StreamDisseminationCrosswalk -{ +public interface StreamDisseminationCrosswalk { /** * Predicate: Can this disseminator crosswalk the given object. * * @param context context - * @param dso dspace object, e.g. an Item. + * @param dso dspace object, e.g. an Item. * @return true when disseminator is capable of producing metadata. */ public boolean canDisseminate(Context context, DSpaceObject dso); @@ -45,14 +44,14 @@ public interface StreamDisseminationCrosswalk * Execute crosswalk on the given object, sending output to the stream. * * @param context the DSpace context - * @param dso the DSpace Object whose metadata to export. - * @param out output stream to write to - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @param dso the DSpace Object whose metadata to export. + * @param out output stream to write to + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ public void disseminate(Context context, DSpaceObject dso, OutputStream out) throws CrosswalkException, IOException, SQLException, AuthorizeException; diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/StreamIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/StreamIngestionCrosswalk.java index 1e6cc0e6b1..442c52cfe9 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/StreamIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/StreamIngestionCrosswalk.java @@ -27,24 +27,23 @@ import org.dspace.core.Context; * are equipped to call these crosswalks as well as the XML-based ones, * just refer to the desired crosswalk by its plugin name. * - * @author Larry Stone + * @author Larry Stone * @version $Revision$ */ -public interface StreamIngestionCrosswalk -{ +public interface StreamIngestionCrosswalk { /** * Execute crosswalk on the given object, taking input from the stream. * - * @param context the DSpace context - * @param dso the DSpace Object whose metadata is being ingested. - * @param in input stream containing the metadata. + * @param context the DSpace context + * @param dso the DSpace Object whose metadata is being ingested. + * @param in input stream containing the metadata. * @param MIMEType MIME type of the ??? - * - * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. - * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. - * @throws IOException I/O failure in services this calls - * @throws SQLException Database failure in services this calls - * @throws AuthorizeException current user not authorized for this operation. + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace + * object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. */ public void ingest(Context context, DSpaceObject dso, InputStream in, String MIMEType) throws CrosswalkException, IOException, SQLException, AuthorizeException; diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/XHTMLHeadDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/XHTMLHeadDisseminationCrosswalk.java index 80f8e651e3..c16a78f376 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/XHTMLHeadDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/XHTMLHeadDisseminationCrosswalk.java @@ -7,9 +7,25 @@ */ package org.dspace.content.crosswalk; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; +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; @@ -20,12 +36,6 @@ import org.jdom.Element; import org.jdom.Namespace; import org.jdom.Verifier; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; - /** * Crosswalk for creating appropriate <meta> elements to appear in the * item display page for a particular item, for improving automated processing @@ -47,24 +57,27 @@ import java.util.*; * TODO: This may usefully be extended later to work with communities and * collections. * - * @version $Revision$ * @author Robert Tansley + * @version $Revision$ */ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements - DisseminationCrosswalk -{ - /** log4j logger */ + DisseminationCrosswalk { + /** + * log4j logger + */ private static Logger log = Logger - .getLogger(XHTMLHeadDisseminationCrosswalk.class); + .getLogger(XHTMLHeadDisseminationCrosswalk.class); - /** Location of config file */ + /** + * Location of config file + */ private final String config = ConfigurationManager - .getProperty("dspace.dir") - + File.separator - + "config" - + File.separator - + "crosswalks" - + File.separator + "xhtml-head-item.properties"; + .getProperty("dspace.dir") + + File.separator + + "config" + + File.separator + + "crosswalks" + + File.separator + "xhtml-head-item.properties"; private static final String XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); @@ -75,14 +88,17 @@ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements */ private Map names; - /** Maps DSpace metadata field to scheme for that field, if any */ + /** + * Maps DSpace metadata field to scheme for that field, if any + */ private Map schemes; - /** Schemas to add -- maps schema.NAME to schema URL */ + /** + * Schemas to add -- maps schema.NAME to schema URL + */ private Map schemaURLs; - public XHTMLHeadDisseminationCrosswalk() throws IOException - { + public XHTMLHeadDisseminationCrosswalk() throws IOException { names = new HashMap(); schemes = new HashMap(); schemaURLs = new HashMap(); @@ -90,47 +106,34 @@ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements // Read in configuration Properties crosswalkProps = new Properties(); FileInputStream fis = new FileInputStream(config); - try - { + try { crosswalkProps.load(fis); - } - finally - { - if (fis != null) - { - try - { + } finally { + if (fis != null) { + try { fis.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } Enumeration e = crosswalkProps.keys(); - while (e.hasMoreElements()) - { + while (e.hasMoreElements()) { String prop = (String) e.nextElement(); - if (prop.startsWith("schema.")) - { + if (prop.startsWith("schema.")) { schemaURLs.put(prop, crosswalkProps.getProperty(prop)); - } - else - { + } else { String[] s = ((String) crosswalkProps.get(prop)).split(","); - if (s.length == 2) - { + if (s.length == 2) { schemes.put(prop, s[1]); } - if (s.length == 1 || s.length == 2) - { + if (s.length == 1 || s.length == 2) { names.put(prop, s[0]); - } else - { + } else { log.warn("Malformed parameter " + prop + " in " + config); } } @@ -138,25 +141,24 @@ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements } @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { return (dso.getType() == Constants.ITEM); } /** * This generates a <head> element around the metadata; in general * this will probably not be used + * * @param context context * @throws CrosswalkException crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public Element disseminateElement(Context context, DSpaceObject dso) - throws CrosswalkException, IOException, SQLException, - AuthorizeException - { + throws CrosswalkException, IOException, SQLException, + AuthorizeException { Element head = new Element("head", XHTML_NAMESPACE); head.addContent(disseminateList(context, dso)); @@ -166,24 +168,23 @@ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements /** * Return <meta> elements that can be put in the <head> element * of an XHTML document. + * * @param context context * @throws CrosswalkException crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { - if (dso.getType() != Constants.ITEM) - { + IOException, SQLException, AuthorizeException { + if (dso.getType() != Constants.ITEM) { String h = dso.getHandle(); throw new CrosswalkObjectNotSupported( - "Can only support items; object passed in with DB ID " - + dso.getID() + ", type " - + Constants.typeText[dso.getType()] + ", handle " - + (h == null ? "null" : h)); + "Can only support items; object passed in with DB ID " + + dso.getID() + ", type " + + Constants.typeText[dso.getType()] + ", handle " + + (h == null ? "null" : h)); } Item item = (Item) dso; @@ -193,8 +194,7 @@ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements // Add in schema URLs e.g. Iterator schemaIterator = schemaURLs.keySet().iterator(); - while (schemaIterator.hasNext()) - { + while (schemaIterator.hasNext()) { String s = schemaIterator.next(); Element e = new Element("link", XHTML_NAMESPACE); e.setAttribute("rel", s); @@ -203,8 +203,7 @@ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements metas.add(e); } - for (int i = 0; i < values.size(); i++) - { + for (int i = 0; i < values.size(); i++) { MetadataValue v = values.get(i); MetadataField metadataField = v.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); @@ -212,71 +211,58 @@ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements // Work out the key for the Maps that will tell us which metadata // name + scheme to use String key = metadataSchema.getName() + "." + metadataField.getElement() - + (metadataField.getQualifier() != null ? "." + metadataField.getQualifier() : ""); + + (metadataField.getQualifier() != null ? "." + metadataField.getQualifier() : ""); String originalKey = key; // For later error msg // Find appropriate metadata field name to put in element String name = names.get(key); // If we don't have a field, try removing qualifier - if (name == null && metadataField.getQualifier() != null) - { + if (name == null && metadataField.getQualifier() != null) { key = metadataSchema.getName() + "." + metadataField.getElement(); name = names.get(key); } - - // Do not include description.provenance - boolean provenance = "description".equals(metadataField.getElement()) && "provenance".equals(metadataField.getQualifier()); - if (name == null) - { + // Do not include description.provenance + boolean provenance = "description".equals(metadataField.getElement()) && "provenance" + .equals(metadataField.getQualifier()); + + if (name == null) { // Most of the time, in this crosswalk, an unrecognised // element is OK, so just report at DEBUG level - if (log.isDebugEnabled()) - { - log.debug("No field for item " - + (handle == null ? String.valueOf(dso.getID()) - : handle) + " field " + originalKey); - } - } - else if (!provenance) - { + if (log.isDebugEnabled()) { + log.debug("No field for item " + + (handle == null ? String.valueOf(dso.getID()) + : handle) + " field " + originalKey); + } + } else if (!provenance) { Element e = new Element("meta", XHTML_NAMESPACE); e.setAttribute("name", name); - if (v.getValue() == null) - { + if (v.getValue() == null) { e.setAttribute("content", ""); - } - else - { + } else { // Check that we can output the content String reason = Verifier.checkCharacterData(v.getValue()); - if (reason == null) - { + if (reason == null) { // TODO: Check valid encoding? We assume UTF-8 // TODO: Check escaping "<>& e.setAttribute("content", v.getValue()); - } - else - { + } else { // Warn that we found invalid characters log.warn("Invalid attribute characters in Metadata: " + reason); // Strip any characters that we can, and if the result is valid, output it String simpleText = v.getValue().replaceAll("\\p{Cntrl}", ""); - if (Verifier.checkCharacterData(simpleText) == null) - { + if (Verifier.checkCharacterData(simpleText) == null) { e.setAttribute("content", simpleText); } } } - if (v.getLanguage() != null && !v.getLanguage().equals("")) - { + if (v.getLanguage() != null && !v.getLanguage().equals("")) { e.setAttribute("lang", v.getLanguage(), Namespace.XML_NAMESPACE); } String schemeAttr = schemes.get(key); - if (schemeAttr != null) - { + if (schemeAttr != null) { e.setAttribute("scheme", schemeAttr); } metas.add(e); @@ -287,26 +273,22 @@ public class XHTMLHeadDisseminationCrosswalk extends SelfNamedPlugin implements } @Override - public Namespace[] getNamespaces() - { + public Namespace[] getNamespaces() { return new Namespace[] {Namespace.getNamespace(XHTML_NAMESPACE)}; } @Override - public String getSchemaLocation() - { + public String getSchemaLocation() { return ""; } @Override - public boolean preferList() - { + public boolean preferList() { return true; } // Plugin Methods - public static String[] getPluginNames() - { + public static String[] getPluginNames() { return new String[] {"XHTML_HEAD_ITEM"}; } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTCrosswalk.java index a3f5fee0ad..8f0f342b2e 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTCrosswalk.java @@ -56,7 +56,7 @@ import org.slf4j.LoggerFactory; * A dissemination crosswalk is described by a * configuration key like *

      crosswalk.dissemination.PluginName.stylesheet = path
    - The alias names the Plugin name, + * The alias names the Plugin name, * and the path value is the pathname (relative to dspace.dir/config) * of the crosswalk stylesheet, e.g. "mycrosswalk.xslt" *

    @@ -73,7 +73,8 @@ import org.slf4j.LoggerFactory; *

    * You must use the PluginService to instantiate an * XSLT crosswalk plugin, e.g. - *

     IngestionCrosswalk xwalk = CoreServiceFactory.getInstance().getPluginService().getPlugin(IngestionCrosswalk.class, "LOM");
    + *
     IngestionCrosswalk xwalk = CoreServiceFactory.getInstance().getPluginService().getPlugin(IngestionCrosswalk
    + * .class, "LOM");
    *

    * Since there is significant overhead in reading the properties file to * configure the crosswalk, and a crosswalk instance may be used any number @@ -84,9 +85,10 @@ import org.slf4j.LoggerFactory; * @author Larry Stone * @version $Revision$ */ -public abstract class XSLTCrosswalk extends SelfNamedPlugin -{ - /** log4j category */ +public abstract class XSLTCrosswalk extends SelfNamedPlugin { + /** + * log4j category + */ private static final Logger LOG = LoggerFactory.getLogger(XSLTCrosswalk.class); /** @@ -95,7 +97,9 @@ public abstract class XSLTCrosswalk extends SelfNamedPlugin public static final Namespace DIM_NS = Namespace.getNamespace("dim", "http://www.dspace.org/xmlns/dspace/dim"); - /** Prefix for all lines in the config file for XSLT plugins. */ + /** + * Prefix for all lines in the config file for XSLT plugins. + */ protected static final String CONFIG_PREFIX = "crosswalk."; private static final String CONFIG_STYLESHEET = ".stylesheet"; @@ -104,35 +108,33 @@ public abstract class XSLTCrosswalk extends SelfNamedPlugin * Derive list of plugin name from DSpace configuration entries * for crosswalks. * - * @param direction - * "dissemination" or "submission", so it looks for keys like - * crosswalk.submission.{NAME}.stylesheet + * @param direction "dissemination" or "submission", so it looks for keys like + * crosswalk.submission.{NAME}.stylesheet * @return names to be given to the plugins of that direction. */ - protected static String[] makeAliases(String direction) - { - String prefix = CONFIG_PREFIX+direction+"."; + protected static String[] makeAliases(String direction) { + String prefix = CONFIG_PREFIX + direction + "."; String suffix = CONFIG_STYLESHEET; List aliasList = new ArrayList<>(); - Enumeration pe = (Enumeration)ConfigurationManager.propertyNames(); + Enumeration pe = (Enumeration) ConfigurationManager.propertyNames(); LOG.debug("XSLTCrosswalk: Looking for config prefix = {}", prefix); - while (pe.hasMoreElements()) - { + while (pe.hasMoreElements()) { String key = pe.nextElement(); - if (key.startsWith(prefix) && key.endsWith(suffix)) - { + if (key.startsWith(prefix) && key.endsWith(suffix)) { LOG.debug("Getting XSLT plugin name from config line: {}", key); - aliasList.add(key.substring(prefix.length(), key.length()-suffix.length())); + aliasList.add(key.substring(prefix.length(), key.length() - suffix.length())); } } return aliasList.toArray(new String[aliasList.size()]); } - /** We need to force this, because some dependency elsewhere interferes. */ + /** + * We need to force this, because some dependency elsewhere interferes. + */ private static final String TRANSFORMER_FACTORY_CLASS - = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"; + = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"; private Transformer transformer = null; private File transformFile = null; @@ -140,30 +142,25 @@ public abstract class XSLTCrosswalk extends SelfNamedPlugin /** * Initialize the Transformation stylesheet from configured stylesheet file. + * * @param direction the direction of xwalk, either "submission" or - * "dissemination" + * "dissemination" * @return transformer or null if there was error initializing. */ - protected Transformer getTransformer(String direction) - { - if (transformFile == null) - { + protected Transformer getTransformer(String direction) { + if (transformFile == null) { String myAlias = getPluginInstanceName(); - if (myAlias == null) - { + if (myAlias == null) { LOG.error("Must use PluginService to instantiate XSLTCrosswalk so the class knows its name."); return null; } - String cmPropName = CONFIG_PREFIX+direction+"."+myAlias+CONFIG_STYLESHEET; + String cmPropName = CONFIG_PREFIX + direction + "." + myAlias + CONFIG_STYLESHEET; String fname = ConfigurationManager.getProperty(cmPropName); - if (fname == null) - { - LOG.error("Missing configuration filename for XSLT-based crosswalk: no "+ - "value for property = {}", cmPropName); + if (fname == null) { + LOG.error("Missing configuration filename for XSLT-based crosswalk: no " + + "value for property = {}", cmPropName); return null; - } - else - { + } else { String parent = ConfigurationManager.getProperty("dspace.dir") + File.separator + "config" + File.separator; transformFile = new File(parent, fname); @@ -172,25 +169,23 @@ public abstract class XSLTCrosswalk extends SelfNamedPlugin // load if first time, or reload if stylesheet changed: if (transformer == null || - transformFile.lastModified() > transformLastModified) - { - try - { - LOG.debug((transformer == null ? "Loading {} XSLT stylesheet from {}" : "Reloading {} XSLT stylesheet from {}"), - getPluginInstanceName(), transformFile.toString()); + transformFile.lastModified() > transformLastModified) { + try { + LOG.debug( + (transformer == null ? "Loading {} XSLT stylesheet from {}" : "Reloading {} XSLT stylesheet from " + + "{}"), + getPluginInstanceName(), transformFile.toString()); Source transformSource - = new StreamSource(new FileInputStream(transformFile)); + = new StreamSource(new FileInputStream(transformFile)); TransformerFactory transformerFactory - = TransformerFactory.newInstance( - TRANSFORMER_FACTORY_CLASS, null); + = TransformerFactory.newInstance( + TRANSFORMER_FACTORY_CLASS, null); transformer = transformerFactory.newTransformer(transformSource); transformLastModified = transformFile.lastModified(); - } - catch (TransformerConfigurationException | FileNotFoundException e) - { + } catch (TransformerConfigurationException | FileNotFoundException e) { LOG.error("Failed to initialize XSLTCrosswalk({}): {}", - getPluginInstanceName(), e.toString()); + getPluginInstanceName(), e.toString()); } } return transformer; diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTDisseminationCrosswalk.java index 23f11368c8..9e505ed87a 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTDisseminationCrosswalk.java @@ -24,7 +24,12 @@ import javax.xml.transform.TransformerException; import org.apache.commons.lang.ArrayUtils; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.Site; import org.dspace.content.authority.Choices; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; @@ -76,24 +81,28 @@ import org.slf4j.LoggerFactory; */ public class XSLTDisseminationCrosswalk extends XSLTCrosswalk - implements ParameterizedDisseminationCrosswalk -{ - /** log4j category */ + implements ParameterizedDisseminationCrosswalk { + /** + * log4j category + */ private static final Logger LOG = LoggerFactory.getLogger(XSLTDisseminationCrosswalk.class); - /** DSpace context, will be created if XSLTDisseminationCrosswalk had been started by command-line. */ + /** + * DSpace context, will be created if XSLTDisseminationCrosswalk had been started by command-line. + */ private static Context context; private static final String DIRECTION = "dissemination"; - protected static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); - protected static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + protected static final CommunityService communityService = ContentServiceFactory.getInstance() + .getCommunityService(); + protected static final CollectionService collectionService = ContentServiceFactory.getInstance() + .getCollectionService(); protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); private static final String aliases[] = makeAliases(DIRECTION); - public static String[] getPluginNames() - { + public static String[] getPluginNames() { return (String[]) ArrayUtils.clone(aliases); } @@ -107,55 +116,47 @@ public class XSLTDisseminationCrosswalk // load the namespace and schema from config private void init() - throws CrosswalkInternalException - { - if (namespaces != null || schemaLocation != null) - { + throws CrosswalkInternalException { + if (namespaces != null || schemaLocation != null) { return; } String myAlias = getPluginInstanceName(); - if (myAlias == null) - { + if (myAlias == null) { LOG.error("Must use PluginService to instantiate XSLTDisseminationCrosswalk so the class knows its name."); - throw new CrosswalkInternalException("Must use PluginService to instantiate XSLTDisseminationCrosswalk so the class knows its name."); + throw new CrosswalkInternalException( + "Must use PluginService to instantiate XSLTDisseminationCrosswalk so the class knows its name."); } // all configs for this plugin instance start with this: - String prefix = CONFIG_PREFIX+DIRECTION+"."+myAlias+"."; + String prefix = CONFIG_PREFIX + DIRECTION + "." + myAlias + "."; // get the schema location string, should already be in the // right format for value of "schemaLocation" attribute. - schemaLocation = ConfigurationManager.getProperty(prefix+"schemaLocation"); - if (schemaLocation == null) - { - LOG.warn("No schemaLocation for crosswalk="+myAlias+", key="+prefix+"schemaLocation"); - } - - // sanity check: schemaLocation should have space. - else if (schemaLocation.length() > 0 && schemaLocation.indexOf(' ') < 0) - { - LOG.warn("Possible INVALID schemaLocation (no space found) for crosswalk="+ - myAlias+", key="+prefix+"schemaLocation"+ - "\n\tCorrect format is \"{namespace} {schema-URL}\""); + schemaLocation = ConfigurationManager.getProperty(prefix + "schemaLocation"); + if (schemaLocation == null) { + LOG.warn("No schemaLocation for crosswalk=" + myAlias + ", key=" + prefix + "schemaLocation"); + } else if (schemaLocation.length() > 0 && schemaLocation.indexOf(' ') < 0) { + // sanity check: schemaLocation should have space. + LOG.warn("Possible INVALID schemaLocation (no space found) for crosswalk=" + + myAlias + ", key=" + prefix + "schemaLocation" + + "\n\tCorrect format is \"{namespace} {schema-URL}\""); } // grovel for namespaces of the form: // crosswalk.diss.{PLUGIN_NAME}.namespace.{PREFIX} = {URI} String nsPrefix = prefix + "namespace."; - Enumeration pe = (Enumeration)ConfigurationManager.propertyNames(); + Enumeration pe = (Enumeration) ConfigurationManager.propertyNames(); List nsList = new ArrayList<>(); - while (pe.hasMoreElements()) - { + while (pe.hasMoreElements()) { String key = pe.nextElement(); - if (key.startsWith(nsPrefix)) - { + if (key.startsWith(nsPrefix)) { nsList.add(Namespace.getNamespace(key.substring(nsPrefix.length()), - ConfigurationManager.getProperty(key))); + ConfigurationManager.getProperty(key))); } } namespaces = nsList.toArray(new Namespace[nsList.size()]); - preferList = ConfigurationManager.getBooleanProperty(prefix+"preferList", false); + preferList = ConfigurationManager.getBooleanProperty(prefix + "preferList", false); } /** @@ -164,14 +165,10 @@ public class XSLTDisseminationCrosswalk * @see DisseminationCrosswalk */ @Override - public Namespace[] getNamespaces() - { - try - { + public Namespace[] getNamespaces() { + try { init(); - } - catch (CrosswalkInternalException e) - { + } catch (CrosswalkInternalException e) { LOG.error(e.toString()); } return (Namespace[]) ArrayUtils.clone(namespaces); @@ -183,14 +180,10 @@ public class XSLTDisseminationCrosswalk * @see DisseminationCrosswalk */ @Override - public String getSchemaLocation() - { - try - { + public String getSchemaLocation() { + try { init(); - } - catch (CrosswalkInternalException e) - { + } catch (CrosswalkInternalException e) { LOG.error(e.toString()); } return schemaLocation; @@ -198,52 +191,46 @@ public class XSLTDisseminationCrosswalk @Override public Element disseminateElement(Context context, DSpaceObject dso) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { return disseminateElement(context, dso, new HashMap()); } @Override public Element disseminateElement(Context context, DSpaceObject dso, - Map parameters) + Map parameters) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { int type = dso.getType(); if (!(type == Constants.ITEM || - type == Constants.COLLECTION || - type == Constants.COMMUNITY)) - { - throw new CrosswalkObjectNotSupported("XSLTDisseminationCrosswalk can only crosswalk items, collections, and communities."); + type == Constants.COLLECTION || + type == Constants.COMMUNITY)) { + throw new CrosswalkObjectNotSupported( + "XSLTDisseminationCrosswalk can only crosswalk items, collections, and communities."); } init(); Transformer xform = getTransformer(DIRECTION); - if (xform == null) - { - throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); + if (xform == null) { + throw new CrosswalkInternalException( + "Failed to initialize transformer, probably error loading stylesheet."); } - for (Map.Entry parameter : parameters.entrySet()) - { + for (Map.Entry parameter : parameters.entrySet()) { LOG.debug("Setting parameter {} to {}", parameter.getKey(), parameter.getValue()); xform.setParameter(parameter.getKey(), parameter.getValue()); } - try - { + try { Document ddim = new Document(createDIM(dso)); JDOMResult result = new JDOMResult(); xform.transform(new JDOMSource(ddim), result); Element root = result.getDocument().getRootElement(); root.detach(); return root; - } - catch (TransformerException e) - { - LOG.error("Got error: "+e.toString()); - throw new CrosswalkInternalException("XSL translation failed: "+e.toString(), e); + } catch (TransformerException e) { + LOG.error("Got error: " + e.toString()); + throw new CrosswalkInternalException("XSL translation failed: " + e.toString(), e); } } @@ -252,42 +239,38 @@ public class XSLTDisseminationCrosswalk * * @param context context * @throws CrosswalkException crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error * @see DisseminationCrosswalk */ @Override public List disseminateList(Context context, DSpaceObject dso) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { int type = dso.getType(); if (!(type == Constants.ITEM || - type == Constants.COLLECTION || - type == Constants.COMMUNITY)) - { - throw new CrosswalkObjectNotSupported("XSLTDisseminationCrosswalk can only crosswalk a items, collections, and communities."); + type == Constants.COLLECTION || + type == Constants.COMMUNITY)) { + throw new CrosswalkObjectNotSupported( + "XSLTDisseminationCrosswalk can only crosswalk a items, collections, and communities."); } init(); Transformer xform = getTransformer(DIRECTION); - if (xform == null) - { - throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); + if (xform == null) { + throw new CrosswalkInternalException( + "Failed to initialize transformer, probably error loading stylesheet."); } - try - { + try { JDOMResult result = new JDOMResult(); xform.transform(new JDOMSource(createDIM(dso).getChildren()), result); return result.getResult(); - } - catch (TransformerException e) - { - LOG.error("Got error: "+e.toString()); - throw new CrosswalkInternalException("XSL translation failed: "+e.toString(), e); + } catch (TransformerException e) { + LOG.error("Got error: " + e.toString()); + throw new CrosswalkInternalException("XSL translation failed: " + e.toString(), e); } } @@ -297,8 +280,7 @@ public class XSLTDisseminationCrosswalk * @see DisseminationCrosswalk */ @Override - public boolean canDisseminate(DSpaceObject dso) - { + public boolean canDisseminate(DSpaceObject dso) { return dso.getType() == Constants.ITEM; } @@ -309,14 +291,10 @@ public class XSLTDisseminationCrosswalk * @see DisseminationCrosswalk */ @Override - public boolean preferList() - { - try - { + public boolean preferList() { + try { init(); - } - catch (CrosswalkInternalException e) - { + } catch (CrosswalkInternalException e) { LOG.error(e.toString()); } return preferList; @@ -325,22 +303,20 @@ public class XSLTDisseminationCrosswalk /** * Generate an intermediate representation of a DSpace object. * - * @param dso The dspace object to build a representation of. + * @param dso The dspace object to build a representation of. * @param dcvs list of metadata * @return element */ - public static Element createDIM(DSpaceObject dso, List dcvs) - { + public static Element createDIM(DSpaceObject dso, List dcvs) { Element dim = new Element("dim", DIM_NS); String type = Constants.typeText[dso.getType()]; - dim.setAttribute("dspaceType",type); + dim.setAttribute("dspaceType", type); - for (int i = 0; i < dcvs.size(); i++) - { + for (int i = 0; i < dcvs.size(); i++) { MockMetadataValue dcv = dcvs.get(i); Element field = - createField(dcv.getSchema(), dcv.getElement(), dcv.getQualifier(), - dcv.getLanguage(), dcv.getValue(), dcv.getAuthority(), dcv.getConfidence()); + createField(dcv.getSchema(), dcv.getElement(), dcv.getQualifier(), + dcv.getLanguage(), dcv.getValue(), dcv.getAuthority(), dcv.getConfidence()); dim.addContent(field); } return dim; @@ -352,21 +328,16 @@ public class XSLTDisseminationCrosswalk * @param dso The dspace object to build a representation of. * @return element */ - public static Element createDIM(DSpaceObject dso) - { - if (dso.getType() == Constants.ITEM) - { + public static Element createDIM(DSpaceObject dso) { + if (dso.getType() == Constants.ITEM) { Item item = (Item) dso; return createDIM(dso, item2Metadata(item)); - } - else - { + } else { Element dim = new Element("dim", DIM_NS); String type = Constants.typeText[dso.getType()]; - dim.setAttribute("dspaceType",type); + dim.setAttribute("dspaceType", type); - if (dso.getType() == Constants.COLLECTION) - { + if (dso.getType() == Constants.COLLECTION) { Collection collection = (Collection) dso; String description = collectionService.getMetadata(collection, "introductory_text"); @@ -378,17 +349,15 @@ public class XSLTDisseminationCrosswalk String rights_license = collectionService.getMetadata(collection, "license"); String title = collectionService.getMetadata(collection, "name"); - dim.addContent(createField("dc","description",null,null,description)); - dim.addContent(createField("dc","description","abstract",null,description_abstract)); - dim.addContent(createField("dc","description","tableofcontents",null,description_table)); - dim.addContent(createField("dc","identifier","uri",null,identifier_uri)); - dim.addContent(createField("dc","provenance",null,null,provenance)); - dim.addContent(createField("dc","rights",null,null,rights)); - dim.addContent(createField("dc","rights","license",null,rights_license)); - dim.addContent(createField("dc","title",null,null,title)); - } - else if (dso.getType() == Constants.COMMUNITY) - { + dim.addContent(createField("dc", "description", null, null, description)); + dim.addContent(createField("dc", "description", "abstract", null, description_abstract)); + dim.addContent(createField("dc", "description", "tableofcontents", null, description_table)); + dim.addContent(createField("dc", "identifier", "uri", null, identifier_uri)); + dim.addContent(createField("dc", "provenance", null, null, provenance)); + dim.addContent(createField("dc", "rights", null, null, rights)); + dim.addContent(createField("dc", "rights", "license", null, rights_license)); + dim.addContent(createField("dc", "title", null, null, title)); + } else if (dso.getType() == Constants.COMMUNITY) { Community community = (Community) dso; String description = communityService.getMetadata(community, "introductory_text"); @@ -398,15 +367,13 @@ public class XSLTDisseminationCrosswalk String rights = communityService.getMetadata(community, "copyright_text"); String title = communityService.getMetadata(community, "name"); - dim.addContent(createField("dc","description",null,null,description)); - dim.addContent(createField("dc","description","abstract",null,description_abstract)); - dim.addContent(createField("dc","description","tableofcontents",null,description_table)); - dim.addContent(createField("dc","identifier","uri",null,identifier_uri)); - dim.addContent(createField("dc","rights",null,null,rights)); - dim.addContent(createField("dc","title",null,null,title)); - } - else if (dso.getType() == Constants.SITE) - { + dim.addContent(createField("dc", "description", null, null, description)); + dim.addContent(createField("dc", "description", "abstract", null, description_abstract)); + dim.addContent(createField("dc", "description", "tableofcontents", null, description_table)); + dim.addContent(createField("dc", "identifier", "uri", null, identifier_uri)); + dim.addContent(createField("dc", "rights", null, null, rights)); + dim.addContent(createField("dc", "title", null, null, title)); + } else if (dso.getType() == Constants.SITE) { Site site = (Site) dso; String identifier_uri = "hdl:" + site.getHandle(); @@ -414,19 +381,18 @@ public class XSLTDisseminationCrosswalk String url = site.getURL(); //FIXME: adding two URIs for now (site handle and URL), in case site isn't using handles - dim.addContent(createField("dc","identifier","uri",null,identifier_uri)); - dim.addContent(createField("dc","identifier","uri",null,url)); - dim.addContent(createField("dc","title",null,null,title)); + dim.addContent(createField("dc", "identifier", "uri", null, identifier_uri)); + dim.addContent(createField("dc", "identifier", "uri", null, url)); + dim.addContent(createField("dc", "title", null, null, title)); } // XXX FIXME: Nothing to crosswalk for bitstream? return dim; } } - protected static List item2Metadata(Item item) - { + protected static List item2Metadata(Item item) { List dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, - Item.ANY); + Item.ANY); List result = new ArrayList<>(); for (MetadataValue metadataValue : dcvs) { result.add(new MockMetadataValue(metadataValue)); @@ -436,53 +402,47 @@ public class XSLTDisseminationCrosswalk } - - /** + /** * Create a new DIM field element with the given attributes. * - * @param schema The schema the DIM field belongs to. - * @param element The element the DIM field belongs to. + * @param schema The schema the DIM field belongs to. + * @param element The element the DIM field belongs to. * @param qualifier The qualifier the DIM field belongs to. - * @param language The language the DIM field belongs to. - * @param value The value of the DIM field. + * @param language The language the DIM field belongs to. + * @param value The value of the DIM field. * @return A new DIM field element */ - private static Element createField(String schema, String element, String qualifier, String language, String value) - { + private static Element createField(String schema, String element, String qualifier, String language, String value) { return createField(schema, element, qualifier, language, value, null, -1); } /** * Create a new DIM field element with the given attributes. * - * @param schema The schema the DIM field belongs to. - * @param element The element the DIM field belongs to. - * @param qualifier The qualifier the DIM field belongs to. - * @param language The language the DIM field belongs to. - * @param value The value of the DIM field. - * @param authority The authority + * @param schema The schema the DIM field belongs to. + * @param element The element the DIM field belongs to. + * @param qualifier The qualifier the DIM field belongs to. + * @param language The language the DIM field belongs to. + * @param value The value of the DIM field. + * @param authority The authority * @param confidence confidence in the authority * @return A new DIM field element */ private static Element createField(String schema, String element, String qualifier, String language, String value, - String authority, int confidence) - { - Element field = new Element("field",DIM_NS); - field.setAttribute("mdschema",schema); - field.setAttribute("element",element); - if (qualifier != null) - { + String authority, int confidence) { + Element field = new Element("field", DIM_NS); + field.setAttribute("mdschema", schema); + field.setAttribute("element", element); + if (qualifier != null) { field.setAttribute("qualifier", qualifier); } - if (language != null) - { + if (language != null) { field.setAttribute("lang", language); } field.setText(checkedString(value)); - if (authority != null) - { + if (authority != null) { field.setAttribute("authority", authority); field.setAttribute("confidence", Choices.getConfidenceText(confidence)); } @@ -491,29 +451,21 @@ public class XSLTDisseminationCrosswalk } // Return string with non-XML characters (i.e. low control chars) excised. - private static String checkedString(String value) - { - if (value == null) - { + private static String checkedString(String value) { + if (value == null) { return null; } String reason = Verifier.checkCharacterData(value); - if (reason == null) - { + if (reason == null) { return value; - } - else - { - if (LOG.isDebugEnabled()) - { + } else { + if (LOG.isDebugEnabled()) { LOG.debug("Filtering out non-XML characters in string, reason=" + reason); } StringBuffer result = new StringBuffer(value.length()); - for (int i = 0; i < value.length(); ++i) - { + for (int i = 0; i < value.length(); ++i) { char c = value.charAt(i); - if (Verifier.isXMLCharacter((int)c)) - { + if (Verifier.isXMLCharacter((int) c)) { result.append(c); } } @@ -528,11 +480,9 @@ public class XSLTDisseminationCrosswalk * @param argv the command line arguments given * @throws Exception if error */ - public static void main(String[] argv) throws Exception - { + public static void main(String[] argv) throws Exception { LOG.error("started."); - if (argv.length < 2 || argv.length > 3) - { + if (argv.length < 2 || argv.length > 3) { System.err.println("Usage: java XSLTDisseminationCrosswalk [output-file]"); LOG.error("You started Dissemination Crosswalk Test/Export with a wrong number of parameters."); System.exit(1); @@ -541,26 +491,21 @@ public class XSLTDisseminationCrosswalk String xwalkname = argv[0]; String handle = argv[1]; OutputStream out = System.out; - if (argv.length > 2) - { - try - { + if (argv.length > 2) { + try { out = new FileOutputStream(argv[2]); - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { System.err.format("Can't write to the specified file: %s%n", - e.getMessage()); + e.getMessage()); System.err.println("Will write output to stdout."); } } - + DisseminationCrosswalk xwalk - = (DisseminationCrosswalk) CoreServiceFactory.getInstance() - .getPluginService() - .getNamedPlugin(DisseminationCrosswalk.class, xwalkname); - if (xwalk == null) - { + = (DisseminationCrosswalk) CoreServiceFactory.getInstance() + .getPluginService() + .getNamedPlugin(DisseminationCrosswalk.class, xwalkname); + if (xwalk == null) { System.err.format("Error: Cannot find a DisseminationCrosswalk plugin for: \"%s\"%n", xwalkname); LOG.error("Cannot find the Dissemination Crosswalk plugin."); System.exit(1); @@ -570,36 +515,29 @@ public class XSLTDisseminationCrosswalk context.turnOffAuthorisationSystem(); DSpaceObject dso = null; - try - { + try { dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, handle); - } - catch (SQLException e) - { - System.err.println("Error: A problem with the database connection occurred, check logs for further information."); + } catch (SQLException e) { + System.err + .println("Error: A problem with the database connection occurred, check logs for further information."); System.exit(1); } - if (null == dso) - { + if (null == dso) { System.err.format("Can't find a DSpaceObject with the handle \"%s\"%n", handle); System.exit(1); } - if (!xwalk.canDisseminate(dso)) - { + if (!xwalk.canDisseminate(dso)) { System.err.println("Dissemination Crosswalk can't disseminate this DSpaceObject."); LOG.error("Dissemination Crosswalk can't disseminate this DSpaceObject."); System.exit(1); } Element root = null; - try - { + try { root = xwalk.disseminateElement(context, dso); - } - catch (CrosswalkException | IOException | SQLException | AuthorizeException e) - { + } catch (CrosswalkException | IOException | SQLException | AuthorizeException e) { // as this script is for testing dissemination crosswalks, we want // verbose information in case of an exception. System.err.println("An error occurred while processing the dissemination crosswalk."); @@ -616,13 +554,10 @@ public class XSLTDisseminationCrosswalk System.exit(1); } - try - { + try { XMLOutputter xmlout = new XMLOutputter(Format.getPrettyFormat()); xmlout.output(new Document(root), out); - } - catch (Exception e) - { + } catch (Exception e) { // as this script is for testing dissemination crosswalks, we want // verbose information in case of an exception. System.err.println("An error occurred after processing the dissemination crosswalk."); @@ -641,8 +576,7 @@ public class XSLTDisseminationCrosswalk } context.complete(); - if (out instanceof FileOutputStream) - { + if (out instanceof FileOutputStream) { out.close(); } } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTIngestionCrosswalk.java index 283711dd2a..de479a4647 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/XSLTIngestionCrosswalk.java @@ -18,7 +18,12 @@ import javax.xml.transform.TransformerException; import org.apache.commons.lang.ArrayUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataSchema; import org.dspace.content.authority.Choices; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.packager.PackageUtils; @@ -36,12 +41,6 @@ import org.jdom.output.XMLOutputter; import org.jdom.transform.JDOMResult; import org.jdom.transform.JDOMSource; -import java.io.FileInputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Configurable XSLT-driven ingestion Crosswalk *

    @@ -52,9 +51,10 @@ import java.util.List; */ public class XSLTIngestionCrosswalk extends XSLTCrosswalk - implements IngestionCrosswalk -{ - /** log4j category */ + implements IngestionCrosswalk { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(XSLTIngestionCrosswalk.class); private static final String DIRECTION = "submission"; @@ -62,38 +62,33 @@ public class XSLTIngestionCrosswalk private static final String aliases[] = makeAliases(DIRECTION); private static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final CollectionService collectionService = ContentServiceFactory.getInstance() + .getCollectionService(); private static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - public static String[] getPluginNames() - { + public static String[] getPluginNames() { return (String[]) ArrayUtils.clone(aliases); } // apply metadata values returned in DIM to the target item. private static void applyDim(Context context, List dimList, Item item, boolean createMissingMetadataFields) - throws CrosswalkException, SQLException, AuthorizeException { - for (Element elt : dimList) - { - if ("field".equals(elt.getName()) && DIM_NS.equals(elt.getNamespace())) - { + throws CrosswalkException, SQLException, AuthorizeException { + for (Element elt : dimList) { + if ("field".equals(elt.getName()) && DIM_NS.equals(elt.getNamespace())) { applyDimField(context, elt, item, createMissingMetadataFields); - } - else if ("dim".equals(elt.getName()) && DIM_NS.equals(elt.getNamespace())) - { + } else if ("dim".equals(elt.getName()) && DIM_NS.equals(elt.getNamespace())) { // if it's a container, apply its guts applyDim(context, elt.getChildren(), item, createMissingMetadataFields); - } - else - { - log.error("Got unexpected element in DIM list: "+elt.toString()); - throw new MetadataValidationException("Got unexpected element in DIM list: "+elt.toString()); + } else { + log.error("Got unexpected element in DIM list: " + elt.toString()); + throw new MetadataValidationException("Got unexpected element in DIM list: " + elt.toString()); } } } // adds the metadata element from one - private static void applyDimField(Context context, Element field, Item item, boolean createMissingMetadataFields) throws CrosswalkException, SQLException, AuthorizeException { + private static void applyDimField(Context context, Element field, Item item, boolean createMissingMetadataFields) + throws CrosswalkException, SQLException, AuthorizeException { String schema = field.getAttributeValue("mdschema"); String element = field.getAttributeValue("element"); String qualifier = field.getAttributeValue("qualifier"); @@ -102,23 +97,20 @@ public class XSLTIngestionCrosswalk String sconf = field.getAttributeValue("confidence"); CrosswalkMetadataValidator metadataValidator = new CrosswalkMetadataValidator(); - MetadataField metadataField = metadataValidator.checkMetadata(context, schema, element, qualifier, createMissingMetadataFields); + MetadataField metadataField = metadataValidator + .checkMetadata(context, schema, element, qualifier, createMissingMetadataFields); // sanity check: some XSL puts an empty string in qualifier, // change it to null so we match the unqualified DC field: - if (qualifier != null && qualifier.equals("")) - { + if (qualifier != null && qualifier.equals("")) { qualifier = null; } if ((authority != null && authority.length() > 0) || - (sconf != null && sconf.length() > 0)) - { + (sconf != null && sconf.length() > 0)) { int confidence = (sconf != null && sconf.length() > 0) ? - Choices.getConfidenceValue(sconf) : Choices.CF_UNSET; + Choices.getConfidenceValue(sconf) : Choices.CF_UNSET; itemService.addMetadata(context, item, metadataField, lang, field.getText(), authority, confidence); - } - else - { + } else { itemService.addMetadata(context, item, metadataField, lang, field.getText()); } } @@ -128,33 +120,30 @@ public class XSLTIngestionCrosswalk * Translation produces a list of DIM "field" elements; * these correspond directly to Item.addMetadata() calls so * they are simply executed. + * * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, List metadata, - boolean createMissingMetadataFields) + boolean createMissingMetadataFields) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { Transformer xform = getTransformer(DIRECTION); - if (xform == null) - { - throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); + if (xform == null) { + throw new CrosswalkInternalException( + "Failed to initialize transformer, probably error loading stylesheet."); } - try - { + try { JDOMResult result = new JDOMResult(); xform.transform(new JDOMSource(metadata), result); ingestDIM(context, dso, result.getResult(), createMissingMetadataFields); - } - catch (TransformerException e) - { - log.error("Got error: "+e.toString()); - throw new CrosswalkInternalException("XSL Transformation failed: "+e.toString(), e); + } catch (TransformerException e) { + log.error("Got error: " + e.toString()); + throw new CrosswalkInternalException("XSL Transformation failed: " + e.toString(), e); } } @@ -162,46 +151,41 @@ public class XSLTIngestionCrosswalk * Ingest a whole document. Build Document object around root element, * and feed that to the transformation, since it may get handled * differently than a List of metadata elements. + * * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { Transformer xform = getTransformer(DIRECTION); - if (xform == null) - { - throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); + if (xform == null) { + throw new CrosswalkInternalException( + "Failed to initialize transformer, probably error loading stylesheet."); } - try - { - JDOMSource source = new JDOMSource(new Document((Element)root.cloneContent())); + try { + JDOMSource source = new JDOMSource(new Document((Element) root.clone())); JDOMResult result = new JDOMResult(); xform.transform(source, result); Document dimDoc = result.getDocument(); ingestDIM(context, dso, dimDoc.getRootElement().getChildren(), createMissingMetadataFields); - } - catch (TransformerException e) - { - log.error("Got error: "+e.toString()); - throw new CrosswalkInternalException("XSL Transformation failed: "+e.toString(), e); + } catch (TransformerException e) { + log.error("Got error: " + e.toString()); + throw new CrosswalkInternalException("XSL Transformation failed: " + e.toString(), e); } } // return coll/comm "metadata" label corresponding to a DIM field. - private static String getMetadataForDIM(Element field) - { + private static String getMetadataForDIM(Element field) { // make up fieldname, then look for it in xwalk String element = field.getAttributeValue("element"); String qualifier = field.getAttributeValue("qualifier"); String fname = "dc." + element; - if (qualifier != null) - { + if (qualifier != null) { fname += "." + qualifier; } return PackageUtils.dcToContainerMetadata(fname); @@ -216,74 +200,57 @@ public class XSLTIngestionCrosswalk * Note that this is ONLY implemented for Item, Collection, and * Community objects. Also only works for the "dc" metadata schema. *

    - * @param context the context - * @param dso object into which to ingest metadata - * @param dim root of a DIM expression + * + * @param context the context + * @param dso object into which to ingest metadata + * @param dim root of a DIM expression * @param createMissingMetadataFields whether to create missing fields * @throws CrosswalkException crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public static void ingestDIM(Context context, DSpaceObject dso, Element dim, boolean createMissingMetadataFields) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { ingestDIM(context, dso, dim.getChildren(), createMissingMetadataFields); } - public static void ingestDIM(Context context, DSpaceObject dso, List fields, boolean createMissingMetadataFields) + public static void ingestDIM(Context context, DSpaceObject dso, List fields, + boolean createMissingMetadataFields) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { int type = dso.getType(); - if (type == Constants.ITEM) - { - Item item = (Item)dso; + if (type == Constants.ITEM) { + Item item = (Item) dso; applyDim(context, fields, item, createMissingMetadataFields); - } - else if (type == Constants.COLLECTION || - type == Constants.COMMUNITY) - { - for (Element field : fields) - { + } else if (type == Constants.COLLECTION || + type == Constants.COMMUNITY) { + for (Element field : fields) { String schema = field.getAttributeValue("mdschema"); - if ("dim".equals(field.getName()) && DIM_NS.equals(field.getNamespace())) - { + if ("dim".equals(field.getName()) && DIM_NS.equals(field.getNamespace())) { ingestDIM(context, dso, field.getChildren(), createMissingMetadataFields); - } - else if ("field".equals(field.getName()) && - DIM_NS.equals(field.getNamespace()) && - schema != null && "dc".equals(schema)) - { + } else if ("field".equals(field.getName()) && + DIM_NS.equals(field.getNamespace()) && + schema != null && "dc".equals(schema)) { String md = getMetadataForDIM(field); - if (md == null) - { + if (md == null) { log.warn("Cannot map to Coll/Comm metadata field, DIM element=" + - field.getAttributeValue("element") + ", qualifier=" + field.getAttributeValue("qualifier")); - } - else - { - if (type == Constants.COLLECTION) - { + field.getAttributeValue("element") + ", qualifier=" + field + .getAttributeValue("qualifier")); + } else { + if (type == Constants.COLLECTION) { collectionService.setMetadata(context, (Collection) dso, md, field.getText()); - } - else - { + } else { communityService.setMetadata(context, (Community) dso, md, field.getText()); } } - } - - else - { + } else { log.warn("ignoring unrecognized DIM element: " + field.toString()); } } - } - else - { + } else { throw new CrosswalkObjectNotSupported("XsltSubmissionionCrosswalk can only crosswalk to an Item."); } @@ -297,10 +264,8 @@ public class XSLTIngestionCrosswalk * @param argv the command line arguments given * @throws Exception if error */ - public static void main(String[] argv) throws Exception - { - if (argv.length < 2) - { + public static void main(String[] argv) throws Exception { + if (argv.length < 2) { System.err.println("Usage: java XSLTIngestionCrosswalk [-l] "); System.exit(1); } @@ -308,39 +273,35 @@ public class XSLTIngestionCrosswalk int i = 0; boolean list = false; // skip first arg if it's the list option - if (argv.length > 2 && argv[0].equals("-l")) - { + if (argv.length > 2 && argv[0].equals("-l")) { ++i; list = true; } - IngestionCrosswalk xwalk = (IngestionCrosswalk) CoreServiceFactory.getInstance().getPluginService().getNamedPlugin( - IngestionCrosswalk.class, argv[i]); - if (xwalk == null) - { - System.err.println("Error, cannot find an IngestionCrosswalk plugin for: \""+argv[i]+"\""); + IngestionCrosswalk xwalk = (IngestionCrosswalk) CoreServiceFactory.getInstance().getPluginService() + .getNamedPlugin( + IngestionCrosswalk.class, argv[i]); + if (xwalk == null) { + System.err.println("Error, cannot find an IngestionCrosswalk plugin for: \"" + argv[i] + "\""); System.exit(1); } - Transformer xform = ((XSLTIngestionCrosswalk)xwalk).getTransformer(DIRECTION); - if (xform == null) - { - throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); + Transformer xform = ((XSLTIngestionCrosswalk) xwalk).getTransformer(DIRECTION); + if (xform == null) { + throw new CrosswalkInternalException( + "Failed to initialize transformer, probably error loading stylesheet."); } SAXBuilder builder = new SAXBuilder(); - Document inDoc = builder.build(new FileInputStream(argv[i+1])); + Document inDoc = builder.build(new FileInputStream(argv[i + 1])); XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat()); List dimList; - if (list) - { + if (list) { JDOMSource source = new JDOMSource(inDoc.getRootElement().getChildren()); JDOMResult result = new JDOMResult(); xform.transform(source, result); dimList = result.getResult(); outputter.output(dimList, System.out); - } - else - { + } else { JDOMSource source = new JDOMSource(inDoc); JDOMResult result = new JDOMResult(); xform.transform(source, result); @@ -352,48 +313,41 @@ public class XSLTIngestionCrosswalk // Sanity-check the generated DIM, make sure it would load. Context context = new Context(); Iterator di = dimList.iterator(); - while (di.hasNext()) - { + while (di.hasNext()) { // skip over comment, text and other trash some XSLs generate.. Object o = di.next(); - if (!(o instanceof Element)) - { + if (!(o instanceof Element)) { continue; } - Element elt = (Element)o; - if (elt.getName().equals("field") && elt.getNamespace().equals(DIM_NS)) - { + Element elt = (Element) o; + if (elt.getName().equals("field") && elt.getNamespace().equals(DIM_NS)) { String schema = elt.getAttributeValue("mdschema"); String element = elt.getAttributeValue("element"); String qualifier = elt.getAttributeValue("qualifier"); - MetadataSchema ms = ContentServiceFactory.getInstance().getMetadataSchemaService().find(context, schema); - if (ms == null ) - { - System.err.println("DIM Error, Cannot find metadata schema for: schema=\""+schema+ - "\" (... element=\""+element+"\", qualifier=\""+qualifier+"\")"); - } - else - { - if (qualifier != null && qualifier.equals("")) - { - System.err.println("DIM Warning, qualifier is empty string: "+ - " schema=\""+schema+"\", element=\""+element+"\", qualifier=\""+qualifier+"\""); + MetadataSchema ms = ContentServiceFactory.getInstance().getMetadataSchemaService() + .find(context, schema); + if (ms == null) { + System.err.println("DIM Error, Cannot find metadata schema for: schema=\"" + schema + + "\" (... element=\"" + element + "\", qualifier=\"" + qualifier + "\")"); + } else { + if (qualifier != null && qualifier.equals("")) { + System.err.println("DIM Warning, qualifier is empty string: " + + " schema=\"" + schema + "\", element=\"" + element + "\", " + + "qualifier=\"" + qualifier + "\""); qualifier = null; } - MetadataField mf = ContentServiceFactory.getInstance().getMetadataFieldService().findByElement(context, - ms, element, qualifier); - if (mf == null) - { + MetadataField mf = ContentServiceFactory.getInstance().getMetadataFieldService() + .findByElement(context, + ms, element, qualifier); + if (mf == null) { System.err.println("DIM Error, Cannot find metadata field for: schema=\"" + schema + - "\", element=\"" + element + "\", qualifier=\"" + qualifier + "\""); + "\", element=\"" + element + "\", qualifier=\"" + qualifier + "\""); } } - } - else - { + } else { // ("Got unexpected element in DIM list: "+elt.toString()); - throw new MetadataValidationException("Got unexpected element in DIM list: "+elt.toString()); + throw new MetadataValidationException("Got unexpected element in DIM list: " + elt.toString()); } } //complete & close Context diff --git a/dspace-api/src/main/java/org/dspace/content/dao/BitstreamDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/BitstreamDAO.java index 268ddab920..c1ef923131 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/BitstreamDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/BitstreamDAO.java @@ -7,19 +7,20 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + 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; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Database Access Object interface class for the Bitstream object. - * The implementation of this class is responsible for all database calls for the Bitstream object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Bitstream object and is autowired + * by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/content/dao/BitstreamFormatDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/BitstreamFormatDAO.java index 3c7c1907ff..4e50ccb0d4 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/BitstreamFormatDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/BitstreamFormatDAO.java @@ -7,28 +7,30 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.BitstreamFormat; import org.dspace.core.Context; import org.dspace.core.GenericDAO; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the BitstreamFormat object. - * The implementation of this class is responsible for all database calls for the BitstreamFormat object and is autowired by spring + * The implementation of this class is responsible for all database calls for the BitstreamFormat object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com */ -public interface BitstreamFormatDAO extends GenericDAO -{ +public interface BitstreamFormatDAO extends GenericDAO { - public BitstreamFormat findByMIMEType(Context context, String mimeType, boolean includeInternal) throws SQLException; + public BitstreamFormat findByMIMEType(Context context, String mimeType, boolean includeInternal) + throws SQLException; public BitstreamFormat findByShortDescription(Context context, String desc) throws SQLException; - public int updateRemovedBitstreamFormat(Context context, BitstreamFormat deletedBitstreamFormat, BitstreamFormat newBitstreamFormat) throws SQLException; + public int updateRemovedBitstreamFormat(Context context, BitstreamFormat deletedBitstreamFormat, + BitstreamFormat newBitstreamFormat) throws SQLException; public List findNonInternal(Context context) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/dao/BundleDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/BundleDAO.java index 0e13711876..da7435d466 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/BundleDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/BundleDAO.java @@ -7,14 +7,15 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; + import org.dspace.content.Bundle; import org.dspace.core.Context; -import java.sql.SQLException; - /** * Database Access Object interface class for the Bundle object. - * The implementation of this class is responsible for all database calls for the Bundle object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Bundle object and is autowired by + * spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/content/dao/CollectionDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/CollectionDAO.java index 616a3997e8..80f06f9072 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/CollectionDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/CollectionDAO.java @@ -7,6 +7,10 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.content.MetadataField; @@ -14,13 +18,10 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; - /** * Database Access Object interface class for the Collection object. - * The implementation of this class is responsible for all database calls for the Collection object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Collection object and is autowired + * by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -29,7 +30,8 @@ public interface CollectionDAO extends DSpaceObjectLegacySupportDAO public List findAll(Context context, MetadataField order) throws SQLException; - public List findAll(Context context, MetadataField order, Integer limit, Integer offset) throws SQLException; + public List findAll(Context context, MetadataField order, Integer limit, Integer offset) + throws SQLException; public Collection findByTemplateItem(Context context, Item item) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/dao/CommunityDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/CommunityDAO.java index 99f422b01f..e09748e144 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/CommunityDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/CommunityDAO.java @@ -7,18 +7,19 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Community; import org.dspace.content.MetadataField; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the Community object. - * The implementation of this class is responsible for all database calls for the Community object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Community object and is autowired + * by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -27,7 +28,8 @@ public interface CommunityDAO extends DSpaceObjectLegacySupportDAO { public List findAll(Context context, MetadataField sortField) throws SQLException; - public List findAll(Context context, MetadataField sortField, Integer limit, Integer offset) throws SQLException; + public List findAll(Context context, MetadataField sortField, Integer limit, Integer offset) + throws SQLException; public Community findByAdminGroup(Context context, Group group) throws SQLException; @@ -35,7 +37,8 @@ public interface CommunityDAO extends DSpaceObjectLegacySupportDAO { public List findAuthorized(Context context, EPerson ePerson, List actions) throws SQLException; - public List findAuthorizedByGroup(Context context, EPerson currentUser, List actions) throws SQLException; + public List findAuthorizedByGroup(Context context, EPerson currentUser, List actions) + throws SQLException; int countRows(Context context) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/DSpaceObjectDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/DSpaceObjectDAO.java index ae734de684..5e71f7f0ed 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/DSpaceObjectDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/DSpaceObjectDAO.java @@ -14,8 +14,8 @@ import org.dspace.core.GenericDAO; * Database Access Object interface class for the DSpaceObject. * All DSpaceObject DAO classes should implement this class since it ensures that the T object is of type DSpaceObject * - * @author kevinvandevelde at atmire.com * @param some implementation of DSpaceObject + * @author kevinvandevelde at atmire.com */ public interface DSpaceObjectDAO extends GenericDAO { } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/DSpaceObjectLegacySupportDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/DSpaceObjectLegacySupportDAO.java index edda89dc14..c82dda4a0f 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/DSpaceObjectLegacySupportDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/DSpaceObjectLegacySupportDAO.java @@ -7,17 +7,18 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; + import org.dspace.content.DSpaceObject; import org.dspace.core.Context; -import java.sql.SQLException; - /** - * Database Access Object interface interface class that adds support to retrieve DSpaceObject by the old integer based identifier which was used + * Database Access Object interface interface class that adds support to retrieve DSpaceObject by the old integer + * based identifier which was used * to identify DSpaceObjects prior to DSpace 6.0 * - * @author kevinvandevelde at atmire.com * @param some implementation of DSpaceObject + * @author kevinvandevelde at atmire.com */ public interface DSpaceObjectLegacySupportDAO extends DSpaceObjectDAO { diff --git a/dspace-api/src/main/java/org/dspace/content/dao/ItemDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/ItemDAO.java index 466b2ce0f8..02ddd1cf3e 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/ItemDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/ItemDAO.java @@ -7,18 +7,18 @@ */ package org.dspace.content.dao; -import org.dspace.content.Collection; -import org.dspace.content.Item; -import org.dspace.content.MetadataField; -import org.dspace.core.Context; -import org.dspace.eperson.EPerson; - import java.sql.SQLException; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.UUID; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; + /** * Database Access Object interface class for the Item object. * The implementation of this class is responsible for all database calls for the Item object and is autowired by spring @@ -26,8 +26,7 @@ import java.util.UUID; * * @author kevinvandevelde at atmire.com */ -public interface ItemDAO extends DSpaceObjectLegacySupportDAO -{ +public interface ItemDAO extends DSpaceObjectLegacySupportDAO { public Iterator findAll(Context context, boolean archived) throws SQLException; public Iterator findAll(Context context, boolean archived, int limit, int offset) throws SQLException; @@ -38,69 +37,83 @@ public interface ItemDAO extends DSpaceObjectLegacySupportDAO * Find all Items modified since a Date. * * @param context Context - * @param since Earliest interesting last-modified date. + * @param since Earliest interesting last-modified date. * @return iterator over items - * @throws SQLException if database error + * @throws SQLException if database error */ public Iterator findByLastModifiedSince(Context context, Date since) - throws SQLException; + throws SQLException; public Iterator findBySubmitter(Context context, EPerson eperson) throws SQLException; - public Iterator findBySubmitter(Context context, EPerson eperson, MetadataField metadataField, int limit) throws SQLException; + public Iterator findBySubmitter(Context context, EPerson eperson, MetadataField metadataField, int limit) + throws SQLException; - public Iterator findByMetadataField(Context context, MetadataField metadataField, String value, boolean inArchive) throws SQLException; + public Iterator findByMetadataField(Context context, MetadataField metadataField, String value, + boolean inArchive) throws SQLException; - public Iterator findByMetadataQuery(Context context, List> listFieldList, List query_op, List query_val, List collectionUuids, String regexClause, int offset, int limit) throws SQLException; + public Iterator findByMetadataQuery(Context context, List> listFieldList, + List query_op, List query_val, List collectionUuids, + String regexClause, int offset, int limit) throws SQLException; - public Iterator findByAuthorityValue(Context context, MetadataField metadataField, String authority, boolean inArchive) throws SQLException; + public Iterator findByAuthorityValue(Context context, MetadataField metadataField, String authority, + boolean inArchive) throws SQLException; - public Iterator findArchivedByCollection(Context context, Collection collection, Integer limit, Integer offset) throws SQLException; + public Iterator findArchivedByCollection(Context context, Collection collection, Integer limit, + Integer offset) throws SQLException; public Iterator findAllByCollection(Context context, Collection collection) throws SQLException; + public Iterator findAllByCollection(Context context, Collection collection, Integer limit, Integer offset) + throws SQLException; + /** * Count number of items in a given collection - * @param context context - * @param collection the collection - * @param includeArchived whether to include archived items in count + * + * @param context context + * @param collection the collection + * @param includeArchived whether to include archived items in count * @param includeWithdrawn whether to include withdrawn items in count * @return item count * @throws SQLException if database error */ - public int countItems(Context context, Collection collection, boolean includeArchived, boolean includeWithdrawn) throws SQLException; - + public int countItems(Context context, Collection collection, boolean includeArchived, boolean includeWithdrawn) + throws SQLException; + /** * Count number of unique items across several collections at once. - * This method can be used with - * {@link org.dspace.content.service.CommunityService#getAllCollections(Context,Community)} + * This method can be used with + * {@link org.dspace.content.service.CommunityService#getAllCollections(Context, Community)} * to determine the unique number of items in a Community. - * - * @param context context - * @param collections the list of collections - * @param includeArchived whether to include archived items in count + * + * @param context context + * @param collections the list of collections + * @param includeArchived whether to include archived items in count * @param includeWithdrawn whether to include withdrawn items in count * @return item count * @throws SQLException if database error */ - public int countItems(Context context, List collections, boolean includeArchived, boolean includeWithdrawn) throws SQLException; + public int countItems(Context context, List collections, boolean includeArchived, + boolean includeWithdrawn) throws SQLException; /** * Get all Items installed or withdrawn, discoverable, and modified since a Date. - * @param context context - * @param archived whether to find archived - * @param withdrawn whether to find withdrawn + * + * @param context context + * @param archived whether to find archived + * @param withdrawn whether to find withdrawn * @param discoverable whether to find discoverable * @param lastModified earliest interesting last-modified date. * @return iterator over items * @throws SQLException if database error */ public Iterator findAll(Context context, boolean archived, - boolean withdrawn, boolean discoverable, Date lastModified) - throws SQLException; + boolean withdrawn, boolean discoverable, Date lastModified) + throws SQLException; /** * Count total number of items (rows in item table) + * * @param context context * @return total count * @throws SQLException if database error @@ -109,12 +122,13 @@ public interface ItemDAO extends DSpaceObjectLegacySupportDAO /** * Count number of items based on specific status flags - * @param context context - * @param includeArchived whether to include archived items in count + * + * @param context context + * @param includeArchived whether to include archived items in count * @param includeWithdrawn whether to include withdrawn items in count * @return count of items * @throws SQLException if database error */ int countItems(Context context, boolean includeArchived, boolean includeWithdrawn) throws SQLException; - + } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/MetadataFieldDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/MetadataFieldDAO.java index 47388761f0..5b694c73eb 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/MetadataFieldDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/MetadataFieldDAO.java @@ -7,36 +7,39 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; import org.dspace.core.Context; import org.dspace.core.GenericDAO; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the MetadataField object. - * The implementation of this class is responsible for all database calls for the MetadataField object and is autowired by spring + * The implementation of this class is responsible for all database calls for the MetadataField object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com */ public interface MetadataFieldDAO extends GenericDAO { - public MetadataField find(Context context, int metadataFieldId, MetadataSchema metadataSchema, String element, String qualifier) - throws SQLException; + public MetadataField find(Context context, int metadataFieldId, MetadataSchema metadataSchema, String element, + String qualifier) + throws SQLException; public MetadataField findByElement(Context context, MetadataSchema metadataSchema, String element, String qualifier) - throws SQLException; + throws SQLException; public MetadataField findByElement(Context context, String metadataSchema, String element, String qualifier) - throws SQLException; + throws SQLException; + + public List findFieldsByElementNameUnqualified(Context context, String metadataSchema, + String element) + throws SQLException; - public List findFieldsByElementNameUnqualified(Context context, String metadataSchema, String element) - throws SQLException; - public List findAllInSchema(Context context, MetadataSchema metadataSchema) - throws SQLException; + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/MetadataSchemaDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/MetadataSchemaDAO.java index 16cf18de5a..b5e1d8f8b1 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/MetadataSchemaDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/MetadataSchemaDAO.java @@ -7,15 +7,16 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; + import org.dspace.content.MetadataSchema; import org.dspace.core.Context; import org.dspace.core.GenericDAO; -import java.sql.SQLException; - /** * Database Access Object interface class for the MetadataSchema object. - * The implementation of this class is responsible for all database calls for the MetadataSchema object and is autowired by spring + * The implementation of this class is responsible for all database calls for the MetadataSchema object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/content/dao/MetadataValueDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/MetadataValueDAO.java index 48d57cd798..393de4d96c 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/MetadataValueDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/MetadataValueDAO.java @@ -7,18 +7,19 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; import org.dspace.core.Context; import org.dspace.core.GenericDAO; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Database Access Object interface class for the MetadataValue object. - * The implementation of this class is responsible for all database calls for the MetadataValue object and is autowired by spring + * The implementation of this class is responsible for all database calls for the MetadataValue object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -32,7 +33,7 @@ public interface MetadataValueDAO extends GenericDAO { public void deleteByMetadataField(Context context, MetadataField metadataField) throws SQLException; public MetadataValue getMinimum(Context context, int metadataFieldId) - throws SQLException; + throws SQLException; int countRows(Context context) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/dao/SiteDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/SiteDAO.java index da35c10a49..ba45b244c4 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/SiteDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/SiteDAO.java @@ -7,11 +7,11 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; + import org.dspace.content.Site; import org.dspace.core.Context; -import java.sql.SQLException; - /** * Database Access Object interface class for the Site object. * The implementation of this class is responsible for all database calls for the Site object and is autowired by spring diff --git a/dspace-api/src/main/java/org/dspace/content/dao/WorkspaceItemDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/WorkspaceItemDAO.java index 4d9f536c04..4ae8dc620b 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/WorkspaceItemDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/WorkspaceItemDAO.java @@ -7,6 +7,10 @@ */ package org.dspace.content.dao; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; @@ -14,13 +18,10 @@ import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; - /** * Database Access Object interface class for the WorkspaceItem object. - * The implementation of this class is responsible for all database calls for the WorkspaceItem object and is autowired by spring + * The implementation of this class is responsible for all database calls for the WorkspaceItem object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -29,12 +30,17 @@ public interface WorkspaceItemDAO extends GenericDAO { public List findByEPerson(Context context, EPerson ep) throws SQLException; + public List findByEPerson(Context context, EPerson ep, Integer limit, Integer offset) + throws SQLException; + public List findByCollection(Context context, Collection c) throws SQLException; public WorkspaceItem findByItem(Context context, Item i) throws SQLException; public List findAll(Context context) throws SQLException; + public List findAll(Context context, Integer limit, Integer offset) throws SQLException; + public List findWithSupervisedGroup(Context context) throws SQLException; public List findBySupervisedGroupMember(Context context, EPerson ePerson) throws SQLException; @@ -42,4 +48,7 @@ public interface WorkspaceItemDAO extends GenericDAO { int countRows(Context context) throws SQLException; List> getStageReachedCounts(Context context) throws SQLException; + + public int countRows(Context context, EPerson ep) throws SQLException; + } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamDAOImpl.java index 0008b9848b..02e3509c31 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamDAOImpl.java @@ -7,7 +7,18 @@ */ package org.dspace.content.dao.impl; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.dspace.content.Bitstream; +import org.dspace.content.Bitstream_; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; @@ -15,13 +26,6 @@ import org.dspace.content.dao.BitstreamDAO; import org.dspace.core.AbstractHibernateDSODAO; import org.dspace.core.Constants; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the Bitstream object. @@ -30,58 +34,53 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class BitstreamDAOImpl extends AbstractHibernateDSODAO implements BitstreamDAO -{ +public class BitstreamDAOImpl extends AbstractHibernateDSODAO implements BitstreamDAO { - protected BitstreamDAOImpl() - { + protected BitstreamDAOImpl() { super(); } @Override public List findDeletedBitstreams(Context context) throws SQLException { - Criteria criteria = createCriteria(context, Bitstream.class); - criteria.add(Restrictions.eq("deleted", true)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Bitstream.class); + Root bitstreamRoot = criteriaQuery.from(Bitstream.class); + criteriaQuery.select(bitstreamRoot); + criteriaQuery.where(criteriaBuilder.equal(bitstreamRoot.get(Bitstream_.deleted), true)); + return list(context, criteriaQuery, false, Bitstream.class, -1, -1); } @Override public List findDuplicateInternalIdentifier(Context context, Bitstream bitstream) throws SQLException { - Criteria criteria = createCriteria(context, Bitstream.class); - criteria.add(Restrictions.and( - Restrictions.eq("internalId", bitstream.getInternalId()), - Restrictions.not(Restrictions.eq("id", bitstream.getID())) - )); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Bitstream.class); + Root bitstreamRoot = criteriaQuery.from(Bitstream.class); + criteriaQuery.select(bitstreamRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(bitstreamRoot.get(Bitstream_.internalId), bitstream.getInternalId()), + criteriaBuilder.notEqual(bitstreamRoot.get(Bitstream_.id), bitstream.getID()) + ) + ); + return list(context, criteriaQuery, false, Bitstream.class, -1, -1); } @Override public List findBitstreamsWithNoRecentChecksum(Context context) throws SQLException { -// "select bitstream.deleted, bitstream.store_number, bitstream.size_bytes, " -// + "bitstreamformatregistry.short_description, bitstream.bitstream_id, " -// + "bitstream.user_format_description, bitstream.internal_id, " -// + "bitstream.source, bitstream.checksum_algorithm, bitstream.checksum, " -// + "bitstream.name, bitstream.description " -// + "from bitstream left outer join bitstreamformatregistry on " -// + "bitstream.bitstream_format_id = bitstreamformatregistry.bitstream_format_id " -// + "where not exists( select 'x' from most_recent_checksum " -// + "where most_recent_checksum.bitstream_id = bitstream.bitstream_id )" - - Query query = createQuery(context, "select b from Bitstream b where b not in (select c.bitstream from MostRecentChecksum c)"); - return query.list(); + Query query = createQuery(context, + "select b from Bitstream b where b not in (select c.bitstream from " + + "MostRecentChecksum c)"); + return query.getResultList(); } @Override public Iterator findByCommunity(Context context, Community community) throws SQLException { Query query = createQuery(context, "select b from Bitstream b " + - "join b.bundles bitBundles " + - "join bitBundles.items item " + - "join item.collections itemColl " + - "join itemColl.communities community " + - "WHERE :community IN community"); + "join b.bundles bitBundles " + + "join bitBundles.items item " + + "join item.collections itemColl " + + "join itemColl.communities community " + + "WHERE :community IN community"); query.setParameter("community", community); @@ -91,10 +90,10 @@ public class BitstreamDAOImpl extends AbstractHibernateDSODAO impleme @Override public Iterator findByCollection(Context context, Collection collection) throws SQLException { Query query = createQuery(context, "select b from Bitstream b " + - "join b.bundles bitBundles " + - "join bitBundles.items item " + - "join item.collections c " + - "WHERE :collection IN c"); + "join b.bundles bitBundles " + + "join bitBundles.items item " + + "join item.collections c " + + "WHERE :collection IN c"); query.setParameter("collection", collection); @@ -104,9 +103,9 @@ public class BitstreamDAOImpl extends AbstractHibernateDSODAO impleme @Override public Iterator findByItem(Context context, Item item) throws SQLException { Query query = createQuery(context, "select b from Bitstream b " + - "join b.bundles bitBundles " + - "join bitBundles.items item " + - "WHERE :item IN item"); + "join b.bundles bitBundles " + + "join bitBundles.items item " + + "WHERE :item IN item"); query.setParameter("item", item); @@ -122,9 +121,14 @@ public class BitstreamDAOImpl extends AbstractHibernateDSODAO impleme @Override public Long countByStoreNumber(Context context, Integer storeNumber) throws SQLException { - Criteria criteria = createCriteria(context, Bitstream.class); - criteria.add(Restrictions.eq("storeNumber", storeNumber)); - return countLong(criteria); + + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root bitstreamRoot = criteriaQuery.from(Bitstream.class); + criteriaQuery.where(criteriaBuilder.equal(bitstreamRoot.get(Bitstream_.storeNumber), storeNumber)); + return countLong(context, criteriaQuery, criteriaBuilder, bitstreamRoot); } @Override @@ -139,26 +143,27 @@ public class BitstreamDAOImpl extends AbstractHibernateDSODAO impleme @Override public int countWithNoPolicy(Context context) throws SQLException { - Query query = createQuery(context,"SELECT count(bit.id) from Bitstream bit where bit.deleted<>true and bit.id not in" + - " (select res.dSpaceObject from ResourcePolicy res where res.resourceTypeId = :typeId )" ); + Query query = createQuery(context, + "SELECT count(bit.id) from Bitstream bit where bit.deleted<>true and bit.id not in" + + " (select res.dSpaceObject from ResourcePolicy res where res.resourceTypeId = " + + ":typeId )"); query.setParameter("typeId", Constants.BITSTREAM); return count(query); } @Override public List getNotReferencedBitstreams(Context context) throws SQLException { - return list(createQuery(context,"select bit from Bitstream bit where bit.deleted != true" + - " and bit.id not in (select bit2.id from Bundle bun join bun.bitstreams bit2)" + - " and bit.id not in (select com.logo.id from Community com)" + - " and bit.id not in (select col.logo.id from Collection col)" + - " and bit.id not in (select bun.primaryBitstream.id from Bundle bun)")); + return list(createQuery(context, "select bit from Bitstream bit where bit.deleted != true" + + " and bit.id not in (select bit2.id from Bundle bun join bun.bitstreams bit2)" + + " and bit.id not in (select com.logo.id from Community com)" + + " and bit.id not in (select col.logo.id from Collection col)" + + " and bit.id not in (select bun.primaryBitstream.id from Bundle bun)")); } @Override public Iterator findAll(Context context, int limit, int offset) throws SQLException { - Query query = createQuery(context, "select b FROM Bitstream b"); - query.setFirstResult(offset); - query.setMaxResults(limit); - return iterate(query); + Map map = new HashMap<>(); + return findByX(context, Bitstream.class, map, true, limit, offset).iterator(); + } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamFormatDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamFormatDAOImpl.java index c25c198785..0824c5c343 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamFormatDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamFormatDAOImpl.java @@ -7,17 +7,19 @@ */ package org.dspace.content.dao.impl; -import org.dspace.content.BitstreamFormat; -import org.dspace.content.dao.BitstreamFormatDAO; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.content.BitstreamFormat; +import org.dspace.content.BitstreamFormat_; +import org.dspace.content.dao.BitstreamFormatDAO; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; /** * Hibernate implementation of the Database Access Object interface class for the BitstreamFormat object. @@ -26,11 +28,9 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class BitstreamFormatDAOImpl extends AbstractHibernateDAO implements BitstreamFormatDAO -{ +public class BitstreamFormatDAOImpl extends AbstractHibernateDAO implements BitstreamFormatDAO { - protected BitstreamFormatDAOImpl() - { + protected BitstreamFormatDAOImpl() { super(); } @@ -50,17 +50,20 @@ public class BitstreamFormatDAOImpl extends AbstractHibernateDAO bitstreamFormatRoot = criteriaQuery.from(BitstreamFormat.class); + criteriaQuery.select(bitstreamFormatRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(bitstreamFormatRoot.get(BitstreamFormat_.internal), includeInternal), + criteriaBuilder.like(bitstreamFormatRoot.get(BitstreamFormat_.mimetype), mimeType) + ) + ); + return singleResult(context, criteriaQuery); } /** @@ -77,20 +80,22 @@ public class BitstreamFormatDAOImpl extends AbstractHibernateDAO bitstreamFormatRoot = criteriaQuery.from(BitstreamFormat.class); + criteriaQuery.select(bitstreamFormatRoot); + criteriaQuery.where(criteriaBuilder.equal(bitstreamFormatRoot.get(BitstreamFormat_.shortDescription), desc)); + return uniqueResult(context, criteriaQuery, false, BitstreamFormat.class, -1, -1); } @Override - public int updateRemovedBitstreamFormat(Context context, BitstreamFormat deletedBitstreamFormat, BitstreamFormat newBitstreamFormat) throws SQLException { + public int updateRemovedBitstreamFormat(Context context, BitstreamFormat deletedBitstreamFormat, + BitstreamFormat newBitstreamFormat) throws SQLException { // Set bitstreams with this format to "unknown" - Query query = createQuery(context, "update Bitstream set bitstreamFormat = :unknown_format where bitstreamFormat = :deleted_format"); + Query query = createQuery(context, + "update Bitstream set bitstreamFormat = :unknown_format where bitstreamFormat = " + + ":deleted_format"); query.setParameter("unknown_format", newBitstreamFormat); query.setParameter("deleted_format", deletedBitstreamFormat); @@ -99,14 +104,28 @@ public class BitstreamFormatDAOImpl extends AbstractHibernateDAO findNonInternal(Context context) throws SQLException { - Criteria criteria = createCriteria(context, BitstreamFormat.class); - criteria.add(Restrictions.and( - Restrictions.eq("internal", false), - Restrictions.not(Restrictions.like("shortDescription", "Unknown")) - )); - criteria.addOrder(Order.desc("supportLevel")).addOrder(Order.asc("shortDescription")); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BitstreamFormat.class); + Root bitstreamFormatRoot = criteriaQuery.from(BitstreamFormat.class); + criteriaQuery.select(bitstreamFormatRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(bitstreamFormatRoot.get(BitstreamFormat_.internal), false), + criteriaBuilder.not( + criteriaBuilder + .like(bitstreamFormatRoot.get(BitstreamFormat_.shortDescription), + "Unknown")) + ) + ); + + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.desc(bitstreamFormatRoot.get(BitstreamFormat_.supportLevel))); + orderList.add(criteriaBuilder.asc(bitstreamFormatRoot.get(BitstreamFormat_.shortDescription))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, BitstreamFormat.class, -1, -1); } @@ -116,17 +135,22 @@ public class BitstreamFormatDAOImpl extends AbstractHibernateDAO findAll(Context context, Class clazz) throws SQLException { - Criteria criteria = createCriteria(context, BitstreamFormat.class); - criteria.addOrder(Order.asc("id")); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BitstreamFormat.class); + Root bitstreamFormatRoot = criteriaQuery.from(BitstreamFormat.class); + criteriaQuery.select(bitstreamFormatRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(bitstreamFormatRoot.get(BitstreamFormat_.id))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, false, BitstreamFormat.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/BundleDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/BundleDAOImpl.java index f1f6c0b826..9916361084 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/BundleDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/BundleDAOImpl.java @@ -7,13 +7,13 @@ */ package org.dspace.content.dao.impl; +import java.sql.SQLException; + import org.dspace.content.Bundle; import org.dspace.content.dao.BundleDAO; import org.dspace.core.AbstractHibernateDSODAO; import org.dspace.core.Context; -import java.sql.SQLException; - /** * Hibernate implementation of the Database Access Object interface class for the Bundle object. * This class is responsible for all database calls for the Bundle object and is autowired by spring @@ -21,10 +21,8 @@ import java.sql.SQLException; * * @author kevinvandevelde at atmire.com */ -public class BundleDAOImpl extends AbstractHibernateDSODAO implements BundleDAO -{ - protected BundleDAOImpl() - { +public class BundleDAOImpl extends AbstractHibernateDSODAO implements BundleDAO { + protected BundleDAOImpl() { super(); } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java index 051296697c..9180fb3c09 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java @@ -7,25 +7,31 @@ */ package org.dspace.content.dao.impl; +import java.sql.SQLException; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.dspace.authorize.ResourcePolicy; +import org.dspace.authorize.ResourcePolicy_; import org.dspace.content.Collection; +import org.dspace.content.Collection_; import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.dao.CollectionDAO; +import org.dspace.core.AbstractHibernateDSODAO; import org.dspace.core.Constants; import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDSODAO; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.Restrictions; -import org.hibernate.transform.BasicTransformerAdapter; - -import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import java.util.Map; /** * Hibernate implementation of the Database Access Object interface class for the Collection object. @@ -34,10 +40,8 @@ import java.util.Map; * * @author kevinvandevelde at atmire.com */ -public class CollectionDAOImpl extends AbstractHibernateDSODAO implements CollectionDAO -{ - protected CollectionDAOImpl() - { +public class CollectionDAOImpl extends AbstractHibernateDSODAO implements CollectionDAO { + protected CollectionDAOImpl() { super(); } @@ -52,24 +56,24 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO imple * @throws SQLException if database error */ @Override - public List findAll(Context context, MetadataField order) throws SQLException - { + public List findAll(Context context, MetadataField order) throws SQLException { return findAll(context, order, null, null); } @Override - public List findAll(Context context, MetadataField order, Integer limit, Integer offset) throws SQLException { + public List findAll(Context context, MetadataField order, Integer limit, Integer offset) + throws SQLException { StringBuilder query = new StringBuilder(); - query.append("SELECT ").append(Collection.class.getSimpleName()).append(" FROM Collection as ").append(Collection.class.getSimpleName()).append(" "); + query.append("SELECT ").append(Collection.class.getSimpleName()).append(" FROM Collection as ") + .append(Collection.class.getSimpleName()).append(" "); addMetadataLeftJoin(query, Collection.class.getSimpleName(), Arrays.asList(order)); addMetadataSortQuery(query, Arrays.asList(order), null); Query hibernateQuery = createQuery(context, query.toString()); - if(offset != null) - { + if (offset != null) { hibernateQuery.setFirstResult(offset); } - if(limit != null){ + if (limit != null) { hibernateQuery.setMaxResults(limit); } hibernateQuery.setParameter(order.toString(), order.getID()); @@ -78,93 +82,72 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO imple @Override public Collection findByTemplateItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, Collection.class); - criteria.add(Restrictions.eq("template_item", item)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Collection.class); + Root collectionRoot = criteriaQuery.from(Collection.class); + criteriaQuery.select(collectionRoot); + criteriaQuery.where(criteriaBuilder.equal(collectionRoot.get(Collection_.template), item)); + return uniqueResult(context, criteriaQuery, false, Collection.class, -1, -1); } @Override public Collection findByGroup(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, Collection.class); - criteria.add( - Restrictions.or( - Restrictions.eq("workflowStep1", group), - Restrictions.eq("workflowStep2", group), - Restrictions.eq("workflowStep3", group), - Restrictions.eq("submitters", group), - Restrictions.eq("admins", group) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Collection.class); + Root collectionRoot = criteriaQuery.from(Collection.class); + criteriaQuery.select(collectionRoot); + criteriaQuery + .where(criteriaBuilder.or(criteriaBuilder.equal(collectionRoot.get(Collection_.workflowStep1), group), + criteriaBuilder.equal(collectionRoot.get(Collection_.workflowStep2), group), + criteriaBuilder.equal(collectionRoot.get(Collection_.workflowStep3), group), + criteriaBuilder.equal(collectionRoot.get(Collection_.submitters), group), + criteriaBuilder.equal(collectionRoot.get(Collection_.admins), group) + ) ); - return singleResult(criteria); + return singleResult(context, criteriaQuery); } @Override - public List findAuthorized(Context context, EPerson ePerson, List actions) throws SQLException { - // TableRowIterator tri = DatabaseManager.query(context, -// "SELECT * FROM collection, resourcepolicy, eperson " + -// "WHERE resourcepolicy.resource_id = collection.collection_id AND " + -// "eperson.eperson_id = resourcepolicy.eperson_id AND "+ -// "resourcepolicy.resource_type_id = 3 AND "+ -// "( resourcepolicy.action_id = 3 OR resourcepolicy.action_id = 11 ) AND "+ -// "eperson.eperson_id = ?", context.getCurrentUser().getID()); - - Criteria criteria = createCriteria(context, Collection.class); - criteria.createAlias("resourcePolicies", "resourcePolicy"); - - Disjunction actionQuery = Restrictions.or(); - for (Integer action : actions) - { - actionQuery.add(Restrictions.eq("resourcePolicy.actionId", action)); + public List findAuthorized(Context context, EPerson ePerson, List actions) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Collection.class); + Root collectionRoot = criteriaQuery.from(Collection.class); + Join join = collectionRoot.join("resourcePolicies"); + List orPredicates = new LinkedList(); + for (Integer action : actions) { + orPredicates.add(criteriaBuilder.equal(join.get(ResourcePolicy_.actionId), action)); } - criteria.add(Restrictions.and( - Restrictions.eq("resourcePolicy.resourceTypeId", Constants.COLLECTION), - Restrictions.eq("resourcePolicy.eperson", ePerson), - actionQuery - )); - criteria.setCacheable(true); - - return list(criteria); + Predicate orPredicate = criteriaBuilder.or(orPredicates.toArray(new Predicate[] {})); + criteriaQuery.select(collectionRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(join.get(ResourcePolicy_.resourceTypeId), Constants.COLLECTION), + criteriaBuilder.equal(join.get(ResourcePolicy_.eperson), ePerson), + orPredicate)); + return list(context, criteriaQuery, true, Collection.class, -1, -1); } @Override - public List findAuthorizedByGroup(Context context, EPerson ePerson, List actions) throws SQLException { - // TableRowIterator tri = DatabaseManager.query(context, - // "SELECT \n" + - // " * \n" + - // "FROM \n" + - // " public.eperson, \n" + - // " public.epersongroup2eperson, \n" + - // " public.epersongroup, \n" + - // " public.group2group, \n" + - // " public.resourcepolicy rp_parent, \n" + - // " public.collection\n" + - // "WHERE \n" + - // " epersongroup2eperson.eperson_id = eperson.eperson_id AND\n" + - // " epersongroup.eperson_group_id = epersongroup2eperson.eperson_group_id AND\n" + - // " group2group.child_id = epersongroup.eperson_group_id AND\n" + - // " rp_parent.epersongroup_id = group2group.parent_id AND\n" + - // " collection.collection_id = rp_parent.resource_id AND\n" + - // " eperson.eperson_id = ? AND \n" + - // " (rp_parent.action_id = 3 OR \n" + - // " rp_parent.action_id = 11 \n" + - // " ) AND rp_parent.resource_type_id = 3;", context.getCurrentUser().getID()); + public List findAuthorizedByGroup(Context context, EPerson ePerson, List actions) + throws SQLException { StringBuilder query = new StringBuilder(); query.append("select c from Collection c join c.resourcePolicies rp join rp.epersonGroup rpGroup WHERE "); for (int i = 0; i < actions.size(); i++) { Integer action = actions.get(i); - if(i != 0) - { + if (i != 0) { query.append(" AND "); } query.append("rp.actionId=").append(action); } query.append(" AND rp.resourceTypeId=").append(Constants.COLLECTION); - query.append(" AND rp.epersonGroup.id IN (select g.id from Group g where (from EPerson e where e.id = :eperson_id) in elements(epeople))"); - Query hibernateQuery = createQuery(context, query.toString()); - hibernateQuery.setParameter("eperson_id", ePerson.getID()); - hibernateQuery.setCacheable(true); + query.append( + " AND rp.epersonGroup.id IN (select g.id from Group g where (from EPerson e where e.id = :eperson_id) in " + + "elements(epeople))"); + Query persistenceQuery = createQuery(context, query.toString()); + persistenceQuery.setParameter("eperson_id", ePerson.getID()); + persistenceQuery.setHint("org.hibernate.cacheable", Boolean.TRUE); - return list(hibernateQuery); + return list(persistenceQuery); } @@ -181,15 +164,17 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO imple @Override @SuppressWarnings("unchecked") - public List> getCollectionsWithBitstreamSizesTotal(Context context) throws SQLException { - String q = "select col as collection, sum(bit.sizeBytes) as totalBytes from Item i join i.collections col join i.bundles bun join bun.bitstreams bit group by col"; + public List> getCollectionsWithBitstreamSizesTotal(Context context) + throws SQLException { + String q = "select col as collection, sum(bit.sizeBytes) as totalBytes from Item i join i.collections col " + + "join i.bundles bun join bun.bitstreams bit group by col"; Query query = createQuery(context, q); - query.setResultTransformer(new BasicTransformerAdapter() { - @Override - public Object transformTuple(Object[] tuple, String[] aliases) { - return new java.util.AbstractMap.SimpleImmutableEntry<>((Collection)tuple[0], (Long)tuple[1]); - } - }); - return ((List>)query.list()); + + List list = query.getResultList(); + List> returnList = new LinkedList<>(); + for (Object[] o : list) { + returnList.add(new AbstractMap.SimpleEntry<>((Collection) o[0], (Long) o[1])); + } + return returnList; } } \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/CommunityDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/CommunityDAOImpl.java index b18141a9a3..67bbd18d91 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/CommunityDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/CommunityDAOImpl.java @@ -7,23 +7,29 @@ */ package org.dspace.content.dao.impl; -import org.apache.commons.collections.ListUtils; -import org.dspace.content.Community; -import org.dspace.content.MetadataField; -import org.dspace.content.dao.CommunityDAO; -import org.dspace.core.Constants; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDSODAO; -import org.dspace.eperson.EPerson; -import org.dspace.eperson.Group; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.dspace.authorize.ResourcePolicy; +import org.dspace.authorize.ResourcePolicy_; +import org.dspace.content.Community; +import org.dspace.content.Community_; +import org.dspace.content.MetadataField; +import org.dspace.content.dao.CommunityDAO; +import org.dspace.core.AbstractHibernateDSODAO; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; /** * Hibernate implementation of the Database Access Object interface class for the Community object. @@ -32,10 +38,8 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class CommunityDAOImpl extends AbstractHibernateDSODAO implements CommunityDAO -{ - protected CommunityDAOImpl() - { +public class CommunityDAOImpl extends AbstractHibernateDSODAO implements CommunityDAO { + protected CommunityDAOImpl() { super(); } @@ -50,24 +54,24 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme * @throws SQLException if database error */ @Override - public List findAll(Context context, MetadataField sortField) throws SQLException - { + public List findAll(Context context, MetadataField sortField) throws SQLException { return findAll(context, sortField, null, null); } @Override - public List findAll(Context context, MetadataField sortField, Integer limit, Integer offset) throws SQLException { + public List findAll(Context context, MetadataField sortField, Integer limit, Integer offset) + throws SQLException { StringBuilder queryBuilder = new StringBuilder(); - queryBuilder.append("SELECT ").append(Community.class.getSimpleName()).append(" FROM Community as ").append(Community.class.getSimpleName()).append(" "); + queryBuilder.append("SELECT ").append(Community.class.getSimpleName()).append(" FROM Community as ") + .append(Community.class.getSimpleName()).append(" "); addMetadataLeftJoin(queryBuilder, Community.class.getSimpleName(), Arrays.asList(sortField)); - addMetadataSortQuery(queryBuilder, Arrays.asList(sortField), ListUtils.EMPTY_LIST); + addMetadataSortQuery(queryBuilder, Arrays.asList(sortField), Collections.EMPTY_LIST); Query query = createQuery(context, queryBuilder.toString()); - if(offset != null) - { + if (offset != null) { query.setFirstResult(offset); } - if(limit != null){ + if (limit != null) { query.setMaxResults(limit); } query.setParameter(sortField.toString(), sortField.getID()); @@ -76,9 +80,12 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme @Override public Community findByAdminGroup(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, Community.class); - criteria.add(Restrictions.eq("admins", group)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Community.class); + Root communityRoot = criteriaQuery.from(Community.class); + criteriaQuery.select(communityRoot); + criteriaQuery.where(criteriaBuilder.equal(communityRoot.get(Community_.admins), group)); + return singleResult(context, criteriaQuery); } @Override @@ -86,12 +93,13 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme StringBuilder queryBuilder = new StringBuilder(); queryBuilder.append("SELECT community FROM Community as community "); addMetadataLeftJoin(queryBuilder, Community.class.getSimpleName().toLowerCase(), Arrays.asList(sortField)); - addMetadataValueWhereQuery(queryBuilder, ListUtils.EMPTY_LIST, null, " community.parentCommunities IS EMPTY"); - addMetadataSortQuery(queryBuilder, Arrays.asList(sortField), ListUtils.EMPTY_LIST); + addMetadataValueWhereQuery(queryBuilder, Collections.EMPTY_LIST, null, " community.parentCommunities IS EMPTY"); + addMetadataSortQuery(queryBuilder, Arrays.asList(sortField), Collections.EMPTY_LIST); Query query = createQuery(context, queryBuilder.toString()); query.setParameter(sortField.toString(), sortField.getID()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); + return findMany(context, query); } @@ -115,61 +123,51 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme " resourcepolicy.resource_id = community.community_id AND\n" + " ( resourcepolicy.action_id = 3 OR \n" + " resourcepolicy.action_id = 11) AND \n" + - " resourcepolicy.resource_type_id = 4 AND eperson.eperson_id = ?", context.getCurrentUser().getID()); + " resourcepolicy.resource_type_id = 4 AND eperson.eperson_id = ?", context.getCurrentUser() + .getID()); */ - Criteria criteria = createCriteria(context, Community.class); - criteria.createAlias("resourcePolicies", "resourcePolicy"); - Disjunction actionQuery = Restrictions.or(); - for (Integer action : actions) - { - actionQuery.add(Restrictions.eq("resourcePolicy.actionId", action)); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Community.class); + Root communityRoot = criteriaQuery.from(Community.class); + Join join = communityRoot.join("resourcePolicies"); + List orPredicates = new LinkedList(); + for (Integer action : actions) { + orPredicates.add(criteriaBuilder.equal(join.get(ResourcePolicy_.actionId), action)); } - criteria.add(Restrictions.and( - Restrictions.eq("resourcePolicy.resourceTypeId", Constants.COMMUNITY), - Restrictions.eq("resourcePolicy.eperson", ePerson), - actionQuery - )); - criteria.setCacheable(true); - - return list(criteria); + Predicate orPredicate = criteriaBuilder.or(orPredicates.toArray(new Predicate[] {})); + criteriaQuery.select(communityRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(join.get(ResourcePolicy_.resourceTypeId), Constants.COMMUNITY), + criteriaBuilder.equal(join.get(ResourcePolicy_.eperson), ePerson), + orPredicate + ) + ); + return list(context, criteriaQuery, true, Community.class, -1, -1); } @Override - public List findAuthorizedByGroup(Context context, EPerson ePerson, List actions) throws SQLException { -// "SELECT \n" + -// " * \n" + -// "FROM \n" + -// " public.eperson, \n" + -// " public.epersongroup2eperson, \n" + -// " public.epersongroup, \n" + -// " public.community, \n" + -// " public.resourcepolicy\n" + -// "WHERE \n" + -// " epersongroup2eperson.eperson_id = eperson.eperson_id AND\n" + -// " epersongroup.eperson_group_id = epersongroup2eperson.eperson_group_id AND\n" + -// " resourcepolicy.epersongroup_id = epersongroup.eperson_group_id AND\n" + -// " resourcepolicy.resource_id = community.community_id AND\n" + -// " ( resourcepolicy.action_id = 3 OR \n" + -// " resourcepolicy.action_id = 11) AND \n" + -// " resourcepolicy.resource_type_id = 4 AND eperson.eperson_id = ?", context.getCurrentUser().getID()); + public List findAuthorizedByGroup(Context context, EPerson ePerson, List actions) + throws SQLException { StringBuilder query = new StringBuilder(); query.append("select c from Community c join c.resourcePolicies rp join rp.epersonGroup rpGroup WHERE "); for (int i = 0; i < actions.size(); i++) { Integer action = actions.get(i); - if(i != 0) - { + if (i != 0) { query.append(" AND "); } query.append("rp.actionId=").append(action); } query.append(" AND rp.resourceTypeId=").append(Constants.COMMUNITY); - query.append(" AND rp.epersonGroup.id IN (select g.id from Group g where (from EPerson e where e.id = :eperson_id) in elements(epeople))"); - Query hibernateQuery = createQuery(context, query.toString()); - hibernateQuery.setParameter("eperson_id", ePerson.getID()); - hibernateQuery.setCacheable(true); + query.append( + " AND rp.epersonGroup.id IN (select g.id from Group g where (from EPerson e where e.id = :eperson_id) in " + + "elements(epeople))"); + Query persistenceQuery = createQuery(context, query.toString()); + persistenceQuery.setParameter("eperson_id", ePerson.getID()); - return list(hibernateQuery); + persistenceQuery.setHint("org.hibernate.cacheable", Boolean.TRUE); + + return list(persistenceQuery); } @Override diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java index bfc16f0c62..67644ee7b4 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java @@ -7,30 +7,32 @@ */ package org.dspace.content.dao.impl; -import org.apache.log4j.Logger; -import org.dspace.content.Collection; -import org.dspace.content.Item; -import org.dspace.content.MetadataField; -import org.dspace.content.MetadataValue; -import org.dspace.content.dao.ItemDAO; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDSODAO; -import org.dspace.eperson.EPerson; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.DetachedCriteria; -import org.hibernate.criterion.Projections; -import org.hibernate.criterion.Property; -import org.hibernate.criterion.Restrictions; -import org.hibernate.criterion.Subqueries; -import org.hibernate.type.StandardBasicTypes; - import java.sql.SQLException; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.UUID; +import javax.persistence.Query; +import javax.persistence.TemporalType; + +import org.apache.log4j.Logger; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataValue; +import org.dspace.content.dao.ItemDAO; +import org.dspace.core.AbstractHibernateDSODAO; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.hibernate.Criteria; +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.DetachedCriteria; +import org.hibernate.criterion.Projections; +import org.hibernate.criterion.Property; +import org.hibernate.criterion.Restrictions; +import org.hibernate.criterion.Subqueries; +import org.hibernate.type.StandardBasicTypes; /** * Hibernate implementation of the Database Access Object interface class for the Item object. @@ -39,12 +41,10 @@ import java.util.UUID; * * @author kevinvandevelde at atmire.com */ -public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDAO -{ +public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDAO { private static final Logger log = Logger.getLogger(ItemDAOImpl.class); - protected ItemDAOImpl() - { + protected ItemDAOImpl() { super(); } @@ -64,7 +64,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA return iterate(query); } - + @Override public Iterator findAll(Context context, boolean archived, boolean withdrawn) throws SQLException { Query query = createQuery(context, "FROM Item WHERE inArchive= :in_archive or withdrawn = :withdrawn"); @@ -75,16 +75,14 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public Iterator findAll(Context context, boolean archived, - boolean withdrawn, boolean discoverable, Date lastModified) - throws SQLException - { + boolean withdrawn, boolean discoverable, Date lastModified) + throws SQLException { StringBuilder queryStr = new StringBuilder(); queryStr.append("SELECT i FROM Item i"); queryStr.append(" WHERE (inArchive = :in_archive OR withdrawn = :withdrawn)"); queryStr.append(" AND discoverable = :discoverable"); - if(lastModified != null) - { + if (lastModified != null) { queryStr.append(" AND last_modified > :last_modified"); } @@ -92,10 +90,9 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA query.setParameter("in_archive", archived); query.setParameter("withdrawn", withdrawn); query.setParameter("discoverable", discoverable); - if(lastModified != null) - { - query.setTimestamp("last_modified", lastModified); - } + if (lastModified != null) { + query.setParameter("last_modified", lastModified, TemporalType.TIMESTAMP); + } return iterate(query); } @@ -108,7 +105,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA } @Override - public Iterator findBySubmitter(Context context, EPerson eperson, MetadataField metadataField, int limit) throws SQLException { + public Iterator findBySubmitter(Context context, EPerson eperson, MetadataField metadataField, int limit) + throws SQLException { StringBuilder query = new StringBuilder(); query.append("SELECT item FROM Item as item "); addMetadataLeftJoin(query, Item.class.getSimpleName().toLowerCase(), Collections.singletonList(metadataField)); @@ -126,93 +124,142 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA } @Override - public Iterator findByMetadataField(Context context, MetadataField metadataField, String value, boolean inArchive) throws SQLException { - String hqlQueryString = "SELECT item FROM Item as item join item.metadata metadatavalue WHERE item.inArchive=:in_archive AND metadatavalue.metadataField = :metadata_field"; - if(value != null) - { + public Iterator findByMetadataField(Context context, MetadataField metadataField, String value, + boolean inArchive) throws SQLException { + String hqlQueryString = "SELECT item FROM Item as item join item.metadata metadatavalue WHERE item" + + ".inArchive=:in_archive AND metadatavalue.metadataField = :metadata_field"; + if (value != null) { hqlQueryString += " AND STR(metadatavalue.value) = :text_value"; } Query query = createQuery(context, hqlQueryString); query.setParameter("in_archive", inArchive); query.setParameter("metadata_field", metadataField); - if(value != null) - { + if (value != null) { query.setParameter("text_value", value); } return iterate(query); } - enum OP {equals,not_equals,like,not_like,contains,doesnt_contain,exists,doesnt_exist,matches,doesnt_match;} - - @Override - public Iterator findByMetadataQuery(Context context, List> listFieldList, List query_op, List query_val, List collectionUuids, String regexClause, int offset, int limit) throws SQLException { - Criteria criteria = createCriteria(context, Item.class, "item"); - criteria.setFirstResult(offset); - criteria.setMaxResults(limit); - - if (!collectionUuids.isEmpty()){ - DetachedCriteria dcollCriteria = DetachedCriteria.forClass(Collection.class, "coll"); - dcollCriteria.setProjection(Projections.property("coll.id")); - dcollCriteria.add(Restrictions.eqProperty("coll.id", "item.owningCollection")); - dcollCriteria.add(Restrictions.in("coll.id", collectionUuids)); - criteria.add(Subqueries.exists(dcollCriteria)); - } - - int index = Math.min(listFieldList.size(), Math.min(query_op.size(), query_val.size())); - StringBuilder sb = new StringBuilder(); + enum OP { + equals { + public Criterion buildPredicate(String val, String regexClause) { + return Property.forName("mv.value").eq(val); + } + }, + not_equals { + public Criterion buildPredicate(String val, String regexClause) { + return OP.equals.buildPredicate(val, regexClause); + } + }, + like { + public Criterion buildPredicate(String val, String regexClause) { + return Property.forName("mv.value").like(val); + } + }, + not_like { + public Criterion buildPredicate(String val, String regexClause) { + return OP.like.buildPredicate(val, regexClause); + } + }, + contains { + public Criterion buildPredicate(String val, String regexClause) { + return Property.forName("mv.value").like("%" + val + "%"); + } + }, + doesnt_contain { + public Criterion buildPredicate(String val, String regexClause) { + return OP.contains.buildPredicate(val, regexClause); + } + }, + exists { + public Criterion buildPredicate(String val, String regexClause) { + return Property.forName("mv.value").isNotNull(); + } + }, + doesnt_exist { + public Criterion buildPredicate(String val, String regexClause) { + return OP.exists.buildPredicate(val, regexClause); + } + }, + matches { + public Criterion buildPredicate(String val, String regexClause) { + return Restrictions.sqlRestriction(regexClause, val, StandardBasicTypes.STRING); + } + }, + doesnt_match { + public Criterion buildPredicate(String val, String regexClause) { + return OP.matches.buildPredicate(val, regexClause); + } - for(int i=0; i findByAuthorityValue(Context context, MetadataField metadataField, String authority, boolean inArchive) throws SQLException { - Query query = createQuery(context, "SELECT item FROM Item as item join item.metadata metadatavalue WHERE item.inArchive=:in_archive AND metadatavalue.metadataField = :metadata_field AND metadatavalue.authority = :authority"); + @Deprecated + public Iterator findByMetadataQuery(Context context, List> listFieldList, + List query_op, List query_val, List collectionUuids, + String regexClause, int offset, int limit) throws SQLException { + + Criteria criteria = getHibernateSession(context).createCriteria(Item.class, "item"); + criteria.setFirstResult(offset); + criteria.setMaxResults(limit); + + if (!collectionUuids.isEmpty()) { + DetachedCriteria dcollCriteria = DetachedCriteria.forClass(Collection.class, "coll"); + dcollCriteria.setProjection(Projections.property("coll.id")); + dcollCriteria.add(Restrictions.eqProperty("coll.id", "item.owningCollection")); + dcollCriteria.add(Restrictions.in("coll.id", collectionUuids)); + criteria.add(Subqueries.exists(dcollCriteria)); + } + + int index = Math.min(listFieldList.size(), Math.min(query_op.size(), query_val.size())); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < index; i++) { + OP op = OP.valueOf(query_op.get(i)); + if (op == null) { + log.warn("Skipping Invalid Operator: " + query_op.get(i)); + continue; + } + + if (op == OP.matches || op == OP.doesnt_match) { + if (regexClause.isEmpty()) { + log.warn("Skipping Unsupported Regex Operator: " + query_op.get(i)); + continue; + } + } + + DetachedCriteria subcriteria = DetachedCriteria.forClass(MetadataValue.class, "mv"); + subcriteria.add(Property.forName("mv.dSpaceObject").eqProperty("item.id")); + subcriteria.setProjection(Projections.property("mv.dSpaceObject")); + + if (!listFieldList.get(i).isEmpty()) { + subcriteria.add(Restrictions.in("metadataField", listFieldList.get(i))); + } + + subcriteria.add(op.buildPredicate(query_val.get(i), regexClause)); + + if (op == OP.exists || op == OP.equals || op == OP.like || op == OP.contains || op == OP.matches) { + criteria.add(Subqueries.exists(subcriteria)); + } else { + criteria.add(Subqueries.notExists(subcriteria)); + } + } + log.debug(String.format("Running custom query with %d filters", index)); + + return ((List) criteria.list()).iterator(); + + } + + @Override + public Iterator findByAuthorityValue(Context context, MetadataField metadataField, String authority, + boolean inArchive) throws SQLException { + Query query = createQuery(context, + "SELECT item FROM Item as item join item.metadata metadatavalue WHERE item" + + ".inArchive=:in_archive AND metadatavalue.metadataField = :metadata_field AND " + + "metadatavalue.authority = :authority"); query.setParameter("in_archive", inArchive); query.setParameter("metadata_field", metadataField); query.setParameter("authority", authority); @@ -220,16 +267,17 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA } @Override - public Iterator findArchivedByCollection(Context context, Collection collection, Integer limit, Integer offset) throws SQLException { - Query query = createQuery(context, "select i from Item i join i.collections c WHERE :collection IN c AND i.inArchive=:in_archive"); + public Iterator findArchivedByCollection(Context context, Collection collection, Integer limit, + Integer offset) throws SQLException { + Query query = createQuery(context, + "select i from Item i join i.collections c WHERE :collection IN c AND i" + + ".inArchive=:in_archive"); query.setParameter("collection", collection); query.setParameter("in_archive", true); - if(offset != null) - { + if (offset != null) { query.setFirstResult(offset); } - if(limit != null) - { + if (limit != null) { query.setMaxResults(limit); } return iterate(query); @@ -244,24 +292,44 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA } @Override - public int countItems(Context context, Collection collection, boolean includeArchived, boolean includeWithdrawn) throws SQLException { - Query query = createQuery(context, "select count(i) from Item i join i.collections c WHERE :collection IN c AND i.inArchive=:in_archive AND i.withdrawn=:withdrawn"); + public Iterator findAllByCollection(Context context, Collection collection, Integer limit, Integer offset) + throws SQLException { + Query query = createQuery(context, "select i from Item i join i.collections c WHERE :collection IN c"); + query.setParameter("collection", collection); + + if (offset != null) { + query.setFirstResult(offset); + } + if (limit != null) { + query.setMaxResults(limit); + } + + return iterate(query); + } + + @Override + public int countItems(Context context, Collection collection, boolean includeArchived, boolean includeWithdrawn) + throws SQLException { + Query query = createQuery(context, + "select count(i) from Item i join i.collections c WHERE :collection IN c AND i" + + ".inArchive=:in_archive AND i.withdrawn=:withdrawn"); query.setParameter("collection", collection); query.setParameter("in_archive", includeArchived); query.setParameter("withdrawn", includeWithdrawn); return count(query); } - + @Override - public int countItems(Context context, List collections, boolean includeArchived, boolean includeWithdrawn) throws SQLException { + public int countItems(Context context, List collections, boolean includeArchived, + boolean includeWithdrawn) throws SQLException { if (collections.size() == 0) { return 0; } Query query = createQuery(context, "select count(distinct i) from Item i " + - "join i.collections collection " + - "WHERE collection IN (:collections) AND i.inArchive=:in_archive AND i.withdrawn=:withdrawn"); - query.setParameterList("collections", collections); + "join i.collections collection " + + "WHERE collection IN (:collections) AND i.inArchive=:in_archive AND i.withdrawn=:withdrawn"); + query.setParameter("collections", collections); query.setParameter("in_archive", includeArchived); query.setParameter("withdrawn", includeWithdrawn); @@ -270,10 +338,9 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public Iterator findByLastModifiedSince(Context context, Date since) - throws SQLException - { + throws SQLException { Query query = createQuery(context, "SELECT i FROM item i WHERE last_modified > :last_modified"); - query.setTimestamp("last_modified", since); + query.setParameter("last_modified", since, TemporalType.TIMESTAMP); return iterate(query); } @@ -284,9 +351,11 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public int countItems(Context context, boolean includeArchived, boolean includeWithdrawn) throws SQLException { - Query query = createQuery(context, "SELECT count(*) FROM Item i WHERE i.inArchive=:in_archive AND i.withdrawn=:withdrawn"); + Query query = createQuery(context, + "SELECT count(*) FROM Item i WHERE i.inArchive=:in_archive AND i" + + ".withdrawn=:withdrawn"); query.setParameter("in_archive", includeArchived); query.setParameter("withdrawn", includeWithdrawn); - return count(query); + return count(query); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataFieldDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataFieldDAOImpl.java index 8902a89c5c..de517765ba 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataFieldDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataFieldDAOImpl.java @@ -7,18 +7,23 @@ */ package org.dspace.content.dao.impl; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; + +import org.apache.commons.lang.StringUtils; import org.dspace.content.MetadataField; +import org.dspace.content.MetadataField_; import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchema_; import org.dspace.content.dao.MetadataFieldDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.FetchMode; -import org.hibernate.Query; -import org.hibernate.criterion.Order; - -import java.sql.SQLException; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the MetadataField object. @@ -27,120 +32,128 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class MetadataFieldDAOImpl extends AbstractHibernateDAO implements MetadataFieldDAO -{ - protected MetadataFieldDAOImpl() - { +public class MetadataFieldDAOImpl extends AbstractHibernateDAO implements MetadataFieldDAO { + protected MetadataFieldDAOImpl() { super(); } @Override public MetadataField find(Context context, int metadataFieldId, MetadataSchema metadataSchema, String element, - String qualifier) throws SQLException{ + String qualifier) throws SQLException { Query query; - if(qualifier != null) { + if (qualifier != null) { query = createQuery(context, "SELECT mf " + - "FROM MetadataField mf " + - "JOIN FETCH mf.metadataSchema ms " + - "WHERE mf.id != :id " + - "AND ms.name = :name AND mf.element = :element " + - "AND qualifier = :qualifier"); + "FROM MetadataField mf " + + "JOIN FETCH mf.metadataSchema ms " + + "WHERE mf.id != :id " + + "AND ms.name = :name AND mf.element = :element " + + "AND qualifier = :qualifier"); } else { query = createQuery(context, "SELECT mf " + - "FROM MetadataField mf " + - "JOIN FETCH mf.metadataSchema ms " + - "WHERE mf.id != :id " + - "AND ms.name = :name AND mf.element = :element " + - "AND mf.qualifier IS NULL"); + "FROM MetadataField mf " + + "JOIN FETCH mf.metadataSchema ms " + + "WHERE mf.id != :id " + + "AND ms.name = :name AND mf.element = :element " + + "AND mf.qualifier IS NULL"); } query.setParameter("id", metadataFieldId); query.setParameter("name", metadataSchema.getName()); query.setParameter("element", element); - if(qualifier != null) { + if (qualifier != null) { query.setParameter("qualifier", qualifier); } + query.setHint("org.hibernate.cacheable", Boolean.TRUE); - query.setCacheable(true); return singleResult(query); } @Override - public MetadataField findByElement(Context context, MetadataSchema metadataSchema, String element, String qualifier) throws SQLException - { + public MetadataField findByElement(Context context, MetadataSchema metadataSchema, String element, String qualifier) + throws SQLException { return findByElement(context, metadataSchema.getName(), element, qualifier); } @Override - public MetadataField findByElement(Context context, String metadataSchema, String element, String qualifier) throws SQLException - { + public MetadataField findByElement(Context context, String metadataSchema, String element, String qualifier) + throws SQLException { Query query; - if(qualifier != null) { + if (StringUtils.isNotBlank(qualifier)) { query = createQuery(context, "SELECT mf " + - "FROM MetadataField mf " + - "JOIN FETCH mf.metadataSchema ms " + - "WHERE ms.name = :name AND mf.element = :element " + - "AND qualifier = :qualifier"); + "FROM MetadataField mf " + + "JOIN FETCH mf.metadataSchema ms " + + "WHERE ms.name = :name AND mf.element = :element " + + "AND qualifier = :qualifier"); } else { query = createQuery(context, "SELECT mf " + - "FROM MetadataField mf " + - "JOIN FETCH mf.metadataSchema ms " + - "WHERE ms.name = :name AND mf.element = :element " + - "AND mf.qualifier IS NULL"); + "FROM MetadataField mf " + + "JOIN FETCH mf.metadataSchema ms " + + "WHERE ms.name = :name AND mf.element = :element " + + "AND mf.qualifier IS NULL"); } query.setParameter("name", metadataSchema); query.setParameter("element", element); - if(qualifier != null) { + if (StringUtils.isNotBlank(qualifier)) { query.setParameter("qualifier", qualifier); } + query.setHint("org.hibernate.cacheable", Boolean.TRUE); - query.setCacheable(true); return singleResult(query); } @Override public List findAll(Context context, Class clazz) throws SQLException { - Criteria criteria = createCriteria(context, MetadataField.class); - criteria.createAlias("metadataSchema", "s").addOrder(Order.asc("s.name")).addOrder(Order.asc("element")).addOrder(Order.asc("qualifier")); - criteria.setFetchMode("metadataSchema", FetchMode.JOIN); - criteria.setCacheable(true); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MetadataField.class); + Root metadataFieldRoot = criteriaQuery.from(MetadataField.class); + Join join = metadataFieldRoot.join("metadataSchema"); + criteriaQuery.select(metadataFieldRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(join.get(MetadataSchema_.name))); + orderList.add(criteriaBuilder.asc(metadataFieldRoot.get(MetadataField_.element))); + orderList.add(criteriaBuilder.asc(metadataFieldRoot.get(MetadataField_.qualifier))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, true, MetadataField.class, -1, -1, false); } @Override - public List findFieldsByElementNameUnqualified(Context context, String metadataSchema, String element) throws SQLException - { + public List findFieldsByElementNameUnqualified(Context context, String metadataSchema, + String element) throws SQLException { Query query = createQuery(context, "SELECT mf " + - "FROM MetadataField mf " + - "JOIN FETCH mf.metadataSchema ms " + - "WHERE ms.name = :name AND mf.element = :element "); + "FROM MetadataField mf " + + "JOIN FETCH mf.metadataSchema ms " + + "WHERE ms.name = :name AND mf.element = :element "); query.setParameter("name", metadataSchema); query.setParameter("element", element); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); - query.setCacheable(true); return list(query); } - + @Override public List findAllInSchema(Context context, MetadataSchema metadataSchema) throws SQLException { Query query = createQuery(context, "SELECT mf " + - "FROM MetadataField mf " + - "JOIN FETCH mf.metadataSchema ms " + - "WHERE ms.name = :name " + - "ORDER BY mf.element ASC, mf.qualifier ASC "); + "FROM MetadataField mf " + + "JOIN FETCH mf.metadataSchema ms " + + "WHERE ms.name = :name " + + "ORDER BY mf.element ASC, mf.qualifier ASC "); query.setParameter("name", metadataSchema.getName()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); + return list(query); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataSchemaDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataSchemaDAOImpl.java index 2aa71e2631..80198a1e89 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataSchemaDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataSchemaDAOImpl.java @@ -7,16 +7,19 @@ */ package org.dspace.content.dao.impl; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchema_; import org.dspace.content.dao.MetadataSchemaDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; - -import java.sql.SQLException; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the MetadataSchema object. @@ -25,10 +28,8 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class MetadataSchemaDAOImpl extends AbstractHibernateDAO implements MetadataSchemaDAO -{ - protected MetadataSchemaDAOImpl() - { +public class MetadataSchemaDAOImpl extends AbstractHibernateDAO implements MetadataSchemaDAO { + protected MetadataSchemaDAOImpl() { super(); } @@ -41,27 +42,32 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO * @throws SQLException if database error */ @Override - public MetadataSchema findByNamespace(Context context, String namespace) throws SQLException - { + public MetadataSchema findByNamespace(Context context, String namespace) throws SQLException { // Grab rows from DB Query query = createQuery(context, - "SELECT ms FROM MetadataSchema ms " + - "WHERE ms.namespace = :namespace "); + "SELECT ms FROM MetadataSchema ms " + + "WHERE ms.namespace = :namespace "); query.setParameter("namespace", namespace); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); - query.setCacheable(true); return singleResult(query); } @Override public List findAll(Context context, Class clazz) throws SQLException { // Get all the metadataschema rows - Criteria criteria = createCriteria(context, MetadataSchema.class); - criteria.addOrder(Order.asc("id")); - criteria.setCacheable(true); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MetadataSchema.class); + Root metadataSchemaRoot = criteriaQuery.from(MetadataSchema.class); + criteriaQuery.select(metadataSchemaRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(metadataSchemaRoot.get(MetadataSchema_.id))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, true, MetadataSchema.class, -1, -1); } /** @@ -75,16 +81,15 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO * @throws SQLException if database error */ @Override - public boolean uniqueNamespace(Context context, int metadataSchemaId, String namespace) throws SQLException - { + public boolean uniqueNamespace(Context context, int metadataSchemaId, String namespace) throws SQLException { Query query = createQuery(context, - "SELECT ms FROM MetadataSchema ms " + - "WHERE ms.namespace = :namespace and ms.id != :id"); + "SELECT ms FROM MetadataSchema ms " + + "WHERE ms.namespace = :namespace and ms.id != :id"); query.setParameter("namespace", namespace); query.setParameter("id", metadataSchemaId); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query) == null; } @@ -98,16 +103,15 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO * @throws SQLException if database error */ @Override - public boolean uniqueShortName(Context context, int metadataSchemaId, String name) throws SQLException - { + public boolean uniqueShortName(Context context, int metadataSchemaId, String name) throws SQLException { Query query = createQuery(context, - "SELECT ms FROM MetadataSchema ms " + - "WHERE ms.name = :name and ms.id != :id"); + "SELECT ms FROM MetadataSchema ms " + + "WHERE ms.name = :name and ms.id != :id"); query.setParameter("name", name); query.setParameter("id", metadataSchemaId); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query) == null; } @@ -122,15 +126,14 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO * @throws SQLException if database error */ @Override - public MetadataSchema find(Context context, String shortName) throws SQLException - { + public MetadataSchema find(Context context, String shortName) throws SQLException { Query query = createQuery(context, - "SELECT ms FROM MetadataSchema ms " + - "WHERE ms.name = :name"); + "SELECT ms FROM MetadataSchema ms " + + "WHERE ms.name = :name"); query.setParameter("name", shortName); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java index 5fdb025455..a4fdf57cba 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java @@ -7,19 +7,21 @@ */ package org.dspace.content.dao.impl; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; + import org.dspace.content.MetadataField; +import org.dspace.content.MetadataField_; import org.dspace.content.MetadataValue; import org.dspace.content.dao.MetadataValueDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.FetchMode; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the MetadataValue object. @@ -28,33 +30,32 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class MetadataValueDAOImpl extends AbstractHibernateDAO implements MetadataValueDAO -{ - protected MetadataValueDAOImpl() - { +public class MetadataValueDAOImpl extends AbstractHibernateDAO implements MetadataValueDAO { + protected MetadataValueDAOImpl() { super(); } @Override - public List findByField(Context context, MetadataField metadataField) throws SQLException - { - Criteria criteria = createCriteria(context, MetadataValue.class); - criteria.add( - Restrictions.eq("metadataField.id", metadataField.getID()) - ); - criteria.setFetchMode("metadataField", FetchMode.JOIN); + public List findByField(Context context, MetadataField metadataField) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MetadataValue.class); + Root metadataValueRoot = criteriaQuery.from(MetadataValue.class); + Join join = metadataValueRoot.join("metadataField"); + criteriaQuery.select(metadataValueRoot); + criteriaQuery.where(criteriaBuilder.equal(join.get(MetadataField_.id), metadataField.getID())); - return list(criteria); + + return list(context, criteriaQuery, false, MetadataValue.class, -1, -1); } @Override public Iterator findByValueLike(Context context, String value) throws SQLException { String queryString = "SELECT m FROM MetadataValue m JOIN m.metadataField f " + - "WHERE m.value like concat('%', concat(:searchString,'%')) ORDER BY m.id ASC"; + "WHERE m.value like concat('%', concat(:searchString,'%')) ORDER BY m.id ASC"; Query query = createQuery(context, queryString); - query.setString("searchString", value); + query.setParameter("searchString", value); return iterate(query); } @@ -69,13 +70,13 @@ public class MetadataValueDAOImpl extends AbstractHibernateDAO im @Override public MetadataValue getMinimum(Context context, int metadataFieldId) - throws SQLException - { - String queryString = "SELECT m FROM MetadataValue m JOIN FETCH m.metadataField WHERE m.metadataField.id = :metadata_field_id ORDER BY text_value"; + throws SQLException { + String queryString = "SELECT m FROM MetadataValue m JOIN FETCH m.metadataField WHERE m.metadataField.id = " + + ":metadata_field_id ORDER BY text_value"; Query query = createQuery(context, queryString); query.setParameter("metadata_field_id", metadataFieldId); query.setMaxResults(1); - return (MetadataValue) query.uniqueResult(); + return (MetadataValue) query.getSingleResult(); } @Override diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/SiteDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/SiteDAOImpl.java index 35661b70b6..4533eab76a 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/SiteDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/SiteDAOImpl.java @@ -7,13 +7,15 @@ */ package org.dspace.content.dao.impl; +import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.dspace.content.Site; import org.dspace.content.dao.SiteDAO; -import org.dspace.core.Context; import org.dspace.core.AbstractHibernateDAO; -import org.hibernate.Criteria; - -import java.sql.SQLException; +import org.dspace.core.Context; /** * Hibernate implementation of the Database Access Object interface class for the Site object. @@ -22,17 +24,17 @@ import java.sql.SQLException; * * @author kevinvandevelde at atmire.com */ -public class SiteDAOImpl extends AbstractHibernateDAO implements SiteDAO -{ - protected SiteDAOImpl() - { +public class SiteDAOImpl extends AbstractHibernateDAO implements SiteDAO { + protected SiteDAOImpl() { super(); } @Override public Site findSite(Context context) throws SQLException { - Criteria criteria = createCriteria(context, Site.class); - criteria.setCacheable(true); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Site.class); + Root siteRoot = criteriaQuery.from(Site.class); + criteriaQuery.select(siteRoot); + return uniqueResult(context, criteriaQuery, true, Site.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/WorkspaceItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/WorkspaceItemDAOImpl.java index 9585474ad5..8e5e803898 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/WorkspaceItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/WorkspaceItemDAOImpl.java @@ -7,22 +7,27 @@ */ package org.dspace.content.dao.impl; +import java.sql.SQLException; +import java.util.AbstractMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; +import org.dspace.content.WorkspaceItem_; import org.dspace.content.dao.WorkspaceItemDAO; -import org.dspace.core.Context; import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; -import org.hibernate.transform.BasicTransformerAdapter; - -import java.sql.SQLException; -import java.util.List; -import java.util.Map; +import org.dspace.eperson.EPerson_; +import org.dspace.eperson.Group; /** * Hibernate implementation of the Database Access Object interface class for the WorkspaceItem object. @@ -31,62 +36,109 @@ import java.util.Map; * * @author kevinvandevelde at atmire.com */ -public class WorkspaceItemDAOImpl extends AbstractHibernateDAO implements WorkspaceItemDAO -{ - protected WorkspaceItemDAOImpl() - { +public class WorkspaceItemDAOImpl extends AbstractHibernateDAO implements WorkspaceItemDAO { + protected WorkspaceItemDAOImpl() { super(); } @Override - public List findByEPerson(Context context, EPerson ep) throws SQLException - { - Query query = createQuery(context, "from WorkspaceItem ws where ws.item.submitter = :submitter order by workspaceItemId"); + public List findByEPerson(Context context, EPerson ep) throws SQLException { + Query query = createQuery(context, + "from WorkspaceItem ws where ws.item.submitter = :submitter order by " + + "workspaceItemId"); query.setParameter("submitter", ep); return list(query); } @Override - public List findByCollection(Context context, Collection c) throws SQLException - { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.add(Restrictions.eq("collection", c)); - return list(criteria); + public List findByEPerson(Context context, EPerson ep, Integer limit, Integer offset) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.equal(workspaceItemRoot.get(WorkspaceItem_.item).get("submitter"), ep)); + criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + return list(context, criteriaQuery, false, WorkspaceItem.class, limit, offset); } @Override - public WorkspaceItem findByItem(Context context, Item i) throws SQLException - { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.add(Restrictions.eq("item", i)); - // Look for the unique workspaceitem entry where 'item_id' references this item - return uniqueResult(criteria); + public List findByCollection(Context context, Collection c) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.equal(workspaceItemRoot.get(WorkspaceItem_.collection), c)); + criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); } @Override - public List findAll(Context context) throws SQLException - { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.addOrder(Order.asc("item")); - return list(criteria); + public WorkspaceItem findByItem(Context context, Item i) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.equal(workspaceItemRoot.get(WorkspaceItem_.item), i)); + return uniqueResult(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); + } + + @Override + public List findAll(Context context) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); + } + + @Override + public List findAll(Context context, Integer limit, Integer offset) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, WorkspaceItem.class, limit, offset); } @Override public List findWithSupervisedGroup(Context context) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.add(Restrictions.isNotEmpty("supervisorGroups")); - criteria.addOrder(Order.asc("workspaceItemId")); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.isNotEmpty(workspaceItemRoot.get(WorkspaceItem_.supervisorGroups))); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + criteriaQuery.orderBy(orderList); + return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); } @Override public List findBySupervisedGroupMember(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.createAlias("supervisorGroups", "supervisorGroup"); - criteria.createAlias("supervisorGroup.epeople", "person"); - criteria.add(Restrictions.eq("person.id", ePerson.getID())); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + Join join = workspaceItemRoot.join("supervisorGroups"); + Join secondJoin = join.join("epeople"); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.equal(secondJoin.get(EPerson_.id), ePerson.getID())); + criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); } @Override @@ -94,18 +146,27 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO im return count(createQuery(context, "SELECT count(*) from WorkspaceItem")); } + @Override + public int countRows(Context context, EPerson ep) throws SQLException { + Query query = createQuery(context, + "SELECT count(*) from WorkspaceItem ws where ws.item.submitter = :submitter"); + query.setParameter("submitter", ep); + return count(query); + } + @Override @SuppressWarnings("unchecked") public List> getStageReachedCounts(Context context) throws SQLException { - Query query = createQuery(context,"SELECT wi.stageReached as stage_reached, count(*) as cnt from WorkspaceItem wi" + - " group by wi.stageReached order by wi.stageReached"); - query.setResultTransformer(new BasicTransformerAdapter() { - @Override - public Object transformTuple(Object[] tuple, String[] aliases) { - return new java.util.AbstractMap.SimpleImmutableEntry((Integer) tuple[0], (Long) tuple[1]); - } - }); - return (List>)query.list(); + Query query = createQuery(context, + "SELECT wi.stageReached as stage_reached, count(*) as cnt from WorkspaceItem wi" + + " group by wi.stageReached order by wi.stageReached"); + + List list = query.getResultList(); + List> returnList = new LinkedList<>(); + for (Object[] o : list) { + returnList.add(new AbstractMap.SimpleEntry<>((Integer) o[0], (Long) o[1])); + } + return returnList; } } diff --git a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java index 0d61c69409..b5f50aa141 100644 --- a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java @@ -7,17 +7,33 @@ */ package org.dspace.content.factory; +import java.util.List; + import org.dspace.content.DSpaceObject; import org.dspace.content.InProgressSubmission; import org.dspace.content.WorkspaceItem; -import org.dspace.content.service.*; +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.DSpaceObjectLegacySupportService; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.content.service.InProgressSubmissionService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.MetadataValueService; +import org.dspace.content.service.SiteService; +import org.dspace.content.service.SupervisedItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.workflow.factory.WorkflowServiceFactory; -import java.util.List; - /** - * Abstract factory to get services for the content package, use ContentServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the content package, use ContentServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -25,7 +41,8 @@ public abstract class ContentServiceFactory { public abstract List> getDSpaceObjectServices(); - public abstract List> getDSpaceObjectLegacySupportServices(); + public abstract List> + getDSpaceObjectLegacySupportServices(); public abstract BitstreamFormatService getBitstreamFormatService(); @@ -53,19 +70,15 @@ public abstract class ContentServiceFactory { public abstract SiteService getSiteService(); - public InProgressSubmissionService getInProgressSubmissionService(InProgressSubmission inProgressSubmission) - { - if(inProgressSubmission instanceof WorkspaceItem) - { + public InProgressSubmissionService getInProgressSubmissionService(InProgressSubmission inProgressSubmission) { + if (inProgressSubmission instanceof WorkspaceItem) { return getWorkspaceItemService(); - } - else - { + } else { return WorkflowServiceFactory.getInstance().getWorkflowItemService(); } } - public DSpaceObjectService getDSpaceObjectService(T dso) - { + + public DSpaceObjectService getDSpaceObjectService(T dso) { // No need to worry when supressing, as long as our "getDSpaceObjectManager" method is properly implemented // no casting issues should occur @SuppressWarnings("unchecked") @@ -73,24 +86,22 @@ public abstract class ContentServiceFactory { return manager; } - public DSpaceObjectService getDSpaceObjectService(int type) - { + public DSpaceObjectService getDSpaceObjectService(int type) { for (int i = 0; i < getDSpaceObjectServices().size(); i++) { DSpaceObjectService objectService = getDSpaceObjectServices().get(i); - if(objectService.getSupportsTypeConstant() == type) - { + if (objectService.getSupportsTypeConstant() == type) { return objectService; } } throw new UnsupportedOperationException("Unknown DSpace type: " + type); } - public DSpaceObjectLegacySupportService getDSpaceLegacyObjectService(int type) - { + public DSpaceObjectLegacySupportService getDSpaceLegacyObjectService(int type) { for (int i = 0; i < getDSpaceObjectLegacySupportServices().size(); i++) { - DSpaceObjectLegacySupportService objectLegacySupportService = getDSpaceObjectLegacySupportServices().get(i); - if(objectLegacySupportService.getSupportsTypeConstant() == type) - { + DSpaceObjectLegacySupportService objectLegacySupportService = + getDSpaceObjectLegacySupportServices() + .get(i); + if (objectLegacySupportService.getSupportsTypeConstant() == type) { return objectLegacySupportService; } @@ -98,8 +109,9 @@ public abstract class ContentServiceFactory { throw new UnsupportedOperationException("Unknown DSpace type: " + type); } - public static ContentServiceFactory getInstance(){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("contentServiceFactory", ContentServiceFactory.class); + public static ContentServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("contentServiceFactory", ContentServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java index 35de1dc76a..ab10bb8bf5 100644 --- a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java @@ -7,14 +7,29 @@ */ package org.dspace.content.factory; -import org.dspace.content.DSpaceObject; -import org.dspace.content.service.*; -import org.springframework.beans.factory.annotation.Autowired; - import java.util.List; +import org.dspace.content.DSpaceObject; +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.DSpaceObjectLegacySupportService; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.MetadataValueService; +import org.dspace.content.service.SiteService; +import org.dspace.content.service.SupervisedItemService; +import org.dspace.content.service.WorkspaceItemService; +import org.springframework.beans.factory.annotation.Autowired; + /** - * Factory implementation to get services for the content package, use ContentServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the content package, use ContentServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -65,62 +80,52 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory { } @Override - public BitstreamFormatService getBitstreamFormatService() - { + public BitstreamFormatService getBitstreamFormatService() { return bitstreamFormatService; } @Override - public BitstreamService getBitstreamService() - { + public BitstreamService getBitstreamService() { return bitstreamService; } @Override - public BundleService getBundleService() - { + public BundleService getBundleService() { return bundleService; } @Override - public CollectionService getCollectionService() - { + public CollectionService getCollectionService() { return collectionService; } @Override - public CommunityService getCommunityService() - { + public CommunityService getCommunityService() { return communityService; } @Override - public ItemService getItemService() - { + public ItemService getItemService() { return itemService; } @Override - public MetadataSchemaService getMetadataSchemaService() - { + public MetadataSchemaService getMetadataSchemaService() { return metadataSchemaService; } @Override - public MetadataFieldService getMetadataFieldService() - { + public MetadataFieldService getMetadataFieldService() { return metadataFieldService; } @Override - public MetadataValueService getMetadataValueService() - { + public MetadataValueService getMetadataValueService() { return metadataValueService; } @Override - public WorkspaceItemService getWorkspaceItemService() - { + public WorkspaceItemService getWorkspaceItemService() { return workspaceItemService; } diff --git a/dspace-api/src/main/java/org/dspace/content/license/FormattableArgument.java b/dspace-api/src/main/java/org/dspace/content/license/FormattableArgument.java index 0e6a7fd3de..bb2143a4a2 100644 --- a/dspace-api/src/main/java/org/dspace/content/license/FormattableArgument.java +++ b/dspace-api/src/main/java/org/dspace/content/license/FormattableArgument.java @@ -16,36 +16,31 @@ import org.dspace.core.factory.CoreServiceFactory; * Wrapper class to make formattable any argument used in the license template. * The formatter behavior is delegated to a specific class on "type" basis * using the PluginService - * + * + * @author bollini * @see Formattable * @see LicenseArgumentFormatter - * @author bollini - * */ -public class FormattableArgument implements Formattable -{ +public class FormattableArgument implements Formattable { private String type; private Object object; - public FormattableArgument(String type, Object object) - { + public FormattableArgument(String type, Object object) { this.type = type; this.object = object; } @Override public void formatTo(Formatter formatter, int flags, int width, - int precision) - { + int precision) { LicenseArgumentFormatter laf = (LicenseArgumentFormatter) CoreServiceFactory.getInstance().getPluginService() - .getNamedPlugin(LicenseArgumentFormatter.class, type); - if (laf != null) - { + .getNamedPlugin( + LicenseArgumentFormatter.class, + type); + if (laf != null) { laf.formatTo(formatter, flags, width, object, type); - } - else - { + } else { formatter.format(object.toString()); } } diff --git a/dspace-api/src/main/java/org/dspace/content/license/LicenseArgumentFormatter.java b/dspace-api/src/main/java/org/dspace/content/license/LicenseArgumentFormatter.java index 5b504cc8dc..8fa8e63b5c 100644 --- a/dspace-api/src/main/java/org/dspace/content/license/LicenseArgumentFormatter.java +++ b/dspace-api/src/main/java/org/dspace/content/license/LicenseArgumentFormatter.java @@ -9,8 +9,7 @@ package org.dspace.content.license; import java.util.Formatter; -public interface LicenseArgumentFormatter -{ +public interface LicenseArgumentFormatter { /** * Format the object following the java.util.Formatter rules. @@ -18,20 +17,15 @@ public interface LicenseArgumentFormatter * assume safe to cast as appropriate. If a null object is * supplied is expected that the implementer will work as if a "sample data" * was requested. - * + * + * @param formatter the current formatter that need to process the object + * @param flags the flags option for the formatter + * @param width the width option for the formatter + * @param object the object to be formatted + * @param type the type of the object (this is an alias not the class name! - + * i.e. item, collection, eperson, etc.) * @see Formatter - * @param formatter - * the current formatter that need to process the object - * @param flags - * the flags option for the formatter - * @param width - * the width option for the formatter - * @param object - * the object to be formatted - * @param type - * the type of the object (this is an alias not the class name! - - * i.e. item, collection, eperson, etc.) */ void formatTo(Formatter formatter, int flags, int width, Object object, - String type); + String type); } diff --git a/dspace-api/src/main/java/org/dspace/content/license/SimpleDSpaceObjectLicenseFormatter.java b/dspace-api/src/main/java/org/dspace/content/license/SimpleDSpaceObjectLicenseFormatter.java index ed8be70134..3ef44a9a47 100644 --- a/dspace-api/src/main/java/org/dspace/content/license/SimpleDSpaceObjectLicenseFormatter.java +++ b/dspace-api/src/main/java/org/dspace/content/license/SimpleDSpaceObjectLicenseFormatter.java @@ -14,31 +14,22 @@ import org.dspace.content.DSpaceObject; /** * This is a simple implementation of the LicenseArgumentFormatter for a * DSpaceObject. The formatter options width/precision are not take in care. - * + * * @author bollini - * */ public class SimpleDSpaceObjectLicenseFormatter implements - LicenseArgumentFormatter -{ + LicenseArgumentFormatter { @Override public void formatTo(Formatter formatter, int flags, int width, - Object object, String type) - { - if (object == null) - { - formatter.format("sample "+type); - } - else - { + Object object, String type) { + if (object == null) { + formatter.format("sample " + type); + } else { DSpaceObject dso = (DSpaceObject) object; String name = dso.getName(); - if (name != null) - { + if (name != null) { formatter.format(name); - } - else - { + } else { formatter.format(""); } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java index eb36bafc47..77de1ef12e 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java @@ -9,9 +9,13 @@ package org.dspace.content.packager; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.sql.SQLException; import java.util.HashMap; import java.util.Iterator; @@ -23,44 +27,42 @@ import java.util.zip.ZipOutputStream; import edu.harvard.hul.ois.mets.AmdSec; import edu.harvard.hul.ois.mets.BinData; import edu.harvard.hul.ois.mets.Checksumtype; +import edu.harvard.hul.ois.mets.DigiprovMD; import edu.harvard.hul.ois.mets.Div; import edu.harvard.hul.ois.mets.DmdSec; -import edu.harvard.hul.ois.mets.MdRef; import edu.harvard.hul.ois.mets.FLocat; import edu.harvard.hul.ois.mets.FileGrp; import edu.harvard.hul.ois.mets.FileSec; import edu.harvard.hul.ois.mets.Fptr; -import edu.harvard.hul.ois.mets.Mptr; import edu.harvard.hul.ois.mets.Loctype; +import edu.harvard.hul.ois.mets.MdRef; import edu.harvard.hul.ois.mets.MdWrap; import edu.harvard.hul.ois.mets.Mdtype; import edu.harvard.hul.ois.mets.Mets; import edu.harvard.hul.ois.mets.MetsHdr; +import edu.harvard.hul.ois.mets.Mptr; +import edu.harvard.hul.ois.mets.RightsMD; +import edu.harvard.hul.ois.mets.SourceMD; import edu.harvard.hul.ois.mets.StructMap; import edu.harvard.hul.ois.mets.TechMD; -import edu.harvard.hul.ois.mets.SourceMD; -import edu.harvard.hul.ois.mets.DigiprovMD; -import edu.harvard.hul.ois.mets.RightsMD; -import edu.harvard.hul.ois.mets.helper.MdSec; import edu.harvard.hul.ois.mets.XmlData; import edu.harvard.hul.ois.mets.helper.Base64; +import edu.harvard.hul.ois.mets.helper.MdSec; import edu.harvard.hul.ois.mets.helper.MetsElement; import edu.harvard.hul.ois.mets.helper.MetsException; import edu.harvard.hul.ois.mets.helper.MetsValidator; import edu.harvard.hul.ois.mets.helper.MetsWriter; import edu.harvard.hul.ois.mets.helper.PreformedXML; -import java.io.File; -import java.io.FileOutputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -import org.apache.log4j.Logger; - import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.crosswalk.AbstractPackagerWrappingCrosswalk; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.CrosswalkObjectNotSupported; @@ -83,11 +85,13 @@ import org.jdom.Element; import org.jdom.Namespace; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Base class for disseminator of * METS (Metadata Encoding and Transmission Standard) Package.
    - * See http://www.loc.gov/standards/mets/ + * See http://www.loc.gov/standards/mets/ *

    * This is a generic packager framework intended to be subclassed to create * packagers for more specific METS "profiles". METS is an @@ -104,11 +108,11 @@ import org.jdom.output.XMLOutputter; *

  • unauthorized -- this determines what is done when the * packager encounters a Bundle or Bitstream it is not authorized to * read. By default, it just quits with an AuthorizeException. - * If this option is present, it must be one of the following values: - *
      - *
    • skip -- simply exclude unreadable content from package.
    • - *
    • zero -- include unreadable bitstreams as 0-length files; - * unreadable Bundles will still cause authorize errors.
  • + * If this option is present, it must be one of the following values: + *
      + *
    • skip -- simply exclude unreadable content from package.
    • + *
    • zero -- include unreadable bitstreams as 0-length files; + * unreadable Bundles will still cause authorize errors.
    * * * @author Larry Stone @@ -117,10 +121,11 @@ import org.jdom.output.XMLOutputter; * @version $Revision$ */ public abstract class AbstractMETSDisseminator - extends AbstractPackageDisseminator -{ - /** log4j category */ - private static Logger log = Logger.getLogger(AbstractMETSDisseminator.class); + extends AbstractPackageDisseminator { + /** + * log4j category + */ + private static final Logger log = LoggerFactory.getLogger(AbstractMETSDisseminator.class); // JDOM xml output writer - indented format for readability. protected static XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat()); @@ -128,8 +133,10 @@ public abstract class AbstractMETSDisseminator protected final AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); protected final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); protected final SiteService siteService = ContentServiceFactory.getInstance().getSiteService(); - protected final CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance().getCreativeCommonsService(); - protected final ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + protected final CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance() + .getCreativeCommonsService(); + protected final ConfigurationService configurationService = DSpaceServicesFactory.getInstance() + .getConfigurationService(); // for gensym() protected int idCounter = 1; @@ -142,7 +149,7 @@ public abstract class AbstractMETSDisseminator * change whenever Zip is regenerated (even if compressed files are unchanged) * 1036368000 seconds * 1000 = Nov 4, 2002 GMT (the date DSpace 1.0 was released) */ - protected static final int DEFAULT_MODIFIED_DATE = 1036368000 * 1000; + protected static final long DEFAULT_MODIFIED_DATE = 1036368000L * 1000; /** * Suffix for Template objects (e.g. Item Templates) @@ -156,25 +163,20 @@ public abstract class AbstractMETSDisseminator * superclasses will put streams in this table when adding an mdRef * element to e.g. a rightsMD segment. */ - protected static class MdStreamCache - { - protected Map extraFiles = new HashMap(); + protected static class MdStreamCache { + protected Map extraFiles = new HashMap(); - public void addStream(MdRef key, InputStream md) - { + public void addStream(MdRef key, InputStream md) { extraFiles.put(key, md); } - public Map getMap() - { + public Map getMap() { return extraFiles; } public void close() - throws IOException - { - for (InputStream is : extraFiles.values()) - { + throws IOException { + for (InputStream is : extraFiles.values()) { is.close(); } } @@ -182,29 +184,27 @@ public abstract class AbstractMETSDisseminator /** * Make a new unique ID symbol with specified prefix. + * * @param prefix the prefix of the identifier, constrained to XML ID schema * @return a new string identifier unique in this session (instance). */ - protected synchronized String gensym(String prefix) - { + protected synchronized String gensym(String prefix) { return prefix + "_" + String.valueOf(idCounter++); } - + /** * Resets the unique ID counter used by gensym() method to * determine the @ID values of METS tags. */ - protected synchronized void resetCounter() - { + protected synchronized void resetCounter() { idCounter = 1; } @Override - public String getMIMEType(PackageParameters params) - { + public String getMIMEType(PackageParameters params) { return (params != null && - (params.getBooleanProperty("manifestOnly", false))) ? - "text/xml" : "application/zip"; + (params.getBooleanProperty("manifestOnly", false))) ? + "text/xml" : "application/zip"; } /** @@ -221,33 +221,30 @@ public abstract class AbstractMETSDisseminator * Throws an exception of the chosen object is not acceptable or there is * a failure creating the package. * - * @param context DSpace context. - * @param dso DSpace object (item, collection, etc) - * @param params Properties-style list of options specific to this packager + * @param context DSpace context. + * @param dso DSpace object (item, collection, etc) + * @param params Properties-style list of options specific to this packager * @param pkgFile File where export package should be written * @throws PackageValidationException if package cannot be created or there - * is a fatal error in creating it. - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error + * is a fatal error in creating it. + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error */ @Override public void disseminate(Context context, DSpaceObject dso, PackageParameters params, File pkgFile) - throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException, IOException - { + throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException, IOException { // Reset our 'unique' ID counter back to 1 (in case a previous dissemination was run) // This ensures that the @ID attributes of METS tags always begin at '1', which // also ensures that the Checksums don't change because of accidental @ID value changes. resetCounter(); - + FileOutputStream outStream = null; - try - { + try { //Make sure our package file exists - if(!pkgFile.exists()) - { + if (!pkgFile.exists()) { PackageUtils.createFile(pkgFile); } @@ -255,47 +252,38 @@ public abstract class AbstractMETSDisseminator outStream = new FileOutputStream(pkgFile); // Generate a true manifest-only "package", no external files/data & no need to zip up - if (params != null && params.getBooleanProperty("manifestOnly", false)) - { + if (params != null && params.getBooleanProperty("manifestOnly", false)) { Mets manifest = makeManifest(context, dso, params, null); //only validate METS if specified (default = true) - if(params.getBooleanProperty("validate", true)) - { + if (params.getBooleanProperty("validate", true)) { manifest.validate(new MetsValidator()); } manifest.write(new MetsWriter(outStream)); - } - else - { + } else { // make a Zip-based package writeZipPackage(context, dso, params, outStream); - }//end if/else - + } //end if/else + // Assuming no errors, log this dissemination log.info(LogManager.getHeader(context, "package_disseminate", - "Disseminated package file=" + pkgFile.getName() + - " for Object, type=" - + Constants.typeText[dso.getType()] + ", handle=" - + dso.getHandle() + ", dbID=" - + String.valueOf(dso.getID()))); - }//end try - catch (MetsException e) - { + "Disseminated package file=" + pkgFile.getName() + + " for Object, type=" + + Constants.typeText[dso.getType()] + ", handle=" + + dso.getHandle() + ", dbID=" + + String.valueOf(dso.getID()))); + } catch (MetsException e) { String errorMsg = "Error exporting METS for DSpace Object, type=" - + Constants.typeText[dso.getType()] + ", handle=" - + dso.getHandle() + ", dbID=" - + String.valueOf(dso.getID()); + + Constants.typeText[dso.getType()] + ", handle=" + + dso.getHandle() + ", dbID=" + + String.valueOf(dso.getID()); // We don't pass up a MetsException, so callers don't need to // know the details of the METS toolkit - log.error(errorMsg,e); + log.error(errorMsg, e); throw new PackageValidationException(errorMsg, e); - } - finally - { + } finally { //Close stream / stop writing to file - if (outStream != null) - { + if (outStream != null) { outStream.close(); } } @@ -306,24 +294,22 @@ public abstract class AbstractMETSDisseminator * Make a Zipped up METS package for the given DSpace Object * * @param context DSpace Context - * @param dso The DSpace Object - * @param params Parameters to the Packager script - * @param pkg Package output stream + * @param dso The DSpace Object + * @param params Parameters to the Packager script + * @param pkg Package output stream * @throws PackageValidationException if package validation error - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws MetsException if METS error - * @throws SQLException if database error - * @throws IOException if IO error + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws MetsException if METS error + * @throws SQLException if database error + * @throws IOException if IO error */ protected void writeZipPackage(Context context, DSpaceObject dso, - PackageParameters params, OutputStream pkg) - throws PackageValidationException, CrosswalkException, MetsException, - AuthorizeException, SQLException, IOException - { + PackageParameters params, OutputStream pkg) + throws PackageValidationException, CrosswalkException, MetsException, + AuthorizeException, SQLException, IOException { long lmTime = 0; - if (dso.getType() == Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { lmTime = ((Item) dso).getLastModified().getTime(); } @@ -334,41 +320,37 @@ public abstract class AbstractMETSDisseminator Mets manifest = makeManifest(context, dso, params, extraStreams); // copy extra (metadata, license, etc) bitstreams into zip, update manifest - if (extraStreams != null) - { - for (Map.Entry ment : extraStreams.getMap().entrySet()) - { + if (extraStreams != null) { + for (Map.Entry ment : extraStreams.getMap().entrySet()) { MdRef ref = ment.getKey(); // Both Deposit Licenses & CC Licenses which are referenced as "extra streams" may already be // included in our Package (if their bundles are already included in the section of manifest). - // So, do a special check to see if we need to link up extra License entries to the bitstream in the . + // So, do a special check to see if we need to link up extra License entries to the bitstream + // in the . // (this ensures that we don't accidentally add the same License file to our package twice) linkLicenseRefsToBitstreams(context, params, dso, ref); //If this 'mdRef' is NOT already linked up to a file in the package, // then its file must be missing. So, we are going to add a new // file to the Zip package. - if(ref.getXlinkHref()==null || ref.getXlinkHref().isEmpty()) - { + if (ref.getXlinkHref() == null || ref.getXlinkHref().isEmpty()) { InputStream is = ment.getValue(); // create a hopefully unique filename within the Zip String fname = gensym("metadata"); // link up this 'mdRef' to point to that file ref.setXlinkHref(fname); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Writing EXTRA stream to Zip: " + fname); } //actually add the file to the Zip package ZipEntry ze = new ZipEntry(fname); - if (lmTime != 0) - { + if (lmTime != 0) { ze.setTime(lmTime); - } - else //Set a default modified date so that checksum of Zip doesn't change if Zip contents are unchanged - { + } else { + // Set a default modified date so that checksum of Zip doesn't change if Zip contents are + // unchanged ze.setTime(DEFAULT_MODIFIED_DATE); } zip.putNextEntry(ze); @@ -382,12 +364,10 @@ public abstract class AbstractMETSDisseminator // write manifest after metadata. ZipEntry me = new ZipEntry(METSManifest.MANIFEST_FILE); - if (lmTime != 0) - { + if (lmTime != 0) { me.setTime(lmTime); - } - else //Set a default modified date so that checksum of Zip doesn't change if Zip contents are unchanged - { + } else { + // Set a default modified date so that checksum of Zip doesn't change if Zip contents are unchanged me.setTime(DEFAULT_MODIFIED_DATE); } @@ -395,8 +375,7 @@ public abstract class AbstractMETSDisseminator // can only validate now after fixing up extraStreams // note: only validate METS if specified (default = true) - if(params.getBooleanProperty("validate", true)) - { + if (params.getBooleanProperty("validate", true)) { manifest.validate(new MetsValidator()); } manifest.write(new MetsWriter(zip)); @@ -408,67 +387,72 @@ public abstract class AbstractMETSDisseminator zip.close(); } + /** * Add Bitstreams associated with a given DSpace Object into an * existing ZipOutputStream + * * @param context DSpace Context - * @param dso The DSpace Object - * @param params Parameters to the Packager script - * @param zip Zip output + * @param dso The DSpace Object + * @param params Parameters to the Packager script + * @param zip Zip output * @throws PackageValidationException if validation error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error */ protected void addBitstreamsToZip(Context context, DSpaceObject dso, - PackageParameters params, ZipOutputStream zip) - throws PackageValidationException, AuthorizeException, SQLException, - IOException - { + PackageParameters params, ZipOutputStream zip) + throws PackageValidationException, AuthorizeException, SQLException, + IOException { // how to handle unauthorized bundle/bitstream: String unauth = (params == null) ? null : params.getProperty("unauthorized"); // copy all non-meta bitstreams into zip - if (dso.getType() == Constants.ITEM) - { - Item item = (Item)dso; + if (dso.getType() == Constants.ITEM) { + Item item = (Item) dso; //get last modified time - long lmTime = ((Item)dso).getLastModified().getTime(); + long lmTime = ((Item) dso).getLastModified().getTime(); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { if (includeBundle(bundle)) { // unauthorized bundle? if (!authorizeService.authorizeActionBoolean(context, - bundle, Constants.READ)) { + bundle, Constants.READ)) { if (unauth != null && - (unauth.equalsIgnoreCase("skip"))) { - log.warn("Skipping Bundle[\"" + bundle.getName() + "\"] because you are not authorized to read it."); + (unauth.equalsIgnoreCase("skip"))) { + log.warn("Skipping Bundle[\"" + bundle + .getName() + "\"] because you are not authorized to read it."); continue; } else { - throw new AuthorizeException("Not authorized to read Bundle named \"" + bundle.getName() + "\""); + throw new AuthorizeException( + "Not authorized to read Bundle named \"" + bundle.getName() + "\""); } } List bitstreams = bundle.getBitstreams(); for (Bitstream bitstream : bitstreams) { boolean auth = authorizeService.authorizeActionBoolean(context, - bitstream, Constants.READ); + bitstream, Constants.READ); if (auth || - (unauth != null && unauth.equalsIgnoreCase("zero"))) { + (unauth != null && unauth.equalsIgnoreCase("zero"))) { String zname = makeBitstreamURL(context, bitstream, params); ZipEntry ze = new ZipEntry(zname); if (log.isDebugEnabled()) { - log.debug(new StringBuilder().append("Writing CONTENT stream of bitstream(").append(bitstream.getID()).append(") to Zip: ").append(zname).append(", size=").append(bitstream.getSize()).toString()); + log.debug(new StringBuilder().append("Writing CONTENT stream of bitstream(") + .append(bitstream.getID()).append(") to Zip: ") + .append(zname).append(", size=") + .append(bitstream.getSizeBytes()).toString()); } if (lmTime != 0) { ze.setTime(lmTime); - } else //Set a default modified date so that checksum of Zip doesn't change if Zip contents are unchanged - { + } else { + // Set a default modified date so that checksum of Zip doesn't change if Zip + // contents are unchanged ze.setTime(DEFAULT_MODIFIED_DATE); } - ze.setSize(auth ? bitstream.getSize() : 0); + ze.setSize(auth ? bitstream.getSizeBytes() : 0); zip.putNextEntry(ze); if (auth) { InputStream input = bitstreamService.retrieve(context, bitstream); @@ -476,37 +460,36 @@ public abstract class AbstractMETSDisseminator input.close(); } else { log.warn("Adding zero-length file for Bitstream, SID=" - + String.valueOf(bitstream.getSequenceID()) - + ", not authorized for READ."); + + String.valueOf(bitstream.getSequenceID()) + + ", not authorized for READ."); } zip.closeEntry(); - } else if (unauth != null && - unauth.equalsIgnoreCase("skip")) { - log.warn("Skipping Bitstream, SID=" + String.valueOf(bitstream.getSequenceID()) + ", not authorized for READ."); + } else if (unauth != null && unauth.equalsIgnoreCase("skip")) { + log.warn("Skipping Bitstream, SID=" + String + .valueOf(bitstream.getSequenceID()) + ", not authorized for READ."); } else { - throw new AuthorizeException("Not authorized to read Bitstream, SID=" + String.valueOf(bitstream.getSequenceID())); + throw new AuthorizeException( + "Not authorized to read Bitstream, SID=" + String.valueOf(bitstream.getSequenceID())); } } } } - } + } else if (dso.getType() == Constants.COLLECTION || dso.getType() == Constants.COMMUNITY) { + // Coll, Comm just add logo bitstream to content if there is one - // Coll, Comm just add logo bitstream to content if there is one - else if (dso.getType() == Constants.COLLECTION || - dso.getType() == Constants.COMMUNITY) - { Bitstream logoBs = dso.getType() == Constants.COLLECTION ? - ((Collection)dso).getLogo() : - ((Community)dso).getLogo(); - if (logoBs != null) - { + ((Collection) dso).getLogo() : + ((Community) dso).getLogo(); + if (logoBs != null) { String zname = makeBitstreamURL(context, logoBs, params); ZipEntry ze = new ZipEntry(zname); - if (log.isDebugEnabled()) - { - log.debug("Writing CONTENT stream of bitstream(" + String.valueOf(logoBs.getID()) + ") to Zip: " + zname + ", size=" + String.valueOf(logoBs.getSize())); + if (log.isDebugEnabled()) { + log.debug("Writing CONTENT stream of bitstream({}) to Zip: {}, size={}", + String.valueOf(logoBs.getID()), + zname, + String.valueOf(logoBs.getSizeBytes())); } - ze.setSize(logoBs.getSize()); + ze.setSize(logoBs.getSizeBytes()); //Set a default modified date so that checksum of Zip doesn't change if Zip contents are unchanged ze.setTime(DEFAULT_MODIFIED_DATE); zip.putNextEntry(ze); @@ -518,14 +501,10 @@ public abstract class AbstractMETSDisseminator // set metadata type - if Mdtype.parse() gets exception, // that means it's not in the MDTYPE vocabulary, so use OTHER. - protected void setMdType(MdWrap mdWrap, String mdtype) - { - try - { + protected void setMdType(MdWrap mdWrap, String mdtype) { + try { mdWrap.setMDTYPE(Mdtype.parse(mdtype)); - } - catch (MetsException e) - { + } catch (MetsException e) { mdWrap.setMDTYPE(Mdtype.OTHER); mdWrap.setOTHERMDTYPE(mdtype); } @@ -533,14 +512,10 @@ public abstract class AbstractMETSDisseminator // set metadata type - if Mdtype.parse() gets exception, // that means it's not in the MDTYPE vocabulary, so use OTHER. - protected void setMdType(MdRef mdRef, String mdtype) - { - try - { + protected void setMdType(MdRef mdRef, String mdtype) { + try { mdRef.setMDTYPE(Mdtype.parse(mdtype)); - } - catch (MetsException e) - { + } catch (MetsException e) { mdRef.setMDTYPE(Mdtype.OTHER); mdRef.setOTHERMDTYPE(mdtype); } @@ -553,47 +528,41 @@ public abstract class AbstractMETSDisseminator * XML-DOM oriented crosswalk first, then if not found looks for * stream crosswalk of the same name. * - * @param context DSpace Context - * @param dso DSpace Object we are generating METS manifest for - * @param mdSecClass class of mdSec (TechMD, RightsMD, DigiProvMD, etc) - * @param typeSpec Type of metadata going into this mdSec (e.g. MODS, DC, PREMIS, etc) - * @param params the PackageParameters + * @param context DSpace Context + * @param dso DSpace Object we are generating METS manifest for + * @param mdSecClass class of mdSec (TechMD, RightsMD, DigiProvMD, etc) + * @param typeSpec Type of metadata going into this mdSec (e.g. MODS, DC, PREMIS, etc) + * @param params the PackageParameters * @param extraStreams list of extra files which need to be added to final dissemination package - * * @return mdSec element or null if xwalk returns empty results. - * - * @throws SQLException if database error + * @throws SQLException if database error * @throws PackageValidationException if package validation error - * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error + * @throws IOException if IO error + * @throws AuthorizeException if authorization error */ protected MdSec makeMdSec(Context context, DSpaceObject dso, Class mdSecClass, String typeSpec, PackageParameters params, MdStreamCache extraStreams) throws SQLException, PackageValidationException, CrosswalkException, - IOException, AuthorizeException - { - try - { + IOException, AuthorizeException { + try { //create our metadata element (dmdSec, techMd, sourceMd, rightsMD etc.) MdSec mdSec = (MdSec) mdSecClass.newInstance(); mdSec.setID(gensym(mdSec.getLocalName())); String parts[] = typeSpec.split(":", 2); - String xwalkName, metsName; + String xwalkName; + String metsName; //determine the name of the crosswalk to use to generate metadata // for dmdSecs this is the part *after* the colon in the 'type' (see getDmdTypes()) // for all other mdSecs this is usually just corresponds to type name. - if (parts.length > 1) - { + if (parts.length > 1) { metsName = parts[0]; xwalkName = parts[1]; - } - else - { + } else { metsName = typeSpec; - xwalkName = typeSpec; + xwalkName = typeSpec; } PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); @@ -601,17 +570,14 @@ public abstract class AbstractMETSDisseminator // First, check to see if the crosswalk we are using is a normal DisseminationCrosswalk boolean xwalkFound = pluginService.hasNamedPlugin(DisseminationCrosswalk.class, xwalkName); - if(xwalkFound) - { + if (xwalkFound) { // Find the crosswalk we will be using to generate the metadata for this mdSec DisseminationCrosswalk xwalk = (DisseminationCrosswalk) pluginService.getNamedPlugin(DisseminationCrosswalk.class, xwalkName); - if (xwalk.canDisseminate(dso)) - { + if (xwalk.canDisseminate(dso)) { // Check if our Crosswalk actually wraps another Packager Plugin - if(xwalk instanceof AbstractPackagerWrappingCrosswalk) - { + if (xwalk instanceof AbstractPackagerWrappingCrosswalk) { // If this crosswalk wraps another Packager Plugin, we can pass it our Packaging Parameters // (which essentially allow us to customize the output of the crosswalk) AbstractPackagerWrappingCrosswalk wrapper = (AbstractPackagerWrappingCrosswalk) xwalk; @@ -623,35 +589,26 @@ public abstract class AbstractMETSDisseminator MdWrap mdWrap = new MdWrap(); setMdType(mdWrap, metsName); XmlData xmlData = new XmlData(); - if (crosswalkToMetsElement(context, xwalk, dso, xmlData) != null) - { + if (crosswalkToMetsElement(context, xwalk, dso, xmlData) != null) { mdWrap.getContent().add(xmlData); mdSec.getContent().add(mdWrap); return mdSec; - } - else - { + } else { return null; } - } - else - { + } else { return null; } - } - // If we didn't find the correct crosswalk, we will check to see if this is - // a StreamDisseminationCrosswalk -- a Stream crosswalk disseminates to an OutputStream - else - { + } else { + // If we didn't find the correct crosswalk, we will check to see if this is + // a StreamDisseminationCrosswalk -- a Stream crosswalk disseminates to an OutputStream + StreamDisseminationCrosswalk sxwalk = (StreamDisseminationCrosswalk) pluginService.getNamedPlugin(StreamDisseminationCrosswalk.class, xwalkName); - if (sxwalk != null) - { - if (sxwalk.canDisseminate(context, dso)) - { + if (sxwalk != null) { + if (sxwalk.canDisseminate(context, dso)) { // Check if our Crosswalk actually wraps another Packager Plugin - if(sxwalk instanceof AbstractPackagerWrappingCrosswalk) - { + if (sxwalk instanceof AbstractPackagerWrappingCrosswalk) { // If this crosswalk wraps another Packager Plugin, we can pass it our Packaging Parameters // (which essentially allow us to customize the output of the crosswalk) AbstractPackagerWrappingCrosswalk wrapper = (AbstractPackagerWrappingCrosswalk) sxwalk; @@ -662,11 +619,11 @@ public abstract class AbstractMETSDisseminator ByteArrayOutputStream disseminateOutput = new ByteArrayOutputStream(); sxwalk.disseminate(context, dso, disseminateOutput); // Convert output to an inputstream, so we can write to manifest or Zip file - ByteArrayInputStream crosswalkedStream = new ByteArrayInputStream(disseminateOutput.toByteArray()); + ByteArrayInputStream crosswalkedStream = new ByteArrayInputStream( + disseminateOutput.toByteArray()); //If we are capturing extra files to put into a Zip package - if(extraStreams!=null) - { + if (extraStreams != null) { //Create an -- we'll just reference the file by name in Zip package MdRef mdRef = new MdRef(); //add the crosswalked Stream to list of files to add to Zip package later @@ -679,9 +636,7 @@ public abstract class AbstractMETSDisseminator setMdType(mdRef, metsName); mdRef.setLOCTYPE(Loctype.URL); mdSec.getContent().add(mdRef); - } - else - { + } else { //If we are *not* capturing extra streams to add to Zip package later, // that means we are likely only generating a METS manifest // (i.e. manifestOnly = true) @@ -702,25 +657,19 @@ public abstract class AbstractMETSDisseminator } return mdSec; - } - else - { + } else { return null; } - } - else - { - throw new PackageValidationException("Cannot find " + xwalkName + " crosswalk plugin, either DisseminationCrosswalk or StreamDisseminationCrosswalk"); + } else { + throw new PackageValidationException( + "Cannot find " + xwalkName + " crosswalk plugin, either DisseminationCrosswalk or " + + "StreamDisseminationCrosswalk"); } } - } - catch (InstantiationException e) - { - throw new PackageValidationException("Error instantiating Mdsec object: "+ e.toString(), e); - } - catch (IllegalAccessException e) - { - throw new PackageValidationException("Error instantiating Mdsec object: "+ e.toString(), e); + } catch (InstantiationException e) { + throw new PackageValidationException("Error instantiating Mdsec object: " + e.toString(), e); + } catch (IllegalAccessException e) { + throw new PackageValidationException("Error instantiating Mdsec object: " + e.toString(), e); } } @@ -728,17 +677,14 @@ public abstract class AbstractMETSDisseminator // mdSecClass determines which type. // mdTypes[] is array of "[metsName:]PluginName" strings, maybe empty. protected void addToAmdSec(AmdSec fAmdSec, String mdTypes[], Class mdSecClass, - Context context, DSpaceObject dso, - PackageParameters params, - MdStreamCache extraStreams) + Context context, DSpaceObject dso, + PackageParameters params, + MdStreamCache extraStreams) throws SQLException, PackageValidationException, CrosswalkException, - IOException, AuthorizeException - { - for (int i = 0; i < mdTypes.length; ++i) - { + IOException, AuthorizeException { + for (int i = 0; i < mdTypes.length; ++i) { MdSec md = makeMdSec(context, dso, mdSecClass, mdTypes[i], params, extraStreams); - if (md != null) - { + if (md != null) { fAmdSec.getContent().add(md); } } @@ -746,19 +692,17 @@ public abstract class AbstractMETSDisseminator // Create amdSec for any tech md's, return its ID attribute. protected String addAmdSec(Context context, DSpaceObject dso, PackageParameters params, - Mets mets, MdStreamCache extraStreams) + Mets mets, MdStreamCache extraStreams) throws SQLException, PackageValidationException, CrosswalkException, - IOException, AuthorizeException - { + IOException, AuthorizeException { String techMdTypes[] = getTechMdTypes(context, dso, params); String rightsMdTypes[] = getRightsMdTypes(context, dso, params); String sourceMdTypes[] = getSourceMdTypes(context, dso, params); String digiprovMdTypes[] = getDigiprovMdTypes(context, dso, params); // only bother if there are any sections to add - if ((techMdTypes.length+sourceMdTypes.length+ - digiprovMdTypes.length+rightsMdTypes.length) > 0) - { + if ((techMdTypes.length + sourceMdTypes.length + + digiprovMdTypes.length + rightsMdTypes.length) > 0) { String result = gensym("amd"); AmdSec fAmdSec = new AmdSec(); fAmdSec.setID(result); @@ -769,26 +713,20 @@ public abstract class AbstractMETSDisseminator mets.getContent().add(fAmdSec); return result; - } - else - { + } else { return null; } } // make the most "persistent" identifier possible, preferably a URN // based on the Handle. - protected String makePersistentID(DSpaceObject dso) - { + protected String makePersistentID(DSpaceObject dso) { String handle = dso.getHandle(); // If no Handle, punt to much-less-satisfactory database ID and type.. - if (handle == null) - { + if (handle == null) { return "DSpace_DB_" + Constants.typeText[dso.getType()] + "_" + String.valueOf(dso.getID()); - } - else - { + } else { return getHandleURN(handle); } } @@ -796,33 +734,33 @@ public abstract class AbstractMETSDisseminator /** * Write out a METS manifest. * Mostly lifted from Rob Tansley's METS exporter. - * @param context context - * @param dso DSpaceObject - * @param params packaging params + * + * @param context context + * @param dso DSpaceObject + * @param params packaging params * @param extraStreams streams * @return METS manifest - * @throws MetsException if mets error + * @throws MetsException if mets error * @throws PackageValidationException if validation error - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error */ protected Mets makeManifest(Context context, DSpaceObject dso, - PackageParameters params, - MdStreamCache extraStreams) - throws MetsException, PackageValidationException, CrosswalkException, AuthorizeException, SQLException, IOException + PackageParameters params, + MdStreamCache extraStreams) + throws MetsException, PackageValidationException, CrosswalkException, AuthorizeException, SQLException, + IOException { - { // Create the METS manifest in memory Mets mets = new Mets(); - + String identifier = "DB-ID-" + dso.getID(); - if(dso.getHandle()!=null) - { + if (dso.getHandle() != null) { identifier = dso.getHandle().replace('/', '-'); } - + // this ID should be globally unique (format: DSpace_[objType]_[handle with slash replaced with a dash]) mets.setID("DSpace_" + Constants.typeText[dso.getType()] + "_" + identifier); @@ -835,8 +773,7 @@ public abstract class AbstractMETSDisseminator mets.setPROFILE(getProfile()); MetsHdr metsHdr = makeMetsHdr(context, dso, params); - if (metsHdr != null) - { + if (metsHdr != null) { mets.getContent().add(metsHdr); } @@ -847,11 +784,9 @@ public abstract class AbstractMETSDisseminator // record of ID of each dmdsec to make DMDID in structmap. String dmdId[] = new String[dmdTypes.length]; - for (int i = 0; i < dmdTypes.length; ++i) - { + for (int i = 0; i < dmdTypes.length; ++i) { MdSec dmdSec = makeMdSec(context, dso, DmdSec.class, dmdTypes[i], params, extraStreams); - if (dmdSec != null) - { + if (dmdSec != null) { mets.getContent().add(dmdSec); dmdId[i] = dmdSec.getID(); } @@ -877,11 +812,10 @@ public abstract class AbstractMETSDisseminator FileSec fileSec = null; // Item-specific manifest - license, bitstreams as Files, etc. - if (dso.getType() == Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { // this tags file ID and group identifiers for bitstreams. String bitstreamIDstart = "bitstream_"; - Item item = (Item)dso; + Item item = (Item) dso; // how to handle unauthorized bundle/bitstream: String unauth = (params == null) ? null : params.getProperty("unauthorized"); @@ -892,8 +826,7 @@ public abstract class AbstractMETSDisseminator // at the same time so we can connect the IDREFs to IDs. fileSec = new FileSec(); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { if (!includeBundle(bundle)) { continue; } @@ -901,12 +834,13 @@ public abstract class AbstractMETSDisseminator // unauthorized bundle? // NOTE: This must match the logic in disseminate() if (!authorizeService.authorizeActionBoolean(context, - bundle, Constants.READ)) { + bundle, Constants.READ)) { if (unauth != null && - (unauth.equalsIgnoreCase("skip"))) { + (unauth.equalsIgnoreCase("skip"))) { continue; } else { - throw new AuthorizeException("Not authorized to read Bundle named \"" + bundle.getName() + "\""); + throw new AuthorizeException( + "Not authorized to read Bundle named \"" + bundle.getName() + "\""); } } @@ -934,20 +868,20 @@ public abstract class AbstractMETSDisseminator } // For each bitstream, add to METS manifest - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { // Check for authorization. Handle unauthorized // bitstreams to match the logic in disseminate(), // i.e. "unauth=zero" means include a 0-length bitstream, // "unauth=skip" means to ignore it (and exclude from // manifest). boolean auth = authorizeService.authorizeActionBoolean(context, - bitstream, Constants.READ); + bitstream, Constants.READ); if (!auth) { if (unauth != null && unauth.equalsIgnoreCase("skip")) { continue; } else if (!(unauth != null && unauth.equalsIgnoreCase("zero"))) { - throw new AuthorizeException("Not authorized to read Bitstream, SID=" + String.valueOf(bitstream.getSequenceID())); + throw new AuthorizeException( + "Not authorized to read Bitstream, SID=" + String.valueOf(bitstream.getSequenceID())); } } @@ -977,20 +911,20 @@ public abstract class AbstractMETSDisseminator */ String groupID = "GROUP_" + bitstreamIDstart + sid; if ((bundle.getName() != null) - && (bundle.getName().equals("THUMBNAIL") || - bundle.getName().startsWith("TEXT"))) { + && (bundle.getName().equals("THUMBNAIL") || + bundle.getName().startsWith("TEXT"))) { // Try and find the original bitstream, and chuck the // derived bitstream in the same group Bitstream original = findOriginalBitstream(item, - bitstream); + bitstream); if (original != null) { groupID = "GROUP_" + bitstreamIDstart - + original.getSequenceID(); + + original.getSequenceID(); } } file.setGROUPID(groupID); file.setMIMETYPE(bitstream.getFormat(context).getMIMEType()); - file.setSIZE(auth ? bitstream.getSize() : 0); + file.setSIZE(auth ? bitstream.getSizeBytes() : 0); // Translate checksum and type to METS String csType = bitstream.getChecksumAlgorithm(); @@ -1018,26 +952,21 @@ public abstract class AbstractMETSDisseminator } fileSec.getContent().add(fileGrp); } - } - else if (dso.getType() == Constants.COLLECTION) - { - Collection collection = (Collection)dso; + } else if (dso.getType() == Constants.COLLECTION) { + Collection collection = (Collection) dso; Iterator ii = itemService.findByCollection(context, collection); - while (ii.hasNext()) - { + while (ii.hasNext()) { //add a child
    for each item in collection Item item = ii.next(); Div childDiv = makeChildDiv(getObjectTypeString(item), item, params); - if(childDiv!=null) - { + if (childDiv != null) { div0.getContent().add(childDiv); } } // add metadata & info for Template Item, if exists Item templateItem = collection.getTemplateItem(); - if(templateItem!=null) - { + if (templateItem != null) { String templateDmdId[] = new String[dmdTypes.length]; // index where we should add the first template item . // Index = number of already added + number of = # of dmdSecs + 1 @@ -1046,11 +975,10 @@ public abstract class AbstractMETSDisseminator //For each type of dmdSec specified, // add a new dmdSec which contains the Template Item metadata // (Note: Template Items are only metadata -- they have no content files) - for (int i = 0; i < dmdTypes.length; ++i) - { - MdSec templateDmdSec = makeMdSec(context, templateItem, DmdSec.class, dmdTypes[i], params, extraStreams); - if (templateDmdSec != null) - { + for (int i = 0; i < dmdTypes.length; ++i) { + MdSec templateDmdSec = makeMdSec(context, templateItem, DmdSec.class, dmdTypes[i], params, + extraStreams); + if (templateDmdSec != null) { mets.getContent().add(dmdIndex, templateDmdSec); dmdIndex++; templateDmdId[i] = templateDmdSec.getID(); @@ -1063,8 +991,7 @@ public abstract class AbstractMETSDisseminator templateItemDiv.setTYPE(getObjectTypeString(templateItem) + TEMPLATE_TYPE_SUFFIX); //Link up the dmdSec(s) for the Template Item to this
    StringBuilder templateDmdIds = new StringBuilder(); - for (String currdmdId : templateDmdId) - { + for (String currdmdId : templateDmdId) { templateDmdIds.append(" ").append(currdmdId); } templateItemDiv.setDMDID(templateDmdIds.substring(1)); @@ -1074,19 +1001,15 @@ public abstract class AbstractMETSDisseminator // add link to Collection Logo, if one exists Bitstream logoBs = collection.getLogo(); - if (logoBs != null) - { + if (logoBs != null) { fileSec = new FileSec(); addLogoBitstream(context, logoBs, fileSec, div0, params); } - } - else if (dso.getType() == Constants.COMMUNITY) - { + } else if (dso.getType() == Constants.COMMUNITY) { // Subcommunities are directly under "DSpace Object Contents"
    , // but are labeled as Communities. - List subcomms = ((Community)dso).getSubcommunities(); - for (Community subcomm : subcomms) - { + List subcomms = ((Community) dso).getSubcommunities(); + for (Community subcomm : subcomms) { //add a child
    for each subcommunity in this community Div childDiv = makeChildDiv(getObjectTypeString(subcomm), subcomm, params); if (childDiv != null) { @@ -1095,9 +1018,8 @@ public abstract class AbstractMETSDisseminator } // Collections are also directly under "DSpace Object Contents"
    , // but are labeled as Collections. - List colls = ((Community)dso).getCollections(); - for (Collection coll : colls) - { + List colls = ((Community) dso).getCollections(); + for (Collection coll : colls) { //add a child
    for each collection in this community Div childDiv = makeChildDiv(getObjectTypeString(coll), coll, params); if (childDiv != null) { @@ -1105,23 +1027,19 @@ public abstract class AbstractMETSDisseminator } } //add Community logo bitstream - Bitstream logoBs = ((Community)dso).getLogo(); - if (logoBs != null) - { + Bitstream logoBs = ((Community) dso).getLogo(); + if (logoBs != null) { fileSec = new FileSec(); addLogoBitstream(context, logoBs, fileSec, div0, params); } - } - else if (dso.getType() == Constants.SITE) - { + } else if (dso.getType() == Constants.SITE) { // This is a site-wide , which just lists the top-level // communities. Each top level community is referenced by a div. List comms = communityService.findAllTop(context); - for (Community comm : comms) - { + for (Community comm : comms) { //add a child
    for each top level community in this site Div childDiv = makeChildDiv(getObjectTypeString(comm), - comm, params); + comm, params); if (childDiv != null) { div0.getContent().add(childDiv); } @@ -1129,24 +1047,21 @@ public abstract class AbstractMETSDisseminator } //Only add the to the METS file if it has content. A must have content. - if (fileSec != null && fileSec.getContent()!=null && !fileSec.getContent().isEmpty()) - { + if (fileSec != null && fileSec.getContent() != null && !fileSec.getContent().isEmpty()) { mets.getContent().add(fileSec); } - + mets.getContent().add(structMap); // set links to metadata for object -- after type-specific // code since that can add to the object metadata. StringBuilder dmdIds = new StringBuilder(); - for (String currdmdId : dmdId) - { + for (String currdmdId : dmdId) { dmdIds.append(" ").append(currdmdId); } div0.setDMDID(dmdIds.substring(1)); - if (objectAMDID != null) - { + if (objectAMDID != null) { div0.setADMID(objectAMDID); } @@ -1159,26 +1074,23 @@ public abstract class AbstractMETSDisseminator // Install logo bitstream into METS for Community, Collection. // Add a file element, and refer to it from an fptr in the first div // of the main structMap. - protected void addLogoBitstream(Context context, Bitstream logoBs, FileSec fileSec, Div div0, PackageParameters params) throws SQLException { + protected void addLogoBitstream(Context context, Bitstream logoBs, FileSec fileSec, Div div0, + PackageParameters params) throws SQLException { edu.harvard.hul.ois.mets.File file = new edu.harvard.hul.ois.mets.File(); String fileID = gensym("logo"); file.setID(fileID); file.setMIMETYPE(logoBs.getFormat(context).getMIMEType()); - file.setSIZE(logoBs.getSize()); + file.setSIZE(logoBs.getSizeBytes()); // Translate checksum and type to METS String csType = logoBs.getChecksumAlgorithm(); String cs = logoBs.getChecksum(); - if (cs != null && csType != null) - { - try - { + if (cs != null && csType != null) { + try { file.setCHECKSUMTYPE(Checksumtype.parse(csType)); file.setCHECKSUM(cs); - } - catch (MetsException e) - { - log.warn("Cannot set bitstream checksum type="+csType+" in METS."); + } catch (MetsException e) { + log.warn("Cannot set bitstream checksum type=" + csType + " in METS."); } } @@ -1199,8 +1111,7 @@ public abstract class AbstractMETSDisseminator } // create
    element pointing to a file - protected Div makeFileDiv(String fileID, String type) - { + protected Div makeFileDiv(String fileID, String type) { Div div = new Div(); div.setID(gensym("div")); div.setTYPE(type); @@ -1214,27 +1125,24 @@ public abstract class AbstractMETSDisseminator * Create a {@code
    } element with {@code } which references a child * object via its handle (and via a local file name, when recursively disseminating * all child objects). - * @param type - type attr value for the {@code
    } - * @param dso - object for which to create the div + * + * @param type - type attr value for the {@code
    } + * @param dso - object for which to create the div * @param params package params * @return a new {@code Div} with {@code dso} as child. */ - protected Div makeChildDiv(String type, DSpaceObject dso, PackageParameters params) - { + protected Div makeChildDiv(String type, DSpaceObject dso, PackageParameters params) { String handle = dso.getHandle(); //start
    Div div = new Div(); div.setID(gensym("div")); div.setTYPE(type); - + //make sure we have a handle - if (handle == null || handle.length()==0) - { - log.warn("METS Disseminator is skipping "+type+" without handle: " + dso.toString()); - } - else - { + if (handle == null || handle.length() == 0) { + log.warn("METS Disseminator is skipping " + type + " without handle: " + dso.toString()); + } else { //create with handle reference Mptr mptr = new Mptr(); mptr.setID(gensym("mptr")); @@ -1245,7 +1153,7 @@ public abstract class AbstractMETSDisseminator //determine file extension of child references, //based on whether we are exporting just a manifest or a full Zip pkg - String childFileExtension = (params.getBooleanProperty("manifestOnly", false)) ? "xml" : "zip"; + String childFileExtension = (params.getBooleanProperty("manifestOnly", false)) ? "xml" : "zip"; // Always create with file-name reference to child package // This is what DSpace will expect the child package to be named during ingestion @@ -1253,7 +1161,8 @@ public abstract class AbstractMETSDisseminator Mptr mptr2 = new Mptr(); mptr2.setID(gensym("mptr")); mptr2.setLOCTYPE(Loctype.URL); - //we get the name of the child package from the Packager -- as it is what will actually create this child pkg file + //we get the name of the child package from the Packager -- as it is what will actually create this child pkg + // file mptr2.setXlinkHref(PackageUtils.getPackageName(dso, childFileExtension)); div.getContent().add(mptr2); @@ -1262,47 +1171,39 @@ public abstract class AbstractMETSDisseminator // put handle in canonical URN format -- note that HandleManager's // canonicalize currently returns HTTP URL format. - protected String getHandleURN(String handle) - { - if (handle.startsWith("hdl:")) - { + protected String getHandleURN(String handle) { + if (handle.startsWith("hdl:")) { return handle; } - return "hdl:"+handle; + return "hdl:" + handle; } /** * For a bitstream that's a thumbnail or extracted text, find the * corresponding bitstream it was derived from, in the ORIGINAL bundle. * - * @param item - * the item we're dealing with - * @param derived - * the derived bitstream - * + * @param item the item we're dealing with + * @param derived the derived bitstream * @return the corresponding original bitstream (or null) * @throws SQLException if database error */ protected Bitstream findOriginalBitstream(Item item, Bitstream derived) - throws SQLException - { + throws SQLException { List bundles = item.getBundles(); // Filename of original will be filename of the derived bitstream // minus the extension (last 4 chars - .jpg or .txt) String originalFilename = derived.getName().substring(0, - derived.getName().length() - 4); + derived.getName().length() - 4); // First find "original" bundle - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { if ((bundle.getName() != null) - && bundle.getName().equals("ORIGINAL")) { + && bundle.getName().equals("ORIGINAL")) { // Now find the corresponding bitstream List bitstreams = bundle.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { if (bitstream.getName().equals(originalFilename)) { return bitstream; } @@ -1318,60 +1219,47 @@ public abstract class AbstractMETSDisseminator // including namespaces and schema. // returns the new/modified element upon success. protected MetsElement crosswalkToMetsElement(Context context, DisseminationCrosswalk xwalk, - DSpaceObject dso, MetsElement me) + DSpaceObject dso, MetsElement me) throws CrosswalkException, - IOException, SQLException, AuthorizeException - { - try - { + IOException, SQLException, AuthorizeException { + try { // add crosswalk's namespaces and schemaLocation to this element: String raw = xwalk.getSchemaLocation(); String sloc[] = raw == null ? null : raw.split("\\s+"); Namespace ns[] = xwalk.getNamespaces(); - for (int i = 0; i < ns.length; ++i) - { + for (int i = 0; i < ns.length; ++i) { String uri = ns[i].getURI(); - if (sloc != null && sloc.length > 1 && uri.equals(sloc[0])) - { + if (sloc != null && sloc.length > 1 && uri.equals(sloc[0])) { me.setSchema(ns[i].getPrefix(), uri, sloc[1]); - } - else - { + } else { me.setSchema(ns[i].getPrefix(), uri); } } // add result of crosswalk PreformedXML pXML = null; - if (xwalk.preferList()) - { + if (xwalk.preferList()) { List res = xwalk.disseminateList(context, dso); - if (!(res == null || res.isEmpty())) - { + if (!(res == null || res.isEmpty())) { pXML = new PreformedXML(outputter.outputString(res)); } - } - else - { + } else { Element res = xwalk.disseminateElement(context, dso); - if (res != null) - { + if (res != null) { pXML = new PreformedXML(outputter.outputString(res)); } } - if (pXML != null) - { + if (pXML != null) { me.getContent().add(pXML); return me; } return null; - } - catch (CrosswalkObjectNotSupported e) - { + } catch (CrosswalkObjectNotSupported e) { // ignore this xwalk if object is unsupported. - if (log.isDebugEnabled()) - { - log.debug("Skipping MDsec because of CrosswalkObjectNotSupported: dso=" + dso.toString() + ", xwalk=" + xwalk.getClass().getName()); + if (log.isDebugEnabled()) { + log.debug( + "Skipping MDsec because of CrosswalkObjectNotSupported: dso=" + dso.toString() + ", xwalk=" + xwalk + .getClass().getName()); } return null; } @@ -1389,61 +1277,56 @@ public abstract class AbstractMETSDisseminator * METS file to look for these inconsistencies/duplications. * * @param context current DSpace Context - * @param params current Packager Parameters - * @param dso current DSpace Object - * @param mdRef the rightsMD {@code } element - * @throws SQLException if database error - * @throws IOException if IO error + * @param params current Packager Parameters + * @param dso current DSpace Object + * @param mdRef the rightsMD {@code } element + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ protected void linkLicenseRefsToBitstreams(Context context, PackageParameters params, - DSpaceObject dso, MdRef mdRef) - throws SQLException, IOException, AuthorizeException - { + DSpaceObject dso, MdRef mdRef) + throws SQLException, IOException, AuthorizeException { //If this is a reference to a DSpace Deposit License - if(mdRef.getMDTYPE()!=null && mdRef.getMDTYPE()==Mdtype.OTHER && - mdRef.getOTHERMDTYPE()!=null && mdRef.getOTHERMDTYPE().equals("DSpaceDepositLicense")) - { + if (mdRef.getMDTYPE() != null && mdRef.getMDTYPE() == Mdtype.OTHER && + mdRef.getOTHERMDTYPE() != null && mdRef.getOTHERMDTYPE().equals("DSpaceDepositLicense")) { //Locate the LICENSE bundle - Item i = (Item)dso; + Item i = (Item) dso; List license = itemService.getBundles(i, Constants.LICENSE_BUNDLE_NAME); //Are we already including the LICENSE bundle's bitstreams in this package? - if(license!=null && license.size()>0 && includeBundle(license.get(0))) - { + if (license != null && license.size() > 0 && includeBundle(license.get(0))) { //Since we are including the LICENSE bitstreams, lets find our LICENSE bitstream path & link to it. - Bitstream licenseBs = PackageUtils.findDepositLicense(context, (Item)dso); + Bitstream licenseBs = PackageUtils.findDepositLicense(context, (Item) dso); mdRef.setXlinkHref(makeBitstreamURL(context, licenseBs, params)); } - } - //If this is a reference to a Creative Commons Textual License - else if(mdRef.getMDTYPE() != null && mdRef.getMDTYPE() == Mdtype.OTHER && - mdRef.getOTHERMDTYPE()!=null && mdRef.getOTHERMDTYPE().equals("CreativeCommonsText")) - { + } else if (mdRef.getMDTYPE() != null && mdRef.getMDTYPE() == Mdtype.OTHER && + mdRef.getOTHERMDTYPE() != null && mdRef.getOTHERMDTYPE().equals("CreativeCommonsText")) { + //If this is a reference to a Creative Commons Textual License + //Locate the CC-LICENSE bundle - Item i = (Item)dso; + Item i = (Item) dso; List license = itemService.getBundles(i, CreativeCommonsService.CC_BUNDLE_NAME); //Are we already including the CC-LICENSE bundle's bitstreams in this package? - if(license!=null && license.size()>0 && includeBundle(license.get(0))) - { - //Since we are including the CC-LICENSE bitstreams, lets find our CC-LICENSE (textual) bitstream path & link to it. + if (license != null && license.size() > 0 && includeBundle(license.get(0))) { + //Since we are including the CC-LICENSE bitstreams, lets find our CC-LICENSE (textual) bitstream path + // & link to it. Bitstream ccText = creativeCommonsService.getLicenseTextBitstream(i); mdRef.setXlinkHref(makeBitstreamURL(context, ccText, params)); } - } - //If this is a reference to a Creative Commons RDF License - else if(mdRef.getMDTYPE() != null && mdRef.getMDTYPE() == Mdtype.OTHER && - mdRef.getOTHERMDTYPE()!=null && mdRef.getOTHERMDTYPE().equals("CreativeCommonsRDF")) - { + } else if (mdRef.getMDTYPE() != null && mdRef.getMDTYPE() == Mdtype.OTHER && + mdRef.getOTHERMDTYPE() != null && mdRef.getOTHERMDTYPE().equals("CreativeCommonsRDF")) { + //If this is a reference to a Creative Commons RDF License + //Locate the CC-LICENSE bundle - Item i = (Item)dso; + Item i = (Item) dso; List license = itemService.getBundles(i, CreativeCommonsService.CC_BUNDLE_NAME); //Are we already including the CC-LICENSE bundle's bitstreams in this package? - if(license!=null && license.size()>0 && includeBundle(license.get(0))) - { - //Since we are including the CC-LICENSE bitstreams, lets find our CC-LICENSE (RDF) bitstream path & link to it. + if (license != null && license.size() > 0 && includeBundle(license.get(0))) { + //Since we are including the CC-LICENSE bitstreams, lets find our CC-LICENSE (RDF) bitstream path & + // link to it. Bitstream ccRdf = creativeCommonsService.getLicenseRdfBitstream(i); mdRef.setXlinkHref(makeBitstreamURL(context, ccRdf, params)); } @@ -1460,10 +1343,9 @@ public abstract class AbstractMETSDisseminator * @return a string which will represent this object Type in METS * @see org.dspace.core.Constants */ - public String getObjectTypeString(DSpaceObject dso) - { + public String getObjectTypeString(DSpaceObject dso) { //Format: "DSpace " (e.g. "DSpace ITEM", "DSpace COLLECTION", etc) - return "DSpace " + Constants.typeText[dso.getType()]; + return "DSpace " + Constants.typeText[dso.getType()]; } @@ -1477,15 +1359,14 @@ public abstract class AbstractMETSDisseminator * with this packager */ @Override - public String getParameterHelp() - { - return "* manifestOnly=[boolean] " + - "If true, only export the METS manifest (mets.xml) and don't export content files (defaults to false)." + - "\n\n" + - "* unauthorized=[value] " + - "If 'skip', skip over any files which the user doesn't have authorization to read. " + - "If 'zero', create a zero-length file for any files the user doesn't have authorization to read. " + - "By default, an AuthorizationException will be thrown for any files the user cannot read."; + public String getParameterHelp() { + return "* manifestOnly=[boolean] " + + "If true, only export the METS manifest (mets.xml) and don't export content files (defaults to false)." + + "\n\n" + + "* unauthorized=[value] " + + "If 'skip', skip over any files which the user doesn't have authorization to read. " + + "If 'zero', create a zero-length file for any files the user doesn't have authorization to read. " + + "By default, an AuthorizationException will be thrown for any files the user cannot read."; } /** @@ -1496,86 +1377,76 @@ public abstract class AbstractMETSDisseminator *

    * For a manifest-only METS, this is a reference to an HTTP URL where * the bitstream should be able to be downloaded from. - * - * @param context context - * @param bitstream the Bitstream - * @param params Packager Parameters + * + * @param context context + * @param bitstream the Bitstream + * @param params Packager Parameters * @return String in URL format naming path to bitstream. * @throws SQLException if database error */ public String makeBitstreamURL(Context context, Bitstream bitstream, PackageParameters params) throws SQLException { // if bare manifest, use external "persistent" URI for bitstreams - if (params != null && (params.getBooleanProperty("manifestOnly", false))) - { + if (params != null && (params.getBooleanProperty("manifestOnly", false))) { // Try to build a persistent(-ish) URI for bitstream // Format: {site-base-url}/bitstream/{item-handle}/{sequence-id}/{bitstream-name} - try - { + try { // get handle of parent Item of this bitstream, if there is one: String handle = null; List bn = bitstream.getBundles(); - if (bn.size() > 0) - { + if (bn.size() > 0) { List bi = bn.get(0).getItems(); - if (bi.size() > 0) - { + if (bi.size() > 0) { handle = bi.get(0).getHandle(); } } - if (handle != null) - { + if (handle != null) { return configurationService - .getProperty("dspace.url") - + "/bitstream/" - + handle - + "/" - + String.valueOf(bitstream.getSequenceID()) - + "/" - + URLEncoder.encode(bitstream.getName(), "UTF-8"); - } - else - { //no Handle assigned, so persistent(-ish) URI for bitstream is + .getProperty("dspace.url") + + "/bitstream/" + + handle + + "/" + + String.valueOf(bitstream.getSequenceID()) + + "/" + + URLEncoder.encode(bitstream.getName(), "UTF-8"); + } else { //no Handle assigned, so persistent(-ish) URI for bitstream is // Format: {site-base-url}/retrieve/{bitstream-internal-id} return configurationService - .getProperty("dspace.url") - + "/retrieve/" - + String.valueOf(bitstream.getID()); + .getProperty("dspace.url") + + "/retrieve/" + + String.valueOf(bitstream.getID()); } - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Database problem", e); - } - catch (UnsupportedEncodingException e) - { + } catch (UnsupportedEncodingException e) { log.error("Unknown character set", e); } // We should only get here if we failed to build a nice URL above // so, by default, we're just going to return the bitstream name. return bitstream.getName(); - } - else - { - String base = "bitstream_"+String.valueOf(bitstream.getID()); + } else { + String base = "bitstream_" + String.valueOf(bitstream.getID()); List ext = bitstream.getFormat(context).getExtensions(); - return (ext.size() > 0) ? base+"."+ext.get(0) : base; + return (ext.size() > 0) ? base + "." + ext.get(0) : base; } } /** * Create metsHdr element - separate so subclasses can override. + * * @param context context - * @param dso DSpaceObject - * @param params packaging params + * @param dso DSpaceObject + * @param params packaging params * @return Mets header * @throws SQLException if database error */ public abstract MetsHdr makeMetsHdr(Context context, DSpaceObject dso, - PackageParameters params) throws SQLException; + PackageParameters params) throws SQLException; + /** * Returns name of METS profile to which this package conforms, e.g. - * "DSpace METS DIP Profile 1.0" + * "DSpace METS DIP Profile 1.0" + * * @return string name of profile. */ public abstract String getProfile(); @@ -1597,28 +1468,30 @@ public abstract class AbstractMETSDisseminator * E.g. the type string "DC:qualifiedDublinCore" tells it to * create a METS section with MDTYPE="DC" and use the plugin * named "qualifiedDublinCore" to obtain the data. + * * @param context context - * @param dso DSpaceObject - * @param params the PackageParameters passed to the disseminator. + * @param dso DSpaceObject + * @param params the PackageParameters passed to the disseminator. * @return array of metadata type strings, never null. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public abstract String [] getDmdTypes(Context context, DSpaceObject dso, PackageParameters params) + public abstract String[] getDmdTypes(Context context, DSpaceObject dso, PackageParameters params) throws SQLException, IOException, AuthorizeException; /** * Get the type string of the technical metadata to create for each * object and each Bitstream in an Item. The type string may be a * simple name or colon-separated compound as specified for - * getDmdTypes() above. + * getDmdTypes() above. + * * @param context context - * @param dso DSpaceObject - * @param params the PackageParameters passed to the disseminator. + * @param dso DSpaceObject + * @param params the PackageParameters passed to the disseminator. * @return array of metadata type strings, never null. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public abstract String[] getTechMdTypes(Context context, DSpaceObject dso, PackageParameters params) @@ -1629,12 +1502,13 @@ public abstract class AbstractMETSDisseminator * object and each Bitstream in an Item. The type string may be a * simple name or colon-separated compound as specified for * getDmdTypes() above. + * * @param context context - * @param dso DSpaceObject - * @param params the PackageParameters passed to the disseminator. + * @param dso DSpaceObject + * @param params the PackageParameters passed to the disseminator. * @return array of metadata type strings, never null. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public abstract String[] getSourceMdTypes(Context context, DSpaceObject dso, PackageParameters params) @@ -1647,11 +1521,11 @@ public abstract class AbstractMETSDisseminator * as specified for getDmdTypes() above. * * @param context context - * @param dso DSpaceObject - * @param params the PackageParameters passed to the disseminator. + * @param dso DSpaceObject + * @param params the PackageParameters passed to the disseminator. * @return array of metadata type strings, never null. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public abstract String[] getDigiprovMdTypes(Context context, DSpaceObject dso, PackageParameters params) @@ -1664,11 +1538,11 @@ public abstract class AbstractMETSDisseminator * as specified for getDmdTypes() above. * * @param context context - * @param dso DSpaceObject - * @param params the PackageParameters passed to the disseminator. + * @param dso DSpaceObject + * @param params the PackageParameters passed to the disseminator. * @return array of metadata type strings, never null. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public abstract String[] getRightsMdTypes(Context context, DSpaceObject dso, PackageParameters params) @@ -1679,23 +1553,24 @@ public abstract class AbstractMETSDisseminator * METS document, as required by this subclass. A simple default * structure map which fulfills the minimal DSpace METS DIP/SIP * requirements is already present, so this does not need to do anything. + * * @param context context - * @param dso DSpaceObject - * @param mets the METS document to which to add structMaps - * @param params the PackageParameters passed to the disseminator. - * @throws IOException if IO error - * @throws SQLException if database error + * @param dso DSpaceObject + * @param mets the METS document to which to add structMaps + * @param params the PackageParameters passed to the disseminator. + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws MetsException if METS error + * @throws MetsException if METS error */ public abstract void addStructMap(Context context, DSpaceObject dso, - PackageParameters params, Mets mets) + PackageParameters params, Mets mets) throws SQLException, IOException, AuthorizeException, MetsException; /** * @param bundle bundle * @return true when this bundle should be included as "content" - * in the package.. e.g. DSpace SIP does not include metadata bundles. + * in the package.. e.g. DSpace SIP does not include metadata bundles. */ public abstract boolean includeBundle(Bundle bundle); } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java index 568ed15731..5ecaa5c09c 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java @@ -19,14 +19,28 @@ import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +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.DSpaceObject; +import org.dspace.content.InProgressSubmission; +import org.dspace.content.Item; +import org.dspace.content.WorkspaceItem; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.MetadataValidationException; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +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.content.service.WorkspaceItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -47,43 +61,43 @@ import org.jdom.Element; * ingesters for more specific METS "profiles". METS is an abstract and flexible * framework that can encompass many different kinds of metadata and inner * package structures. - * + * *

    * Package Parameters: *

      - *
    • validate -- true/false attempt to schema-validate the METS + *
    • validate -- true/false attempt to schema-validate the METS * manifest.
    • - *
    • manifestOnly -- package consists only of a manifest + *
    • manifestOnly -- package consists only of a manifest * document.
    • - *
    • ignoreHandle -- true/false, ignore AIP's idea of handle + *
    • ignoreHandle -- true/false, ignore AIP's idea of handle * when ingesting.
    • - *
    • ignoreParent -- true/false, ignore AIP's idea of parent + *
    • ignoreParent -- true/false, ignore AIP's idea of parent * when ingesting.
    • *
    *

    * Configuration Properties: *

      - *
    • mets.CONFIGNAME.ingest.preserveManifest - if true, + *
    • mets.CONFIGNAME.ingest.preserveManifest - if true, * the METS manifest itself is preserved in a bitstream named * mets.xml in the METADATA bundle. If it is * false (the default), the manifest is discarded after ingestion.
    • - * - *
    • mets.CONFIGNAME.ingest.manifestBitstreamFormat - short name + * + *
    • mets.CONFIGNAME.ingest.manifestBitstreamFormat - short name * of the bitstream format to apply to the manifest; MUST be specified when * preserveManifest is true.
    • - * - *
    • mets.default.ingest.crosswalk.MD_SEC_NAME = PLUGIN_NAME + * + *
    • mets.default.ingest.crosswalk.MD_SEC_NAME = PLUGIN_NAME * Establishes a default crosswalk plugin for the given type of metadata in a * METS mdSec (e.g. "DC", "MODS"). The plugin may be either a stream or * XML-oriented ingestion crosswalk. Subclasses can override the default mapping * with their own, substituting their configurationName for "default" in the * configuration property key above.
    • - * - *
    • mets.CONFIGNAME.ingest.useCollectionTemplate - if + * + *
    • mets.CONFIGNAME.ingest.useCollectionTemplate - if * true, when an item is created, use the collection template. If it is * false (the default), any existing collection template is ignored.
    • *
    - * + * * @author Larry Stone * @author Tim Donohue * @version $Revision$ @@ -91,19 +105,22 @@ import org.jdom.Element; * @see AbstractPackageIngester * @see PackageIngester */ -public abstract class AbstractMETSIngester extends AbstractPackageIngester -{ - /** log4j category */ +public abstract class AbstractMETSIngester extends AbstractPackageIngester { + /** + * log4j category + */ private static Logger log = Logger.getLogger(AbstractMETSIngester.class); protected final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - protected final BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + protected final BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); protected final BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); protected final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - protected final WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); + protected final WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance() + .getWorkspaceItemService(); /** *

    @@ -115,15 +132,13 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester * metadata bitstreams. Match an mdRef by finding the bitstream with the * same name. */ - protected static final class MdrefManager implements METSManifest.Mdref - { + protected static final class MdrefManager implements METSManifest.Mdref { private File packageFile = null; private PackageParameters params; // constructor initializes from package file - private MdrefManager(File packageFile, PackageParameters params) - { + private MdrefManager(File packageFile, PackageParameters params) { super(); this.packageFile = packageFile; this.params = params; @@ -133,90 +148,79 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester * Make the contents of an external resource mentioned in an * mdRef element available as an InputStream. * See the METSManifest.MdRef interface for details. - * - * @param mdref - * the METS mdRef element to locate the input for. + * + * @param mdref the METS mdRef element to locate the input for. * @return the input stream of its content. * @throws MetadataValidationException if validation error - * @throws IOException if IO error + * @throws IOException if IO error * @see METSManifest */ @Override public InputStream getInputStream(Element mdref) - throws MetadataValidationException, IOException - { + throws MetadataValidationException, IOException { String path = METSManifest.getFileName(mdref); - if (packageFile == null) - { + if (packageFile == null) { throw new MetadataValidationException( - "Failed referencing mdRef element, because there is no package specified."); + "Failed referencing mdRef element, because there is no package specified."); } // Use the 'getFileInputStream()' method from the // AbstractMETSIngester to retrieve the inputstream for the // referenced external metadata file. return AbstractMETSIngester.getFileInputStream(packageFile, params, - path); + path); } - }// end MdrefManager class + } // end MdrefManager class /** * Create a new DSpace object out of a METS content package. All contents * are dictated by the METS manifest. Package is a ZIP archive (or * optionally bare manifest XML document). In a Zip, all files relative to * top level and the manifest (as per spec) in mets.xml. - * - * @param context - * DSpace context. - * @param parent - * parent under which to create new object (may be null -- in - * which case ingester must determine parent from package or - * throw an error). - * @param pkgFile - * The package file to ingest - * @param params - * Properties-style list of options (interpreted by each - * packager). - * @param license - * may be null, which takes default license. + * + * @param context DSpace context. + * @param parent parent under which to create new object (may be null -- in + * which case ingester must determine parent from package or + * throw an error). + * @param pkgFile The package file to ingest + * @param params Properties-style list of options (interpreted by each + * packager). + * @param license may be null, which takes default license. * @return DSpaceObject created by ingest. - * * @throws PackageValidationException if package validation error - * if package is unacceptable or there is a fatal error turning - * it into a DSpaceObject. - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error - * @throws WorkflowException if workflow error + * if package is unacceptable or there is a fatal error turning + * it into a DSpaceObject. + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error + * @throws WorkflowException if workflow error */ @Override public DSpaceObject ingest(Context context, DSpaceObject parent, - File pkgFile, PackageParameters params, String license) - throws PackageValidationException, CrosswalkException, - AuthorizeException, SQLException, IOException, WorkflowException { + File pkgFile, PackageParameters params, String license) + throws PackageValidationException, CrosswalkException, + AuthorizeException, SQLException, IOException, WorkflowException { // parsed out METS Manifest from the file. METSManifest manifest = null; // new DSpace object created DSpaceObject dso = null; - try - { + try { log.info(LogManager.getHeader(context, "package_parse", - "Parsing package for ingest, file=" + pkgFile.getName())); + "Parsing package for ingest, file=" + pkgFile.getName())); // Parse our ingest package, extracting out the METS manifest in the // package manifest = parsePackage(context, pkgFile, params); // must have a METS Manifest to ingest anything - if (manifest == null) - { + if (manifest == null) { throw new PackageValidationException( - "No METS Manifest found (filename=" - + METSManifest.MANIFEST_FILE - + "). Package is unacceptable!"); + "No METS Manifest found (filename=" + + METSManifest.MANIFEST_FILE + + "). Package is unacceptable!"); } // validate our manifest @@ -226,45 +230,41 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // object) then, default the 'ignoreHandle' option to true (as a new // object should get a new handle by default) if (!params.restoreModeEnabled() - && !params.containsKey("ignoreHandle")) - { // ignore the handle in the manifest, and instead create a new - // handle + && !params.containsKey("ignoreHandle")) { // ignore the handle in the manifest, and instead create a new + // handle params.addProperty("ignoreHandle", "true"); } // if we have a Parent Object, default 'ignoreParent' option to True // (this will ignore the Parent specified in manifest) - if (parent != null && !params.containsKey("ignoreParent")) - { // ignore the parent in the manifest, and instead use the - // specified parent object + if (parent != null && !params + .containsKey("ignoreParent")) { // ignore the parent in the manifest, and instead use the + // specified parent object params.addProperty("ignoreParent", "true"); } // Actually ingest the object described by the METS Manifest dso = ingestObject(context, parent, manifest, pkgFile, params, - license); + license); //if ingestion was successful - if (dso!=null) - { + if (dso != null) { // Log whether we finished an ingest (create new obj) or a restore // (restore previously existing obj) String action = "package_ingest"; - if (params.restoreModeEnabled()) - { + if (params.restoreModeEnabled()) { action = "package_restore"; } log.info(LogManager.getHeader(context, action, - "Created new Object, type=" - + Constants.typeText[dso.getType()] + ", handle=" - + dso.getHandle() + ", dbID=" - + String.valueOf(dso.getID()))); + "Created new Object, type=" + + Constants.typeText[dso.getType()] + ", handle=" + + dso.getHandle() + ", dbID=" + + String.valueOf(dso.getID()))); // Check if the Packager is currently running recursively. // If so, this means the Packager will attempt to recursively // ingest all referenced child packages. - if (params.recursiveModeEnabled()) - { + if (params.recursiveModeEnabled()) { // Retrieve list of all Child object METS file paths from the // current METS manifest. // This is our list of known child packages @@ -274,17 +274,14 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // DSpaceObject the pkgs relate to). // NOTE: The AbstractPackageIngester itself will perform the // recursive ingest call, based on these child pkg references - for (int i = 0; i < childFilePaths.length; i++) - { + for (int i = 0; i < childFilePaths.length; i++) { addPackageReference(dso, childFilePaths[i]); } } - }//end if dso not null - + } //end if dso not null + return dso; - } - catch (SQLException se) - { + } catch (SQLException se) { // no need to really clean anything up, // transaction rollback will get rid of it anyway. dso = null; @@ -297,23 +294,19 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester /** * Parse a given input package, ultimately returning the METS manifest out * of the package. METS manifest is assumed to be a file named 'mets.xml' - * - * @param context - * DSpace Context - * @param pkgFile - * package to parse - * @param params - * Ingestion parameters + * + * @param context DSpace Context + * @param pkgFile package to parse + * @param params Ingestion parameters * @return parsed out METSManifest - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error * @throws MetadataValidationException if metadata validation error */ protected METSManifest parsePackage(Context context, File pkgFile, - PackageParameters params) throws IOException, SQLException, - AuthorizeException, MetadataValidationException - { + PackageParameters params) throws IOException, SQLException, + AuthorizeException, MetadataValidationException { // whether or not to validate the METSManifest before processing // (default=false) // (Even though it's preferable to validate -- it's costly and takes a @@ -326,24 +319,19 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // try to locate the METS Manifest in package // 1. read "package" stream: it will be either bare Manifest // or Package contents into bitstreams, depending on params: - if (params.getBooleanProperty("manifestOnly", false)) - { + if (params.getBooleanProperty("manifestOnly", false)) { // parse the bare METS manifest and sanity-check it. manifest = METSManifest.create(new FileInputStream(pkgFile), - validate, getConfigurationName()); - } - else - { - try(ZipFile zip = new ZipFile(pkgFile)) - { + validate, getConfigurationName()); + } else { + try (ZipFile zip = new ZipFile(pkgFile)) { // Retrieve the manifest file entry (named mets.xml) ZipEntry manifestEntry = zip.getEntry(METSManifest.MANIFEST_FILE); - if (manifestEntry!=null) - { + if (manifestEntry != null) { // parse the manifest and sanity-check it. manifest = METSManifest.create(zip.getInputStream(manifestEntry), - validate, getConfigurationName()); + validate, getConfigurationName()); } } } @@ -355,34 +343,28 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester /** * Ingest/import a single DSpace Object, based on the associated METS * Manifest and the parameters passed to the METSIngester - * - * @param context - * DSpace Context - * @param parent - * Parent DSpace Object - * @param manifest - * the parsed METS Manifest - * @param pkgFile - * the full package file (which may include content files if a - * zip) - * @param params - * Parameters passed to METSIngester - * @param license - * DSpace license agreement + * + * @param context DSpace Context + * @param parent Parent DSpace Object + * @param manifest the parsed METS Manifest + * @param pkgFile the full package file (which may include content files if a + * zip) + * @param params Parameters passed to METSIngester + * @param license DSpace license agreement * @return completed result as a DSpace object - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws CrosswalkException if crosswalk error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error * @throws MetadataValidationException if metadata validation error - * @throws WorkflowException if workflow error - * @throws PackageValidationException if package validation error + * @throws WorkflowException if workflow error + * @throws PackageValidationException if package validation error */ protected DSpaceObject ingestObject(Context context, DSpaceObject parent, - METSManifest manifest, File pkgFile, PackageParameters params, - String license) throws IOException, SQLException, - AuthorizeException, CrosswalkException, - PackageValidationException, WorkflowException { + METSManifest manifest, File pkgFile, PackageParameters params, + String license) throws IOException, SQLException, + AuthorizeException, CrosswalkException, + PackageValidationException, WorkflowException { // type of DSpace Object (one of the type constants) int type; @@ -394,29 +376,26 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // if no parent passed in (or ignoreParent is false), // attempt to determine parent DSpace object from manifest if (type != Constants.SITE - && (parent == null || !params.getBooleanProperty( - "ignoreParent", false))) - { - try - { + && (parent == null || !params.getBooleanProperty( + "ignoreParent", false))) { + try { // get parent object from manifest parent = getParentObject(context, manifest); - } - catch(UnsupportedOperationException e) - { + } catch (UnsupportedOperationException e) { //If user specified to skip item ingest if any "missing parent" error message occur - if (params.getBooleanProperty("skipIfParentMissing", false)) - { + if (params.getBooleanProperty("skipIfParentMissing", false)) { //log a warning instead of throwing an error log.warn(LogManager.getHeader(context, "package_ingest", - "SKIPPING ingest of object '" + manifest.getObjID() - + "' as parent DSpace Object could not be found. " - + "If you are running a recursive ingest, it is likely this object will be created as soon as its parent is created.")); + "SKIPPING ingest of object '" + manifest.getObjID() + + "' as parent DSpace Object could not be found. " + + "If you are running a recursive ingest, it is likely this " + + "object will be created as soon as its parent is created.")); //return a null object (nothing ingested as parent was missing) return null; - } - else //else, throw exception upward to display to user + } else { + //else, throw exception upward to display to user throw e; + } } } @@ -424,8 +403,7 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester String handle = null; // if we are *not* ignoring the handle in manifest (i.e. ignoreHandle is // false) - if (!params.getBooleanProperty("ignoreHandle", false)) - { + if (!params.getBooleanProperty("ignoreHandle", false)) { // get handle from manifest handle = getObjectHandle(manifest); } @@ -434,24 +412,20 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // Create our DSpace Object based on info parsed from manifest, and // packager params DSpaceObject dso; - try - { + try { dso = PackageUtils.createDSpaceObject(context, parent, - type, handle, params); - } - catch (SQLException sqle) - { + type, handle, params); + } catch (SQLException sqle) { throw new PackageValidationException("Exception while ingesting " - + pkgFile.getPath(), sqle); + + pkgFile.getPath(), sqle); } // if we are uninitialized, throw an error -- something's wrong! - if (dso == null) - { + if (dso == null) { throw new PackageValidationException( - "Unable to initialize object specified by package (type='" - + type + "', handle='" + handle + "' and parent='" - + parent.getHandle() + "')."); + "Unable to initialize object specified by package (type='" + + type + "', handle='" + handle + "' and parent='" + + parent.getHandle() + "')."); } // -- Step 3 -- @@ -471,18 +445,16 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // -- Step 4 -- // Run our Descriptive metadata (dublin core, etc) crosswalks! crosswalkObjectDmd(context, dso, manifest, callback, manifest - .getItemDmds(), params); + .getItemDmds(), params); // For Items, also sanity-check the metadata for minimum requirements. - if (type == Constants.ITEM) - { + if (type == Constants.ITEM) { PackageUtils.checkItemMetadata((Item) dso); } // -- Step 5 -- // Add all content files as bitstreams on new DSpace Object - if (type == Constants.ITEM) - { + if (type == Constants.ITEM) { Item item = (Item) dso; //Check if this item is still in a user's workspace. @@ -491,18 +463,15 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // Get collection this item is being submitted to Collection collection = item.getOwningCollection(); - if (collection == null) - { + if (collection == null) { // Get the collection this workspace item belongs to - if (wsi != null) - { + if (wsi != null) { collection = wsi.getCollection(); } } // save manifest as a bitstream in Item if desired - if (preserveManifest()) - { + if (preserveManifest()) { addManifestBitstream(context, item, manifest); } @@ -516,47 +485,39 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // (this allows subclasses to do some final validation / changes as // necessary) finishObject(context, dso, params); - + // Finally, if item is still in the workspace, then we actually need // to install it into the archive & assign its handle. - if (wsi!=null) - { + if (wsi != null) { // Finish creating the item. This actually assigns the handle, // and will either install item immediately or start a workflow, based on params PackageUtils.finishCreateItem(context, wsi, handle, params); } - } // end if ITEM - else if (type == Constants.COLLECTION || type == Constants.COMMUNITY) - { + } else if (type == Constants.COLLECTION || type == Constants.COMMUNITY) { // Add logo if one is referenced from manifest addContainerLogo(context, dso, manifest, pkgFile, params); - if (type==Constants.COLLECTION) - { + if (type == Constants.COLLECTION) { //Add template item if one is referenced from manifest (only for Collections) addTemplateItem(context, dso, manifest, pkgFile, params, callback); } - + // Subclass hook for final checks and rearrangements // (this allows subclasses to do some final validation / changes as // necessary) finishObject(context, dso, params); - }// end if Community/Collection - else if (type == Constants.SITE) - { + } else if (type == Constants.SITE) { // Do nothing by default -- Crosswalks will handle anything necessary to ingest at Site-level - + // Subclass hook for final checks and rearrangements // (this allows subclasses to do some final validation / changes as // necessary) finishObject(context, dso, params); - } - else - { + } else { throw new PackageValidationException( - "Unknown DSpace Object type in package, type=" - + String.valueOf(type)); + "Unknown DSpace Object type in package, type=" + + String.valueOf(type)); } // -- Step 6 -- @@ -571,54 +532,45 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester /** * Replace the contents of a single DSpace Object, based on the associated * METS Manifest and the parameters passed to the METSIngester. - * - * @param context - * DSpace Context - * @param dso - * DSpace Object to replace - * @param manifest - * the parsed METS Manifest - * @param pkgFile - * the full package file (which may include content files if a - * zip) - * @param params - * Parameters passed to METSIngester - * @param license - * DSpace license agreement + * + * @param context DSpace Context + * @param dso DSpace Object to replace + * @param manifest the parsed METS Manifest + * @param pkgFile the full package file (which may include content files if a + * zip) + * @param params Parameters passed to METSIngester + * @param license DSpace license agreement * @return completed result as a DSpace object - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws CrosswalkException if crosswalk error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error * @throws MetadataValidationException if metadata validation error - * @throws PackageValidationException if package validation error + * @throws PackageValidationException if package validation error */ protected DSpaceObject replaceObject(Context context, DSpaceObject dso, - METSManifest manifest, File pkgFile, PackageParameters params, - String license) throws IOException, SQLException, - AuthorizeException, CrosswalkException, - MetadataValidationException, PackageValidationException - { + METSManifest manifest, File pkgFile, PackageParameters params, + String license) throws IOException, SQLException, + AuthorizeException, CrosswalkException, + MetadataValidationException, PackageValidationException { // -- Step 1 -- // Before going forward with the replace, let's verify these objects are // of the same TYPE! (We don't want to go around trying to replace a // COMMUNITY with an ITEM -- that's dangerous.) int manifestType = getObjectType(manifest); - if (manifestType != dso.getType()) - { + if (manifestType != dso.getType()) { throw new PackageValidationException( - "The object type of the METS manifest (" - + Constants.typeText[manifestType] - + ") does not match up with the object type (" - + Constants.typeText[dso.getType()] - + ") of the DSpaceObject to be replaced!"); + "The object type of the METS manifest (" + + Constants.typeText[manifestType] + + ") does not match up with the object type (" + + Constants.typeText[dso.getType()] + + ") of the DSpaceObject to be replaced!"); } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Object to be replaced (handle=" + dso.getHandle() - + ") is " + Constants.typeText[dso.getType()] + " id=" - + dso.getID()); + + ") is " + Constants.typeText[dso.getType()] + " id=" + + dso.getID()); } // -- Step 2 -- @@ -656,13 +608,11 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // -- Step 4 -- // Add all content files as bitstreams on new DSpace Object - if (dso.getType() == Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { Item item = (Item) dso; // save manifest as a bitstream in Item if desired - if (preserveManifest()) - { + if (preserveManifest()) { addManifestBitstream(context, item, manifest); } @@ -670,45 +620,39 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester addBitstreams(context, item, manifest, pkgFile, params, callback); // have subclass manage license since it may be extra package file. - Collection owningCollection = (Collection) ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getParentObject(context, dso); - if (owningCollection == null) - { + Collection owningCollection = (Collection) ContentServiceFactory.getInstance().getDSpaceObjectService(dso) + .getParentObject(context, dso); + if (owningCollection == null) { //We are probably dealing with an item that isn't archived yet InProgressSubmission inProgressSubmission = workspaceItemService.findByItem(context, item); - if (inProgressSubmission == null) - { - inProgressSubmission = WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(context, item); + if (inProgressSubmission == null) { + inProgressSubmission = WorkflowServiceFactory.getInstance().getWorkflowItemService() + .findByItem(context, item); } owningCollection = inProgressSubmission.getCollection(); } addLicense(context, item, license, owningCollection - , params); + , params); // FIXME ? // should set lastModifiedTime e.g. when ingesting AIP. // maybe only do it in the finishObject() callback for AIP. - } // end if ITEM - else if (dso.getType() == Constants.COLLECTION - || dso.getType() == Constants.COMMUNITY) - { + } else if (dso.getType() == Constants.COLLECTION || dso.getType() == Constants.COMMUNITY) { // Add logo if one is referenced from manifest addContainerLogo(context, dso, manifest, pkgFile, params); - } // end if Community/Collection - else if (dso.getType() == Constants.SITE) - { + } else if (dso.getType() == Constants.SITE) { // Do nothing -- Crosswalks will handle anything necessary to replace at Site-level } // -- Step 5 -- // Run our Descriptive metadata (dublin core, etc) crosswalks! crosswalkObjectDmd(context, dso, manifest, callback, manifest - .getItemDmds(), params); + .getItemDmds(), params); // For Items, also sanity-check the metadata for minimum requirements. - if (dso.getType() == Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { PackageUtils.checkItemMetadata((Item) dso); } @@ -728,41 +672,32 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester /** * Add Bitstreams to an Item, based on the files listed in the METS Manifest - * - * @param context - * DSpace Context - * @param item - * DSpace Item - * @param manifest - * METS Manifest - * @param pkgFile - * the full package file (which may include content files if a - * zip) - * @param params - * Ingestion Parameters - * @param mdRefCallback - * MdrefManager storing info about mdRefs in manifest - * @throws SQLException if database error - * @throws IOException if IO error - * @throws AuthorizeException if authorization error + * + * @param context DSpace Context + * @param item DSpace Item + * @param manifest METS Manifest + * @param pkgFile the full package file (which may include content files if a + * zip) + * @param params Ingestion Parameters + * @param mdRefCallback MdrefManager storing info about mdRefs in manifest + * @throws SQLException if database error + * @throws IOException if IO error + * @throws AuthorizeException if authorization error * @throws MetadataValidationException if metadata validation error - * @throws CrosswalkException if crosswalk error - * @throws PackageValidationException if package validation error + * @throws CrosswalkException if crosswalk error + * @throws PackageValidationException if package validation error */ protected void addBitstreams(Context context, Item item, - METSManifest manifest, File pkgFile, PackageParameters params, - MdrefManager mdRefCallback) throws SQLException, IOException, - AuthorizeException, MetadataValidationException, - CrosswalkException, PackageValidationException - { + METSManifest manifest, File pkgFile, PackageParameters params, + MdrefManager mdRefCallback) throws SQLException, IOException, + AuthorizeException, MetadataValidationException, + CrosswalkException, PackageValidationException { // Step 1 -- find the ID of the primary or Logo bitstream in manifest String primaryID = null; Element primaryFile = manifest.getPrimaryOrLogoBitstream(); - if (primaryFile != null) - { + if (primaryFile != null) { primaryID = primaryFile.getAttributeValue("ID"); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Got primary bitstream file ID=\"" + primaryID + "\""); } } @@ -770,24 +705,22 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // Step 2 -- find list of all content files from manifest // Loop through these files, and add them one by one to Item List manifestContentFiles = manifest - .getContentFiles(); + .getContentFiles(); List manifestBundleFiles = manifest - .getBundleFiles(); + .getBundleFiles(); boolean setPrimaryBitstream = false; BitstreamFormat unknownFormat = bitstreamFormatService.findUnknown(context); for (Iterator mi = manifestContentFiles.iterator(); mi - .hasNext();) - { + .hasNext(); ) { Element mfile = mi.next(); // basic validation -- check that it has an ID attribute String mfileID = mfile.getAttributeValue("ID"); - if (mfileID == null) - { + if (mfileID == null) { throw new PackageValidationException( - "Invalid METS Manifest: file element without ID attribute."); + "Invalid METS Manifest: file element without ID attribute."); } // retrieve path/name of file in manifest @@ -803,12 +736,9 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // Find or create the bundle where bitstream should be attached Bundle bundle; List bns = itemService.getBundles(item, bundleName); - if (CollectionUtils.isNotEmpty(bns)) - { + if (CollectionUtils.isNotEmpty(bns)) { bundle = bns.get(0); - } - else - { + } else { bundle = bundleService.create(context, item, bundleName); } @@ -816,19 +746,19 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester Bitstream bitstream = bitstreamService.create(context, bundle, fileStream); bitstream.setName(context, path); - // Set bitstream sequence id, if known + // Set bitstream sequence id, if known String seqID = mfile.getAttributeValue("SEQ"); - if (seqID!=null && !seqID.isEmpty()) + if (seqID != null && !seqID.isEmpty()) { bitstream.setSequenceID(Integer.parseInt(seqID)); - + } + // crosswalk this bitstream's administrative metadata located in // METS manifest (or referenced externally) manifest.crosswalkBitstream(context, params, bitstream, mfileID, - mdRefCallback); + mdRefCallback); // is this the primary bitstream? - if (primaryID != null && mfileID.equals(primaryID)) - { + if (primaryID != null && mfileID.equals(primaryID)) { bundle.setPrimaryBitstreamID(bitstream); bundleService.update(context, bundle); setPrimaryBitstream = true; @@ -842,109 +772,92 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // set it: // 1. attempt to guess from MIME type // 2. if that fails, guess from "name" extension. - if (bitstream.getFormat(context).equals(unknownFormat)) - { - if (log.isDebugEnabled()) - { + if (bitstream.getFormat(context).equals(unknownFormat)) { + if (log.isDebugEnabled()) { log.debug("Guessing format of Bitstream left un-set: " - + bitstream.toString()); + + bitstream.toString()); } String mimeType = mfile.getAttributeValue("MIMETYPE"); BitstreamFormat bf = (mimeType == null) ? null - : bitstreamFormatService.findByMIMEType(context, mimeType); - if (bf == null) - { + : bitstreamFormatService.findByMIMEType(context, mimeType); + if (bf == null) { bf = bitstreamFormatService.guessFormat(context, bitstream); } bitstreamService.setFormat(context, bitstream, bf); } bitstreamService.update(context, bitstream); - }// end for each manifest file + } // end for each manifest file for (Iterator mi = manifestBundleFiles.iterator(); mi - .hasNext();) - { + .hasNext(); ) { Element mfile = mi.next(); String bundleName = METSManifest.getBundleName(mfile, false); Bundle bundle; List bns = itemService.getBundles(item, bundleName); - if (CollectionUtils.isNotEmpty(bns)) - { + if (CollectionUtils.isNotEmpty(bns)) { bundle = bns.get(0); - } - else - { + } else { bundle = bundleService.create(context, item, bundleName); } String mfileGrp = mfile.getAttributeValue("ADMID"); - if (mfileGrp != null) - { - manifest.crosswalkBundle(context, params, bundle, mfileGrp,mdRefCallback); - } - else - { - if (log.isDebugEnabled()) - { + if (mfileGrp != null) { + manifest.crosswalkBundle(context, params, bundle, mfileGrp, mdRefCallback); + } else { + if (log.isDebugEnabled()) { log.debug("Ingesting bundle with no ADMID, not crosswalking bundle metadata"); } } bundleService.update(context, bundle); - }// end for each manifest file + } // end for each manifest file // Step 3 -- Sanity checks // sanity check for primary bitstream - if (primaryID != null && !setPrimaryBitstream) - { + if (primaryID != null && !setPrimaryBitstream) { log.warn("Could not find primary bitstream file ID=\"" + primaryID - + "\" in manifest file \"" + pkgFile.getAbsolutePath() - + "\""); + + "\" in manifest file \"" + pkgFile.getAbsolutePath() + + "\""); } } /** * Save/Preserve the METS Manifest as a Bitstream attached to the given * DSpace item. - * - * @param context - * DSpace Context - * @param item - * DSpace Item - * @param manifest - * The METS Manifest - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * + * @param context DSpace Context + * @param item DSpace Item + * @param manifest The METS Manifest + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error * @throws PackageValidationException if package validation error */ protected void addManifestBitstream(Context context, Item item, - METSManifest manifest) throws IOException, SQLException, - AuthorizeException, PackageValidationException - { + METSManifest manifest) throws IOException, SQLException, + AuthorizeException, PackageValidationException { // We'll save the METS Manifest as part of the METADATA bundle. Bundle mdBundle = bundleService.create(context, item, Constants.METADATA_BUNDLE_NAME); // Create a Bitstream from the METS Manifest's content Bitstream manifestBitstream = bitstreamService.create(context, mdBundle, manifest - .getMetsAsStream()); + .getMetsAsStream()); manifestBitstream.setName(context, METSManifest.MANIFEST_FILE); manifestBitstream.setSource(context, METSManifest.MANIFEST_FILE); bitstreamService.update(context, manifestBitstream); // Get magic bitstream format to identify manifest. String fmtName = getManifestBitstreamFormat(); - if (fmtName == null) - { + if (fmtName == null) { throw new PackageValidationException( - "Configuration Error: No Manifest BitstreamFormat configured for METS ingester type=" - + getConfigurationName()); + "Configuration Error: No Manifest BitstreamFormat configured for METS ingester type=" + + getConfigurationName()); } BitstreamFormat manifestFormat = PackageUtils - .findOrCreateBitstreamFormat(context, fmtName, - "application/xml", fmtName + " package manifest"); + .findOrCreateBitstreamFormat(context, fmtName, + "application/xml", fmtName + " package manifest"); manifestBitstream.setFormat(context, manifestFormat); bitstreamService.update(context, manifestBitstream); } @@ -952,133 +865,110 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester /** * Add a Logo to a Community or Collection container object based on a METS * Manifest. - * - * @param context - * DSpace Context - * @param dso - * DSpace Container Object - * @param manifest - * METS Manifest - * @param pkgFile - * the full package file (which may include content files if a - * zip) - * @param params - * Ingestion Parameters - * @throws SQLException if database error - * @throws IOException if IO error - * @throws AuthorizeException if authorization error + * + * @param context DSpace Context + * @param dso DSpace Container Object + * @param manifest METS Manifest + * @param pkgFile the full package file (which may include content files if a + * zip) + * @param params Ingestion Parameters + * @throws SQLException if database error + * @throws IOException if IO error + * @throws AuthorizeException if authorization error * @throws MetadataValidationException if metadata validation error - * @throws PackageValidationException if package validation error + * @throws PackageValidationException if package validation error */ protected void addContainerLogo(Context context, DSpaceObject dso, - METSManifest manifest, File pkgFile, PackageParameters params) - throws SQLException, IOException, AuthorizeException, - MetadataValidationException, PackageValidationException - { + METSManifest manifest, File pkgFile, PackageParameters params) + throws SQLException, IOException, AuthorizeException, + MetadataValidationException, PackageValidationException { Element logoRef = manifest.getPrimaryOrLogoBitstream(); // only continue if a logo specified in manifest - if (logoRef != null) - { + if (logoRef != null) { // Find ID of logo file String logoID = logoRef.getAttributeValue("ID"); // Loop through manifest content files to find actual logo file for (Iterator mi = manifest - .getContentFiles().iterator(); mi.hasNext();) - { + .getContentFiles().iterator(); mi.hasNext(); ) { Element mfile = mi.next(); - if (logoID.equals(mfile.getAttributeValue("ID"))) - { + if (logoID.equals(mfile.getAttributeValue("ID"))) { String path = METSManifest.getFileName(mfile); // extract the file input stream from package (or retrieve // externally, if it is an externally referenced file) InputStream fileStream = getFileInputStream(pkgFile, - params, path); + params, path); // Add this logo to the Community/Collection - if (dso.getType() == Constants.COLLECTION) - { + if (dso.getType() == Constants.COLLECTION) { collectionService.setLogo(context, ((Collection) dso), fileStream); - } - else - { + } else { communityService.setLogo(context, ((Community) dso), fileStream); } break; } - }// end for each file in manifest - }// end if logo reference found + } // end for each file in manifest + } // end if logo reference found } /** * Add a Template Item to a Collection container object based on a METS * Manifest. * - * @param context - * DSpace Context - * @param dso - * DSpace Container Object - * @param manifest - * METS Manifest - * @param pkgFile - * the full package file (which may include content files if a - * zip) - * @param params - * Ingestion Parameters - * @param callback - * the MdrefManager (manages all external metadata files - * referenced by METS mdref elements) - * @throws SQLException if database error - * @throws IOException if IO error - * @throws AuthorizeException if authorization error + * @param context DSpace Context + * @param dso DSpace Container Object + * @param manifest METS Manifest + * @param pkgFile the full package file (which may include content files if a + * zip) + * @param params Ingestion Parameters + * @param callback the MdrefManager (manages all external metadata files + * referenced by METS mdref elements) + * @throws SQLException if database error + * @throws IOException if IO error + * @throws AuthorizeException if authorization error * @throws MetadataValidationException if metadata validation error - * @throws PackageValidationException if package validation error + * @throws PackageValidationException if package validation error */ protected void addTemplateItem(Context context, DSpaceObject dso, - METSManifest manifest, File pkgFile, PackageParameters params, - MdrefManager callback) - throws SQLException, IOException, AuthorizeException, - CrosswalkException, PackageValidationException - { + METSManifest manifest, File pkgFile, PackageParameters params, + MdrefManager callback) + throws SQLException, IOException, AuthorizeException, + CrosswalkException, PackageValidationException { //Template items only valid for collections - if (dso.getType()!=Constants.COLLECTION) + if (dso.getType() != Constants.COLLECTION) { return; - + } + Collection collection = (Collection) dso; //retrieve list of all

    s representing child objects from manifest List childObjList = manifest.getChildObjDivs(); - if (childObjList!=null && !childObjList.isEmpty()) - { + if (childObjList != null && !childObjList.isEmpty()) { Element templateItemDiv = null; Iterator childIterator = childObjList.iterator(); //Search for the child with a type of "DSpace ITEM Template" - while (childIterator.hasNext()) - { + while (childIterator.hasNext()) { Element childDiv = (Element) childIterator.next(); String childType = childDiv.getAttributeValue("TYPE"); //should be the only child of type "ITEM" with "Template" for a suffix if (childType.contains(Constants.typeText[Constants.ITEM]) && - childType.endsWith(AbstractMETSDisseminator.TEMPLATE_TYPE_SUFFIX)) - { + childType.endsWith(AbstractMETSDisseminator.TEMPLATE_TYPE_SUFFIX)) { templateItemDiv = childDiv; break; } } //If an Template Item was found, create it with the specified metadata - if (templateItemDiv!=null) - { + if (templateItemDiv != null) { //make sure this templateItemDiv is associated with one or more dmdSecs String templateDmdIds = templateItemDiv.getAttributeValue("DMDID"); - if (templateDmdIds!=null) - { + if (templateDmdIds != null) { //create our template item & get a reference to it itemService.createTemplateItem(context, collection); Item templateItem = collection.getTemplateItem(); @@ -1105,73 +995,63 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester * This method is similar to ingest(), except that if the object already * exists in DSpace, it is emptied of files and metadata. The METS-based * package is then used to ingest new values for these. - * - * @param context - * DSpace Context - * @param dsoToReplace - * DSpace Object to be replaced (may be null if it will be - * specified in the METS manifest itself) - * @param pkgFile - * The package file to ingest - * @param params - * Parameters passed from the packager script + * + * @param context DSpace Context + * @param dsoToReplace DSpace Object to be replaced (may be null if it will be + * specified in the METS manifest itself) + * @param pkgFile The package file to ingest + * @param params Parameters passed from the packager script * @return DSpaceObject created by ingest. * @throws PackageValidationException if package validation error - * if package is unacceptable or there is a fatal error turning - * it into a DSpace Object. - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws CrosswalkException if crosswalk error - * @throws WorkflowException if workflow error + * if package is unacceptable or there is a fatal error turning + * it into a DSpace Object. + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error + * @throws WorkflowException if workflow error */ @Override public DSpaceObject replace(Context context, DSpaceObject dsoToReplace, - File pkgFile, PackageParameters params) - throws PackageValidationException, CrosswalkException, - AuthorizeException, SQLException, IOException, WorkflowException { + File pkgFile, PackageParameters params) + throws PackageValidationException, CrosswalkException, + AuthorizeException, SQLException, IOException, WorkflowException { // parsed out METS Manifest from the file. METSManifest manifest = null; // resulting DSpace Object DSpaceObject dso = null; - try - { + try { log.info(LogManager.getHeader(context, "package_parse", - "Parsing package for replace, file=" + pkgFile.getName())); + "Parsing package for replace, file=" + pkgFile.getName())); // Parse our ingest package, extracting out the METS manifest in the // package manifest = parsePackage(context, pkgFile, params); // must have a METS Manifest to replace anything - if (manifest == null) - { + if (manifest == null) { throw new PackageValidationException( - "No METS Manifest found (filename=" - + METSManifest.MANIFEST_FILE - + "). Package is unacceptable!"); + "No METS Manifest found (filename=" + + METSManifest.MANIFEST_FILE + + "). Package is unacceptable!"); } // It's possible that the object to replace will be passed in as // null. Let's determine the handle of the object to replace. - if (dsoToReplace == null) - { + if (dsoToReplace == null) { // since we don't know what we are replacing, we'll have to // try to determine it from the parsed manifest // Handle of object described by METS should be in OBJID String handleURI = manifest.getObjID(); String handle = decodeHandleURN(handleURI); - try - { + try { // Attempt to resolve this handle to an existing object dsoToReplace = handleService.resolveToObject(context, - handle); - } - catch (IllegalStateException ie) - { + handle); + } catch (IllegalStateException ie) { // We don't care if this errors out -- we can continue // whether or not an object exists with this handle. } @@ -1184,52 +1064,46 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // If we were unable to find the object to replace, then assume we // are restoring it - if (dsoToReplace == null) - { + if (dsoToReplace == null) { // As this object doesn't already exist, we will perform an // ingest of a new object in order to restore it // NOTE: passing 'null' as parent object in order to force // ingestObject() method to determine parent using manifest. dso = ingestObject(context, null, manifest, pkgFile, params, - null); + null); //if ingestion was successful - if (dso!=null) - { + if (dso != null) { // Log that we created an object log.info(LogManager.getHeader(context, "package_replace", - "Created new Object, type=" - + Constants.typeText[dso.getType()] - + ", handle=" + dso.getHandle() + ", dbID=" - + String.valueOf(dso.getID()))); + "Created new Object, type=" + + Constants.typeText[dso.getType()] + + ", handle=" + dso.getHandle() + ", dbID=" + + String.valueOf(dso.getID()))); } - } - else - // otherwise, we found the DSpaceObject to replace -- so, replace - // it! - { + } else { + // otherwise, we found the DSpaceObject to replace -- so, replace it! + // Actually replace the object described by the METS Manifest. // NOTE: This will perform an in-place replace of all metadata // and files currently associated with the object. dso = replaceObject(context, dsoToReplace, manifest, pkgFile, - params, null); + params, null); // Log that we replaced an object log.info(LogManager.getHeader(context, "package_replace", - "Replaced Object, type=" - + Constants.typeText[dso.getType()] - + ", handle=" + dso.getHandle() + ", dbID=" - + String.valueOf(dso.getID()))); + "Replaced Object, type=" + + Constants.typeText[dso.getType()] + + ", handle=" + dso.getHandle() + ", dbID=" + + String.valueOf(dso.getID()))); } //if ingest/restore/replace successful - if (dso!=null) - { + if (dso != null) { // Check if the Packager is currently running recursively. // If so, this means the Packager will attempt to recursively // replace all referenced child packages. - if (params.recursiveModeEnabled()) - { + if (params.recursiveModeEnabled()) { // Retrieve list of all Child object METS file paths from the // current METS manifest. // This is our list of known child packages. @@ -1239,17 +1113,14 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester // DSpaceObject the pkgs relate to) // NOTE: The AbstractPackageIngester itself will perform the // recursive ingest call, based on these child pkg references. - for (int i = 0; i < childFilePaths.length; i++) - { + for (int i = 0; i < childFilePaths.length; i++) { addPackageReference(dso, childFilePaths[i]); } } } return dso; - } - catch (SQLException se) - { + } catch (SQLException se) { // no need to really clean anything up, // transaction rollback will get rid of it anyway, and will also // restore everything to previous state. @@ -1261,82 +1132,73 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester } // whether or not to save manifest as a bitstream in METADATA bundle. - protected boolean preserveManifest() - { + protected boolean preserveManifest() { return ConfigurationManager.getBooleanProperty("mets." - + getConfigurationName() + ".ingest.preserveManifest", false); + + getConfigurationName() + ".ingest.preserveManifest", + false); } // return short name of manifest bitstream format - protected String getManifestBitstreamFormat() - { + protected String getManifestBitstreamFormat() { return ConfigurationManager.getProperty("mets." - + getConfigurationName() + ".ingest.manifestBitstreamFormat"); + + getConfigurationName() + ".ingest.manifestBitstreamFormat"); } // whether or not to use Collection Templates when creating a new item - protected boolean useCollectionTemplate() - { + protected boolean useCollectionTemplate() { return ConfigurationManager.getBooleanProperty("mets." - + getConfigurationName() + ".ingest.useCollectionTemplate", - false); + + getConfigurationName() + ".ingest.useCollectionTemplate", + false); } /** * Parse the hdl: URI/URN format into a raw Handle. - * - * @param value - * handle URI string + * + * @param value handle URI string * @return raw handle (with 'hdl:' prefix removed) */ - protected String decodeHandleURN(String value) - { - if (value != null && value.startsWith("hdl:")) - { + protected String decodeHandleURN(String value) { + if (value != null && value.startsWith("hdl:")) { return value.substring(4); - } - else - { + } else { return null; } } /** * Remove an existing DSpace Object (called during a replace) - * + * * @param context context - * @param dso - * DSpace Object - * @throws IOException if IO error - * @throws SQLException if database error + * @param dso DSpace Object + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ protected void removeObject(Context context, DSpaceObject dso) - throws AuthorizeException, SQLException, IOException - { - if (log.isDebugEnabled()) - { + throws AuthorizeException, SQLException, IOException { + if (log.isDebugEnabled()) { log.debug("Removing object " + Constants.typeText[dso.getType()] - + " id=" + dso.getID()); + + " id=" + dso.getID()); } - switch (dso.getType()) - { - case Constants.ITEM: - Item item = (Item) dso; + switch (dso.getType()) { + case Constants.ITEM: + Item item = (Item) dso; - itemService.delete(context, item); - break; + itemService.delete(context, item); + break; - case Constants.COLLECTION: - Collection collection = (Collection) dso; - collectionService.delete(context, collection); - break; + case Constants.COLLECTION: + Collection collection = (Collection) dso; + collectionService.delete(context, collection); + break; - case Constants.COMMUNITY: - // Just remove the Community entirely - communityService.delete(context, (Community) dso); - break; + case Constants.COMMUNITY: + // Just remove the Community entirely + communityService.delete(context, (Community) dso); + break; + default: + break; } } @@ -1348,45 +1210,40 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester * specified in a <structMap LABEL="Parent">. You should override this * method if your METS manifest specifies the parent object in another * location. - * - * @param context - * DSpace Context - * @param manifest - * METS manifest + * + * @param context DSpace Context + * @param manifest METS manifest * @return a DSpace Object which is the parent (or null, if not found) - * @throws PackageValidationException if package validation error - * if parent reference cannot be found in manifest + * @throws PackageValidationException if package validation error + * if parent reference cannot be found in manifest * @throws MetadataValidationException if metadata validation error - * @throws SQLException if database error + * @throws SQLException if database error */ public DSpaceObject getParentObject(Context context, METSManifest manifest) - throws PackageValidationException, MetadataValidationException, - SQLException - { + throws PackageValidationException, MetadataValidationException, + SQLException { DSpaceObject parent = null; // look for a Parent Object link in manifest String parentLink = manifest.getParentOwnerLink(); // verify we have a valid Parent Object - if (parentLink != null && parentLink.length() > 0) - { + if (parentLink != null && parentLink.length() > 0) { parent = handleService.resolveToObject(context, parentLink); - if (parent == null) - { + if (parent == null) { throw new UnsupportedOperationException( - "Could not find a parent DSpaceObject referenced as '" - + parentLink - + "' in the METS Manifest for object " - + manifest.getObjID() - + ". A parent DSpaceObject must be specified from either the 'packager' command or noted in the METS Manifest itself."); + "Could not find a parent DSpaceObject referenced as '" + + parentLink + + "' in the METS Manifest for object " + + manifest.getObjID() + + ". A parent DSpaceObject must be specified from either the 'packager' command or noted in " + + "the METS Manifest itself."); } - } - else - { + } else { throw new UnsupportedOperationException( - "Could not find a parent DSpaceObject where we can ingest the packaged object " + "Could not find a parent DSpaceObject where we can ingest the packaged object " + manifest.getObjID() - + ". A parent DSpaceObject must be specified from either the 'packager' command or noted in the METS Manifest itself."); + + ". A parent DSpaceObject must be specified from either the 'packager' command or noted in the " + + "METS Manifest itself."); } return parent; @@ -1399,21 +1256,19 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester * Object can be found in the <mets> @OBJID attribute. You should * override this method if your METS manifest specifies the handle in * another location. - * + * * If no handle was found then null is returned. - * - * @param manifest - * METS manifest + * + * @param manifest METS manifest * @return handle as a string (or null, if not found) - * @throws PackageValidationException if package validation error - * if handle cannot be found in manifest + * @throws PackageValidationException if package validation error + * if handle cannot be found in manifest * @throws MetadataValidationException if validation error - * @throws SQLException if database error + * @throws SQLException if database error */ public String getObjectHandle(METSManifest manifest) - throws PackageValidationException, MetadataValidationException, - SQLException - { + throws PackageValidationException, MetadataValidationException, + SQLException { // retrieve handle URI from manifest String handleURI = manifest.getObjID(); @@ -1433,48 +1288,39 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester *

    * Otherwise, the pkgFile is a Zip, so the file should be retrieved from * within that Zip package. - * - * @param pkgFile - * the full package file (which may include content files if a - * zip) - * @param params - * Parameters passed to METSIngester - * @param path - * the File path (either path in Zip package or a URL) + * + * @param pkgFile the full package file (which may include content files if a + * zip) + * @param params Parameters passed to METSIngester + * @param path the File path (either path in Zip package or a URL) * @return the InputStream for the file * @throws MetadataValidationException if validation error - * @throws IOException if IO error + * @throws IOException if IO error */ protected static InputStream getFileInputStream(File pkgFile, - PackageParameters params, String path) - throws MetadataValidationException, IOException - { + PackageParameters params, String path) + throws MetadataValidationException, IOException { // If this is a manifest only package (i.e. not a zip file) - if (params.getBooleanProperty("manifestOnly", false)) - { + if (params.getBooleanProperty("manifestOnly", false)) { // NOTE: since we are only dealing with a METS manifest, // we will assume all external files are available via URLs. - try - { + try { // attempt to open a connection to given URL URL fileURL = new URL(path); URLConnection connection = fileURL.openConnection(); // open stream to access file contents return connection.getInputStream(); - } - catch (IOException io) - { + } catch (IOException io) { log - .error("Unable to retrieve external file from URL '" - + path - + "' for manifest-only METS package. All externally referenced files must be retrievable via URLs."); + .error("Unable to retrieve external file from URL '" + + path + + "' for manifest-only METS package. All externally referenced files must be " + + "retrievable via URLs."); // pass exception upwards throw io; } - } - else - { + } else { // open the Zip package ZipFile zipPackage = new ZipFile(pkgFile); @@ -1482,12 +1328,11 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester ZipEntry manifestEntry = zipPackage.getEntry(path); // Get inputStream associated with this file - if (manifestEntry != null) + if (manifestEntry != null) { return zipPackage.getInputStream(manifestEntry); - else - { + } else { throw new MetadataValidationException("Manifest file references file '" - + path + "' not included in the zip."); + + path + "' not included in the zip."); } } } @@ -1503,34 +1348,40 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester * with this packager */ @Override - public String getParameterHelp() - { + public String getParameterHelp() { return "* ignoreHandle=[boolean] " + - "If true, the ingester will ignore any Handle specified in the METS manifest itself, and instead create a new Handle during the ingest process (this is the default when running in Submit mode, using the -s flag). " + - "If false, the ingester attempts to restore the Handles specified in the METS manifest (this is the default when running in Restore/replace mode, using the -r flag). " + - "\n\n" + - "* ignoreParent=[boolean] " + - "If true, the ingester will ignore any Parent object specified in the METS manifest itself, and instead ingest under a new Parent object (this is the default when running in Submit mode, using the -s flag). The new Parent object must be specified via the -p flag. " + - "If false, the ingester attempts to restore the object directly under its old Parent (this is the default when running in Restore/replace mode, using the -r flag). " + - "\n\n" + - "* manifestOnly=[boolean] " + - "Specify true if the ingest package consists of just a METS manifest (mets.xml), without any content files (defaults to false)." + - "\n\n" + - "* validate=[boolean] " + - "If true, enable XML validation of METS file using schemas in document (default is true)."; + "If true, the ingester will ignore any Handle specified in the METS manifest itself, and instead create a" + + " new Handle during the ingest process (this is the default when running in Submit mode, using the -s " + + "flag). " + + "If false, the ingester attempts to restore the Handles specified in the METS manifest (this is the " + + "default when running in Restore/replace mode, using the -r flag). " + + "\n\n" + + "* ignoreParent=[boolean] " + + "If true, the ingester will ignore any Parent object specified in the METS manifest itself, and instead " + + "ingest under a new Parent object (this is the default when running in Submit mode, using the -s flag). " + + "The new Parent object must be specified via the -p flag. " + + "If false, the ingester attempts to restore the object directly under its old Parent (this is the default" + + " when running in Restore/replace mode, using the -r flag). " + + "\n\n" + + "* manifestOnly=[boolean] " + + "Specify true if the ingest package consists of just a METS manifest (mets.xml), without any content " + + "files (defaults to false)." + + "\n\n" + + "* validate=[boolean] " + + "If true, enable XML validation of METS file using schemas in document (default is true)."; } /** * Profile-specific tests to validate manifest. The implementation can * access the METS document through the manifest variable, an * instance of METSManifest. - * + * * @throws MetadataValidationException if metadata validation error - * if there is a fatal problem with the METS document's - * conformance to the expected profile. + * if there is a fatal problem with the METS document's + * conformance to the expected profile. */ abstract void checkManifest(METSManifest manifest) - throws MetadataValidationException; + throws MetadataValidationException; /** * Select the dmdSec element(s) to apply to the Item. The @@ -1545,30 +1396,26 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester *

    * Note that item and manifest are available as * protected fields from the superclass. - * - * @param context the DSpace context - * @param dso DSpace Object - * @param manifest - * the METSManifest - * @param callback - * the MdrefManager (manages all external metadata files - * referenced by METS mdref elements) - * @param dmds - * array of Elements, each a METS dmdSec that - * applies to the Item as a whole. - * @param params - * Packager Parameters - * @throws CrosswalkException if crosswalk error + * + * @param context the DSpace context + * @param dso DSpace Object + * @param manifest the METSManifest + * @param callback the MdrefManager (manages all external metadata files + * referenced by METS mdref elements) + * @param dmds array of Elements, each a METS dmdSec that + * applies to the Item as a whole. + * @param params Packager Parameters + * @throws CrosswalkException if crosswalk error * @throws PackageValidationException if package validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public abstract void crosswalkObjectDmd(Context context, DSpaceObject dso, - METSManifest manifest, MdrefManager callback, Element dmds[], - PackageParameters params) throws CrosswalkException, - PackageValidationException, AuthorizeException, SQLException, - IOException; + METSManifest manifest, MdrefManager callback, Element dmds[], + PackageParameters params) throws CrosswalkException, + PackageValidationException, AuthorizeException, SQLException, + IOException; /** * Add license(s) to Item based on contents of METS and other policies. The @@ -1584,80 +1431,75 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester *

    * Note that crosswalking rightsMD sections can also add a deposit or CC * license to the object. - * - * @param context - * the DSpace context - * @param item Item - * @param collection - * DSpace Collection to which the item is being submitted. - * @param license - * optional user-supplied Deposit License text (may be null) - * @param params - * Packager Parameters + * + * @param context the DSpace context + * @param item Item + * @param collection DSpace Collection to which the item is being submitted. + * @param license optional user-supplied Deposit License text (may be null) + * @param params Packager Parameters * @throws PackageValidationException if package validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public abstract void addLicense(Context context, Item item, String license, - Collection collection, PackageParameters params) - throws PackageValidationException, AuthorizeException, - SQLException, IOException; + Collection collection, PackageParameters params) + throws PackageValidationException, AuthorizeException, + SQLException, IOException; /** * Hook for final "finishing" operations on the new Object. This method is * called when the new Object is otherwise complete and ready to be * returned. The implementation should use this opportunity to make whatever * final checks and modifications are necessary. - * - * @param context - * the DSpace context - * @param dso - * the DSpace Object - * @param params - * the Packager Parameters - * @throws CrosswalkException if crosswalk error + * + * @param context the DSpace context + * @param dso the DSpace Object + * @param params the Packager Parameters + * @throws CrosswalkException if crosswalk error * @throws PackageValidationException if package validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public abstract void finishObject(Context context, DSpaceObject dso, - PackageParameters params) throws PackageValidationException, - CrosswalkException, AuthorizeException, SQLException, IOException; + PackageParameters params) throws PackageValidationException, + CrosswalkException, AuthorizeException, SQLException, IOException; /** * Determines what type of DSpace object is represented in this METS doc. - * + * * @param manifest METS manifest * @return one of the object types in Constants. * @throws PackageValidationException if package validation error */ public abstract int getObjectType(METSManifest manifest) - throws PackageValidationException; + throws PackageValidationException; /** * Subclass-dependent final processing on a Bitstream; could include fixing * up the name, bundle, other attributes. - * @param context context + * + * @param context context * @param manifest METS manifest - * @param bs bitstream - * @param mfile element - * @param params package params + * @param bs bitstream + * @param mfile element + * @param params package params * @throws MetadataValidationException if validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public abstract void finishBitstream(Context context, Bitstream bs, - Element mfile, METSManifest manifest, PackageParameters params) - throws MetadataValidationException, SQLException, - AuthorizeException, IOException; + Element mfile, METSManifest manifest, PackageParameters params) + throws MetadataValidationException, SQLException, + AuthorizeException, IOException; /** * Returns keyword that makes the configuration keys of this subclass * unique, e.g. if it returns NAME, the key would be: * "mets.NAME.ingest.preserveManifest = true" + * * @return name */ public abstract String getConfigurationName(); diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractPackageDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractPackageDisseminator.java index 8e06918438..0649318637 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractPackageDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractPackageDisseminator.java @@ -7,6 +7,13 @@ */ package org.dspace.content.packager; +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.Community; @@ -19,13 +26,6 @@ import org.dspace.content.service.ItemService; import org.dspace.core.Constants; import org.dspace.core.Context; -import java.io.File; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - /** * An abstract implementation of a DSpace Package Disseminator, which * implements a few helper/utility methods that most (all?) PackageDisseminators @@ -43,9 +43,10 @@ import java.util.List; * @see org.dspace.core.service.PluginService */ public abstract class AbstractPackageDisseminator - implements PackageDisseminator -{ - /** List of all successfully disseminated package files */ + implements PackageDisseminator { + /** + * List of all successfully disseminated package files + */ private List packageFileList = new ArrayList(); protected final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); @@ -69,67 +70,59 @@ public abstract class AbstractPackageDisseminator * Throws an exception of the initial object is not acceptable or there is * a failure creating the package. * - * @param context DSpace context. - * @param dso initial DSpace object - * @param params Properties-style list of options specific to this packager + * @param context DSpace context. + * @param dso initial DSpace object + * @param params Properties-style list of options specific to this packager * @param pkgFile File where initial package should be written. All other - * packages will be written to the same directory as this File. + * packages will be written to the same directory as this File. * @throws PackageValidationException if package cannot be created or there is - * a fatal error in creating it. - * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * a fatal error in creating it. + * @throws CrosswalkException if crosswalk error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ @Override public List disseminateAll(Context context, DSpaceObject dso, - PackageParameters params, File pkgFile) + PackageParameters params, File pkgFile) throws PackageException, CrosswalkException, - AuthorizeException, SQLException, IOException - { + AuthorizeException, SQLException, IOException { //If unset, make sure the Parameters specifies this is a recursive dissemination - if(!params.recursiveModeEnabled()) - { + if (!params.recursiveModeEnabled()) { params.setRecursiveModeEnabled(true); } // If this object package has NOT already been disseminated // NOTE: This ensures we don't accidentally disseminate the same object // TWICE, e.g. when an Item is mapped into multiple Collections. - if(!getPackageList().contains(pkgFile)) - { + if (!getPackageList().contains(pkgFile)) { // Disseminate the object using provided PackageDisseminator disseminate(context, dso, params, pkgFile); } //check if package was disseminated - if(pkgFile.exists()) - { + if (pkgFile.exists()) { //add to list of successfully disseminated packages addToPackageList(pkgFile); //We can only recursively disseminate non-Items //(NOTE: Items have no children, as Bitstreams/Bundles are created from Item packages) - if(dso.getType()!=Constants.ITEM) - { + if (dso.getType() != Constants.ITEM) { //Determine where first file package was disseminated to, as all //others will be written to same directory String pkgDirectory = pkgFile.getCanonicalFile().getParent(); - if(!pkgDirectory.endsWith(File.separator)) - { + if (!pkgDirectory.endsWith(File.separator)) { pkgDirectory += File.separator; } String fileExtension = PackageUtils.getFileExtension(pkgFile.getName()); //recursively disseminate content, based on object type - switch (dso.getType()) - { - case Constants.COLLECTION : + switch (dso.getType()) { + case Constants.COLLECTION: //Also find all Items in this Collection and disseminate Collection collection = (Collection) dso; Iterator iterator = itemService.findByCollection(context, collection); - while(iterator.hasNext()) - { + while (iterator.hasNext()) { Item item = iterator.next(); //disseminate all items (recursively!) @@ -138,41 +131,43 @@ public abstract class AbstractPackageDisseminator } break; - case Constants.COMMUNITY : + case Constants.COMMUNITY: //Also find all SubCommunities in this Community and disseminate Community community = (Community) dso; List subcommunities = community.getSubcommunities(); - for (Community subcommunity : subcommunities) - { + for (Community subcommunity : subcommunities) { //disseminate all sub-communities (recursively!) - String childFileName = pkgDirectory + PackageUtils.getPackageName(subcommunity, fileExtension); + String childFileName = pkgDirectory + PackageUtils + .getPackageName(subcommunity, fileExtension); disseminateAll(context, subcommunity, params, new File(childFileName)); } //Also find all Collections in this Community and disseminate List collections = community.getCollections(); - for(int i=0; i topCommunities = communityService.findAllTop(context); - for (Community topCommunity : topCommunities) - { + for (Community topCommunity : topCommunities) { //disseminate all top-level communities (recursively!) - String childFileName = pkgDirectory + PackageUtils.getPackageName(topCommunity, fileExtension); + String childFileName = pkgDirectory + PackageUtils + .getPackageName(topCommunity, fileExtension); disseminateAll(context, topCommunity, params, new File(childFileName)); } break; - }//end switch - }//end if not an Item - }//end if pkgFile exists + default: + break; + } //end switch + } //end if not an Item + } //end if pkgFile exists //return list of all successfully disseminated packages return getPackageList(); @@ -180,13 +175,12 @@ public abstract class AbstractPackageDisseminator /** * Add File to list of successfully disseminated package files + * * @param f added File. */ - protected void addToPackageList(File f) - { + protected void addToPackageList(File f) { //add to list of successfully disseminated packages - if(!packageFileList.contains(f)) - { + if (!packageFileList.contains(f)) { packageFileList.add(f); } } @@ -201,8 +195,7 @@ public abstract class AbstractPackageDisseminator * * @return List of Files which correspond to the disseminated packages */ - protected List getPackageList() - { + protected List getPackageList() { return packageFileList; } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractPackageIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractPackageIngester.java index ead6225f75..a9e8b9a509 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractPackageIngester.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractPackageIngester.java @@ -17,7 +17,6 @@ import java.util.List; import java.util.Map; import org.apache.log4j.Logger; - import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; @@ -56,23 +55,24 @@ import org.dspace.workflow.WorkflowException; * @see org.dspace.core.service.PluginService */ public abstract class AbstractPackageIngester - implements PackageIngester -{ - /** log4j category */ + implements PackageIngester { + /** + * log4j category + */ private static Logger log = Logger.getLogger(AbstractPackageIngester.class); protected final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - /** + /** * References to other packages -- these are the next packages to ingest recursively * Key = DSpace Object just ingested, Value = List of all packages relating to a DSpaceObject **/ - private Map> packageReferences = new HashMap>(); - - /** - * Map of all successfully ingested/replaced DSpace objects for current + private Map> packageReferences = new HashMap>(); + + /** + * Map of all successfully ingested/replaced DSpace objects for current * import process (used by ingestAll()/replaceAll()). * The key is the package file (which was used to create the object), * and the value is the Identifier (i.e. Handle) of the DSpaceObject created/replaced. @@ -101,95 +101,84 @@ public abstract class AbstractPackageIngester * package formats. It is optional and may be given as * null. * - * @param context DSpace context. - * @param parent parent under which to create the initial object - * (may be null -- in which case ingester must determine parent from package - * or throw an error). - * @param pkgFile The initial package file to ingest - * @param params Properties-style list of options (interpreted by each packager). - * @param license may be null, which takes default license. + * @param context DSpace context. + * @param parent parent under which to create the initial object + * (may be null -- in which case ingester must determine parent from package + * or throw an error). + * @param pkgFile The initial package file to ingest + * @param params Properties-style list of options (interpreted by each packager). + * @param license may be null, which takes default license. * @return List of DSpaceObjects created - * - * @throws PackageValidationException if initial package (or any referenced package) - * is unacceptable or there is a fatal error in creating a DSpaceObject + * @throws PackageValidationException if initial package (or any referenced package) + * is unacceptable or there is a fatal error in creating a DSpaceObject * @throws UnsupportedOperationException if this packager does not - * implement ingestAll - * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws WorkflowException if workflow error + * implement ingestAll + * @throws CrosswalkException if crosswalk error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws WorkflowException if workflow error */ @Override public List ingestAll(Context context, DSpaceObject parent, File pkgFile, - PackageParameters params, String license) - throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, - SQLException, IOException, WorkflowException { + PackageParameters params, String license) + throws PackageException, UnsupportedOperationException, + CrosswalkException, AuthorizeException, + SQLException, IOException, WorkflowException { //If unset, make sure the Parameters specifies this is a recursive ingest - if(!params.recursiveModeEnabled()) - { + if (!params.recursiveModeEnabled()) { params.setRecursiveModeEnabled(true); } //Initial DSpace Object to ingest DSpaceObject dso = null; - + // If we have not previously parsed/ingested this package file // NOTE: This ensures we don't accidentally ingest the same package - // TWICE, e.g. an Item's package may be referenced from multiple + // TWICE, e.g. an Item's package may be referenced from multiple // Collection packages (if Item is mapped to multiple Collections) - if(!getIngestedMap().containsKey(pkgFile)) - { - try - { + if (!getIngestedMap().containsKey(pkgFile)) { + try { //actually ingest pkg using provided PackageIngester dso = ingest(context, parent, pkgFile, params, license); - } - catch(IllegalStateException ie) - { + } 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(params.keepExistingModeEnabled()) - { - log.warn(LogManager.getHeader(context, "skip_package_ingest", "Object already exists, package-skipped=" + pkgFile.getName())); - } - else // Pass this exception on -- which essentially causes a full rollback of all changes (this is the default) - { + if (params.keepExistingModeEnabled()) { + log.warn(LogManager.getHeader(context, "skip_package_ingest", + "Object already exists, package-skipped=" + pkgFile.getName())); + } else { + // Pass this exception on -- which essentially causes a full rollback of all changes (this is + // the default) throw ie; } } - } - else - { - log.info(LogManager.getHeader(context, "skip_package_ingest", "Object was already ingested, package-skipped=" + pkgFile.getName())); + } else { + log.info(LogManager.getHeader(context, "skip_package_ingest", + "Object was already ingested, package-skipped=" + pkgFile.getName())); } // As long as an object was successfully created from this package - if(dso!=null) - { + if (dso != null) { // Add to map of successfully ingested packages/objects (if not already added) addToIngestedMap(pkgFile, dso); //We can only recursively ingest non-Item packages //(NOTE: Items have no children, as Bitstreams/Bundles are created from Item packages) - if(dso.getType()!=Constants.ITEM) - { + if (dso.getType() != Constants.ITEM) { //Check if we found child package references when ingesting this latest DSpaceObject List childPkgRefs = getPackageReferences(dso); - + //we can only recursively ingest child packages - //if we have references to them - if(childPkgRefs!=null && !childPkgRefs.isEmpty()) - { + //if we have references to them + if (childPkgRefs != null && !childPkgRefs.isEmpty()) { //Recursively ingest each child package, using this current object as the parent DSpace Object - for(String childPkgRef : childPkgRefs) - { + for (String childPkgRef : childPkgRefs) { //Assume package reference is relative to current (parent) package location File childPkg = new File(pkgFile.getAbsoluteFile().getParent(), childPkgRef); - + // fun, it's recursive! -- ingested referenced package // NOTE: we are passing "null" as the Parent object, since we want to restore to the // Parent object specified in the child Package. @@ -199,27 +188,24 @@ public abstract class AbstractPackageIngester // A Collection can map to Items that it does not "own". // If a Collection package has an Item as a child, it // should be mapped regardless of ownership. - if (Constants.COLLECTION == dso.getType()) - { + if (Constants.COLLECTION == dso.getType()) { // If this newly ingested parent object was a Collection, // lookup the newly ingested child Item and make sure // it is mapped to this Collection. String childHandle = getIngestedMap().get(childPkg); - if(childHandle!=null) - { + if (childHandle != null) { Item childItem = (Item) handleService.resolveToObject(context, childHandle); // Ensure Item is mapped to Collection that referenced it Collection collection = (Collection) dso; - if (childItem!=null && !itemService.isIn(childItem, collection)) - { + if (childItem != null && !itemService.isIn(childItem, collection)) { collectionService.addItem(context, collection, childItem); } } } } - }//end if child pkgs - }//end if not an Item - }//end if DSpaceObject not null + } //end if child pkgs + } //end if not an Item + } //end if DSpaceObject not null //Return list of all objects ingested return getIngestedList(); @@ -248,74 +234,66 @@ public abstract class AbstractPackageIngester * may choose to forward the call to replace if it is unable to * support recursive replacement. * - * @param context DSpace context. - * @param dso initial existing DSpace Object to be replaced, may be null - * if object to replace can be determined from package - * @param pkgFile The package file to ingest. - * @param params Properties-style list of options specific to this packager + * @param context DSpace context. + * @param dso initial existing DSpace Object to be replaced, may be null + * if object to replace can be determined from package + * @param pkgFile The package file to ingest. + * @param params Properties-style list of options specific to this packager * @return List of Identifiers of DSpaceObjects replaced - * - * @throws PackageValidationException if initial package (or any referenced package) - * is unacceptable or there is a fatal error in creating a DSpaceObject + * @throws PackageValidationException if initial package (or any referenced package) + * is unacceptable or there is a fatal error in creating a DSpaceObject * @throws UnsupportedOperationException if this packager does not - * implement replaceAll - * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws WorkflowException if workflow error + * implement replaceAll + * @throws CrosswalkException if crosswalk error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws WorkflowException if workflow error */ @Override public List replaceAll(Context context, DSpaceObject dso, - File pkgFile, PackageParameters params) - throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, - SQLException, IOException, WorkflowException { + File pkgFile, PackageParameters params) + throws PackageException, UnsupportedOperationException, + CrosswalkException, AuthorizeException, + SQLException, IOException, WorkflowException { //If unset, make sure the Parameters specifies this is a recursive replace - if(!params.recursiveModeEnabled()) - { + if (!params.recursiveModeEnabled()) { params.setRecursiveModeEnabled(true); } //Initial DSpace Object to replace DSpaceObject replacedDso = null; - + // If we have not previously parsed/ingested this package file // NOTE: This ensures we don't accidentally ingest the same package - // TWICE, e.g. an Item's package may be referenced from multiple + // TWICE, e.g. an Item's package may be referenced from multiple // Collection packages (if Item is mapped to multiple Collections) - if(!getIngestedMap().containsKey(pkgFile)) - { + if (!getIngestedMap().containsKey(pkgFile)) { //Actually ingest pkg using provided PackageIngester, and replace object //NOTE: 'dso' may be null! If it is null, the PackageIngester must determine // the object to be replaced from the package itself. replacedDso = replace(context, dso, pkgFile, params); - } - else - { - log.info(LogManager.getHeader(context, "skip_package_replace", "Object was already replaced, package-skipped=" + pkgFile.getName())); + } else { + log.info(LogManager.getHeader(context, "skip_package_replace", + "Object was already replaced, package-skipped=" + pkgFile.getName())); } // As long as an object was successfully replaced from this package - if(replacedDso!=null) - { + if (replacedDso != null) { // Add to map of successfully ingested packages/objects (if not already added) addToIngestedMap(pkgFile, replacedDso); //We can only recursively ingest non-Item packages //(NOTE: Items have no children, as Bitstreams/Bundles are created from Item packages) - if(replacedDso.getType()!=Constants.ITEM) - { + if (replacedDso.getType() != Constants.ITEM) { //Check if we found child package references when replacing this latest DSpaceObject List childPkgRefs = getPackageReferences(replacedDso); //we can only recursively ingest child packages //if we have references to them - if(childPkgRefs!=null && !childPkgRefs.isEmpty()) - { + if (childPkgRefs != null && !childPkgRefs.isEmpty()) { //Recursively replace each child package - for(String childPkgRef : childPkgRefs) - { + for (String childPkgRef : childPkgRefs) { //Assume package reference is relative to current package location File childPkg = new File(pkgFile.getAbsoluteFile().getParent(), childPkgRef); @@ -327,33 +305,30 @@ public abstract class AbstractPackageIngester // A Collection can map to Items that it does not "own". // If a Collection package has an Item as a child, it // should be mapped regardless of ownership. - if (Constants.COLLECTION == replacedDso.getType()) - { + if (Constants.COLLECTION == replacedDso.getType()) { // If this newly ingested parent object was a Collection, // lookup the newly ingested child Item and make sure // it is mapped to this Collection. String childHandle = getIngestedMap().get(childPkg); - if(childHandle!=null) - { + if (childHandle != null) { Item childItem = (Item) handleService.resolveToObject(context, childHandle); // Ensure Item is mapped to Collection that referenced it Collection collection = (Collection) replacedDso; - if (childItem!=null && !itemService.isIn(childItem, collection)) - { + if (childItem != null && !itemService.isIn(childItem, collection)) { collectionService.addItem(context, collection, childItem); } } } } - }//end if child pkgs - }//end if not an Item - }//end if DSpaceObject not null + } //end if child pkgs + } //end if not an Item + } //end if DSpaceObject not null //Return list of all objects replaced return getIngestedList(); } - + /** * During ingestion process, some submission information packages (SIPs) * may reference other packages to be ingested (recursively). @@ -365,20 +340,16 @@ public abstract class AbstractPackageIngester * References are collected based on the DSpaceObject created from the SIP * (this way we keep the context of these references). * - * @param dso DSpaceObject whose SIP referenced another package + * @param dso DSpaceObject whose SIP referenced another package * @param packageRef A reference to another package, which can be ingested after this one */ - public void addPackageReference(DSpaceObject dso, String packageRef) - { + public void addPackageReference(DSpaceObject dso, String packageRef) { List packageRefValues = null; // Check if we already have an entry for packages reference by this object - if(packageReferences.containsKey(dso)) - { + if (packageReferences.containsKey(dso)) { packageRefValues = packageReferences.get(dso); - } - else - { + } else { //Create a new empty list of references packageRefValues = new ArrayList(); } @@ -399,43 +370,40 @@ public abstract class AbstractPackageIngester * * @param dso DSpaceObject whose SIP referenced other SIPs * @return List of Strings which are the references to external submission ingestion packages - * (may be null if no SIPs were referenced) + * (may be null if no SIPs were referenced) */ - public List getPackageReferences(DSpaceObject dso) - { + public List getPackageReferences(DSpaceObject dso) { return packageReferences.get(dso); } /** - * Add parsed package and resulting DSpaceObject to list of successfully + * Add parsed package and resulting DSpaceObject to list of successfully * ingested/replaced objects. + * * @param pkgFile the package file that was used to create the object - * @param dso the DSpaceObject created/replaced + * @param dso the DSpaceObject created/replaced */ - protected void addToIngestedMap(File pkgFile, DSpaceObject dso) - { + protected void addToIngestedMap(File pkgFile, DSpaceObject dso) { // Add to list of successfully ingested packages - if(!pkgIngestedMap.containsKey(pkgFile)) - { + if (!pkgIngestedMap.containsKey(pkgFile)) { pkgIngestedMap.put(pkgFile, dso.getHandle()); } } /** - * Return Map of all packages ingested and the DSpaceObjects which have been + * Return Map of all packages ingested and the DSpaceObjects which have been * created/replaced by this instance of the Ingester. - * + * *

    * The Map "key" is the package file which was parsed, and the "value" * is the Identifier (i.e. Handle) of the DSpaceObject which was created/replaced. - * + * * @return Map of DSpaceObjects which have been created/replaced. */ - protected Map getIngestedMap() - { + protected Map getIngestedMap() { return pkgIngestedMap; } - + /** * Return List of all DSpaceObject Identifiers which have been ingested/replaced by * this instance of the Ingester. @@ -446,15 +414,15 @@ public abstract class AbstractPackageIngester * * @return List of Identifiers for DSpaceObjects which have been added/replaced */ - protected List getIngestedList() - { + protected List getIngestedList() { // We have the list of ingested objects in our IngestedMap. // So, we simply have to convert that Collection to a List java.util.Collection coll = pkgIngestedMap.values(); - - if(coll instanceof List) + + if (coll instanceof List) { return (List) coll; - else + } else { return new ArrayList(coll); - } + } + } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/DSpaceAIPDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/DSpaceAIPDisseminator.java index 31def67bed..2fb65dc1bb 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/DSpaceAIPDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/DSpaceAIPDisseminator.java @@ -10,37 +10,36 @@ package org.dspace.content.packager; import java.io.File; import java.io.IOException; import java.sql.SQLException; -import java.util.List; -import java.util.Arrays; import java.util.ArrayList; - -import org.apache.commons.collections.CollectionUtils; -import org.apache.log4j.Logger; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Bundle; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; -import org.dspace.content.Collection; -import org.dspace.content.Community; -import org.dspace.content.crosswalk.CrosswalkException; -import org.dspace.core.Constants; -import org.dspace.core.Context; +import java.util.Arrays; +import java.util.Date; +import java.util.List; import edu.harvard.hul.ois.mets.Agent; +import edu.harvard.hul.ois.mets.Div; import edu.harvard.hul.ois.mets.Loctype; import edu.harvard.hul.ois.mets.Mets; import edu.harvard.hul.ois.mets.MetsHdr; +import edu.harvard.hul.ois.mets.Mptr; import edu.harvard.hul.ois.mets.Name; import edu.harvard.hul.ois.mets.Role; -import edu.harvard.hul.ois.mets.Div; -import edu.harvard.hul.ois.mets.Mptr; import edu.harvard.hul.ois.mets.StructMap; import edu.harvard.hul.ois.mets.Type; import edu.harvard.hul.ois.mets.helper.MetsException; import edu.harvard.hul.ois.mets.helper.PCData; -import java.util.Date; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.ArrayUtils; +import org.apache.log4j.Logger; +import org.dspace.app.util.Util; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.crosswalk.CrosswalkException; +import org.dspace.core.Constants; +import org.dspace.core.Context; import org.dspace.core.Utils; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; @@ -60,21 +59,21 @@ import org.dspace.services.factory.DSpaceServicesFactory; * The value may be a simple crosswalk name, or a METS MDsec-name followed by * a colon and the crosswalk name e.g. "DSpaceDepositLicense:DSPACE_DEPLICENSE" * - * # MD types to put in the sourceMD section of the object. - * aip.disseminate.sourceMD = AIP-TECHMD + * # MD types to put in the sourceMD section of the object. + * aip.disseminate.sourceMD = AIP-TECHMD * - * # MD types to put in the techMD section of the object (and member Bitstreams if an Item) - * aip.disseminate.techMD = PREMIS + * # MD types to put in the techMD section of the object (and member Bitstreams if an Item) + * aip.disseminate.techMD = PREMIS * - * # MD types to put in digiprovMD section of the object. - * #aip.disseminate.digiprovMD = + * # MD types to put in digiprovMD section of the object. + * #aip.disseminate.digiprovMD = * - * # MD types to put in the rightsMD section of the object. - * aip.disseminate.rightsMD = DSpaceDepositLicense:DSPACE_DEPLICENSE, \ - * CreativeCommonsRDF:DSPACE_CCRDF, CreativeCommonsText:DSPACE_CCTXT, METSRights + * # MD types to put in the rightsMD section of the object. + * aip.disseminate.rightsMD = DSpaceDepositLicense:DSPACE_DEPLICENSE, \ + * CreativeCommonsRDF:DSPACE_CCRDF, CreativeCommonsText:DSPACE_CCTXT, METSRights * - * # MD types to put in dmdSec's corresponding the object. - * aip.disseminate.dmd = MODS, DIM + * # MD types to put in dmdSec's corresponding the object. + * aip.disseminate.dmd = MODS, DIM * * @author Larry Stone * @author Tim Donohue @@ -82,10 +81,9 @@ import org.dspace.services.factory.DSpaceServicesFactory; * @see AbstractMETSDisseminator * @see AbstractPackageDisseminator */ -public class DSpaceAIPDisseminator extends AbstractMETSDisseminator -{ +public class DSpaceAIPDisseminator extends AbstractMETSDisseminator { private static final Logger log = Logger.getLogger(DSpaceAIPDisseminator.class); - + /** * Unique identifier for the profile of the METS document. * To ensure uniqueness, it is the URL that the XML schema document would @@ -94,7 +92,9 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator public static final String PROFILE_1_0 = "http://www.dspace.org/schema/aip/mets_aip_1_0.xsd"; - /** TYPE of the div containing AIP's parent handle in its mptr. */ + /** + * TYPE of the div containing AIP's parent handle in its mptr. + */ public static final String PARENT_DIV_TYPE = "AIP Parent Link"; // Default MDTYPE value for deposit license -- "magic string" @@ -114,21 +114,20 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator // dissemination parameters passed to the AIP Disseminator protected PackageParameters disseminateParams = null; - + // List of Bundles to filter on, when building AIP protected List filterBundles = new ArrayList(); // Whether 'filterBundles' specifies an exclusion list (default) or inclusion list. protected boolean excludeBundles = true; - - protected ConfigurationService configurationService = - DSpaceServicesFactory.getInstance().getConfigurationService(); + + protected ConfigurationService configurationService = + DSpaceServicesFactory.getInstance().getConfigurationService(); @Override public void disseminate(Context context, DSpaceObject dso, PackageParameters params, File pkgFile) - throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException, IOException - { + throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException, IOException { //Before disseminating anything, save the passed in PackageParameters, so they can be used by all methods disseminateParams = params; @@ -137,30 +136,26 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator //if user specified to only disseminate objects updated *after* a specific date // (Note: this only works for Items right now, as DSpace doesn't store a // last modified date for Collections or Communities) - if(disseminateParams.containsKey("updatedAfter") && dso.getType()==Constants.ITEM) - { + if (disseminateParams.containsKey("updatedAfter") && dso.getType() == Constants.ITEM) { Date afterDate = Utils.parseISO8601Date(disseminateParams.getProperty("updatedAfter")); //if null is returned, we couldn't parse the date! - if(afterDate==null) - { - throw new IOException("Invalid date passed in via 'updatedAfter' option. Date must be in ISO-8601 format, and include both a day and time (e.g. 2010-01-01T00:00:00)."); + if (afterDate == null) { + throw new IOException( + "Invalid date passed in via 'updatedAfter' option. Date must be in ISO-8601 format, and include " + + "both a day and time (e.g. 2010-01-01T00:00:00)."); } //check when this item was last modified. Item i = (Item) dso; - if(i.getLastModified().after(afterDate)) - { + if (i.getLastModified().after(afterDate)) { disseminate = true; - } - else - { + } else { disseminate = false; } } - if(disseminate) - { + if (disseminate) { //just do a normal dissemination as specified by AbstractMETSDisseminator super.disseminate(context, dso, params, pkgFile); } @@ -172,8 +167,7 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * @return string name of profile. */ @Override - public String getProfile() - { + public String getProfile() { return PROFILE_1_0; } @@ -185,8 +179,7 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * @return string name of fileGrp */ @Override - public String bundleToFileGrp(String bname) - { + public String bundleToFileGrp(String bname) { return bname; } @@ -198,8 +191,8 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * Agent describes the archive this belongs to. * * @param context DSpace Context - * @param dso current DSpace Object - * @param params Packager Parameters + * @param dso current DSpace Object + * @param params Packager Parameters * @return List of crosswalk names to run * @throws SQLException if error */ @@ -213,8 +206,7 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator // has changed. Adding a CREATEDATE changes checksum each time. // Add a LASTMODDATE for items - if (dso.getType() == Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { metsHdr.setLASTMODDATE(((Item) dso).getLastModified()); } @@ -225,7 +217,7 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator agent.setOTHERTYPE("DSpace Archive"); Name name = new Name(); name.getContent() - .add(new PCData(siteService.findSite(context).getHandle())); + .add(new PCData(siteService.findSite(context).getHandle())); agent.getContent().add(name); metsHdr.getContent().add(agent); @@ -236,10 +228,10 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator agentCreator.setOTHERTYPE("DSpace Software"); Name creatorName = new Name(); creatorName.getContent() - .add(new PCData("DSpace " + Util.getSourceVersion())); + .add(new PCData("DSpace " + Util.getSourceVersion())); agentCreator.getContent().add(creatorName); metsHdr.getContent().add(agentCreator); - + return metsHdr; } @@ -250,24 +242,20 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * Default is DIM (DSpace Internal Metadata) and MODS. * * @param context DSpace Context - * @param dso current DSpace Object - * @param params Packager Parameters + * @param dso current DSpace Object + * @param params Packager Parameters * @return List of crosswalk names to run - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ @Override - public String [] getDmdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + public String[] getDmdTypes(Context context, DSpaceObject dso, PackageParameters params) + throws SQLException, IOException, AuthorizeException { String[] dmdTypes = configurationService.getArrayProperty("aip.disseminate.dmd"); - if (ArrayUtils.isEmpty(dmdTypes)) - { - return new String[] { "MODS","DIM"}; - } - else - { + if (ArrayUtils.isEmpty(dmdTypes)) { + return new String[] {"MODS", "DIM"}; + } else { return dmdTypes; } } @@ -279,31 +267,24 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * Default is PREMIS. * * @param context DSpace Context - * @param dso current DSpace Object - * @param params Packager Parameters + * @param dso current DSpace Object + * @param params Packager Parameters * @return List of crosswalk names to run - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ @Override public String[] getTechMdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { String[] techTypes = configurationService.getArrayProperty("aip.disseminate.techMD"); - if (ArrayUtils.isEmpty(techTypes)) - { - if (dso.getType() == Constants.BITSTREAM) - { - return new String[]{"PREMIS"}; - } - else - { + if (ArrayUtils.isEmpty(techTypes)) { + if (dso.getType() == Constants.BITSTREAM) { + return new String[] {"PREMIS"}; + } else { return new String[0]; } - } - else - { + } else { return techTypes; } } @@ -319,53 +300,45 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * (Handle) of its parent in the archive, so that it can be restored. * * @param context DSpace Context - * @param dso current DSpace Object - * @param params Packager Parameters + * @param dso current DSpace Object + * @param params Packager Parameters * @return List of crosswalk names to run - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ @Override public String[] getSourceMdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { String[] sourceTypes = configurationService.getArrayProperty("aip.disseminate.sourceMD"); - if (ArrayUtils.isEmpty(sourceTypes)) - { + if (ArrayUtils.isEmpty(sourceTypes)) { return new String[] {"AIP-TECHMD"}; - } - else - { + } else { return sourceTypes; } } /** * Return the name of all crosswalks to run for the digiprovMD section of - * the METS Manifest. + * the METS Manifest. *

    * By default, none are returned * * @param context DSpace Context - * @param dso current DSpace Object - * @param params Packager Parameters + * @param dso current DSpace Object + * @param params Packager Parameters * @return List of crosswalk names to run - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ @Override public String[] getDigiprovMdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { String[] dpTypes = configurationService.getArrayProperty("aip.disseminate.digiprovMD"); - if (ArrayUtils.isEmpty(dpTypes)) - { + if (ArrayUtils.isEmpty(dpTypes)) { return new String[0]; - } - else - { + } else { return dpTypes; } } @@ -376,51 +349,42 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator *

    * By default, Deposit Licenses and CC Licenses will be added for Items. * Also, by default METSRights info will be added for all objects. - * + * * @param context DSpace Context - * @param dso current DSpace Object - * @param params Packager Parameters + * @param dso current DSpace Object + * @param params Packager Parameters * @return List of crosswalk names to run - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ @Override public String[] getRightsMdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { List result = new ArrayList(); String[] rTypes = configurationService.getArrayProperty("aip.disseminate.rightsMD"); //If unspecified in configuration file, add default settings - if (ArrayUtils.isEmpty(rTypes)) - { + if (ArrayUtils.isEmpty(rTypes)) { // Licenses only apply to an Item - if (dso.getType() == Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { //By default, disseminate Deposit License, and any CC Licenses // to an item's rightsMD section - if (PackageUtils.findDepositLicense(context, (Item)dso) != null) - { + if (PackageUtils.findDepositLicense(context, (Item) dso) != null) { result.add(DSPACE_DEPOSIT_LICENSE_MDTYPE); } - if (creativeCommonsService.getLicenseRdfBitstream((Item) dso) != null) - { + if (creativeCommonsService.getLicenseRdfBitstream((Item) dso) != null) { result.add(CREATIVE_COMMONS_RDF_MDTYPE); - } - else if (creativeCommonsService.getLicenseTextBitstream((Item) dso) != null) - { + } else if (creativeCommonsService.getLicenseTextBitstream((Item) dso) != null) { result.add(CREATIVE_COMMONS_TEXT_MDTYPE); } } - + //By default, also add METSRights info to the rightsMD result.add("METSRights"); - } - else - { + } else { return rTypes; } @@ -445,51 +409,47 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * by crosswalks (e.g. AIP techMd) for the parent, it has to be at * a higher level in the AIP manifest. The structMap is an obvious * and standards-compliant location for it. - * + * * @param context DSpace context - * @param dso Current DSpace object - * @param params Packager Parameters - * @param mets METS manifest - * @throws SQLException if database error - * @throws IOException if IO error + * @param dso Current DSpace object + * @param params Packager Parameters + * @param mets METS manifest + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error - * @throws MetsException - * METS Java toolkit exception class. + * @throws MetsException METS Java toolkit exception class. */ @Override public void addStructMap(Context context, DSpaceObject dso, - PackageParameters params, Mets mets) - throws SQLException, IOException, AuthorizeException, MetsException - { + PackageParameters params, Mets mets) + throws SQLException, IOException, AuthorizeException, MetsException { // find parent Handle String parentHandle = null; - switch (dso.getType()) - { + switch (dso.getType()) { case Constants.ITEM: - parentHandle = ((Item)dso).getOwningCollection().getHandle(); + parentHandle = ((Item) dso).getOwningCollection().getHandle(); break; case Constants.COLLECTION: - parentHandle = (((Collection)dso).getCommunities()).get(0).getHandle(); + parentHandle = (((Collection) dso).getCommunities()).get(0).getHandle(); break; case Constants.COMMUNITY: - List parents = ((Community)dso).getParentCommunities(); - if (CollectionUtils.isEmpty(parents)) - { + List parents = ((Community) dso).getParentCommunities(); + if (CollectionUtils.isEmpty(parents)) { parentHandle = siteService.findSite(context).getHandle(); - } - else - { + } else { parentHandle = parents.get(0).getHandle(); } - case Constants.SITE: + break; + case Constants.SITE: + break; + default: break; } // Parent Handle should only be null if we are creating a site-wide AIP - if(parentHandle!=null) - { + if (parentHandle != null) { // add a structMap to contain div pointing to parent: StructMap structMap = new StructMap(); structMap.setID(gensym("struct")); @@ -513,49 +473,45 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * By default, include all bundles in AIP as content. *

    * However, if the user specified a comma separated list of bundle names - * via the "filterBundles" (or "includeBundles") option, then check if this + * via the "filterBundles" (or "includeBundles") option, then check if this * bundle is in that list. If it is, return true. If it is not, return false. * * @param bundle Bundle to check for * @return true if bundle should be disseminated when disseminating Item AIPs */ @Override - public boolean includeBundle(Bundle bundle) - { + public boolean includeBundle(Bundle bundle) { List bundleList = getBundleList(); //Check if we are disseminating all bundles - if(bundleList.size()==1 && bundleList.get(0).equalsIgnoreCase("all") && !this.excludeBundles) - { + if (bundleList.size() == 1 && bundleList.get(0).equalsIgnoreCase("all") && !this.excludeBundles) { return true; //all bundles should be disseminated - } - else - { + } else { //Check if bundle name is in our list of filtered bundles boolean inList = filterBundles.contains(bundle.getName()); - //Based on whether this is an inclusion or exclusion filter, + //Based on whether this is an inclusion or exclusion filter, //return whether this bundle should be included. return this.excludeBundles ? !inList : inList; } } - + /** - * Get our list of bundles to include/exclude in this AIP, + * Get our list of bundles to include/exclude in this AIP, * based on the passed in parameters + * * @return List of bundles to filter on */ - protected List getBundleList() - { + protected List getBundleList() { // Check if we already have our list of bundles to filter on, if so, just return it. - if(this.filterBundles!=null && !this.filterBundles.isEmpty()) + if (this.filterBundles != null && !this.filterBundles.isEmpty()) { return this.filterBundles; - + } + // Check for 'filterBundles' option, as this allows for inclusion/exclusion of bundles. String bundleList = this.disseminateParams.getProperty("filterBundles"); - - if(bundleList==null || bundleList.isEmpty()) - { - //For backwards compatibility with DSpace 1.7.x, check the + + if (bundleList == null || bundleList.isEmpty()) { + //For backwards compatibility with DSpace 1.7.x, check the //'includeBundles' option to see if a list of bundles was provided bundleList = this.disseminateParams.getProperty("includeBundles", "+all"); //if we are taking the 'includeBundles' value, prepend "+" to specify that this is an inclusion @@ -563,25 +519,24 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator } // At this point, 'bundleList' will be *non-null*. If neither option was passed in, // then 'bundleList' defaults to "+all" (i.e. include all bundles). - + //If our filter list of bundles begins with a '+', then this list - // specifies all the bundles to *include*. Otherwise all + // specifies all the bundles to *include*. Otherwise all // bundles *except* the listed ones are included - if(bundleList.startsWith("+")) - { + if (bundleList.startsWith("+")) { this.excludeBundles = false; //remove the preceding '+' from our bundle list bundleList = bundleList.substring(1); } - + //Split our list of bundles to filter on commas this.filterBundles = Arrays.asList(bundleList.split(",")); - - + + return this.filterBundles; } - - + + /** * Returns a user help string which should describe the * additional valid command-line options that this packager @@ -592,17 +547,18 @@ public class DSpaceAIPDisseminator extends AbstractMETSDisseminator * with this packager */ @Override - public String getParameterHelp() - { + public String getParameterHelp() { String parentHelp = super.getParameterHelp(); //Return superclass help info, plus the extra parameter/option that this class supports return parentHelp + - "\n\n" + - "* filterBundles=[bundleList] " + - "List of bundles specifying which Bundles should be included in an AIP. If this list starts with a '+' symbol," + - " then it represents a list of bundles to *include* in the AIP. By default, the list represents a list of bundles" + - " to *exclude* from the AIP."; + "\n\n" + + "* filterBundles=[bundleList] " + + "List of bundles specifying which Bundles should be included in an AIP. If this list starts with a '+' " + + "symbol," + + " then it represents a list of bundles to *include* in the AIP. By default, the list represents a list " + + "of bundles" + + " to *exclude* from the AIP."; } - + } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/DSpaceAIPIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/DSpaceAIPIngester.java index b964cfa621..e23ab5f0b4 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/DSpaceAIPIngester.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/DSpaceAIPIngester.java @@ -10,8 +10,6 @@ package org.dspace.content.packager; import java.io.IOException; import java.sql.SQLException; -import org.jdom.Element; - import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; @@ -20,8 +18,9 @@ import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.MetadataValidationException; -import org.dspace.core.Context; import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.jdom.Element; /** * Subclass of the METS packager framework to ingest a DSpace @@ -32,7 +31,7 @@ import org.dspace.core.Constants; *

    * This ingester recognizes two distinct types of AIPs: "Manifest-Only" and "External". * The Manifest-Only AIP, which is selected by specifying a PackageParameters - * key "manifestOnly" with the value "true", refers to all its contents by + * key "manifestOnly" with the value "true", refers to all its contents by * reference only. For Community or Collection AIPs this means all references to their * child objects are just via Handles. For Item AIPs all Bitreams are just * referenced by their asset store location instead of finding them in the "package". @@ -44,27 +43,27 @@ import org.dspace.core.Constants; * * Configuration keys: * - * # instructs which xwalk plugin to use for a given type of metadata - * mets.dspaceAIP.ingest.crosswalk.{mdSecName} = {pluginName} - * mets.dspaceAIP.ingest.crosswalk.DC = QDC - * mets.dspaceAIP.ingest.crosswalk.DSpaceDepositLicense = NULLSTREAM + * # instructs which xwalk plugin to use for a given type of metadata + * mets.dspaceAIP.ingest.crosswalk.{mdSecName} = {pluginName} + * mets.dspaceAIP.ingest.crosswalk.DC = QDC + * mets.dspaceAIP.ingest.crosswalk.DSpaceDepositLicense = NULLSTREAM * - * # Option to save METS manifest in the item: (default is false) - * mets.default.ingest.preserveManifest = false + * # Option to save METS manifest in the item: (default is false) + * mets.default.ingest.preserveManifest = false * * @author Larry Stone * @author Tim Donohue * @version $Revision: 1.1 $ - * * @see AbstractMETSIngester * @see AbstractPackageIngester * @see PackageIngester * @see org.dspace.content.packager.METSManifest */ public class DSpaceAIPIngester - extends AbstractMETSIngester -{ - /** log4j category */ + extends AbstractMETSIngester { + /** + * log4j category + */ private static Logger log = Logger.getLogger(DSpaceAIPIngester.class); /** @@ -72,15 +71,11 @@ public class DSpaceAIPIngester */ @Override void checkManifest(METSManifest manifest) - throws MetadataValidationException - { + throws MetadataValidationException { String profile = manifest.getProfile(); - if (profile == null) - { + if (profile == null) { throw new MetadataValidationException("Cannot accept METS with no PROFILE attribute!"); - } - else if (!profile.equals(DSpaceAIPDisseminator.PROFILE_1_0)) - { + } else if (!profile.equals(DSpaceAIPDisseminator.PROFILE_1_0)) { throw new MetadataValidationException("METS has unacceptable PROFILE attribute, profile=" + profile); } } @@ -93,115 +88,89 @@ public class DSpaceAIPIngester * 1. Use whatever the dmd parameter specifies as the primary DMD.
    * 2. If (1) is unspecified, find DIM (preferably) or MODS as primary DMD.
    * 3. If (1) or (2) succeeds, crosswalk it and ignore all other DMDs with - * same GROUPID
    + * same GROUPID
    * 4. Crosswalk remaining DMDs not eliminated already. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object - * @param manifest - * the METSManifest - * @param callback - * the MdrefManager (manages all external metadata files - * referenced by METS mdref elements) - * @param dmds - * array of Elements, each a METS dmdSec that - * applies to the Item as a whole. - * @param params - * Packager Parameters + * @param context The relevant DSpace Context. + * @param dso DSpace object + * @param manifest the METSManifest + * @param callback the MdrefManager (manages all external metadata files + * referenced by METS mdref elements) + * @param dmds array of Elements, each a METS dmdSec that + * applies to the Item as a whole. + * @param params Packager Parameters * @throws PackageValidationException validation error - * @throws CrosswalkException if crosswalk error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ @Override public void crosswalkObjectDmd(Context context, DSpaceObject dso, - METSManifest manifest, - MdrefManager callback, - Element dmds[], PackageParameters params) + METSManifest manifest, + MdrefManager callback, + Element dmds[], PackageParameters params) throws CrosswalkException, PackageValidationException, - AuthorizeException, SQLException, IOException - { + AuthorizeException, SQLException, IOException { int found = -1; // Check to see what dmdSec the user specified in the 'dmd' parameter String userDmd = null; - if (params != null) - { + if (params != null) { userDmd = params.getProperty("dmd"); } - if (userDmd != null && userDmd.length() > 0) - { - for (int i = 0; i < dmds.length; ++i) - { - if (userDmd.equalsIgnoreCase(manifest.getMdType(dmds[i]))) - { + if (userDmd != null && userDmd.length() > 0) { + for (int i = 0; i < dmds.length; ++i) { + if (userDmd.equalsIgnoreCase(manifest.getMdType(dmds[i]))) { found = i; } } } // DIM is preferred, if nothing specified by user - if (found == -1) - { + if (found == -1) { // DIM is preferred for AIP - for (int i = 0; i < dmds.length; ++i) - { + for (int i = 0; i < dmds.length; ++i) { //NOTE: METS standard actually says this should be DIM (all uppercase). But, // just in case, we're going to be a bit more forgiving. - if ("DIM".equalsIgnoreCase(manifest.getMdType(dmds[i]))) - { + if ("DIM".equalsIgnoreCase(manifest.getMdType(dmds[i]))) { found = i; } } } // MODS is acceptable otehrwise.. - if (found == -1) - { - for (int i = 0; i < dmds.length; ++i) - { + if (found == -1) { + for (int i = 0; i < dmds.length; ++i) { //NOTE: METS standard actually says this should be MODS (all uppercase). But, // just in case, we're going to be a bit more forgiving. - if ("MODS".equalsIgnoreCase(manifest.getMdType(dmds[i]))) - { + if ("MODS".equalsIgnoreCase(manifest.getMdType(dmds[i]))) { found = i; } } } String groupID = null; - if (found >= 0) - { + if (found >= 0) { manifest.crosswalkItemDmd(context, params, dso, dmds[found], callback); groupID = dmds[found].getAttributeValue("GROUPID"); - if (groupID != null) - { - for (int i = 0; i < dmds.length; ++i) - { + if (groupID != null) { + for (int i = 0; i < dmds.length; ++i) { String g = dmds[i].getAttributeValue("GROUPID"); - if (g != null && !g.equals(groupID)) - { + if (g != null && !g.equals(groupID)) { manifest.crosswalkItemDmd(context, params, dso, dmds[i], callback); } } } - } - - // otherwise take the first. Don't xwalk more than one because - // each xwalk _adds_ metadata, and could add duplicate fields. - else if (dmds.length > 0) - { + } else if (dmds.length > 0) { + // otherwise take the first. Don't xwalk more than one because + // each xwalk _adds_ metadata, and could add duplicate fields. manifest.crosswalkItemDmd(context, params, dso, dmds[0], callback); - } - - // it's an error if there is nothing to crosswalk: - else - { - throw new MetadataValidationException("DSpaceAIPIngester: Could not find an acceptable object-wide DMD section in manifest."); + } else { + // it's an error if there is nothing to crosswalk: + throw new MetadataValidationException( + "DSpaceAIPIngester: Could not find an acceptable object-wide DMD section in manifest."); } } @@ -214,29 +183,23 @@ public class DSpaceAIPIngester * default deposit license. * Normally the rightsMD crosswalks should provide a license. * - * @param context - * The relevant DSpace Context. - * @param item - * item to add license to - * @param collection - * collection to get the default license from - * @param params - * Packager Parameters + * @param context The relevant DSpace Context. + * @param item item to add license to + * @param collection collection to get the default license from + * @param params Packager Parameters * @throws PackageValidationException validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ @Override public void addLicense(Context context, Item item, String license, - Collection collection, PackageParameters params) + Collection collection, PackageParameters params) throws PackageValidationException, - AuthorizeException, SQLException, IOException - { + AuthorizeException, SQLException, IOException { boolean newLicense = false; - if (!params.restoreModeEnabled()) - { + if (!params.restoreModeEnabled()) { //AIP is not being restored/replaced, so treat it like a SIP -- every new SIP needs a new license newLicense = true; } @@ -244,13 +207,11 @@ public class DSpaceAIPIngester // Add deposit license if there isn't one in the object, // and it's not a restoration of an "manifestOnly" AIP: if (!params.getBooleanProperty("manifestOnly", false) && - PackageUtils.findDepositLicense(context, item) == null) - { + PackageUtils.findDepositLicense(context, item) == null) { newLicense = true; } - if (newLicense) - { + if (newLicense) { PackageUtils.addDepositLicense(context, license, item, collection); } } @@ -263,36 +224,30 @@ public class DSpaceAIPIngester * will throw errors when we attempt to save/update the Item) *

    * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object - * @param params - * Packager Parameters - * @throws PackageValidationException - * Failure when importing or exporting a package - * caused by invalid unacceptable package format or contents - * @throws CrosswalkException - * Superclass for more-specific crosswalk exceptions. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param dso DSpace object + * @param params Packager Parameters + * @throws PackageValidationException Failure when importing or exporting a package + * caused by invalid unacceptable package format or contents + * @throws CrosswalkException Superclass for more-specific crosswalk exceptions. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O + * operations. + * @throws SQLException An exception that provides information on a database access error or other + * errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ @Override public void finishObject(Context context, DSpaceObject dso, PackageParameters params) throws PackageValidationException, CrosswalkException, - AuthorizeException, SQLException, IOException - { + AuthorizeException, SQLException, IOException { //Metadata fields are now required before adding, so this logic isn't needed anymore /*if (dso.getType()==Constants.ITEM) { // Check if 'createMetadataFields' option is enabled (default=true) // This defaults to true as by default we should attempt to restore as much metadata as we can. - // When 'createMetadataFields' is set to false, an ingest will fail if it attempts to ingest content to a missing metadata field. + // When 'createMetadataFields' is set to false, an ingest will fail if it attempts to ingest content to a + m issing metadata field. if (params.getBooleanProperty("createMetadataFields", true)) { // We want to verify that all the Metadata Fields we've crosswalked @@ -305,45 +260,42 @@ public class DSpaceAIPIngester /** * Nothing extra to do to bitstream after ingestion. + * * @throws MetadataValidationException if validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ @Override public void finishBitstream(Context context, - Bitstream bs, - Element mfile, - METSManifest manifest, - PackageParameters params) - throws MetadataValidationException, SQLException, AuthorizeException, IOException - { + Bitstream bs, + Element mfile, + METSManifest manifest, + PackageParameters params) + throws MetadataValidationException, SQLException, AuthorizeException, IOException { // nothing to do. } /** * Return the type of DSpaceObject in this package; it is * in the TYPE attribute of the mets:mets element. + * * @return type * @throws PackageValidationException if package validation error */ @Override public int getObjectType(METSManifest manifest) - throws PackageValidationException - { + throws PackageValidationException { Element mets = manifest.getMets(); String typeStr = mets.getAttributeValue("TYPE"); - if (typeStr == null || typeStr.length() == 0) - { + if (typeStr == null || typeStr.length() == 0) { throw new PackageValidationException("Manifest is missing the required mets@TYPE attribute."); } - if (typeStr.startsWith("DSpace ")) - { + if (typeStr.startsWith("DSpace ")) { typeStr = typeStr.substring(7); } int type = Constants.getTypeID(typeStr); - if (type < 0) - { + if (type < 0) { throw new PackageValidationException("Manifest has unrecognized value in mets@TYPE attribute: " + typeStr); } return type; @@ -351,11 +303,11 @@ public class DSpaceAIPIngester /** * Name used to distinguish DSpace Configuration entries for this subclass. + * * @return config name */ @Override - public String getConfigurationName() - { + public String getConfigurationName() { return "dspaceAIP"; } @@ -369,19 +321,19 @@ public class DSpaceAIPIngester * with this packager */ @Override - public String getParameterHelp() - { + public String getParameterHelp() { String parentHelp = super.getParameterHelp(); //Return superclass help info, plus the extra parameters/options that this class supports return parentHelp + - "\n\n" + - "* createMetadataFields=[boolean] " + - "If true, ingest attempts to create any missing metadata fields." + - "If false, ingest will fail if a metadata field is encountered which doesn't already exist. (default = true)" + - "\n\n" + - "* dmd=[dmdSecType] " + - "Type of the METS which should be used to restore item metadata (defaults to DIM, then MODS)"; + "\n\n" + + "* createMetadataFields=[boolean] " + + "If true, ingest attempts to create any missing metadata fields." + + "If false, ingest will fail if a metadata field is encountered which doesn't already exist. (default = " + + "true)" + + "\n\n" + + "* dmd=[dmdSecType] " + + "Type of the METS which should be used to restore item metadata (defaults to DIM, then MODS)"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/DSpaceMETSDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/DSpaceMETSDisseminator.java index de96d561aa..74f763729c 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/DSpaceMETSDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/DSpaceMETSDisseminator.java @@ -9,26 +9,25 @@ package org.dspace.content.packager; import java.io.IOException; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.ArrayList; - -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Bundle; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; -import org.dspace.core.Constants; -import org.dspace.core.ConfigurationManager; -import org.dspace.core.Context; import edu.harvard.hul.ois.mets.Agent; import edu.harvard.hul.ois.mets.Mets; import edu.harvard.hul.ois.mets.MetsHdr; -import edu.harvard.hul.ois.mets.Role; -import edu.harvard.hul.ois.mets.helper.MetsException; -import edu.harvard.hul.ois.mets.Type; import edu.harvard.hul.ois.mets.Name; +import edu.harvard.hul.ois.mets.Role; +import edu.harvard.hul.ois.mets.Type; +import edu.harvard.hul.ois.mets.helper.MetsException; import edu.harvard.hul.ois.mets.helper.PCData; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; /** * Packager plugin to produce a @@ -49,8 +48,7 @@ import edu.harvard.hul.ois.mets.helper.PCData; * @version $Revision$ */ public class DSpaceMETSDisseminator - extends AbstractMETSDisseminator -{ + extends AbstractMETSDisseminator { /** * Identifier for the package we produce, i.e. DSpace METS SIP * Profile. Though not strictly true, there is no DIP standard yet @@ -76,8 +74,7 @@ public class DSpaceMETSDisseminator * @return string name of profile. */ @Override - public String getProfile() - { + public String getProfile() { return PROFILE_LABEL; } @@ -86,32 +83,29 @@ public class DSpaceMETSDisseminator * They are mostly the same except for bundle "ORIGINAL" maps to "CONTENT". * Don't worry about the metadata bundles since they are not * packaged as fileGrps, but in *mdSecs. + * * @param bname name of DSpace bundle. * @return string name of fileGrp */ @Override - public String bundleToFileGrp(String bname) - { - if (bname.equals("ORIGINAL")) - { + public String bundleToFileGrp(String bname) { + if (bname.equals("ORIGINAL")) { return "CONTENT"; - } - else - { + } else { return bname; } } /** * Create metsHdr element - separate so subclasses can override. + * * @return mets header */ @Override public MetsHdr makeMetsHdr(Context context, DSpaceObject dso, - PackageParameters params) - { + PackageParameters params) { MetsHdr metsHdr = new MetsHdr(); - + // FIXME: CREATEDATE is now: maybe should be item create? metsHdr.setCREATEDATE(new Date()); @@ -121,7 +115,7 @@ public class DSpaceMETSDisseminator agent.setTYPE(Type.ORGANIZATION); Name name = new Name(); name.getContent() - .add(new PCData(ConfigurationManager + .add(new PCData(ConfigurationManager .getProperty("dspace.name"))); agent.getContent().add(name); metsHdr.getContent().add(agent); @@ -135,25 +129,23 @@ public class DSpaceMETSDisseminator * params may contain one or more values for "dmd"; each of those is * the name of a crosswalk plugin, optionally followed by colon and * its METS MDTYPE name. + * * @return array of DMD types - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override - public String [] getDmdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + public String[] getDmdTypes(Context context, DSpaceObject dso, PackageParameters params) + throws SQLException, IOException, AuthorizeException { - // XXX FIXME maybe let dmd choices be configured in DSpace config? + // XXX FIXME maybe let dmd choices be configured in DSpace config? String result[] = null; - if (params != null) - { + if (params != null) { result = params.getProperties("dmd"); } - if (result == null || result.length == 0) - { + if (result == null || result.length == 0) { result = new String[1]; result[0] = "MODS"; } @@ -164,89 +156,77 @@ public class DSpaceMETSDisseminator * Get name of technical metadata crosswalk for Bitstreams. * Default is PREMIS. This is both the name of the crosswalk plugin * and the METS MDTYPE. + * * @return array of TechMD types - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ @Override public String[] getTechMdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { - if (dso.getType() == Constants.BITSTREAM) - { + throws SQLException, IOException, AuthorizeException { + if (dso.getType() == Constants.BITSTREAM) { String result[] = new String[1]; result[0] = "PREMIS"; return result; - } - else - { + } else { return new String[0]; } } @Override public String[] getSourceMdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { return new String[0]; } @Override public String[] getDigiprovMdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { return new String[0]; } /** * Add rights MD (licenses) for DSpace item. These * may include a deposit license, and Creative Commons. + * * @return array of RightsMD types - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ @Override public String[] getRightsMdTypes(Context context, DSpaceObject dso, PackageParameters params) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { List result = new ArrayList(); - if (dso.getType() == Constants.ITEM) - { - Item item = (Item)dso; - if (PackageUtils.findDepositLicense(context, item) != null) - { + if (dso.getType() == Constants.ITEM) { + Item item = (Item) dso; + if (PackageUtils.findDepositLicense(context, item) != null) { result.add(DSPACE_DEPOSIT_LICENSE_MDTYPE); } - if (creativeCommonsService.getLicenseRdfBitstream(item) != null) - { + if (creativeCommonsService.getLicenseRdfBitstream(item) != null) { result.add(CREATIVE_COMMONS_RDF_MDTYPE); - } - else if (creativeCommonsService.getLicenseTextBitstream(item) != null) - { + } else if (creativeCommonsService.getLicenseTextBitstream(item) != null) { result.add(CREATIVE_COMMONS_TEXT_MDTYPE); } } - + return result.toArray(new String[result.size()]); } // This is where we'd elaborate on the default structMap; nothing to add, yet. @Override public void addStructMap(Context context, DSpaceObject dso, - PackageParameters params, Mets mets) - throws SQLException, IOException, AuthorizeException, MetsException - { + PackageParameters params, Mets mets) + throws SQLException, IOException, AuthorizeException, MetsException { } // only exclude metadata bundles from package. @Override - public boolean includeBundle(Bundle bundle) - { - return ! PackageUtils.isMetaInfoBundle(bundle); + public boolean includeBundle(Bundle bundle) { + return !PackageUtils.isMetaInfoBundle(bundle); } /** @@ -259,14 +239,14 @@ public class DSpaceMETSDisseminator * with this packager */ @Override - public String getParameterHelp() - { + public String getParameterHelp() { String parentHelp = super.getParameterHelp(); //Return superclass help info, plus the extra parameter/option that this class supports return parentHelp + - "\n\n" + - "* dmd=[dmdSecType] " + - "(Repeatable) Type(s) of the METS which should be created in the dissemination package (defaults to MODS)"; + "\n\n" + + "* dmd=[dmdSecType] " + + "(Repeatable) Type(s) of the METS which should be created in the dissemination package (defaults" + + " to MODS)"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/DSpaceMETSIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/DSpaceMETSIngester.java index 4ea1f3e349..da3965534f 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/DSpaceMETSIngester.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/DSpaceMETSIngester.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; +import org.dspace.app.mediafilter.MediaFilter; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.Collection; @@ -18,12 +19,10 @@ import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.MetadataValidationException; -import org.dspace.core.Context; import org.dspace.core.Constants; -import org.dspace.app.mediafilter.MediaFilter; +import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.core.service.PluginService; - import org.jdom.Element; /** @@ -46,23 +45,18 @@ import org.jdom.Element; * @see PackageIngester */ public class DSpaceMETSIngester - extends AbstractMETSIngester -{ + extends AbstractMETSIngester { // first part of required mets@PROFILE value protected static final String PROFILE_START = "DSpace METS SIP Profile"; // just check the profile name. @Override void checkManifest(METSManifest manifest) - throws MetadataValidationException - { + throws MetadataValidationException { String profile = manifest.getProfile(); - if (profile == null) - { + if (profile == null) { throw new MetadataValidationException("Cannot accept METS with no PROFILE attribute!"); - } - else if (!profile.startsWith(PROFILE_START)) - { + } else if (!profile.startsWith(PROFILE_START)) { throw new MetadataValidationException("METS has unacceptable PROFILE value, profile=" + profile); } } @@ -74,93 +68,76 @@ public class DSpaceMETSIngester * 1. Use whatever the dmd parameter specifies as the primary DMD.
    * 2. If (1) is unspecified, find MODS (preferably) or DC as primary DMD.
    * 3. If (1) or (2) succeeds, crosswalk it and ignore all other DMDs with - * same GROUPID
    + * same GROUPID
    * 4. Crosswalk remaining DMDs not eliminated already. - * @throws CrosswalkException if crosswalk error + * + * @throws CrosswalkException if crosswalk error * @throws PackageValidationException if validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ @Override public void crosswalkObjectDmd(Context context, DSpaceObject dso, - METSManifest manifest, - MdrefManager callback, - Element dmds[], PackageParameters params) + METSManifest manifest, + MdrefManager callback, + Element dmds[], PackageParameters params) throws CrosswalkException, PackageValidationException, - AuthorizeException, SQLException, IOException - { + AuthorizeException, SQLException, IOException { int found = -1; // Check to see what dmdSec the user specified in the 'dmd' parameter String userDmd = null; - if (params != null) - { + if (params != null) { userDmd = params.getProperty("dmd"); } - if (userDmd != null && userDmd.length() > 0) - { - for (int i = 0; i < dmds.length; ++i) - { - if (userDmd.equalsIgnoreCase(manifest.getMdType(dmds[i]))) - { + if (userDmd != null && userDmd.length() > 0) { + for (int i = 0; i < dmds.length; ++i) { + if (userDmd.equalsIgnoreCase(manifest.getMdType(dmds[i]))) { found = i; } } } // MODS is preferred, if nothing specified by user - if (found == -1) - { - for (int i = 0; i < dmds.length; ++i) - { + if (found == -1) { + for (int i = 0; i < dmds.length; ++i) { //NOTE: METS standard actually says this should be MODS (all uppercase). But, // just in case, we're going to be a bit more forgiving. - if ("MODS".equalsIgnoreCase(manifest.getMdType(dmds[i]))) - { + if ("MODS".equalsIgnoreCase(manifest.getMdType(dmds[i]))) { found = i; } } } // DC acceptable if no MODS - if (found == -1) - { - for (int i = 0; i < dmds.length; ++i) - { + if (found == -1) { + for (int i = 0; i < dmds.length; ++i) { //NOTE: METS standard actually says this should be DC (all uppercase). But, // just in case, we're going to be a bit more forgiving. - if ("DC".equalsIgnoreCase(manifest.getMdType(dmds[i]))) - { + if ("DC".equalsIgnoreCase(manifest.getMdType(dmds[i]))) { found = i; } } } String groupID = null; - if (found >= 0) - { + if (found >= 0) { manifest.crosswalkItemDmd(context, params, dso, dmds[found], callback); groupID = dmds[found].getAttributeValue("GROUPID"); - if (groupID != null) - { - for (int i = 0; i < dmds.length; ++i) - { + if (groupID != null) { + for (int i = 0; i < dmds.length; ++i) { String g = dmds[i].getAttributeValue("GROUPID"); - if (g != null && !g.equals(groupID)) - { + if (g != null && !g.equals(groupID)) { manifest.crosswalkItemDmd(context, params, dso, dmds[i], callback); } } } - } - else - { + } else { // otherwise take the first. Don't xwalk more than one because // each xwalk _adds_ metadata, and could add duplicate fields. - if (dmds.length > 0) - { + if (dmds.length > 0) { manifest.crosswalkItemDmd(context, params, dso, dmds[0], callback); } } @@ -172,19 +149,18 @@ public class DSpaceMETSIngester * supplied by explicit argument first, else use collection's * default deposit license. * For Creative Commons, look for a rightsMd containing a CC license. + * * @throws PackageValidationException if validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ @Override public void addLicense(Context context, Item item, String license, - Collection collection, PackageParameters params) + Collection collection, PackageParameters params) throws PackageValidationException, - AuthorizeException, SQLException, IOException - { - if (PackageUtils.findDepositLicense(context, item) == null) - { + AuthorizeException, SQLException, IOException { + if (PackageUtils.findDepositLicense(context, item) == null) { PackageUtils.addDepositLicense(context, license, item, collection); } } @@ -193,32 +169,27 @@ public class DSpaceMETSIngester public void finishObject(Context context, DSpaceObject dso, PackageParameters params) throws PackageValidationException, CrosswalkException, - AuthorizeException, SQLException, IOException - { + AuthorizeException, SQLException, IOException { // nothing to do. } @Override public int getObjectType(METSManifest manifest) - throws PackageValidationException - { + throws PackageValidationException { return Constants.ITEM; } // return name of derived file as if MediaFilter created it, or null // only needed when importing a SIP without canonical DSpace derived file naming. - private String makeDerivedFilename(String bundleName, String origName) - { + private String makeDerivedFilename(String bundleName, String origName) { PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); // get the MediaFilter that would create this bundle: String mfNames[] = pluginService.getAllPluginNames(MediaFilter.class); - for (int i = 0; i < mfNames.length; ++i) - { - MediaFilter mf = (MediaFilter)pluginService.getNamedPlugin(MediaFilter.class, mfNames[i]); - if (bundleName.equals(mf.getBundleName())) - { + for (int i = 0; i < mfNames.length; ++i) { + MediaFilter mf = (MediaFilter) pluginService.getNamedPlugin(MediaFilter.class, mfNames[i]); + if (bundleName.equals(mf.getBundleName())) { return mf.getFilteredName(origName); } } @@ -229,32 +200,29 @@ public class DSpaceMETSIngester /** * Take a second pass over files to correct names of derived files * (e.g. thumbnails, extracted text) to what DSpace expects: + * * @throws MetadataValidationException if validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ @Override public void finishBitstream(Context context, - Bitstream bs, - Element mfile, - METSManifest manifest, - PackageParameters params) - throws MetadataValidationException, SQLException, AuthorizeException, IOException - { + Bitstream bs, + Element mfile, + METSManifest manifest, + PackageParameters params) + throws MetadataValidationException, SQLException, AuthorizeException, IOException { String bundleName = METSManifest.getBundleName(mfile); - if (!bundleName.equals(Constants.CONTENT_BUNDLE_NAME)) - { + if (!bundleName.equals(Constants.CONTENT_BUNDLE_NAME)) { String opath = manifest.getOriginalFilePath(mfile); - if (opath != null) - { + if (opath != null) { // String ofileId = origFile.getAttributeValue("ID"); // Bitstream obs = (Bitstream)fileIdToBitstream.get(ofileId); String newName = makeDerivedFilename(bundleName, opath); - if (newName != null) - { + if (newName != null) { //String mfileId = mfile.getAttributeValue("ID"); //Bitstream bs = (Bitstream)fileIdToBitstream.get(mfileId); bs.setName(context, newName); @@ -265,14 +233,12 @@ public class DSpaceMETSIngester } @Override - public String getConfigurationName() - { + public String getConfigurationName() { return "dspaceSIP"; } - public boolean probe(Context context, InputStream in, PackageParameters params) - { + public boolean probe(Context context, InputStream in, PackageParameters params) { throw new UnsupportedOperationException("PDF package ingester does not implement probe()"); } @@ -286,14 +252,13 @@ public class DSpaceMETSIngester * with this packager */ @Override - public String getParameterHelp() - { + public String getParameterHelp() { String parentHelp = super.getParameterHelp(); //Return superclass help info, plus the extra parameter/option that this class supports return parentHelp + - "\n\n" + - "* dmd=[dmdSecType] " + - "Type of the METS which should be used for primary item metadata (defaults to MODS, then DC)"; + "\n\n" + + "* dmd=[dmdSecType] " + + "Type of the METS which should be used for primary item metadata (defaults to MODS, then DC)"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/METSManifest.java b/dspace-api/src/main/java/org/dspace/content/packager/METSManifest.java index 44a5c49334..d9d860d04e 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/METSManifest.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/METSManifest.java @@ -26,15 +26,15 @@ import org.dspace.content.DSpaceObject; import org.dspace.content.crosswalk.AbstractPackagerWrappingCrosswalk; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.CrosswalkObjectNotSupported; -import org.dspace.content.crosswalk.MetadataValidationException; import org.dspace.content.crosswalk.IngestionCrosswalk; +import org.dspace.content.crosswalk.MetadataValidationException; import org.dspace.content.crosswalk.StreamIngestionCrosswalk; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; -import org.jdom.Document; import org.jdom.Content; +import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; @@ -78,21 +78,18 @@ import org.jdom.xpath.XPath; * * * - * * @author Robert Tansley * @author WeiHua Huang * @author Rita Lee * @author Larry Stone */ -public class METSManifest -{ +public class METSManifest { /** * Callback interface to retrieve data streams in mdRef elements. * "Package" or file reader returns an input stream for the * given relative path, e.g. to dereference mdRef elements. */ - public interface Mdref - { + public interface Mdref { /** * Make the contents of an external resource mentioned in * an mdRef element available as an InputStream. @@ -107,134 +104,145 @@ public class METSManifest * @param mdRef JDOM element of mdRef in the METS manifest. * @return stream containing the metadata mentioned in mdRef. * @throws MetadataValidationException if the mdRef is unacceptable or missing required information. - * @throws PackageValidationException if package validation error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws PackageValidationException if package validation error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public InputStream getInputStream(Element mdRef) throws MetadataValidationException, PackageValidationException, - IOException, SQLException, AuthorizeException; + IOException, SQLException, AuthorizeException; } - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(METSManifest.class); - /** Canonical filename of METS manifest within a package or as a bitstream. */ + /** + * Canonical filename of METS manifest within a package or as a bitstream. + */ public static final String MANIFEST_FILE = "mets.xml"; - /** Prefix of DSpace configuration lines that map METS metadata type to + /** + * Prefix of DSpace configuration lines that map METS metadata type to * crosswalk plugin names. */ public static final String CONFIG_METS_PREFIX = "mets."; - /** prefix of config lines identifying local XML Schema (XSD) files */ - protected static final String CONFIG_XSD_PREFIX = CONFIG_METS_PREFIX+"xsd."; + /** + * prefix of config lines identifying local XML Schema (XSD) files + */ + protected static final String CONFIG_XSD_PREFIX = CONFIG_METS_PREFIX + "xsd."; - /** Dublin core element namespace */ + /** + * Dublin core element namespace + */ protected static final Namespace dcNS = Namespace - .getNamespace("http://purl.org/dc/elements/1.1/"); + .getNamespace("http://purl.org/dc/elements/1.1/"); - /** Dublin core term namespace (for qualified DC) */ + /** + * Dublin core term namespace (for qualified DC) + */ protected static final Namespace dcTermNS = Namespace - .getNamespace("http://purl.org/dc/terms/"); + .getNamespace("http://purl.org/dc/terms/"); - /** METS namespace -- includes "mets" prefix for use in XPaths */ + /** + * METS namespace -- includes "mets" prefix for use in XPaths + */ public static final Namespace metsNS = Namespace - .getNamespace("mets", "http://www.loc.gov/METS/"); + .getNamespace("mets", "http://www.loc.gov/METS/"); - /** XLink namespace -- includes "xlink" prefix prefix for use in XPaths */ + /** + * XLink namespace -- includes "xlink" prefix prefix for use in XPaths + */ public static final Namespace xlinkNS = Namespace - .getNamespace("xlink", "http://www.w3.org/1999/xlink"); + .getNamespace("xlink", "http://www.w3.org/1999/xlink"); - /** root element of the current METS manifest. */ + /** + * root element of the current METS manifest. + */ protected Element mets = null; - /** all mdRef elements in the manifest */ + /** + * all mdRef elements in the manifest + */ protected List mdFiles = null; - /** {@code } elements in "original" file group (bundle) */ + /** + * {@code } elements in "original" file group (bundle) + */ protected List contentFiles = null; protected List bundleFiles = null; - /** builder to use for mdRef streams, inherited from create() */ + /** + * builder to use for mdRef streams, inherited from create() + */ protected SAXBuilder parser = null; - /** name of packager who created this manifest object, for looking up configuration entries. */ + /** + * name of packager who created this manifest object, for looking up configuration entries. + */ protected String configName; // Create list of local schemas at load time, since it depends only // on the DSpace configuration. protected static String localSchemas; - static - { - String dspace_dir = ConfigurationManager.getProperty("dspace.dir"); - File xsdPath1 = new File(dspace_dir+"/config/schemas/"); - File xsdPath2 = new File(dspace_dir+"/config/"); - Enumeration pe = (Enumeration)ConfigurationManager.propertyNames(); + static { + String dspace_dir = ConfigurationManager.getProperty("dspace.dir"); + File xsdPath1 = new File(dspace_dir + "/config/schemas/"); + File xsdPath2 = new File(dspace_dir + "/config/"); + + Enumeration pe = (Enumeration) ConfigurationManager.propertyNames(); StringBuffer result = new StringBuffer(); - while (pe.hasMoreElements()) - { + while (pe.hasMoreElements()) { // config lines have the format: // mets.xsd.{identifier} = {namespace} {xsd-URL} // e.g. // mets.xsd.dc = http://purl.org/dc/elements/1.1/ dc.xsd // (filename is relative to {dspace_dir}/config/schemas/) String key = pe.nextElement(); - if (key.startsWith(CONFIG_XSD_PREFIX)) - { - String spec = ConfigurationManager.getProperty(key); + if (key.startsWith(CONFIG_XSD_PREFIX)) { + String spec = ConfigurationManager.getProperty(key); String val[] = spec.trim().split("\\s+"); - if (val.length == 2) - { + if (val.length == 2) { File xsd = new File(xsdPath1, val[1]); - if (!xsd.exists()) - { + if (!xsd.exists()) { xsd = new File(xsdPath2, val[1]); } - if (!xsd.exists()) - { + if (!xsd.exists()) { log.warn("Schema file not found for config entry=\"" + spec + "\""); - } - else - { - try - { + } else { + try { String u = xsd.toURL().toString(); - if (result.length() > 0) - { + if (result.length() > 0) { result.append(" "); } result.append(val[0]).append(" ").append(u); - } - catch (java.net.MalformedURLException e) - { - log.warn("Skipping badly formed XSD URL: "+e.toString()); + } catch (java.net.MalformedURLException e) { + log.warn("Skipping badly formed XSD URL: " + e.toString()); } } - } - else - { + } else { log.warn("Schema config entry has wrong format, entry=\"" + spec + "\""); } } } localSchemas = result.toString(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Got local schemas = \"" + localSchemas + "\""); } } /** * Default constructor, only called internally. - * @param builder XML parser (for parsing mdRef'd files and binData) - * @param mets parsed METS document + * + * @param builder XML parser (for parsing mdRef'd files and binData) + * @param mets parsed METS document * @param configName config name */ - protected METSManifest(SAXBuilder builder, Element mets, String configName) - { + protected METSManifest(SAXBuilder builder, Element mets, String configName) { super(); this.mets = mets; parser = builder; @@ -244,41 +252,38 @@ public class METSManifest /** * Create a new manifest object from a serialized METS XML document. * Parse document read from the input stream, optionally validating. - * @param is input stream containing serialized XML - * @param validate if true, enable XML validation using schemas - * in document. Also validates any sub-documents. + * + * @param is input stream containing serialized XML + * @param validate if true, enable XML validation using schemas + * in document. Also validates any sub-documents. * @param configName config name - * @throws IOException if IO error - * @throws MetadataValidationException if there is any error parsing - * or validating the METS. * @return new METSManifest object. + * @throws IOException if IO error + * @throws MetadataValidationException if there is any error parsing + * or validating the METS. */ public static METSManifest create(InputStream is, boolean validate, String configName) - throws IOException, - MetadataValidationException - { + throws IOException, + MetadataValidationException { SAXBuilder builder = new SAXBuilder(validate); builder.setIgnoringElementContentWhitespace(true); // Set validation feature - if (validate) - { + if (validate) { builder.setFeature("http://apache.org/xml/features/validation/schema", true); } // Tell the parser where local copies of schemas are, to speed up // validation. Local XSDs are identified in the configuration file. - if (localSchemas.length() > 0) - { + if (localSchemas.length() > 0) { builder.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", localSchemas); } // Parse the METS file Document metsDocument; - try - { + try { metsDocument = builder.build(is); /*** XXX leave commented out except if needed for @@ -288,11 +293,9 @@ public class METSManifest * log.debug("Got METS DOCUMENT:"); * log.debug(outputPretty.outputString(metsDocument)); ****/ - } - catch (JDOMException je) - { + } catch (JDOMException je) { throw new MetadataValidationException("Error validating METS in " - + is.toString(), je); + + is.toString(), je); } return new METSManifest(builder, metsDocument.getRootElement(), configName); @@ -300,10 +303,10 @@ public class METSManifest /** * Gets name of the profile to which this METS document conforms. + * * @return value the PROFILE attribute of mets element, or null if none. */ - public String getProfile() - { + public String getProfile() { return mets.getAttributeValue("PROFILE"); } @@ -313,34 +316,30 @@ public class METSManifest * * @return OBJID attribute of METS manifest */ - public String getObjID() - { + public String getObjID() { return mets.getAttributeValue("OBJID"); } /** * Gets all file elements which make up - * the item's content. + * the item's content. + * * @return a List of Elements. * @throws MetadataValidationException if validation error */ public List getBundleFiles() - throws MetadataValidationException - { - if (bundleFiles != null) - { + throws MetadataValidationException { + if (bundleFiles != null) { return bundleFiles; } bundleFiles = new ArrayList(); Element fileSec = mets.getChild("fileSec", metsNS); - if (fileSec != null) - { + if (fileSec != null) { Iterator fgi = fileSec.getChildren("fileGrp", metsNS).iterator(); - while (fgi.hasNext()) - { - Element fg = (Element)fgi.next(); + while (fgi.hasNext()) { + Element fg = (Element) fgi.next(); bundleFiles.add(fg); } } @@ -348,26 +347,21 @@ public class METSManifest } public List getContentFiles() - throws MetadataValidationException - { - if (contentFiles != null) - { + throws MetadataValidationException { + if (contentFiles != null) { return contentFiles; } contentFiles = new ArrayList(); Element fileSec = mets.getChild("fileSec", metsNS); - if (fileSec != null) - { + if (fileSec != null) { Iterator fgi = fileSec.getChildren("fileGrp", metsNS).iterator(); - while (fgi.hasNext()) - { - Element fg = (Element)fgi.next(); + while (fgi.hasNext()) { + Element fg = (Element) fgi.next(); Iterator fi = fg.getChildren("file", metsNS).iterator(); - while (fi.hasNext()) - { - Element f = (Element)fi.next(); + while (fi.hasNext()) { + Element f = (Element) fi.next(); contentFiles.add(f); } } @@ -377,26 +371,22 @@ public class METSManifest /** * Gets list of all mdRef elements in the METS - * document. Used by ingester to e.g. check that all - * required files are present. + * document. Used by ingester to e.g. check that all + * required files are present. + * * @return a List of Elements. * @throws MetadataValidationException if validation error */ public List getMdFiles() - throws MetadataValidationException - { - if (mdFiles == null) - { - try - { + throws MetadataValidationException { + if (mdFiles == null) { + try { // Use a special namespace with known prefix // so we get the right prefix. XPath xpath = XPath.newInstance("descendant::mets:mdRef"); xpath.addNamespace(metsNS); mdFiles = xpath.selectNodes(mets); - } - catch (JDOMException je) - { + } catch (JDOMException je) { throw new MetadataValidationException("Failed while searching for mdRef elements in manifest: ", je); } } @@ -412,54 +402,43 @@ public class METSManifest * NOTE: This pattern of relating derived files through the GROUPID * attribute is peculiar to the DSpace METS SIP profile, and may not be * generally useful with other sorts of METS documents. + * * @param file METS file element of derived file * @return file path of original or null if none found. */ - public String getOriginalFilePath(Element file) - { + public String getOriginalFilePath(Element file) { String groupID = file.getAttributeValue("GROUPID"); - if (groupID == null || groupID.equals("")) - { + if (groupID == null || groupID.equals("")) { return null; } - try - { + try { XPath xpath = XPath.newInstance( -"mets:fileSec/mets:fileGrp[@USE=\"CONTENT\"]/mets:file[@GROUPID=\""+groupID+"\"]"); + "mets:fileSec/mets:fileGrp[@USE=\"CONTENT\"]/mets:file[@GROUPID=\"" + groupID + "\"]"); xpath.addNamespace(metsNS); List oFiles = xpath.selectNodes(mets); - if (oFiles.size() > 0) - { - if (log.isDebugEnabled()) - { + if (oFiles.size() > 0) { + if (log.isDebugEnabled()) { log.debug("Got ORIGINAL file for derived=" + file.toString()); } - Element flocat = ((Element)oFiles.get(0)).getChild("FLocat", metsNS); - if (flocat != null) - { + Element flocat = ((Element) oFiles.get(0)).getChild("FLocat", metsNS); + if (flocat != null) { return flocat.getAttributeValue("href", xlinkNS); } } - return null; - } - catch (JDOMException je) - { - log.warn("Got exception on XPATH looking for Original file, "+je.toString()); + return null; + } catch (JDOMException je) { + log.warn("Got exception on XPATH looking for Original file, " + je.toString()); return null; } } // translate bundle name from METS to DSpace; METS may be "CONTENT" // or "ORIGINAL" for the DSpace "ORIGINAL", rest are left alone. - protected static String normalizeBundleName(String in) - { - if (in.equals("CONTENT")) - { + protected static String normalizeBundleName(String in) { + if (in.equals("CONTENT")) { return Constants.CONTENT_BUNDLE_NAME; - } - else if (in.equals("MANIFESTMD")) - { + } else if (in.equals("MANIFESTMD")) { return Constants.METADATA_BUNDLE_NAME; } return in; @@ -468,38 +447,35 @@ public class METSManifest /** * Get the DSpace bundle name corresponding to the USE * attribute of the file group enclosing this file element. - * + * * @param file file element * @return DSpace bundle name * @throws MetadataValidationException when there is no USE attribute on the enclosing fileGrp. */ public static String getBundleName(Element file) - throws MetadataValidationException - { + throws MetadataValidationException { return getBundleName(file, true); } - + /** * Get the DSpace bundle name corresponding to the USE * attribute of the file group enclosing this file element. - * - * @param file file element + * + * @param file file element * @param getParent parent flag * @return DSpace bundle name * @throws MetadataValidationException when there is no USE attribute on the enclosing fileGrp. */ public static String getBundleName(Element file, boolean getParent) - throws MetadataValidationException - { + throws MetadataValidationException { Element fg = file; - if (getParent) - { + if (getParent) { fg = file.getParentElement(); } String fgUse = fg.getAttributeValue("USE"); - if (fgUse == null) - { - throw new MetadataValidationException("Invalid METS Manifest: every fileGrp element must have a USE attribute."); + if (fgUse == null) { + throw new MetadataValidationException( + "Invalid METS Manifest: every fileGrp element must have a USE attribute."); } return normalizeBundleName(fgUse); } @@ -509,50 +485,44 @@ public class METSManifest * By "local" we mean the reference to the actual resource containing * the data for this file, e.g. a relative path within a Zip or tar archive * if the METS is serving as a manifest for that sort of package. + * * @param file file element * @return "local" file name (i.e. relative to package or content - * directory) corresponding to this file or mdRef element. + * directory) corresponding to this file or mdRef element. * @throws MetadataValidationException when there is not enough information to find a resource identifier. */ public static String getFileName(Element file) - throws MetadataValidationException - { + throws MetadataValidationException { Element ref; - if (file.getName().equals("file")) - { + if (file.getName().equals("file")) { ref = file.getChild("FLocat", metsNS); - if (ref == null) - { + if (ref == null) { // check for forbidden FContent child first: - if (file.getChild("FContent", metsNS) == null) - { - throw new MetadataValidationException("Invalid METS Manifest: Every file element must have FLocat child."); - } - else - { - throw new MetadataValidationException("Invalid METS Manifest: file element has forbidden FContent child, only FLocat is allowed."); + if (file.getChild("FContent", metsNS) == null) { + throw new MetadataValidationException( + "Invalid METS Manifest: Every file element must have FLocat child."); + } else { + throw new MetadataValidationException( + "Invalid METS Manifest: file element has forbidden FContent child, only FLocat is allowed."); } } - } - else if (file.getName().equals("mdRef")) - { + } else if (file.getName().equals("mdRef")) { ref = file; - } - else - { - throw new MetadataValidationException("getFileName() called with recognized element type: " + file.toString()); + } else { + throw new MetadataValidationException( + "getFileName() called with recognized element type: " + file.toString()); } String loctype = ref.getAttributeValue("LOCTYPE"); - if (loctype != null && loctype.equals("URL")) - { + if (loctype != null && loctype.equals("URL")) { String result = ref.getAttributeValue("href", xlinkNS); - if (result == null) - { - throw new MetadataValidationException("Invalid METS Manifest: FLocat/mdRef is missing the required xlink:href attribute."); + if (result == null) { + throw new MetadataValidationException( + "Invalid METS Manifest: FLocat/mdRef is missing the required xlink:href attribute."); } return result; } - throw new MetadataValidationException("Invalid METS Manifest: FLocat/mdRef does not have LOCTYPE=\"URL\" attribute."); + throw new MetadataValidationException( + "Invalid METS Manifest: FLocat/mdRef does not have LOCTYPE=\"URL\" attribute."); } /** @@ -564,79 +534,72 @@ public class METSManifest * @throws MetadataValidationException if validation error */ public Element getPrimaryOrLogoBitstream() - throws MetadataValidationException - { + throws MetadataValidationException { Element objDiv = getObjStructDiv(); Element fptr = objDiv.getChild("fptr", metsNS); - if (fptr == null) - { + if (fptr == null) { return null; } String id = fptr.getAttributeValue("FILEID"); - if (id == null) - { - throw new MetadataValidationException("fptr for Primary Bitstream is missing the required FILEID attribute."); + if (id == null) { + throw new MetadataValidationException( + "fptr for Primary Bitstream is missing the required FILEID attribute."); } - Element result = getElementByXPath("descendant::mets:file[@ID=\""+id+"\"]", false); - if (result == null) - { - throw new MetadataValidationException("Cannot find file element for Primary Bitstream: looking for ID=" + id); + Element result = getElementByXPath("descendant::mets:file[@ID=\"" + id + "\"]", false); + if (result == null) { + throw new MetadataValidationException( + "Cannot find file element for Primary Bitstream: looking for ID=" + id); } return result; } /** * Get the metadata type from within a *mdSec element. + * * @param mdSec mdSec element * @return metadata type name. * @throws MetadataValidationException if validation error */ public String getMdType(Element mdSec) - throws MetadataValidationException - { + throws MetadataValidationException { Element md = mdSec.getChild("mdRef", metsNS); - if (md == null) - { + if (md == null) { md = mdSec.getChild("mdWrap", metsNS); } - if (md == null) - { - throw new MetadataValidationException("Invalid METS Manifest: ?mdSec element has neither mdRef nor mdWrap child."); + if (md == null) { + throw new MetadataValidationException( + "Invalid METS Manifest: ?mdSec element has neither mdRef nor mdWrap child."); } String result = md.getAttributeValue("MDTYPE"); - if (result != null && result.equals("OTHER")) - { + if (result != null && result.equals("OTHER")) { result = md.getAttributeValue("OTHERMDTYPE"); } - if (result == null) - { - throw new MetadataValidationException("Invalid METS Manifest: " + md.getName() + " has no MDTYPE or OTHERMDTYPE attribute."); + if (result == null) { + throw new MetadataValidationException( + "Invalid METS Manifest: " + md.getName() + " has no MDTYPE or OTHERMDTYPE attribute."); } return result; } /** - * Returns MIME type of metadata content, if available. + * Returns MIME type of metadata content, if available. + * * @param mdSec mdSec element - * @return MIMEtype word, or null if none is available. + * @return MIMEtype word, or null if none is available. * @throws MetadataValidationException if validation error */ public String getMdContentMimeType(Element mdSec) - throws MetadataValidationException - { + throws MetadataValidationException { Element mdWrap = mdSec.getChild("mdWrap", metsNS); - if (mdWrap != null) - { + if (mdWrap != null) { String mimeType = mdWrap.getAttributeValue("MIMETYPE"); - if (mimeType == null && mdWrap.getChild("xmlData", metsNS) != null) - { + if (mimeType == null && mdWrap.getChild("xmlData", metsNS) != null) { mimeType = "text/xml"; } return mimeType; } Element mdRef = mdSec.getChild("mdRef", metsNS); - if (mdRef != null) - { + if (mdRef != null) { return mdRef.getAttributeValue("MIMETYPE"); } return null; @@ -646,105 +609,87 @@ public class METSManifest * Return contents of *md element as List of XML Element objects. * Gets content, dereferencing mdRef if necessary, or decoding and parsing * a binData that contains XML. - * @param mdSec mdSec element + * + * @param mdSec mdSec element * @param callback mdref callback * @return contents of metadata section, or empty list if no XML content is available. * @throws MetadataValidationException if METS is invalid, or there is an error parsing the XML. - * @throws PackageValidationException if invalid package - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws PackageValidationException if invalid package + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public List getMdContentAsXml(Element mdSec, Mdref callback) throws MetadataValidationException, PackageValidationException, - IOException, SQLException, AuthorizeException - { - try - { + IOException, SQLException, AuthorizeException { + try { // XXX sanity check: if this has more than one child, consider it // an error since we cannot deal with more than one mdRef|mdWrap // child. This may be considered a bug and need to be fixed, // so it's best to bring it to the attention of users. List mdc = mdSec.getChildren(); - if (mdc.size() > 1) - { + if (mdc.size() > 1) { // XXX scaffolding for debugging diagnosis; at least one // XML parser stupidly includes newlines in prettyprinting // as text content objects.. String id = mdSec.getAttributeValue("ID"); StringBuffer sb = new StringBuffer(); - for (Iterator mi = mdc.iterator(); mi.hasNext();) - { - sb.append(", ").append(((Content)mi.next()).toString()); + for (Iterator mi = mdc.iterator(); mi.hasNext(); ) { + sb.append(", ").append(((Content) mi.next()).toString()); } - throw new MetadataValidationException("Cannot parse METS with "+mdSec.getQualifiedName()+" element that contains more than one child, size="+String.valueOf(mdc.size())+", ID="+id+"Kids="+sb.toString()); + throw new MetadataValidationException("Cannot parse METS with " + mdSec + .getQualifiedName() + " element that contains more than one child, size=" + String + .valueOf(mdc.size()) + ", ID=" + id + "Kids=" + sb.toString()); } Element mdRef = null; Element mdWrap = mdSec.getChild("mdWrap", metsNS); - if (mdWrap != null) - { + if (mdWrap != null) { Element xmlData = mdWrap.getChild("xmlData", metsNS); - if (xmlData == null) - { + if (xmlData == null) { Element bin = mdWrap.getChild("binData", metsNS); - if (bin == null) - { - throw new MetadataValidationException("Invalid METS Manifest: mdWrap element with neither xmlData nor binData child."); - } + if (bin == null) { + throw new MetadataValidationException( + "Invalid METS Manifest: mdWrap element with neither xmlData nor binData child."); + } else { + // if binData is actually XML, return it; otherwise ignore. - // if binData is actually XML, return it; otherwise ignore. - else - { String mimeType = mdWrap.getAttributeValue("MIMETYPE"); - if (mimeType != null && mimeType.equalsIgnoreCase("text/xml")) - { + if (mimeType != null && mimeType.equalsIgnoreCase("text/xml")) { byte value[] = Base64.decodeBase64(bin.getText().getBytes()); Document mdd = parser.build(new ByteArrayInputStream(value)); List result = new ArrayList(1); result.add(mdd.getRootElement()); return result; - } - else - { - log.warn("Ignoring binData section because MIMETYPE is not XML, but: "+mimeType); + } else { + log.warn("Ignoring binData section because MIMETYPE is not XML, but: " + mimeType); return new ArrayList(0); } - } - } - else - { + } + } else { return xmlData.getChildren(); } - } - else - { + } else { mdRef = mdSec.getChild("mdRef", metsNS); - if (mdRef != null) - { + if (mdRef != null) { String mimeType = mdRef.getAttributeValue("MIMETYPE"); - if (mimeType != null && mimeType.equalsIgnoreCase("text/xml")) - { + if (mimeType != null && mimeType.equalsIgnoreCase("text/xml")) { Document mdd = parser.build(callback.getInputStream(mdRef)); List result = new ArrayList(1); result.add(mdd.getRootElement()); return result; - } - else - { - log.warn("Ignoring mdRef section because MIMETYPE is not XML, but: "+mimeType); + } else { + log.warn("Ignoring mdRef section because MIMETYPE is not XML, but: " + mimeType); return new ArrayList(0); } - } - else - { - throw new MetadataValidationException("Invalid METS Manifest: ?mdSec element with neither mdRef nor mdWrap child."); + } else { + throw new MetadataValidationException( + "Invalid METS Manifest: ?mdSec element with neither mdRef nor mdWrap child."); } } - } - catch (JDOMException je) - { - throw new MetadataValidationException("Error parsing or validating metadata section in mdRef or binData within "+mdSec.toString(), je); + } catch (JDOMException je) { + throw new MetadataValidationException( + "Error parsing or validating metadata section in mdRef or binData within " + mdSec.toString(), je); } } @@ -753,55 +698,44 @@ public class METSManifest * Return contents of *md element as stream. * Gets content, dereferencing mdRef if necessary, or decoding * a binData element if necessary. - * @param mdSec mdSec element + * + * @param mdSec mdSec element * @param callback mdref callback * @return Stream containing contents of metadata section. Never returns null. * @throws MetadataValidationException if METS format does not contain any metadata. - * @throws PackageValidationException if invalid package - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws PackageValidationException if invalid package + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public InputStream getMdContentAsStream(Element mdSec, Mdref callback) throws MetadataValidationException, PackageValidationException, - IOException, SQLException, AuthorizeException - { + IOException, SQLException, AuthorizeException { Element mdRef = null; Element mdWrap = mdSec.getChild("mdWrap", metsNS); - if (mdWrap != null) - { + if (mdWrap != null) { Element xmlData = mdWrap.getChild("xmlData", metsNS); - if (xmlData == null) - { + if (xmlData == null) { Element bin = mdWrap.getChild("binData", metsNS); - if (bin == null) - { - throw new MetadataValidationException("Invalid METS Manifest: mdWrap element with neither xmlData nor binData child."); - } - - else - { + if (bin == null) { + throw new MetadataValidationException( + "Invalid METS Manifest: mdWrap element with neither xmlData nor binData child."); + } else { byte value[] = Base64.decodeBase64(bin.getText().getBytes()); return new ByteArrayInputStream(value); } - } - else - { + } else { XMLOutputter outputPretty = new XMLOutputter(Format.getPrettyFormat()); return new ByteArrayInputStream( - outputPretty.outputString(xmlData.getChildren()).getBytes()); + outputPretty.outputString(xmlData.getChildren()).getBytes()); } - } - else - { + } else { mdRef = mdSec.getChild("mdRef", metsNS); - if (mdRef != null) - { + if (mdRef != null) { return callback.getInputStream(mdRef); - } - else - { - throw new MetadataValidationException("Invalid METS Manifest: ?mdSec element with neither mdRef nor mdWrap child."); + } else { + throw new MetadataValidationException( + "Invalid METS Manifest: ?mdSec element with neither mdRef nor mdWrap child."); } } } @@ -816,40 +750,36 @@ public class METSManifest * @throws MetadataValidationException if metadata validation error */ public Element getObjStructDiv() - throws MetadataValidationException - { + throws MetadataValidationException { //get first Element sm = mets.getChild("structMap", metsNS); - if (sm == null) - { + if (sm == null) { throw new MetadataValidationException("METS document is missing the required structMap element."); } //get first
    Element result = sm.getChild("div", metsNS); - if (result == null) - { - throw new MetadataValidationException("METS document is missing the required first div element in first structMap."); + if (result == null) { + throw new MetadataValidationException( + "METS document is missing the required first div element in first structMap."); } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Got getObjStructDiv result=" + result.toString()); } - - return (Element)result; + + return (Element) result; } /** * Get an array of child object {@code
    }s from the METS Manifest {@code }. * These {@code
    }s reference the location of any child objects METS manifests. - * + * * @return a List of {@code Element}s, each a {@code
    }. May be empty but NOT null. * @throws MetadataValidationException if metadata validation error */ public List getChildObjDivs() - throws MetadataValidationException - { + throws MetadataValidationException { //get the
    in which describes the current object's contents Element objDiv = getObjStructDiv(); @@ -865,44 +795,37 @@ public class METSManifest * @throws MetadataValidationException if metadata validation error */ public String[] getChildMetsFilePaths() - throws MetadataValidationException - { + throws MetadataValidationException { //get our child object
    s List childObjDivs = getChildObjDivs(); List childPathList = new ArrayList(); - if(childObjDivs != null && !childObjDivs.isEmpty()) - { + if (childObjDivs != null && !childObjDivs.isEmpty()) { Iterator childIterator = childObjDivs.iterator(); //For each Div, we want to find the underlying with @LOCTYPE=URL - while(childIterator.hasNext()) - { + while (childIterator.hasNext()) { Element childDiv = (Element) childIterator.next(); //get all child 's List childMptrs = childDiv.getChildren("mptr", metsNS); - if(childMptrs!=null && !childMptrs.isEmpty()) - { - Iterator mptrIterator = childMptrs.iterator(); - //For each mptr, we want to find the one with @LOCTYPE=URL - while(mptrIterator.hasNext()) - { - Element mptr = (Element) mptrIterator.next(); - String locType = mptr.getAttributeValue("LOCTYPE"); - //if @LOCTYPE=URL, then capture @xlink:href as the METS Manifest file path - if (locType!=null && locType.equals("URL")) - { + if (childMptrs != null && !childMptrs.isEmpty()) { + Iterator mptrIterator = childMptrs.iterator(); + //For each mptr, we want to find the one with @LOCTYPE=URL + while (mptrIterator.hasNext()) { + Element mptr = (Element) mptrIterator.next(); + String locType = mptr.getAttributeValue("LOCTYPE"); + //if @LOCTYPE=URL, then capture @xlink:href as the METS Manifest file path + if (locType != null && locType.equals("URL")) { String filePath = mptr.getAttributeValue("href", xlinkNS); - if(filePath!=null && filePath.length()>0) - { + if (filePath != null && filePath.length() > 0) { childPathList.add(filePath); } - } - }//end loop - }//end if 's exist - }//end child
    loop - }//end if child
    s exist + } + } //end loop + } //end if 's exist + } //end child
    loop + } //end if child
    s exist String[] childPaths = new String[childPathList.size()]; childPaths = (String[]) childPathList.toArray(childPaths); @@ -917,46 +840,41 @@ public class METSManifest * @throws MetadataValidationException if metadata validation error */ public String getParentOwnerLink() - throws MetadataValidationException - { - + throws MetadataValidationException { + //get a list of our structMaps List childStructMaps = mets.getChildren("structMap", metsNS); Element parentStructMap = null; // find the - if(!childStructMaps.isEmpty()) - { - for (Element structMap : childStructMaps) - { + if (!childStructMaps.isEmpty()) { + for (Element structMap : childStructMaps) { String label = structMap.getAttributeValue("LABEL"); - if(label!=null && label.equalsIgnoreCase("Parent")) - { + if (label != null && label.equalsIgnoreCase("Parent")) { parentStructMap = structMap; break; } } } - if (parentStructMap == null) - { - throw new MetadataValidationException("METS document is missing the required structMap[@LABEL='Parent'] element."); + if (parentStructMap == null) { + throw new MetadataValidationException( + "METS document is missing the required structMap[@LABEL='Parent'] element."); } //get first
    Element linkDiv = parentStructMap.getChild("div", metsNS); - if (linkDiv == null) - { - throw new MetadataValidationException("METS document is missing the required first div element in structMap[@LABEL='Parent']."); + if (linkDiv == null) { + throw new MetadataValidationException( + "METS document is missing the required first div element in structMap[@LABEL='Parent']."); } //the link is in the in the @xlink:href attribute Element mptr = linkDiv.getChild("mptr", metsNS); - if (mptr != null) - { + if (mptr != null) { return mptr.getAttributeValue("href", xlinkNS); } - + //return null if we couldn't find the link return null; } @@ -965,36 +883,26 @@ public class METSManifest // return a single Element node found by one-off path. // use only when path varies each time you call it. protected Element getElementByXPath(String path, boolean nullOk) - throws MetadataValidationException - { - try - { + throws MetadataValidationException { + try { XPath xpath = XPath.newInstance(path); xpath.addNamespace(metsNS); xpath.addNamespace(xlinkNS); Object result = xpath.selectSingleNode(mets); - if (result == null && nullOk) - { + if (result == null && nullOk) { return null; - } - else if (result instanceof Element) - { + } else if (result instanceof Element) { return (Element) result; - } - else - { + } else { throw new MetadataValidationException("METSManifest: Failed to resolve XPath, path=\"" + path + "\""); } - } - catch (JDOMException je) - { - throw new MetadataValidationException("METSManifest: Failed to resolve XPath, path=\""+path+"\"", je); + } catch (JDOMException je) { + throw new MetadataValidationException("METSManifest: Failed to resolve XPath, path=\"" + path + "\"", je); } } // Find crosswalk for the indicated metadata type (e.g. "DC", "MODS") - protected Object getCrosswalk(String type, Class clazz) - { + protected Object getCrosswalk(String type, Class clazz) { /** * Allow DSpace Config to map the metadata type to a * different crosswalk name either per-packager or for METS @@ -1004,13 +912,11 @@ public class METSManifest * mets.default.ingest.crosswalk.MDNAME = XWALKNAME */ String xwalkName = ConfigurationManager.getProperty( - CONFIG_METS_PREFIX+configName+".ingest.crosswalk."+type); - if (xwalkName == null) - { + CONFIG_METS_PREFIX + configName + ".ingest.crosswalk." + type); + if (xwalkName == null) { xwalkName = ConfigurationManager.getProperty( - CONFIG_METS_PREFIX+"default.ingest.crosswalk."+type); - if (xwalkName == null) - { + CONFIG_METS_PREFIX + "default.ingest.crosswalk." + type); + if (xwalkName == null) { xwalkName = type; } } @@ -1022,19 +928,19 @@ public class METSManifest * * @return array of Elements, each a dmdSec. May be empty but NOT null. * @throws MetadataValidationException if the METS is missing a reference to item-wide - * DMDs in the correct place. + * DMDs in the correct place. */ public Element[] getItemDmds() - throws MetadataValidationException - { + throws MetadataValidationException { // div@DMDID is actually IDREFS, a space-separated list of IDs: Element objDiv = getObjStructDiv(); String dmds = objDiv.getAttributeValue("DMDID"); - if (dmds == null) - { - throw new MetadataValidationException("Invalid METS: Missing reference to Item descriptive metadata, first div on first structmap must have a DMDID attribute."); + if (dmds == null) { + throw new MetadataValidationException( + "Invalid METS: Missing reference to Item descriptive metadata, first div on first structmap must have" + + " a DMDID attribute."); } - + return getDmdElements(dmds); } @@ -1045,24 +951,19 @@ public class METSManifest * @param dmdList space-separated list of DMDIDs * @return array of Elements, each a dmdSec. May be empty but NOT null. * @throws MetadataValidationException if the METS is missing a reference to item-wide - * DMDs in the correct place. + * DMDs in the correct place. */ public Element[] getDmdElements(String dmdList) - throws MetadataValidationException - { - if(dmdList!=null && !dmdList.isEmpty()) - { + throws MetadataValidationException { + if (dmdList != null && !dmdList.isEmpty()) { String dmdID[] = dmdList.split("\\s+"); Element result[] = new Element[dmdID.length]; - for (int i = 0; i < dmdID.length; ++i) - { - result[i] = getElementByXPath("mets:dmdSec[@ID=\""+dmdID[i]+"\"]", false); + for (int i = 0; i < dmdID.length; ++i) { + result[i] = getElementByXPath("mets:dmdSec[@ID=\"" + dmdID[i] + "\"]", false); } return result; - } - else - { + } else { return new Element[0]; } } @@ -1070,31 +971,28 @@ public class METSManifest /** * Return rights metadata section(s) relevant to item as a whole. + * * @return array of rightsMd elements, possibly empty but never null. * @throws MetadataValidationException if METS is invalid, e.g. referenced amdSec is missing. */ public Element[] getItemRightsMD() - throws MetadataValidationException - { + throws MetadataValidationException { // div@ADMID is actually IDREFS, a space-separated list of IDs: Element objDiv = getObjStructDiv(); String amds = objDiv.getAttributeValue("ADMID"); - if (amds == null) - { - if (log.isDebugEnabled()) - { + if (amds == null) { + if (log.isDebugEnabled()) { log.debug("getItemRightsMD: No ADMID references found."); } return new Element[0]; } String amdID[] = amds.split("\\s+"); List resultList = new ArrayList(); - for (int i = 0; i < amdID.length; ++i) - { - List rmds = getElementByXPath("mets:amdSec[@ID=\""+amdID[i]+"\"]", false). - getChildren("rightsMD", metsNS); - if (rmds.size() > 0) - { + for (int i = 0; i < amdID.length; ++i) { + List rmds = getElementByXPath("mets:amdSec[@ID=\"" + amdID[i] + "\"]", false). + getChildren("rightsMD", + metsNS); + if (rmds.size() > 0) { resultList.addAll(rmds); } } @@ -1103,90 +1001,84 @@ public class METSManifest /** * Invokes appropriate crosswalks on Item-wide descriptive metadata. - * @param context context + * + * @param context context * @param callback mdref callback - * @param dso DSpaceObject - * @param params package params - * @param dmdSec dmdSec element + * @param dso DSpaceObject + * @param params package params + * @param dmdSec dmdSec element * @throws MetadataValidationException if METS error - * @throws CrosswalkException if crosswalk error - * @throws PackageValidationException if invalid package - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error + * @throws PackageValidationException if invalid package + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public void crosswalkItemDmd(Context context, PackageParameters params, - DSpaceObject dso, - Element dmdSec, Mdref callback) + DSpaceObject dso, + Element dmdSec, Mdref callback) throws MetadataValidationException, PackageValidationException, - CrosswalkException, IOException, SQLException, AuthorizeException - { + CrosswalkException, IOException, SQLException, AuthorizeException { crosswalkXmd(context, params, dso, dmdSec, callback, false); } /** * Crosswalk all technical and source metadata sections that belong * to the whole object. - * @param context context + * + * @param context context * @param callback mdref callback - * @param params package params - * @param dso DSpaceObject + * @param params package params + * @param dso DSpaceObject * @throws MetadataValidationException if METS is invalid, e.g. referenced amdSec is missing. - * @throws PackageValidationException if invalid package - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * @throws PackageValidationException if invalid package + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error */ public void crosswalkObjectOtherAdminMD(Context context, PackageParameters params, - DSpaceObject dso, Mdref callback) + DSpaceObject dso, Mdref callback) throws MetadataValidationException, PackageValidationException, - CrosswalkException, IOException, SQLException, AuthorizeException - { - for (String amdID : getAmdIDs()) - { - Element amdSec = getElementByXPath("mets:amdSec[@ID=\""+amdID+"\"]", false); - for (Iterator ti = amdSec.getChildren("techMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, dso, (Element)ti.next(), callback, false); + CrosswalkException, IOException, SQLException, AuthorizeException { + for (String amdID : getAmdIDs()) { + Element amdSec = getElementByXPath("mets:amdSec[@ID=\"" + amdID + "\"]", false); + for (Iterator ti = amdSec.getChildren("techMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, dso, (Element) ti.next(), callback, false); } - for (Iterator ti = amdSec.getChildren("digiprovMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, dso, (Element)ti.next(), callback, false); + for (Iterator ti = amdSec.getChildren("digiprovMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, dso, (Element) ti.next(), callback, false); } - for (Iterator ti = amdSec.getChildren("rightsMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, dso, (Element)ti.next(), callback, false); + for (Iterator ti = amdSec.getChildren("rightsMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, dso, (Element) ti.next(), callback, false); } } } /** * Just crosswalk the sourceMD sections; used to set the handle and parent of AIP. - * @param context context + * + * @param context context * @param callback mdref callback - * @param params package params - * @param dso DSpaceObject + * @param params package params + * @param dso DSpaceObject * @return true if any metadata section was actually crosswalked, false otherwise * @throws MetadataValidationException if METS is invalid, e.g. referenced amdSec is missing. - * @throws PackageValidationException if invalid package - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws CrosswalkException if crosswalk error + * @throws PackageValidationException if invalid package + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error */ public boolean crosswalkObjectSourceMD(Context context, PackageParameters params, - DSpaceObject dso, Mdref callback) + DSpaceObject dso, Mdref callback) throws MetadataValidationException, PackageValidationException, - CrosswalkException, IOException, SQLException, AuthorizeException - { + CrosswalkException, IOException, SQLException, AuthorizeException { boolean result = false; - for (String amdID : getAmdIDs()) - { - Element amdSec = getElementByXPath("mets:amdSec[@ID=\""+amdID+"\"]", false); - for (Iterator ti = amdSec.getChildren("sourceMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, dso, (Element)ti.next(), callback, false); + for (String amdID : getAmdIDs()) { + Element amdSec = getElementByXPath("mets:amdSec[@ID=\"" + amdID + "\"]", false); + for (Iterator ti = amdSec.getChildren("sourceMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, dso, (Element) ti.next(), callback, false); result = true; } } @@ -1195,20 +1087,17 @@ public class METSManifest /** * Get an array of all AMDID values for this object - * + * * @return array of all AMDID values for this object * @throws MetadataValidationException if metadata validation error */ protected String[] getAmdIDs() - throws MetadataValidationException - { + throws MetadataValidationException { // div@ADMID is actually IDREFS, a space-separated list of IDs: Element objDiv = getObjStructDiv(); String amds = objDiv.getAttributeValue("ADMID"); - if (amds == null) - { - if (log.isDebugEnabled()) - { + if (amds == null) { + if (log.isDebugEnabled()) { log.debug("crosswalkObjectTechMD: No ADMID references found."); } return new String[0]; @@ -1218,45 +1107,37 @@ public class METSManifest // Crosswalk *any* kind of metadata section - techMD, rightsMD, etc. protected void crosswalkXmd(Context context, PackageParameters params, - DSpaceObject dso, - Element xmd, Mdref callback, boolean createMissingMetadataFields) + DSpaceObject dso, + Element xmd, Mdref callback, boolean createMissingMetadataFields) throws MetadataValidationException, PackageValidationException, - CrosswalkException, IOException, SQLException, AuthorizeException - { + CrosswalkException, IOException, SQLException, AuthorizeException { String type = getMdType(xmd); //First, try to find the IngestionCrosswalk to use - IngestionCrosswalk xwalk = (IngestionCrosswalk)getCrosswalk(type, IngestionCrosswalk.class); + IngestionCrosswalk xwalk = (IngestionCrosswalk) getCrosswalk(type, IngestionCrosswalk.class); // If metadata is not simply applicable to object, // let it go with a warning. - try - { + try { // If we found the IngestionCrosswalk, crosswalk our XML-based content - if (xwalk != null) - { + if (xwalk != null) { // Check if our Crosswalk actually wraps another Packager Plugin - if(xwalk instanceof AbstractPackagerWrappingCrosswalk) - { + if (xwalk instanceof AbstractPackagerWrappingCrosswalk) { // If this crosswalk wraps another Packager Plugin, we can pass it our Packaging Parameters // (which essentially allow us to customize the ingest process of the crosswalk) AbstractPackagerWrappingCrosswalk wrapper = (AbstractPackagerWrappingCrosswalk) xwalk; wrapper.setPackagingParameters(params); } - xwalk.ingest(context, dso, getMdContentAsXml(xmd,callback), false); - } - // Otherwise, try stream-based crosswalk - else - { + xwalk.ingest(context, dso, getMdContentAsXml(xmd, callback), false); + } else { + // Otherwise, try stream-based crosswalk StreamIngestionCrosswalk sxwalk = - (StreamIngestionCrosswalk)getCrosswalk(type, StreamIngestionCrosswalk.class); + (StreamIngestionCrosswalk) getCrosswalk(type, StreamIngestionCrosswalk.class); - if (sxwalk != null) - { + if (sxwalk != null) { // Check if our Crosswalk actually wraps another Packager Plugin - if(sxwalk instanceof AbstractPackagerWrappingCrosswalk) - { + if (sxwalk instanceof AbstractPackagerWrappingCrosswalk) { // If this crosswalk wraps another Packager Plugin, we can pass it our Packaging Parameters // (which essentially allow us to customize the ingest process of the crosswalk) AbstractPackagerWrappingCrosswalk wrapper = (AbstractPackagerWrappingCrosswalk) sxwalk; @@ -1268,114 +1149,102 @@ public class METSManifest // references in METS via an element // (which is how METS references external files) Element mdRef = xmd.getChild("mdRef", metsNS); - if (mdRef != null) - { + if (mdRef != null) { InputStream in = null; - try - { + try { in = callback.getInputStream(mdRef); sxwalk.ingest(context, dso, in, mdRef.getAttributeValue("MIMETYPE")); - } - finally - { - if (in != null) - { + } finally { + if (in != null) { in.close(); } } - } // If we couldn't find an , then we'll try an - // with a element instead. - // (this is how METS wraps embedded base64-encoded content streams) - else - { + } else { + // If we couldn't find an , then we'll try an + // with a element instead. + // (this is how METS wraps embedded base64-encoded content streams) + Element mdWrap = xmd.getChild("mdWrap", metsNS); - if (mdWrap != null) - { + if (mdWrap != null) { Element bin = mdWrap.getChild("binData", metsNS); - if (bin == null) - { - throw new MetadataValidationException("Invalid METS Manifest: mdWrap element for streaming crosswalk without binData child."); - } - else - { + if (bin == null) { + throw new MetadataValidationException( + "Invalid METS Manifest: mdWrap element for streaming crosswalk without binData " + + "child."); + } else { byte value[] = Base64.decodeBase64(bin.getText().getBytes()); sxwalk.ingest(context, dso, new ByteArrayInputStream(value), mdWrap.getAttributeValue("MIMETYPE")); } - } - else - { + } else { throw new MetadataValidationException("Cannot process METS Manifest: " + - "Metadata of type=" + type + " requires a reference to a stream (mdRef), which was not found in " + xmd.getName()); + "Metadata of type=" + type + " requires a " + + "reference to a stream (mdRef), which was not " + + "found in " + xmd + .getName()); } } - } - else - { + } else { throw new MetadataValidationException("Cannot process METS Manifest: " + - "No crosswalk found for contents of " + xmd.getName() + " element, MDTYPE=" + type); + "No crosswalk found for contents of " + xmd + .getName() + " element, MDTYPE=" + type); } } - } - catch (CrosswalkObjectNotSupported e) - { - log.warn("Skipping metadata section "+xmd.getName()+", type="+type+" inappropriate for this type of object: Object="+dso.toString()+", error="+e.toString()); + } catch (CrosswalkObjectNotSupported e) { + log.warn("Skipping metadata section " + xmd + .getName() + ", type=" + type + " inappropriate for this type of object: Object=" + dso + .toString() + ", error=" + e.toString()); } } /** * Crosswalk the metadata associated with a particular file * element into the bitstream it corresponds to. - * @param context a dspace context. - * @param params any PackageParameters which may affect how bitstreams are crosswalked + * + * @param context a dspace context. + * @param params any PackageParameters which may affect how bitstreams are crosswalked * @param bitstream bitstream target of the crosswalk - * @param fileId value of ID attribute in the file element responsible - * for the contents of that bitstream. - * @param callback mdref callback + * @param fileId value of ID attribute in the file element responsible + * for the contents of that bitstream. + * @param callback mdref callback * @throws MetadataValidationException if METS is invalid, e.g. referenced amdSec is missing. - * @throws PackageValidationException if invalid package - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws CrosswalkException if crosswalk error + * @throws PackageValidationException if invalid package + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error */ public void crosswalkBitstream(Context context, PackageParameters params, Bitstream bitstream, String fileId, Mdref callback) throws MetadataValidationException, PackageValidationException, - CrosswalkException, IOException, SQLException, AuthorizeException - { - Element file = getElementByXPath("descendant::mets:file[@ID=\""+fileId+"\"]", false); - if (file == null) - { - throw new MetadataValidationException("Failed in Bitstream crosswalk, Could not find file element with ID=" + fileId); + CrosswalkException, IOException, SQLException, AuthorizeException { + Element file = getElementByXPath("descendant::mets:file[@ID=\"" + fileId + "\"]", false); + if (file == null) { + throw new MetadataValidationException( + "Failed in Bitstream crosswalk, Could not find file element with ID=" + fileId); } // In DSpace METS SIP spec, admin metadata is only "highly // recommended", not "required", so it is OK if there is no ADMID. String amds = file.getAttributeValue("ADMID"); - if (amds == null) - { - log.warn("Got no bitstream ADMID, file@ID="+fileId); + if (amds == null) { + log.warn("Got no bitstream ADMID, file@ID=" + fileId); return; } String amdID[] = amds.split("\\s+"); - for (int i = 0; i < amdID.length; ++i) - { - Element amdSec = getElementByXPath("mets:amdSec[@ID=\""+amdID[i]+"\"]", false); - for (Iterator ti = amdSec.getChildren("techMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, bitstream, (Element)ti.next(), callback, false); + for (int i = 0; i < amdID.length; ++i) { + Element amdSec = getElementByXPath("mets:amdSec[@ID=\"" + amdID[i] + "\"]", false); + for (Iterator ti = amdSec.getChildren("techMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, bitstream, (Element) ti.next(), callback, false); } - for (Iterator ti = amdSec.getChildren("sourceMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, bitstream, (Element)ti.next(), callback, false); + for (Iterator ti = amdSec.getChildren("sourceMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, bitstream, (Element) ti.next(), callback, false); } - for (Iterator ti = amdSec.getChildren("rightsMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, bitstream, (Element)ti.next(), callback, false); + for (Iterator ti = amdSec.getChildren("rightsMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, bitstream, (Element) ti.next(), callback, false); } } } @@ -1385,58 +1254,51 @@ public class METSManifest Bundle bundle, String fileId, Mdref callback) throws MetadataValidationException, PackageValidationException, - CrosswalkException, IOException, SQLException, AuthorizeException - { - Element file = getElementByXPath("descendant::mets:fileGrp[@ADMID=\""+fileId+"\"]", false); - if (file == null) - { - throw new MetadataValidationException("Failed in Bitstream crosswalk, Could not find file element with ID=" + fileId); + CrosswalkException, IOException, SQLException, AuthorizeException { + Element file = getElementByXPath("descendant::mets:fileGrp[@ADMID=\"" + fileId + "\"]", false); + if (file == null) { + throw new MetadataValidationException( + "Failed in Bitstream crosswalk, Could not find file element with ID=" + fileId); } // In DSpace METS SIP spec, admin metadata is only "highly // recommended", not "required", so it is OK if there is no ADMID. String amds = file.getAttributeValue("ADMID"); - if (amds == null) - { - log.warn("Got no bitstream ADMID, file@ID="+fileId); + if (amds == null) { + log.warn("Got no bitstream ADMID, file@ID=" + fileId); return; } String amdID[] = amds.split("\\s+"); - for (int i = 0; i < amdID.length; ++i) - { - Element amdSec = getElementByXPath("mets:amdSec[@ID=\""+amdID[i]+"\"]", false); - for (Iterator ti = amdSec.getChildren("techMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, bundle, (Element)ti.next(), callback, false); + for (int i = 0; i < amdID.length; ++i) { + Element amdSec = getElementByXPath("mets:amdSec[@ID=\"" + amdID[i] + "\"]", false); + for (Iterator ti = amdSec.getChildren("techMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, bundle, (Element) ti.next(), callback, false); } - for (Iterator ti = amdSec.getChildren("sourceMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, bundle, (Element)ti.next(), callback, false); + for (Iterator ti = amdSec.getChildren("sourceMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, bundle, (Element) ti.next(), callback, false); } - for (Iterator ti = amdSec.getChildren("rightsMD", metsNS).iterator(); ti.hasNext();) - { - crosswalkXmd(context, params, bundle, (Element)ti.next(), callback, false); + for (Iterator ti = amdSec.getChildren("rightsMD", metsNS).iterator(); ti.hasNext(); ) { + crosswalkXmd(context, params, bundle, (Element) ti.next(), callback, false); } } } + /** * @return root element of METS document. */ - public Element getMets() - { + public Element getMets() { return mets; } /** * Return entire METS document as an inputStream - * + * * @return entire METS document as a stream */ - public InputStream getMetsAsStream() - { + public InputStream getMetsAsStream() { XMLOutputter outputPretty = new XMLOutputter(Format.getPrettyFormat()); return new ByteArrayInputStream( - outputPretty.outputString(mets).getBytes()); + outputPretty.outputString(mets).getBytes()); } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PDFPackager.java b/dspace-api/src/main/java/org/dspace/content/packager/PDFPackager.java index 7c4087fa6e..0b26cc867b 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PDFPackager.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PDFPackager.java @@ -19,18 +19,30 @@ import java.util.List; import org.apache.commons.lang.ArrayUtils; import org.apache.log4j.Logger; import org.apache.pdfbox.cos.COSDocument; -import org.apache.pdfbox.pdfparser.PDFParser; -import org.apache.pdfbox.io.ScratchFile; import org.apache.pdfbox.io.MemoryUsageSetting; import org.apache.pdfbox.io.RandomAccessBufferedFileInputStream; +import org.apache.pdfbox.io.ScratchFile; +import org.apache.pdfbox.pdfparser.PDFParser; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.WorkspaceItem; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.MetadataValidationException; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +import org.dspace.content.service.BitstreamFormatService; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.BundleService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.LogManager; @@ -56,31 +68,32 @@ import org.dspace.workflow.WorkflowException; * @see PackageDisseminator */ public class PDFPackager - extends SelfNamedPlugin - implements PackageIngester, PackageDisseminator -{ - /** log4j category */ + extends SelfNamedPlugin + implements PackageIngester, PackageDisseminator { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(PDFPackager.class); protected static final String BITSTREAM_FORMAT_NAME = "Adobe PDF"; - protected static String aliases[] = { "PDF", "Adobe PDF", "pdf", "application/pdf" }; + protected static String aliases[] = {"PDF", "Adobe PDF", "pdf", "application/pdf"}; - public static String[] getPluginNames() - { + public static String[] getPluginNames() { return (String[]) ArrayUtils.clone(aliases); } protected final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); protected final BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); - protected final BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + protected final BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - protected final WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); + protected final WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance() + .getWorkspaceItemService(); // utility to grovel bitstream formats.. protected void setFormatToMIMEType(Context context, Bitstream bs, String mimeType) - throws SQLException - { + throws SQLException { List bf = bitstreamFormatService.findNonInternal(context); for (BitstreamFormat aBf : bf) { if (aBf.getMIMEType().equalsIgnoreCase(mimeType)) { @@ -100,48 +113,44 @@ public class PDFPackager * for package metadata. If the PDF file hasn't got the minimal * metadata available, it is rejected. *

    - * @param context DSpace context. + * + * @param context DSpace context. * @param parent collection under which to create new item. - * @param pkgFile The package file to ingest + * @param pkgFile The package file to ingest * @param params package parameters (none recognized) - * @param license may be null, which takes default license. + * @param license may be null, which takes default license. * @return workspace item created by ingest. * @throws PackageValidationException if package invalid - * @throws CrosswalkException if crosswalking fails - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error - * @throws WorkflowException if workflow error + * @throws CrosswalkException if crosswalking fails + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error + * @throws WorkflowException if workflow error */ @Override public DSpaceObject ingest(Context context, DSpaceObject parent, - File pkgFile, PackageParameters params, - String license) - throws PackageValidationException, CrosswalkException, - AuthorizeException, SQLException, IOException, WorkflowException { + File pkgFile, PackageParameters params, + String license) + throws PackageValidationException, CrosswalkException, + AuthorizeException, SQLException, IOException, WorkflowException { boolean success = false; Bundle original = null; Bitstream bs = null; WorkspaceItem wi = null; - try - { + try { // Save the PDF in a bitstream first, since the parser // has to read it as well, and we cannot "rewind" it after that. - wi = workspaceItemService.create(context, (Collection)parent, false); + wi = workspaceItemService.create(context, (Collection) parent, false); Item myitem = wi.getItem(); original = bundleService.create(context, myitem, "ORIGINAL"); InputStream fileStream = null; - try - { + try { fileStream = new FileInputStream(pkgFile); bs = bitstreamService.create(context, original, fileStream); - } - finally - { - if (fileStream != null) - { + } finally { + if (fileStream != null) { fileStream.close(); } } @@ -149,8 +158,7 @@ public class PDFPackager bs.setName(context, "package.pdf"); setFormatToMIMEType(context, bs, "application/pdf"); bitstreamService.update(context, bs); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Created bitstream ID=" + String.valueOf(bs.getID()) + ", parsing..."); } @@ -159,23 +167,18 @@ public class PDFPackager workspaceItemService.update(context, wi); success = true; log.info(LogManager.getHeader(context, "ingest", - "Created new Item, db ID="+String.valueOf(myitem.getID())+ - ", WorkspaceItem ID="+String.valueOf(wi.getID()))); + "Created new Item, db ID=" + String.valueOf(myitem.getID()) + + ", WorkspaceItem ID=" + String.valueOf(wi.getID()))); myitem = PackageUtils.finishCreateItem(context, wi, null, params); return myitem; - } - finally - { + } finally { // get rid of bitstream and item if ingest fails - if (!success) - { - if (original != null && bs != null) - { + if (!success) { + if (original != null && bs != null) { bundleService.removeBitstream(context, original, bs); } - if (wi != null) - { + if (wi != null) { workspaceItemService.deleteAll(context, wi); } } @@ -185,114 +188,108 @@ public class PDFPackager /** * IngestAll() cannot be implemented for a PDF ingester, because there's only one PDF to ingest + * * @throws UnsupportedOperationException if unsupported operation - * @throws PackageException if package error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws CrosswalkException if crosswalk error + * @throws PackageException if package error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error */ @Override public List ingestAll(Context context, DSpaceObject parent, File pkgFile, - PackageParameters params, String license) + PackageParameters params, String license) throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, - SQLException, IOException - { - throw new UnsupportedOperationException("PDF packager does not support the ingestAll() operation at this time."); + CrosswalkException, AuthorizeException, + SQLException, IOException { + throw new UnsupportedOperationException( + "PDF packager does not support the ingestAll() operation at this time."); } /** * Replace is not implemented. + * * @throws UnsupportedOperationException if unsupported operation - * @throws PackageException if package error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws CrosswalkException if crosswalk error + * @throws PackageException if package error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error */ @Override public DSpaceObject replace(Context context, DSpaceObject dso, - File pkgFile, PackageParameters params) + File pkgFile, PackageParameters params) throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, - SQLException, IOException - { + CrosswalkException, AuthorizeException, + SQLException, IOException { throw new UnsupportedOperationException("PDF packager does not support the replace() operation at this time."); } /** * ReplaceAll() cannot be implemented for a PDF ingester, because there's only one PDF to ingest + * * @throws UnsupportedOperationException if unsupported operation - * @throws PackageException if package error - * @throws IOException if IO error - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws CrosswalkException if crosswalk error + * @throws PackageException if package error + * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws CrosswalkException if crosswalk error */ @Override public List replaceAll(Context context, DSpaceObject dso, - File pkgFile, PackageParameters params) + File pkgFile, PackageParameters params) throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, - SQLException, IOException - { - throw new UnsupportedOperationException("PDF packager does not support the replaceAll() operation at this time."); + CrosswalkException, AuthorizeException, + SQLException, IOException { + throw new UnsupportedOperationException( + "PDF packager does not support the replaceAll() operation at this time."); } /** * VERY crude dissemination: just look for the first * bitstream with the PDF package type, and toss it out. * Works on packages importer with this packager, and maybe some others. + * * @param dso DSpaceObject * @throws CrosswalkException if crosswalk error * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error */ @Override public void disseminate(Context context, DSpaceObject dso, PackageParameters params, File pkgFile) throws PackageValidationException, CrosswalkException, - AuthorizeException, SQLException, IOException - { - if (dso.getType() != Constants.ITEM) - { + AuthorizeException, SQLException, IOException { + if (dso.getType() != Constants.ITEM) { throw new PackageValidationException("This disseminator can only handle objects of type ITEM."); } - Item item = (Item)dso; + Item item = (Item) dso; BitstreamFormat pdff = bitstreamFormatService.findByShortDescription(context, - BITSTREAM_FORMAT_NAME); - if (pdff == null) - { + BITSTREAM_FORMAT_NAME); + if (pdff == null) { throw new PackageValidationException("Cannot find BitstreamFormat \"" + BITSTREAM_FORMAT_NAME + "\""); } Bitstream pkgBs = PackageUtils.getBitstreamByFormat(context, item, pdff, Constants.DEFAULT_BUNDLE_NAME); - if (pkgBs == null) - { + if (pkgBs == null) { throw new PackageValidationException("Cannot find Bitstream with format \"" + BITSTREAM_FORMAT_NAME + "\""); } //Make sure our package file exists - if(!pkgFile.exists()) - { + if (!pkgFile.exists()) { PackageUtils.createFile(pkgFile); } //open up output stream to copy bitstream to file FileOutputStream out = null; - try - { + try { //open up output stream to copy bitstream to file out = new FileOutputStream(pkgFile); Utils.copy(bitstreamService.retrieve(context, pkgBs), out); - } - finally - { - if (out != null) - { + } finally { + if (out != null) { out.close(); } } @@ -300,19 +297,20 @@ public class PDFPackager /** * disseminateAll() cannot be implemented for a PDF disseminator, because there's only one PDF to disseminate - * @throws PackageException if package error + * + * @throws PackageException if package error * @throws CrosswalkException if crosswalk error * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error */ @Override public List disseminateAll(Context context, DSpaceObject dso, - PackageParameters params, File pkgFile) + PackageParameters params, File pkgFile) throws PackageException, CrosswalkException, - AuthorizeException, SQLException, IOException - { - throw new UnsupportedOperationException("PDF packager does not support the disseminateAll() operation at this time."); + AuthorizeException, SQLException, IOException { + throw new UnsupportedOperationException( + "PDF packager does not support the disseminateAll() operation at this time."); } @@ -323,36 +321,30 @@ public class PDFPackager * @return the MIME type (content-type header) of the package to be returned */ @Override - public String getMIMEType(PackageParameters params) - { + public String getMIMEType(PackageParameters params) { return "application/pdf"; } private void crosswalkPDF(Context context, Item item, InputStream metadata) - throws CrosswalkException, IOException, SQLException, AuthorizeException - { + throws CrosswalkException, IOException, SQLException, AuthorizeException { COSDocument cos = null; - try - { + try { ScratchFile scratchFile = null; - try - { - long useRAM = Runtime.getRuntime().freeMemory()*80/100; // use up to 80% of JVM free memory - scratchFile = new ScratchFile(MemoryUsageSetting.setupMixed(useRAM)); // then fallback to temp file (unlimited size) - } - catch (IOException ioe) - { + try { + long useRAM = Runtime.getRuntime().freeMemory() * 80 / 100; // use up to 80% of JVM free memory + scratchFile = new ScratchFile( + MemoryUsageSetting.setupMixed(useRAM)); // then fallback to temp file (unlimited size) + } catch (IOException ioe) { log.warn("Error initializing scratch file: " + ioe.getMessage()); } - + PDFParser parser = new PDFParser(new RandomAccessBufferedFileInputStream(metadata), scratchFile); parser.parse(); cos = parser.getDocument(); // sanity check: PDFBox breaks on encrypted documents, so give up. - if(cos.getEncryptionDictionary() != null) - { + if (cos.getEncryptionDictionary() != null) { throw new MetadataValidationException("This packager cannot accept an encrypted PDF document."); } @@ -378,70 +370,59 @@ public class PDFPackager String title = docinfo.getTitle(); // sanity check: item must have a title. - if (title == null) - { - throw new MetadataValidationException("This PDF file is unacceptable, it does not have a value for \"Title\" in its Info dictionary."); + if (title == null) { + throw new MetadataValidationException( + "This PDF file is unacceptable, it does not have a value for \"Title\" in its Info dictionary."); } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("PDF Info dict title=\"" + title + "\""); } itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "title", null, "en", title); String value = docinfo.getAuthor(); - if (value != null) - { + if (value != null) { itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "contributor", "author", null, value); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("PDF Info dict author=\"" + value + "\""); } } value = docinfo.getCreator(); - if (value != null) - { + if (value != null) { itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", - "Application that created the original document: " + value); + "Application that created the original document: " + value); } value = docinfo.getProducer(); - if (value != null) - { + if (value != null) { itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", - "Original document converted to PDF by: " + value); + "Original document converted to PDF by: " + value); } value = docinfo.getSubject(); - if (value != null) - { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "abstract", null, value); + if (value != null) { + itemService + .addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "abstract", null, value); } value = docinfo.getKeywords(); - if (value != null) - { + if (value != null) { itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "subject", "other", null, value); } // Take either CreationDate or ModDate as "date.created", // Too bad there's no place to put "last modified" in the DC. Calendar calValue = docinfo.getCreationDate(); - if (calValue == null) - { + if (calValue == null) { calValue = docinfo.getModificationDate(); } - if (calValue != null) - { + if (calValue != null) { itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "created", null, - (new DCDate(calValue.getTime())).toString()); + (new DCDate(calValue.getTime())).toString()); } itemService.update(context, item); - } - finally - { - if (cos != null) - { + } finally { + if (cos != null) { cos.close(); } } @@ -458,8 +439,7 @@ public class PDFPackager * with this packager */ @Override - public String getParameterHelp() - { + public String getParameterHelp() { return "No additional options available."; } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageDisseminator.java index e15aa06316..c5ebffc9f8 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PackageDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageDisseminator.java @@ -45,8 +45,7 @@ import org.dspace.core.Context; * @version $Revision$ * @see PackageParameters */ -public interface PackageDisseminator -{ +public interface PackageDisseminator { /** * Export the object (Item, Collection, or Community) as a * "package" on the indicated OutputStream. Package is any serialized @@ -61,21 +60,21 @@ public interface PackageDisseminator * Throws an exception of the chosen object is not acceptable or there is * a failure creating the package. * - * @param context DSpace context. + * @param context DSpace context. * @param object DSpace object (item, collection, etc) - * @param params Properties-style list of options specific to this packager + * @param params Properties-style list of options specific to this packager * @param pkgFile File where export package should be written * @throws PackageValidationException if package cannot be created or there is - * a fatal error in creating it. - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error + * a fatal error in creating it. + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error */ void disseminate(Context context, DSpaceObject object, PackageParameters params, File pkgFile) throws PackageException, CrosswalkException, - AuthorizeException, SQLException, IOException; + AuthorizeException, SQLException, IOException; /** * Recursively export one or more DSpace Objects as a series of packages. @@ -99,23 +98,23 @@ public interface PackageDisseminator * or simply forward the call to disseminate if it is unable to * support recursive dissemination. * - * @param context DSpace context. - * @param dso initial DSpace object - * @param params Properties-style list of options specific to this packager + * @param context DSpace context. + * @param dso initial DSpace object + * @param params Properties-style list of options specific to this packager * @param pkgFile File where initial package should be written. All other - * packages will be written to the same directory as this File. + * packages will be written to the same directory as this File. * @return List of all package Files which were successfully disseminated * @throws PackageValidationException if package cannot be created or there is - * a fatal error in creating it. - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error + * a fatal error in creating it. + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error */ List disseminateAll(Context context, DSpaceObject dso, - PackageParameters params, File pkgFile) + PackageParameters params, File pkgFile) throws PackageException, CrosswalkException, - AuthorizeException, SQLException, IOException; + AuthorizeException, SQLException, IOException; /** @@ -129,7 +128,7 @@ public interface PackageDisseminator String getMIMEType(PackageParameters params); - /** + /** * Returns a user help string which should describe the * additional valid command-line options that this packager * implementation will accept when using the -o or diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageException.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageException.java index 0257387b7a..3da64df783 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PackageException.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageException.java @@ -21,58 +21,54 @@ import org.apache.log4j.Logger; * @author Larry Stone * @version $Revision$ */ -public class PackageException extends Exception -{ +public class PackageException extends Exception { /** * Create a new exception with no message. */ - public PackageException() - { + public PackageException() { super(); } /** * Create a new exception with the given message. + * * @param message - message text. */ - public PackageException(String message) - { + public PackageException(String message) { super(message); } /** * Create a new exception wrapping the given underlying cause. + * * @param cause - exception specifying the cause of this failure. */ - public PackageException(Throwable cause) - { + public PackageException(Throwable cause) { super(cause); } /** * Create a new exception wrapping it around another exception. + * * @param message - message text. - * @param cause - exception specifying the cause of this failure. + * @param cause - exception specifying the cause of this failure. */ - public PackageException(String message, Throwable cause) - { + public PackageException(String message, Throwable cause) { super(message, cause); } /** * Write details of this exception to the indicated logger. * Dump a stack trace to the log to aid in debugging. + * * @param log logger */ - public void log(Logger log) - { + public void log(Logger log) { log.error(toString()); Throwable cause = getCause(); - if (cause != null) - { - if (cause.getCause() != null) - { + if (cause != null) { + if (cause.getCause() != null) { cause = cause.getCause(); } StringWriter sw = new StringWriter(); @@ -81,10 +77,9 @@ public class PackageException extends Exception } } - public String toString() - { + public String toString() { String base = getClass().getName() + ": " + getMessage(); return (getCause() == null) ? base : - base + ", Reason: "+getCause().toString(); + base + ", Reason: " + getCause().toString(); } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageIngester.java index 85733fe200..9b1d9f4f49 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PackageIngester.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageIngester.java @@ -43,8 +43,7 @@ import org.dspace.workflow.WorkflowException; * @see PackageParameters * @see AbstractPackageIngester */ -public interface PackageIngester -{ +public interface PackageIngester { /** * Create new DSpaceObject out of the ingested package. The object * is created under the indicated parent. This creates a @@ -59,27 +58,26 @@ public interface PackageIngester * Use ingestAll method to perform a recursive ingest of all * packages which are referenced by an initial package. * - * @param context DSpace context. - * @param parent parent under which to create new object - * (may be null -- in which case ingester must determine parent from package - * or throw an error). - * @param pkgFile The package file to ingest - * @param params Properties-style list of options (interpreted by each packager). - * @param license may be null, which takes default license. + * @param context DSpace context. + * @param parent parent under which to create new object + * (may be null -- in which case ingester must determine parent from package + * or throw an error). + * @param pkgFile The package file to ingest + * @param params Properties-style list of options (interpreted by each packager). + * @param license may be null, which takes default license. * @return DSpaceObject created by ingest. - * * @throws PackageValidationException if package is unacceptable or there is - * a fatal error turning it into a DSpaceObject. - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error - * @throws WorkflowException if workflow error + * a fatal error turning it into a DSpaceObject. + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error + * @throws WorkflowException if workflow error */ DSpaceObject ingest(Context context, DSpaceObject parent, File pkgFile, - PackageParameters params, String license) - throws PackageException, CrosswalkException, - AuthorizeException, SQLException, IOException, WorkflowException; + PackageParameters params, String license) + throws PackageException, CrosswalkException, + AuthorizeException, SQLException, IOException, WorkflowException; /** @@ -104,30 +102,29 @@ public interface PackageIngester * package formats. It is optional and may be given as * null. * - * @param context DSpace context. - * @param parent parent under which to create the initial object - * (may be null -- in which case ingester must determine parent from package - * or throw an error). - * @param pkgFile The initial package file to ingest - * @param params Properties-style list of options (interpreted by each packager). - * @param license may be null, which takes default license. + * @param context DSpace context. + * @param parent parent under which to create the initial object + * (may be null -- in which case ingester must determine parent from package + * or throw an error). + * @param pkgFile The initial package file to ingest + * @param params Properties-style list of options (interpreted by each packager). + * @param license may be null, which takes default license. * @return List of Identifiers of DSpaceObjects created - * - * @throws PackageValidationException if initial package (or any referenced package) - * is unacceptable or there is a fatal error in creating a DSpaceObject + * @throws PackageValidationException if initial package (or any referenced package) + * is unacceptable or there is a fatal error in creating a DSpaceObject * @throws UnsupportedOperationException if this packager does not - * implement ingestAll - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error - * @throws WorkflowException if workflow error + * implement ingestAll + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error + * @throws WorkflowException if workflow error */ List ingestAll(Context context, DSpaceObject parent, File pkgFile, - PackageParameters params, String license) - throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, - SQLException, IOException, WorkflowException; + PackageParameters params, String license) + throws PackageException, UnsupportedOperationException, + CrosswalkException, AuthorizeException, + SQLException, IOException, WorkflowException; /** * Replace an existing DSpace Object with contents of the ingested package. @@ -138,28 +135,27 @@ public interface PackageIngester * Use replaceAll method to perform a recursive replace of * objects referenced by a set of packages. * - * @param context DSpace context. - * @param dso existing DSpace Object to be replaced, may be null - * if object to replace can be determined from package - * @param pkgFile The package file to ingest. - * @param params Properties-style list of options specific to this packager + * @param context DSpace context. + * @param dso existing DSpace Object to be replaced, may be null + * if object to replace can be determined from package + * @param pkgFile The package file to ingest. + * @param params Properties-style list of options specific to this packager * @return DSpaceObject with contents replaced - * - * @throws PackageValidationException if package is unacceptable or there is - * a fatal error turning it into an Item. + * @throws PackageValidationException if package is unacceptable or there is + * a fatal error turning it into an Item. * @throws UnsupportedOperationException if this packager does not - * implement replace. - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error - * @throws WorkflowException if workflow error + * implement replace. + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error + * @throws WorkflowException if workflow error */ DSpaceObject replace(Context context, DSpaceObject dso, - File pkgFile, PackageParameters params) - throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, - SQLException, IOException, WorkflowException; + File pkgFile, PackageParameters params) + throws PackageException, UnsupportedOperationException, + CrosswalkException, AuthorizeException, + SQLException, IOException, WorkflowException; /** * Recursively replace one or more DSpace Objects out of the contents @@ -183,28 +179,27 @@ public interface PackageIngester * may choose to forward the call to replace if it is unable to * support recursive replacement. * - * @param context DSpace context. - * @param dso initial existing DSpace Object to be replaced, may be null - * if object to replace can be determined from package - * @param pkgFile The package file to ingest. - * @param params Properties-style list of options specific to this packager + * @param context DSpace context. + * @param dso initial existing DSpace Object to be replaced, may be null + * if object to replace can be determined from package + * @param pkgFile The package file to ingest. + * @param params Properties-style list of options specific to this packager * @return List of Identifiers of DSpaceObjects replaced - * - * @throws PackageValidationException if initial package (or any referenced package) - * is unacceptable or there is a fatal error in creating a DSpaceObject + * @throws PackageValidationException if initial package (or any referenced package) + * is unacceptable or there is a fatal error in creating a DSpaceObject * @throws UnsupportedOperationException if this packager does not - * implement replaceAll - * @throws CrosswalkException if crosswalk error - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error - * @throws WorkflowException if workflow error + * implement replaceAll + * @throws CrosswalkException if crosswalk error + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws IOException if IO error + * @throws WorkflowException if workflow error */ List replaceAll(Context context, DSpaceObject dso, - File pkgFile, PackageParameters params) - throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, - SQLException, IOException, WorkflowException; + File pkgFile, PackageParameters params) + throws PackageException, UnsupportedOperationException, + CrosswalkException, AuthorizeException, + SQLException, IOException, WorkflowException; /** diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageParameters.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageParameters.java index 462ad32dc7..1bd68bea26 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PackageParameters.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageParameters.java @@ -9,7 +9,6 @@ package org.dspace.content.packager; import java.util.Enumeration; import java.util.Properties; - import javax.servlet.ServletRequest; /** @@ -24,21 +23,18 @@ import javax.servlet.ServletRequest; * @version $Revision$ */ -public class PackageParameters extends Properties -{ +public class PackageParameters extends Properties { // Use non-printing FS (file separator) as arg-sep token, like Perl $; protected static final String SEPARATOR = "\034"; // Regular expression to match the separator token: protected static final String SEPARATOR_REGEX = "\\034"; - public PackageParameters() - { + public PackageParameters() { super(); } - public PackageParameters(Properties defaults) - { + public PackageParameters(Properties defaults) { super(defaults); } @@ -49,30 +45,21 @@ public class PackageParameters extends Properties * @param request - the request from which to take the values * @return new parameters object. */ - public static PackageParameters create(ServletRequest request) - { + public static PackageParameters create(ServletRequest request) { PackageParameters result = new PackageParameters(); Enumeration pe = request.getParameterNames(); - while (pe.hasMoreElements()) - { - String name = (String)pe.nextElement(); + while (pe.hasMoreElements()) { + String name = (String) pe.nextElement(); String v[] = request.getParameterValues(name); - if (v.length == 0) - { + if (v.length == 0) { result.setProperty(name, ""); - } - else if (v.length == 1) - { + } else if (v.length == 1) { result.setProperty(name, v[0]); - } - else - { + } else { StringBuffer sb = new StringBuffer(); - for (int i = 0; i < v.length; ++i) - { - if (i > 0) - { + for (int i = 0; i < v.length; ++i) { + if (i > 0) { sb.append(SEPARATOR); } sb.append(v[i]); @@ -88,20 +75,16 @@ public class PackageParameters extends Properties * Adds a value to a property; if property already has value(s), * this is tacked onto the end, otherwise it acts like setProperty(). * - * @param key - the key to be placed into this property list. + * @param key - the key to be placed into this property list. * @param value - the new value to add, corresponding to this key. * @return the previous value of the specified key in this property list, or - * null if it did not have one. + * null if it did not have one. */ - public Object addProperty(String key, String value) - { + public Object addProperty(String key, String value) { String oldVal = getProperty(key); - if (oldVal == null) - { + if (oldVal == null) { setProperty(key, value); - } - else - { + } else { setProperty(key, oldVal + SEPARATOR + value); } return oldVal; @@ -113,39 +96,32 @@ public class PackageParameters extends Properties * @param key - the key to look for in this property list. * @return all values in an array, or null if this property is unset. */ - public String[] getProperties(String key) - { + public String[] getProperties(String key) { String val = getProperty(key); - if (val == null) - { + if (val == null) { return null; - } - else - { + } else { return val.split(SEPARATOR_REGEX); } } /** * Returns boolean form of property with selectable default - * @param key the key to look for in this property list. + * + * @param key the key to look for in this property list. * @param defaultAnswer default to return if there is no such property * @return the boolean derived from the value of property, or default - * if it was not specified. + * if it was not specified. */ - public boolean getBooleanProperty(String key, boolean defaultAnswer) - { + public boolean getBooleanProperty(String key, boolean defaultAnswer) { String stringValue = getProperty(key); - if (stringValue == null) - { + if (stringValue == null) { return defaultAnswer; - } - else - { + } else { return stringValue.equalsIgnoreCase("true") || - stringValue.equalsIgnoreCase("on") || - stringValue.equalsIgnoreCase("yes"); + stringValue.equalsIgnoreCase("on") || + stringValue.equalsIgnoreCase("yes"); } } @@ -159,8 +135,7 @@ public class PackageParameters extends Properties * * @return boolean result */ - public boolean workflowEnabled() - { + public boolean workflowEnabled() { return getBooleanProperty("useWorkflow", true); } @@ -169,8 +144,7 @@ public class PackageParameters extends Properties * * @param value boolean value (true = workflow enabled, false = workflow disabled) */ - public void setWorkflowEnabled(boolean value) - { + public void setWorkflowEnabled(boolean value) { addProperty("useWorkflow", String.valueOf(value)); } @@ -186,18 +160,17 @@ public class PackageParameters extends Properties * object which already exists. Use 'keep-existing' or 'replace' mode to * either skip-over (keep) or replace existing objects. *

    - * Defaults to 'false' if previously unset. NOTE: 'replace' mode and + * Defaults to 'false' if previously unset. NOTE: 'replace' mode and * 'keep-existing' mode are special types of "restores". So, when either * replaceModeEnabled() or keepExistingModeEnabled() is true, this method * should also return true. * * @return boolean result */ - public boolean restoreModeEnabled() - { + public boolean restoreModeEnabled() { return (getBooleanProperty("restoreMode", false) || - replaceModeEnabled() || - keepExistingModeEnabled()); + replaceModeEnabled() || + keepExistingModeEnabled()); } /*** @@ -212,8 +185,7 @@ public class PackageParameters extends Properties * * @param value boolean value (true = restore enabled, false = restore disabled) */ - public void setRestoreModeEnabled(boolean value) - { + public void setRestoreModeEnabled(boolean value) { addProperty("restoreMode", String.valueOf(value)); } @@ -229,8 +201,7 @@ public class PackageParameters extends Properties * * @return boolean result */ - public boolean replaceModeEnabled() - { + public boolean replaceModeEnabled() { return getBooleanProperty("replaceMode", false); } @@ -243,8 +214,7 @@ public class PackageParameters extends Properties * * @param value boolean value (true = replace enabled, false = replace disabled) */ - public void setReplaceModeEnabled(boolean value) - { + public void setReplaceModeEnabled(boolean value) { addProperty("replaceMode", String.valueOf(value)); } @@ -260,8 +230,7 @@ public class PackageParameters extends Properties * * @return boolean result */ - public boolean keepExistingModeEnabled() - { + public boolean keepExistingModeEnabled() { return getBooleanProperty("keepExistingMode", false); } @@ -274,8 +243,7 @@ public class PackageParameters extends Properties * * @param value boolean value (true = replace enabled, false = replace disabled) */ - public void setKeepExistingModeEnabled(boolean value) - { + public void setKeepExistingModeEnabled(boolean value) { addProperty("keepExistingMode", String.valueOf(value)); } @@ -287,8 +255,7 @@ public class PackageParameters extends Properties * * @return boolean result */ - public boolean useCollectionTemplate() - { + public boolean useCollectionTemplate() { return getBooleanProperty("useCollectionTemplate", false); } @@ -300,8 +267,7 @@ public class PackageParameters extends Properties * * @param value boolean value (true = template enabled, false = template disabled) */ - public void setUseCollectionTemplate(boolean value) - { + public void setUseCollectionTemplate(boolean value) { addProperty("useCollectionTemplate", String.valueOf(value)); } @@ -318,8 +284,7 @@ public class PackageParameters extends Properties * * @return boolean result */ - public boolean recursiveModeEnabled() - { + public boolean recursiveModeEnabled() { return getBooleanProperty("recursiveMode", false); } @@ -332,8 +297,7 @@ public class PackageParameters extends Properties * * @param value boolean value (true = recursion enabled, false = recursion disabled) */ - public void setRecursiveModeEnabled(boolean value) - { + public void setRecursiveModeEnabled(boolean value) { addProperty("recursiveMode", String.valueOf(value)); } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java index 15d0c64174..045f7963d0 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java @@ -13,19 +13,37 @@ import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; -import java.util.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.log4j.Logger; - import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +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.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; +import org.dspace.content.WorkspaceItem; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +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.DSpaceObjectService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.SiteService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; @@ -42,17 +60,17 @@ import org.dspace.workflow.factory.WorkflowServiceFactory; * @version $Revision$ */ -public class PackageUtils -{ +public class PackageUtils { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(PackageUtils.class); // Map of metadata elements for Communities and Collections // Format is alternating key/value in a straight array; use this // to initialize hash tables that convert to and from. - protected static final String ccMetadataMap[] = - { + protected static final String ccMetadataMap[] = { // getMetadata() -> DC element.term "name", "dc.title", "introductory_text", "dc.description", @@ -65,43 +83,51 @@ public class PackageUtils // HashMaps to convert Community/Collection metadata to/from Dublin Core // (useful when crosswalking Communities/Collections) - protected static final Map ccMetadataToDC = new HashMap(); - protected static final Map ccDCToMetadata = new HashMap(); + protected static final Map ccMetadataToDC = new HashMap(); + protected static final Map ccDCToMetadata = new HashMap(); - protected static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - protected static final BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + protected static final BitstreamService bitstreamService = ContentServiceFactory.getInstance() + .getBitstreamService(); + protected static final BitstreamFormatService bitstreamFormatService = + ContentServiceFactory.getInstance().getBitstreamFormatService(); protected static final BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); - protected static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); - protected static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); - protected static final InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService(); + protected static final CommunityService communityService = ContentServiceFactory.getInstance() + .getCommunityService(); + protected static final CollectionService collectionService = ContentServiceFactory.getInstance() + .getCollectionService(); + protected static final InstallItemService installItemService = ContentServiceFactory.getInstance() + .getInstallItemService(); protected static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - protected static final WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); + protected static final WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance() + .getWorkspaceItemService(); protected static final SiteService siteService = ContentServiceFactory.getInstance().getSiteService(); protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - static - { - for (int i = 0; i < ccMetadataMap.length; i += 2) - { - ccMetadataToDC.put(ccMetadataMap[i], ccMetadataMap[i+1]); - ccDCToMetadata.put(ccMetadataMap[i+1], ccMetadataMap[i]); + static { + for (int i = 0; i < ccMetadataMap.length; i += 2) { + ccMetadataToDC.put(ccMetadataMap[i], ccMetadataMap[i + 1]); + ccDCToMetadata.put(ccMetadataMap[i + 1], ccMetadataMap[i]); } } + /** + * Default constructor + */ + private PackageUtils() { } + /** * Translate a Dublin Core metadata field into a Container's (Community or Collection) * database column for that metadata entry. *

    * e.g. "dc.title" would translate to the "name" database column *

    - * This method is of use when crosswalking Community or Collection metadata for ingest, + * This method is of use when crosswalking Community or Collection metadata for ingest, * as most ingest Crosswalks tend to deal with translating to DC-based metadata. - * + * * @param dcField The dublin core metadata field * @return The Community or Collection DB column where this metadata info is stored. */ - public static String dcToContainerMetadata(String dcField) - { + public static String dcToContainerMetadata(String dcField) { return ccDCToMetadata.get(dcField); } @@ -114,12 +140,10 @@ public class PackageUtils * This method is of use when crosswalking Community or Collection metadata for dissemination, * as most dissemination Crosswalks tend to deal with translating from DC-based metadata. * - * * @param databaseField The Community or Collection DB column * @return The Dublin Core metadata field that this metadata translates to. */ - public static String containerMetadataToDC(String databaseField) - { + public static String containerMetadataToDC(String databaseField) { return ccMetadataToDC.get(databaseField); } @@ -133,11 +157,9 @@ public class PackageUtils * @throws PackageValidationException if validation error */ public static void checkItemMetadata(Item item) - throws PackageValidationException - { + throws PackageValidationException { List t = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); - if (t == null || t.size() == 0) - { + if (t == null || t.size() == 0) { throw new PackageValidationException("Item cannot be created without the required \"title\" DC metadata."); } } @@ -148,20 +170,18 @@ public class PackageUtils * a default one if none was given; creates new bitstream in the * "LICENSE" bundle and gives it the special license bitstream format. * - * @param context - dspace context - * @param license - license string to add, may be null to invoke default. - * @param item - the item. + * @param context - dspace context + * @param license - license string to add, may be null to invoke default. + * @param item - the item. * @param collection - get the default license from here. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public static void addDepositLicense(Context context, String license, - Item item, Collection collection) - throws SQLException, IOException, AuthorizeException - { - if (license == null) - { + Item item, Collection collection) + throws SQLException, IOException, AuthorizeException { + if (license == null) { license = collection.getLicenseCollection(); } InputStream lis = new ByteArrayInputStream(license.getBytes()); @@ -169,12 +189,9 @@ public class PackageUtils Bundle lb; //If LICENSE bundle is missing, create it List bundles = itemService.getBundles(item, Constants.LICENSE_BUNDLE_NAME); - if(CollectionUtils.isEmpty(bundles)) - { + if (CollectionUtils.isEmpty(bundles)) { lb = bundleService.create(context, item, Constants.LICENSE_BUNDLE_NAME); - } - else - { + } else { lb = bundles.get(0); } @@ -182,8 +199,7 @@ public class PackageUtils Bitstream lbs = bitstreamService.create(context, lb, lis); lis.close(); BitstreamFormat bf = bitstreamFormatService.findByShortDescription(context, "License"); - if (bf == null) - { + if (bf == null) { bf = bitstreamFormatService.guessFormat(context, lbs); } lbs.setFormat(context, bf); @@ -201,38 +217,31 @@ public class PackageUtils * @throws SQLException if database error */ public static Bitstream getBitstreamByName(Item item, String name) - throws SQLException - { + throws SQLException { return getBitstreamByName(item, name, null); } /** * Find bitstream by its Name, looking in specific named bundle. * - * @param item - dspace item whose bundles to search. + * @param item - dspace item whose bundles to search. * @param bsName - name of bitstream to match. * @param bnName - bundle name to match, or null for all. * @return the format found or null if none found. * @throws SQLException if database error */ public static Bitstream getBitstreamByName(Item item, String bsName, String bnName) - throws SQLException - { + throws SQLException { List bundles; - if (bnName == null) - { + if (bnName == null) { bundles = item.getBundles(); - } - else - { + } else { bundles = itemService.getBundles(item, bnName); } - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { List bitstreams = bundle.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { if (bsName.equals(bitstream.getName())) { return bitstream; } @@ -246,24 +255,20 @@ public class PackageUtils * Used to look for particularly-typed Package Manifest bitstreams. * * @param context context - * @param item - dspace item whose bundles to search. - * @param bsf - BitstreamFormat object to match. - * @param bnName - bundle name to match, or null for all. + * @param item - dspace item whose bundles to search. + * @param bsf - BitstreamFormat object to match. + * @param bnName - bundle name to match, or null for all. * @return the format found or null if none found. * @throws SQLException if database error */ public static Bitstream getBitstreamByFormat(Context context, Item item, - BitstreamFormat bsf, String bnName) - throws SQLException - { + BitstreamFormat bsf, String bnName) + throws SQLException { int fid = bsf.getID(); List bundles; - if (bnName == null) - { + if (bnName == null) { bundles = item.getBundles(); - } - else - { + } else { bundles = itemService.getBundles(item, bnName); } for (Bundle bundle : bundles) { @@ -287,11 +292,10 @@ public class PackageUtils * @param bn -- the bundle * @return true if this bundle name indicates it is a meta-info bundle. */ - public static boolean isMetaInfoBundle(Bundle bn) - { + public static boolean isMetaInfoBundle(Bundle bn) { return (bn.getName().equals(Constants.LICENSE_BUNDLE_NAME) || - bn.getName().equals(CreativeCommonsService.CC_BUNDLE_NAME) || - bn.getName().equals(Constants.METADATA_BUNDLE_NAME)); + bn.getName().equals(CreativeCommonsService.CC_BUNDLE_NAME) || + bn.getName().equals(Constants.METADATA_BUNDLE_NAME)); } /** @@ -306,10 +310,8 @@ public class PackageUtils * Bitstream bs = bundle.createBitstream(new PackageUtils.UnclosableInputStream(zipInput)); * */ - public static class UnclosableInputStream extends FilterInputStream - { - public UnclosableInputStream(InputStream in) - { + public static class UnclosableInputStream extends FilterInputStream { + public UnclosableInputStream(InputStream in) { super(in); } @@ -317,8 +319,7 @@ public class PackageUtils * Do nothing, to prevent wrapped stream from being closed prematurely. */ @Override - public void close() - { + public void close() { } } @@ -329,22 +330,22 @@ public class PackageUtils * format for the manifest (and/or metadata) file. *

    * NOTE: When creating a new format, do NOT set any extensions, since - * we don't want any file with the same extension, which may be something - * generic like ".xml", to accidentally get set to this format. - * @param context - the context. + * we don't want any file with the same extension, which may be something + * generic like ".xml", to accidentally get set to this format. + * + * @param context - the context. * @param shortDesc - short descriptive name, used to locate existing format. - * @param MIMEType - MIME content-type - * @param desc - long description + * @param MIMEType - MIME content-type + * @param desc - long description * @return BitstreamFormat object that was found or created. Never null. - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public static BitstreamFormat findOrCreateBitstreamFormat(Context context, - String shortDesc, String MIMEType, String desc) - throws SQLException, AuthorizeException - { + public static BitstreamFormat findOrCreateBitstreamFormat(Context context, + String shortDesc, String MIMEType, String desc) + throws SQLException, AuthorizeException { return findOrCreateBitstreamFormat(context, shortDesc, MIMEType, desc, BitstreamFormat.KNOWN, false); - } + } /** * Find or create a bitstream format to match the given short @@ -353,27 +354,27 @@ public class PackageUtils * format for the manifest (and/or metadata) file. *

    * NOTE: When creating a new format, do NOT set any extensions, since - * we don't want any file with the same extension, which may be something - * generic like ".xml", to accidentally get set to this format. - * @param context - the context. - * @param shortDesc - short descriptive name, used to locate existing format. - * @param MIMEType - mime content-type - * @param desc - long description + * we don't want any file with the same extension, which may be something + * generic like ".xml", to accidentally get set to this format. + * + * @param context - the context. + * @param shortDesc - short descriptive name, used to locate existing format. + * @param MIMEType - mime content-type + * @param desc - long description * @param supportLevel support level - * @param internal value for the 'internal' flag of a new format if created. + * @param internal value for the 'internal' flag of a new format if created. * @return BitstreamFormat object that was found or created. Never null. - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public static BitstreamFormat findOrCreateBitstreamFormat(Context context, - String shortDesc, String MIMEType, String desc, int supportLevel, boolean internal) - throws SQLException, AuthorizeException - { + public static BitstreamFormat findOrCreateBitstreamFormat(Context context, + String shortDesc, String MIMEType, String desc, + int supportLevel, boolean internal) + throws SQLException, AuthorizeException { BitstreamFormat bsf = bitstreamFormatService.findByShortDescription(context, - shortDesc); + shortDesc); // not found, try to create one - if (bsf == null) - { + if (bsf == null) { bsf = bitstreamFormatService.create(context); bsf.setShortDescription(context, shortDesc); bsf.setMIMEType(MIMEType); @@ -388,35 +389,29 @@ public class PackageUtils /** * Utility to find the license bitstream from an item * - * @param context - * DSpace context - * @param item - * the item + * @param context DSpace context + * @param item the item * @return the license bitstream or null - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if the license bitstream can't be read + * @throws IOException if the license bitstream can't be read */ public static Bitstream findDepositLicense(Context context, Item item) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { // get license format ID int licenseFormatId = -1; BitstreamFormat bf = bitstreamFormatService.findByShortDescription(context, - "License"); - if (bf != null) - { + "License"); + if (bf != null) { licenseFormatId = bf.getID(); } List bundles = itemService.getBundles(item, Constants.LICENSE_BUNDLE_NAME); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { // Assume license will be in its own bundle List bitstreams = bundle.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { // The License should have a file format of "License" if (bitstream.getFormat(context).getID() == licenseFormatId) { //found a bitstream with format "License" -- return it @@ -448,34 +443,30 @@ public class PackageUtils * to create the object) * * @param context DSpace Context - * @param parent Parent Object - * @param type Type of new Object - * @param handle Handle of new Object (may be null) - * @param params Properties-style list of options (interpreted by each packager). + * @param parent Parent Object + * @param type Type of new Object + * @param handle Handle of new Object (may be null) + * @param params Properties-style list of options (interpreted by each packager). * @return newly created DSpace Object (or null) * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error */ - public static DSpaceObject createDSpaceObject(Context context, DSpaceObject parent, int type, String handle, PackageParameters params) - throws AuthorizeException, SQLException, IOException - { + public static DSpaceObject createDSpaceObject(Context context, DSpaceObject parent, int type, String handle, + PackageParameters params) + throws AuthorizeException, SQLException, IOException { DSpaceObject dso = null; - switch (type) - { + switch (type) { case Constants.COLLECTION: dso = collectionService.create(context, (Community) parent, handle); return dso; case Constants.COMMUNITY: // top-level community? - if (parent == null || parent.getType() == Constants.SITE) - { + if (parent == null || parent.getType() == Constants.SITE) { dso = communityService.create(null, context, handle); - } - else - { + } else { dso = communityService.createSubcommunity(context, ((Community) parent), handle); } return dso; @@ -483,18 +474,19 @@ public class PackageUtils case Constants.ITEM: //Initialize a WorkspaceItem //(Note: Handle is not set until item is finished) - WorkspaceItem wsi = workspaceItemService.create(context, (Collection)parent, params.useCollectionTemplate()); + WorkspaceItem wsi = workspaceItemService + .create(context, (Collection) parent, params.useCollectionTemplate()); // Please note that we are returning an Item which is *NOT* yet in the Archive, // and doesn't yet have a handle assigned. // This Item will remain "incomplete" until 'PackageUtils.finishCreateItem()' is called return wsi.getItem(); - + case Constants.SITE: return siteService.findSite(context); + default: + return null; } - - return null; } /** @@ -505,46 +497,42 @@ public class PackageUtils * or archiving it (based on params passed in) * * @param context DSpace Context - * @param wsi Workspace Item that requires finishing - * @param handle Handle to assign to item (may be null) - * @param params Properties-style list of options (interpreted by each packager). + * @param wsi Workspace Item that requires finishing + * @param handle Handle to assign to item (may be null) + * @param params Properties-style list of options (interpreted by each packager). * @return finished Item - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws WorkflowException if workflow error + * @throws WorkflowException if workflow error */ public static Item finishCreateItem(Context context, WorkspaceItem wsi, String handle, PackageParameters params) - throws IOException, SQLException, AuthorizeException, WorkflowException { + throws IOException, SQLException, AuthorizeException, WorkflowException { // if we are restoring/replacing existing object using the package - if (params.restoreModeEnabled()) - { + if (params.restoreModeEnabled()) { // Restore & install item immediately //(i.e. skip over any Collection workflows, as we are essentially restoring item from backup) installItemService.restoreItem(context, wsi, handle); //return newly restored item return wsi.getItem(); - } - // if we are treating package as a SIP, and we are told to respect workflows - else if (params.workflowEnabled()) - { + } else if (params.workflowEnabled()) { + // if we are treating package as a SIP, and we are told to respect workflows + WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService(); // Start an item workflow // (NOTICE: The specified handle is ignored, as Workflows *always* end in a new handle being assigned) return workflowService.startWithoutNotify(context, wsi).getItem(); - } + } else { + // default: skip workflow, but otherwise normal submission (i.e. package treated like a SIP) - // default: skip workflow, but otherwise normal submission (i.e. package treated like a SIP) - else - { // Install item immediately with the specified handle installItemService.installItem(context, wsi, handle); // return newly installed item return wsi.getItem(); } - }//end finishCreateItem + } //end finishCreateItem /** @@ -553,17 +541,16 @@ public class PackageUtils * This method is necessary as there is no generic 'update()' on a DSpaceObject * * @param context context - * @param dso DSpaceObject to update - * @throws SQLException if database error + * @param dso DSpaceObject to update + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public static void updateDSpaceObject(Context context, DSpaceObject dso) - throws AuthorizeException, SQLException, IOException - { - if (dso != null) - { - DSpaceObjectService dsoService = ContentServiceFactory.getInstance().getDSpaceObjectService(dso); + throws AuthorizeException, SQLException, IOException { + if (dso != null) { + DSpaceObjectService dsoService = ContentServiceFactory.getInstance() + .getDSpaceObjectService(dso); dsoService.update(context, dso); } } @@ -575,14 +562,12 @@ public class PackageUtils * @param filename Full filename * @return file extension */ - public static String getFileExtension(String filename) - { + public static String getFileExtension(String filename) { // Extract the file extension off of a filename String extension = filename; int lastDot = filename.lastIndexOf('.'); - if (lastDot != -1) - { + if (lastDot != -1) { extension = filename.substring(lastDot + 1); } @@ -597,20 +582,17 @@ public class PackageUtils * Format: [dspace-obj-type]@[handle-with-dashes].[fileExtension] * OR [dspace-obj-type]@internal-id-[dspace-ID].[fileExtension] * - * @param dso DSpace Object to create file name for + * @param dso DSpace Object to create file name for * @param fileExtension file Extension of output file. * @return filename of a DIP representing the DSpace Object */ - public static String getPackageName(DSpaceObject dso, String fileExtension) - { + public static String getPackageName(DSpaceObject dso, String fileExtension) { String handle = dso.getHandle(); // if Handle is empty, use internal ID for name - if(handle==null || handle.isEmpty()) - { + if (handle == null || handle.isEmpty()) { handle = "internal-id-" + dso.getID(); - } - else // if Handle exists, replace '/' with '-' to meet normal file naming conventions - { + } else { + // if Handle exists, replace '/' with '-' to meet normal file naming conventions handle = handle.replace("/", "-"); } @@ -619,8 +601,7 @@ public class PackageUtils String type = Constants.typeText[typeID]; //check if passed in file extension already starts with "." - if(!fileExtension.startsWith(".")) - { + if (!fileExtension.startsWith(".")) { fileExtension = "." + fileExtension; } @@ -633,25 +614,22 @@ public class PackageUtils /** * Creates the specified file (along with all parent directories) if it doesn't already * exist. If the file already exists, nothing happens. - * + * * @param file file * @return boolean true if succeeded, false otherwise * @throws IOException if IO error */ public static boolean createFile(File file) - throws IOException - { + throws IOException { boolean success = false; //Check if file exists - if(!file.exists()) - { + if (!file.exists()) { //file doesn't exist yet, does its parent directory exist? File parentFile = file.getCanonicalFile().getParentFile(); //create the parent directory structure - if ((null != parentFile) && !parentFile.exists() && !parentFile.mkdirs()) - { + if ((null != parentFile) && !parentFile.exists() && !parentFile.mkdirs()) { log.error("Unable to create parent directory"); } //create actual file @@ -669,17 +647,15 @@ public class PackageUtils * This method is useful for replace functionality. * * @param context context - * @param dso The object to remove all bitstreams from - * @throws IOException if IO error - * @throws SQLException if database error + * @param dso The object to remove all bitstreams from + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public static void removeAllBitstreams(Context context, DSpaceObject dso) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { //If we are dealing with an Item - if(dso.getType()==Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { Item item = (Item) dso; // Get a reference to all Bundles in Item (which contain the bitstreams) Iterator bunds = item.getBundles().iterator(); @@ -690,15 +666,11 @@ public class PackageUtils bunds.remove(); itemService.removeBundle(context, item, bundle); } - } - else if (dso.getType()==Constants.COLLECTION) - { + } else if (dso.getType() == Constants.COLLECTION) { Collection collection = (Collection) dso; //clear out the logo for this collection collectionService.setLogo(context, collection, null); - } - else if (dso.getType()==Constants.COMMUNITY) - { + } else if (dso.getType() == Constants.COMMUNITY) { Community community = (Community) dso; //clear out the logo for this community communityService.setLogo(context, community, null); @@ -712,56 +684,42 @@ public class PackageUtils * This method is useful for replace functionality. * * @param context context - * @param dso The object to remove all metadata from - * @throws IOException if IO error - * @throws SQLException if database error + * @param dso The object to remove all metadata from + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public static void clearAllMetadata(Context context, DSpaceObject dso) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { //If we are dealing with an Item - if(dso.getType()==Constants.ITEM) - { + if (dso.getType() == Constants.ITEM) { Item item = (Item) dso; //clear all metadata entries itemService.clearMetadata(context, item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - } - //Else if collection, clear its database table values - else if (dso.getType()==Constants.COLLECTION) - { + } else if (dso.getType() == Constants.COLLECTION) { + //Else if collection, clear its database table values Collection collection = (Collection) dso; // Use the MetadataToDC map (defined privately in this class) // to clear out all the Collection database fields. - for(String dbField : ccMetadataToDC.keySet()) - { - try - { + for (String dbField : ccMetadataToDC.keySet()) { + try { collectionService.setMetadata(context, collection, dbField, null); - } - catch(IllegalArgumentException ie) - { + } catch (IllegalArgumentException ie) { // ignore the error -- just means the field doesn't exist in DB // Communities & Collections don't include the exact same metadata fields } } - } - //Else if community, clear its database table values - else if (dso.getType()==Constants.COMMUNITY) - { + } else if (dso.getType() == Constants.COMMUNITY) { + //Else if community, clear its database table values Community community = (Community) dso; // Use the MetadataToDC map (defined privately in this class) // to clear out all the Community database fields. - for(String dbField : ccMetadataToDC.keySet()) - { - try - { + for (String dbField : ccMetadataToDC.keySet()) { + try { communityService.setMetadata(context, community, dbField, null); - } - catch(IllegalArgumentException ie) - { + } catch (IllegalArgumentException ie) { // ignore the error -- just means the field doesn't exist in DB // Communities & Collections don't include the exact same metadata fields } @@ -770,7 +728,8 @@ public class PackageUtils } - /** Lookaside list for translations we've already done, so we don't generate + /** + * Lookaside list for translations we've already done, so we don't generate * multiple names for the same group */ protected static final Map orphanGroups = new HashMap(); @@ -793,7 +752,7 @@ public class PackageUtils *

    * This format replaces the internal ID with an external Handle identifier * (which is expected to be more meaningful even when content is exported - * from DSpace). + * from DSpace). *

    * This method prepares group names for export by replacing any found * internal IDs with the appropriate external Handle identifier. If @@ -809,19 +768,17 @@ public class PackageUtils * Also see the translateGroupNameForImport() method which does the opposite * of this method. * - * @param context current DSpace Context + * @param context current DSpace Context * @param groupName Group's name * @return the group name, with any internal IDs translated to Handles * @throws PackageException if package error */ public static String translateGroupNameForExport(Context context, String groupName) - throws PackageException - { + throws PackageException { Pattern defaultGroupNamePattern = Pattern.compile("^([^_]+)_([^_]+)_(.+)$"); // Check if this looks like a default Group name Matcher matcher = defaultGroupNamePattern.matcher(groupName); - if(!matcher.matches()) - { + if (!matcher.matches()) { //if this is not a valid default group name, just return group name as-is (no crosswalking necessary) return groupName; } @@ -831,30 +788,28 @@ public class PackageUtils String groupType = matcher.group(3); int objType = Constants.getTypeID(objTypeText); - if (objID == null || objType == -1) + if (objID == null || objType == -1) { return groupName; + } - try - { + try { //We'll translate this internal ID into a Handle //First, get the object via the Internal ID - DSpaceObject dso = ContentServiceFactory.getInstance().getDSpaceLegacyObjectService(objType).findByIdOrLegacyId(context, objID); - ; + DSpaceObject dso = ContentServiceFactory.getInstance().getDSpaceLegacyObjectService(objType) + .findByIdOrLegacyId(context, objID); - if(dso==null) - { + if (dso == null) { // No such object. Change the name to something harmless, but predictable. // NOTE: this name *must* be predictable. If we generate the same AIP // twice in a row, we must end up with the same group name each time. String newName; - if (orphanGroups.containsKey(groupName)) - newName = orphanGroups.get(groupName); - else - { - newName= "ORPHANED_" + objType + "_GROUP_" - + objID + "_" + groupType; + if (orphanGroups.containsKey(groupName)) { + newName = orphanGroups.get(groupName); + } else { + newName = "ORPHANED_" + objType + "_GROUP_" + + objID + "_" + groupType; orphanGroups.put(groupName, newName); // A given group should only be translated once, since the // new name contains unique random elements which would be @@ -865,9 +820,9 @@ public class PackageUtils // cleaned up when the associated DSpace Object was removed. // So, we don't want to throw an error and stop all other processing. log.warn("DSpace Object (ID='" + objID - + "', type ='" + objType - + "') no longer exists -- translating " + groupName - + " to " + newName + "."); + + "', type ='" + objType + + "') no longer exists -- translating " + groupName + + " to " + newName + "."); return newName; } @@ -875,10 +830,9 @@ public class PackageUtils //Create an updated group name, using the Handle to replace the InternalID // Format: _hdl:_ return objTypeText + "_" + "hdl:" + dso.getHandle() + "_" + groupType; - } - catch (SQLException sqle) - { - throw new PackageException("Database error while attempting to translate group name ('" + groupName + "') for export.", sqle); + } catch (SQLException sqle) { + throw new PackageException( + "Database error while attempting to translate group name ('" + groupName + "') for export.", sqle); } } @@ -904,17 +858,16 @@ public class PackageUtils * Also see the translateGroupNameForExport() method which does the opposite * of this method. * - * @param context current DSpace Context + * @param context current DSpace Context * @param groupName Group's name * @return the group name, with any Handles translated to internal IDs * @throws PackageException if package error */ public static String translateGroupNameForImport(Context context, String groupName) - throws PackageException - { - // Check if this looks like a default Group name -- must have at LEAST two underscores surrounded by other characters - if(!groupName.matches("^.+_.+_.+$")) - { + throws PackageException { + // Check if this looks like a default Group name -- must have at LEAST two underscores surrounded by other + // characters + if (!groupName.matches("^.+_.+_.+$")) { //if this is not a valid default group name, just return group name as-is (no crosswalking necessary) return groupName; } @@ -923,14 +876,12 @@ public class PackageUtils // Format: __ // (e.g. COLLECTION_123_ADMIN) String objType = groupName.substring(0, groupName.indexOf('_')); - String tmpEndString = groupName.substring(groupName.indexOf('_')+1); + String tmpEndString = groupName.substring(groupName.indexOf('_') + 1); String objID = tmpEndString.substring(0, tmpEndString.indexOf('_')); - String groupType = tmpEndString.substring(tmpEndString.indexOf('_')+1); + String groupType = tmpEndString.substring(tmpEndString.indexOf('_') + 1); - try - { - if(objID.startsWith("hdl:")) - { + try { + if (objID.startsWith("hdl:")) { //We'll translate this handle into an internal ID //Format for Handle => "hdl:/" // (e.g. "hdl:123456789/10") @@ -938,30 +889,32 @@ public class PackageUtils //First, get the object via the Handle DSpaceObject dso = handleService.resolveToObject(context, objID.substring(4)); - if(dso==null) - { - //throw an error as we cannot accurately rename/recreate this Group without its related DSpace Object - throw new PackageException("Unable to translate Handle to Internal ID in group named '" + groupName + "' as DSpace Object (Handle='" + objID + "') does not exist."); + if (dso == null) { + //throw an error as we cannot accurately rename/recreate this Group without its related DSpace + // Object + throw new PackageException( + "Unable to translate Handle to Internal ID in group named '" + groupName + "' as DSpace " + + "Object (Handle='" + objID + "') does not exist."); } //verify our group specified object Type corresponds to this object's type - if(Constants.getTypeID(objType)!=dso.getType()) - { - throw new PackageValidationException("DSpace Object referenced by handle '" + objID + "' does not correspond to the object type specified by Group named '" + groupName + "'. This Group doesn't seem to correspond to this DSpace Object!"); + if (Constants.getTypeID(objType) != dso.getType()) { + throw new PackageValidationException( + "DSpace Object referenced by handle '" + objID + "' does not correspond to the object type " + + "specified by Group named '" + groupName + "'. This Group doesn't seem to correspond to " + + "this DSpace Object!"); } //Create an updated group name, using the Internal ID to replace the Handle // Format: __ return objType + "_" + dso.getID() + "_" + groupType; - } - else // default -- return group name as is - { + } else { + // default -- return group name as is return groupName; } - } - catch (SQLException sqle) - { - throw new PackageException("Database error while attempting to translate group name ('" + groupName + "') for import.", sqle); + } catch (SQLException sqle) { + throw new PackageException( + "Database error while attempting to translate group name ('" + groupName + "') for import.", sqle); } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageValidationException.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageValidationException.java index 5b36692d95..7f46768806 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PackageValidationException.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageValidationException.java @@ -24,28 +24,26 @@ package org.dspace.content.packager; * @author Larry Stone * @version $Revision$ */ -public class PackageValidationException extends PackageException -{ +public class PackageValidationException extends PackageException { /** * Create a new exception with the given message. + * * @param message - diagnostic message. */ - public PackageValidationException(String message) - { + public PackageValidationException(String message) { super(message); } /** * Create a new exception wrapping it around another exception. + * * @param exception - exception specifying the cause of this failure. */ - public PackageValidationException(Exception exception) - { + public PackageValidationException(Exception exception) { super(exception); } - public PackageValidationException(String message, Exception exception) - { + public PackageValidationException(String message, Exception exception) { super(message, exception); } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java index fedc54ac44..5fc538e086 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java @@ -7,6 +7,20 @@ */ package org.dspace.content.packager; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; @@ -23,23 +37,16 @@ import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; import org.jdom.Namespace; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; -import java.io.*; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /** * Plugin to export all Group and EPerson objects in XML, perhaps for reloading. - * + * * @author Mark Wood */ -public class RoleDisseminator implements PackageDisseminator -{ +public class RoleDisseminator implements PackageDisseminator { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(RoleDisseminator.class); /** @@ -84,7 +91,7 @@ public class RoleDisseminator implements PackageDisseminator /* * (non-Javadoc) - * + * * @see * org.dspace.content.packager.PackageDisseminator#disseminate(org.dspace * .core.Context, org.dspace.content.DSpaceObject, @@ -92,24 +99,19 @@ public class RoleDisseminator implements PackageDisseminator */ @Override public void disseminate(Context context, DSpaceObject object, - PackageParameters params, File pkgFile) + PackageParameters params, File pkgFile) throws PackageException, CrosswalkException, - AuthorizeException, SQLException, IOException - { + AuthorizeException, SQLException, IOException { boolean emitPasswords = params.containsKey("passwords"); FileOutputStream fileOut = null; - try - { + try { //open file stream for writing fileOut = new FileOutputStream(pkgFile); writeToStream(context, object, fileOut, emitPasswords); - } - finally - { + } finally { //close file stream & save - if (fileOut != null) - { + if (fileOut != null) { fileOut.close(); } } @@ -118,22 +120,21 @@ public class RoleDisseminator implements PackageDisseminator /** * Make serialized users and groups available on an InputStream, for code * which wants to read one. - * + * * @param emitPasswords true if password hashes should be included. * @return the stream of XML representing users and groups. * @throws IOException if IO error - * if a PipedOutputStream or PipedInputStream cannot be created. + * if a PipedOutputStream or PipedInputStream cannot be created. */ InputStream asStream(Context context, DSpaceObject object, boolean emitPasswords) - throws IOException - { + throws IOException { // Create a PipedOutputStream to which to write some XML PipedOutputStream outStream = new PipedOutputStream(); PipedInputStream inStream = new PipedInputStream(outStream); // Create a new Thread to push serialized objects into the pipe Serializer serializer = new Serializer(context, object, outStream, - emitPasswords); + emitPasswords); new Thread(serializer).start(); return inStream; @@ -141,28 +142,27 @@ public class RoleDisseminator implements PackageDisseminator /** * Embody a thread for serializing users and groups. - * + * * @author mwood */ - protected class Serializer implements Runnable - { + protected class Serializer implements Runnable { private Context context; private DSpaceObject object; private OutputStream stream; private boolean emitPasswords; - + @SuppressWarnings("unused") - private Serializer() {} + private Serializer() { + } /** * @param context - * @param object the DSpaceObject - * @param stream receives serialized user and group objects. Will be - * closed when serialization is complete. + * @param object the DSpaceObject + * @param stream receives serialized user and group objects. Will be + * closed when serialization is complete. * @param emitPasswords true if password hashes should be included. */ - Serializer(Context context, DSpaceObject object, OutputStream stream, boolean emitPasswords) - { + Serializer(Context context, DSpaceObject object, OutputStream stream, boolean emitPasswords) { this.context = context; this.object = object; this.stream = stream; @@ -170,19 +170,13 @@ public class RoleDisseminator implements PackageDisseminator } @Override - public void run() - { - try - { + public void run() { + try { writeToStream(context, object, stream, emitPasswords); stream.close(); - } - catch (IOException e) - { + } catch (IOException e) { log.error(e); - } - catch (PackageException e) - { + } catch (PackageException e) { log.error(e); } } @@ -190,27 +184,24 @@ public class RoleDisseminator implements PackageDisseminator /** * Serialize users and groups to a stream. - * - * @param context current Context - * @param object DSpaceObject - * @param stream receives the output. Is not closed by this method. + * + * @param context current Context + * @param object DSpaceObject + * @param stream receives the output. Is not closed by this method. * @param emitPasswords true if password hashes should be included. * @throws PackageException if error */ protected void writeToStream(Context context, DSpaceObject object, OutputStream stream, - boolean emitPasswords) - throws PackageException - { - try - { + boolean emitPasswords) + throws PackageException { + try { //First, find all Groups/People associated with our current Object List groups = findAssociatedGroups(context, object); List people = findAssociatedPeople(context, object); //Only continue if we've found Groups or People which we need to disseminate - if((groups!=null && groups.size()>0) || - (people!=null && people.size()>0)) - { + if ((groups != null && groups.size() > 0) || + (people != null && people.size() > 0)) { XMLOutputFactory factory = XMLOutputFactory.newInstance(); XMLStreamWriter writer; @@ -220,12 +211,10 @@ public class RoleDisseminator implements PackageDisseminator writer.writeStartElement(DSPACE_ROLES); //Only disseminate a element if some groups exist - if(groups!=null) - { + if (groups != null) { writer.writeStartElement(GROUPS); - for (Group group : groups) - { + for (Group group : groups) { writeGroup(context, object, group, writer); } @@ -233,12 +222,10 @@ public class RoleDisseminator implements PackageDisseminator } //Only disseminate an element if some people exist - if(people!=null) - { + if (people != null) { writer.writeStartElement(EPERSONS); - for (EPerson eperson : people) - { + for (EPerson eperson : people) { writeEPerson(eperson, writer, emitPasswords); } @@ -248,71 +235,63 @@ public class RoleDisseminator implements PackageDisseminator writer.writeEndElement(); // DSPACE_ROLES writer.writeEndDocument(); writer.close(); - }//end if Groups or People exist - } - catch (Exception e) - { + } //end if Groups or People exist + } catch (Exception e) { throw new PackageException(e); } } /* (non-Javadoc) - * + * * @see * org.dspace.content.packager.PackageDisseminator#disseminateAll(org.dspace * .core.Context, org.dspace.content.DSpaceObject, * org.dspace.content.packager.PackageParameters, java.io.File) */ @Override - public List disseminateAll(Context context, DSpaceObject dso, - PackageParameters params, File pkgFile) + public List disseminateAll(Context context, DSpaceObject dso, + PackageParameters params, File pkgFile) throws PackageException, CrosswalkException, - AuthorizeException, SQLException, IOException - { - throw new PackageException("disseminateAll() is not implemented, as disseminate() method already handles dissemination of all roles to an external file."); + AuthorizeException, SQLException, IOException { + throw new PackageException( + "disseminateAll() is not implemented, as disseminate() method already handles dissemination of all roles " + + "to an external file."); } /* * (non-Javadoc) - * + * * @see * org.dspace.content.packager.PackageDisseminator#getMIMEType(org.dspace * .content.packager.PackageParameters) */ @Override - public String getMIMEType(PackageParameters params) - { + public String getMIMEType(PackageParameters params) { return "application/xml"; } /** * Emit XML describing a single Group. * - * @param context - * the DSpace Context - * @param relatedObject - * the DSpaceObject related to this group (if any) - * @param group - * the Group to describe - * @param writer - * the description to this stream + * @param context the DSpace Context + * @param relatedObject the DSpaceObject related to this group (if any) + * @param group the Group to describe + * @param writer the description to this stream * @throws XMLStreamException if XML error - * @throws PackageException if packaging error + * @throws PackageException if packaging error */ protected void writeGroup(Context context, DSpaceObject relatedObject, Group group, XMLStreamWriter writer) - throws XMLStreamException, PackageException - { + throws XMLStreamException, PackageException { //Translate the Group name for export. This ensures that groups with Internal IDs in their names // (e.g. COLLECTION_1_ADMIN) are properly translated using the corresponding Handle or external identifier. String exportGroupName = PackageUtils.translateGroupNameForExport(context, group.getName()); - //If translated group name is returned as "null", this means the Group name + //If translated group name is returned as "null", this means the Group name // had an Internal Collection/Community ID embedded, which could not be // translated properly to a Handle. We will NOT export these groups, // as they could cause conflicts or data integrity problems if they are // imported into another DSpace system. - if(exportGroupName==null) - { + if (exportGroupName == null) { return; } @@ -321,36 +300,31 @@ public class RoleDisseminator implements PackageDisseminator writer.writeAttribute(NAME, exportGroupName); String groupType = getGroupType(relatedObject, group); - if(groupType!=null && !groupType.isEmpty()) - { + if (groupType != null && !groupType.isEmpty()) { writer.writeAttribute(TYPE, groupType); } //Add People to Group (if any belong to this group) - if(group.getMembers().size()>0) - { + if (group.getMembers().size() > 0) { writer.writeStartElement(MEMBERS); - for (EPerson member : group.getMembers()) - { + for (EPerson member : group.getMembers()) { writer.writeEmptyElement(MEMBER); writer.writeAttribute(ID, String.valueOf(member.getID())); - if (null != member.getName()) + if (null != member.getName()) { writer.writeAttribute(NAME, member.getName()); + } } writer.writeEndElement(); } //Add Groups as Member Groups (if any belong to this group) - if(group.getMemberGroups().size()>0) - { + if (group.getMemberGroups().size() > 0) { writer.writeStartElement(MEMBER_GROUPS); - for (Group member : group.getMemberGroups()) - { + for (Group member : group.getMemberGroups()) { String exportMemberName = PackageUtils.translateGroupNameForExport(context, member.getName()); //Only export member group if its name can be properly translated for export. As noted above, // we don't want groups that are *unable* to be accurately translated causing issues on import. - if(exportMemberName!=null) - { + if (exportMemberName != null) { writer.writeEmptyElement(MEMBER_GROUP); writer.writeAttribute(ID, String.valueOf(member.getID())); writer.writeAttribute(NAME, exportMemberName); @@ -371,55 +345,38 @@ public class RoleDisseminator implements PackageDisseminator *

    * If type string cannot be determined, null is returned. * - * @param dso - * the related DSpaceObject - * @param group - * the group + * @param dso the related DSpaceObject + * @param group the group * @return a group type string or null */ - protected String getGroupType(DSpaceObject dso, Group group) - { - if (dso == null || group == null) - { + protected String getGroupType(DSpaceObject dso, Group group) { + if (dso == null || group == null) { return null; } - if( dso.getType()==Constants.COMMUNITY) - { + if (dso.getType() == Constants.COMMUNITY) { Community community = (Community) dso; //Check if this is the ADMIN group for this community - if (group.equals(community.getAdministrators())) - { + if (group.equals(community.getAdministrators())) { return GROUP_TYPE_ADMIN; } - } - else if(dso.getType() == Constants.COLLECTION) - { + } else if (dso.getType() == Constants.COLLECTION) { Collection collection = (Collection) dso; - if (group.equals(collection.getAdministrators())) - { + if (group.equals(collection.getAdministrators())) { //Check if this is the ADMIN group for this collection return GROUP_TYPE_ADMIN; - } - else if (group.equals(collection.getSubmitters())) - { + } else if (group.equals(collection.getSubmitters())) { //Check if Submitters group return GROUP_TYPE_SUBMIT; - } - else if (group.equals(collection.getWorkflowStep1())) - { + } else if (group.equals(collection.getWorkflowStep1())) { //Check if workflow step 1 group return GROUP_TYPE_WORKFLOW_STEP_1; - } - else if (group.equals(collection.getWorkflowStep2())) - { + } else if (group.equals(collection.getWorkflowStep2())) { //check if workflow step 2 group return GROUP_TYPE_WORKFLOW_STEP_2; - } - else if (group.equals(collection.getWorkflowStep3())) - { + } else if (group.equals(collection.getWorkflowStep3())) { //check if workflow step 3 group return GROUP_TYPE_WORKFLOW_STEP_3; } @@ -431,72 +388,59 @@ public class RoleDisseminator implements PackageDisseminator /** * Emit XML describing a single EPerson. - * - * @param eperson - * the EPerson to describe - * @param writer - * the description to this stream - * @param emitPassword - * do not export the password hash unless true + * + * @param eperson the EPerson to describe + * @param writer the description to this stream + * @param emitPassword do not export the password hash unless true * @throws XMLStreamException if XML error */ protected void writeEPerson(EPerson eperson, XMLStreamWriter writer, - boolean emitPassword) throws XMLStreamException - { + boolean emitPassword) throws XMLStreamException { writer.writeStartElement(EPERSON); writer.writeAttribute(ID, String.valueOf(eperson.getID())); - if (eperson.getEmail()!=null) - { + if (eperson.getEmail() != null) { writer.writeStartElement(EMAIL); writer.writeCharacters(eperson.getEmail()); writer.writeEndElement(); } - if(eperson.getNetid()!=null) - { + if (eperson.getNetid() != null) { writer.writeStartElement(NETID); writer.writeCharacters(eperson.getNetid()); writer.writeEndElement(); } - if(eperson.getFirstName()!=null) - { + if (eperson.getFirstName() != null) { writer.writeStartElement(FIRST_NAME); writer.writeCharacters(eperson.getFirstName()); writer.writeEndElement(); } - if(eperson.getLastName()!=null) - { + if (eperson.getLastName() != null) { writer.writeStartElement(LAST_NAME); writer.writeCharacters(eperson.getLastName()); writer.writeEndElement(); } - if(eperson.getLanguage()!=null) - { + if (eperson.getLanguage() != null) { writer.writeStartElement(LANGUAGE); writer.writeCharacters(eperson.getLanguage()); writer.writeEndElement(); } - - if (emitPassword) - { + + if (emitPassword) { PasswordHash password = ePersonService.getPasswordHash(eperson); - if (null != password) - { + if (null != password) { writer.writeStartElement(PASSWORD_HASH); String algorithm = password.getAlgorithm(); - if (null != algorithm) - { + if (null != algorithm) { writer.writeAttribute(PASSWORD_DIGEST, algorithm); } String salt = password.getSaltString(); - if (null != salt) - { + if (null != salt) { writer.writeAttribute(PASSWORD_SALT, salt); } @@ -505,18 +449,15 @@ public class RoleDisseminator implements PackageDisseminator } } - if (eperson.canLogIn()) - { + if (eperson.canLogIn()) { writer.writeEmptyElement(CAN_LOGIN); } - if (eperson.getRequireCertificate()) - { + if (eperson.getRequireCertificate()) { writer.writeEmptyElement(REQUIRE_CERTIFICATE); } - if (eperson.getSelfRegistered()) - { + if (eperson.getSelfRegistered()) { writer.writeEmptyElement(SELF_REGISTERED); } @@ -534,92 +475,74 @@ public class RoleDisseminator implements PackageDisseminator * For all other objects, null is returned. * * @param context The DSpace context - * @param object the DSpace object + * @param object the DSpace object * @return array of all associated groups * @throws SQLException if database error */ protected List findAssociatedGroups(Context context, DSpaceObject object) - throws SQLException - { - if(object.getType()==Constants.SITE) - { + throws SQLException { + if (object.getType() == Constants.SITE) { // TODO FIXME -- if there was a way to ONLY export Groups which are NOT // associated with a Community or Collection, we should be doing that instead! return groupService.findAll(context, null); - } - else if(object.getType()==Constants.COMMUNITY) - { + } else if (object.getType() == Constants.COMMUNITY) { Community community = (Community) object; ArrayList list = new ArrayList(); //check for admin group - if(community.getAdministrators()!=null) - { + if (community.getAdministrators() != null) { list.add(community.getAdministrators()); } // FINAL CATCH-ALL -> Find any other groups where name begins with "COMMUNITY__" // (There should be none, but this code is here just in case) List matchingGroups = groupService.search(context, "COMMUNITY\\_" + community.getID() + "\\_"); - for(Group g : matchingGroups) - { - if(!list.contains(g)) - { + for (Group g : matchingGroups) { + if (!list.contains(g)) { list.add(g); } } - if(list.size()>0) - { + if (list.size() > 0) { return list; } - } - else if(object.getType()==Constants.COLLECTION) - { + } else if (object.getType() == Constants.COLLECTION) { Collection collection = (Collection) object; - + ArrayList list = new ArrayList(); - + //check for admin group - if(collection.getAdministrators()!=null) - { + if (collection.getAdministrators() != null) { list.add(collection.getAdministrators()); } //check for submitters group - if(collection.getSubmitters()!=null) - { + if (collection.getSubmitters() != null) { list.add(collection.getSubmitters()); } //check for workflow step 1 group - if(collection.getWorkflowStep1()!=null) - { + if (collection.getWorkflowStep1() != null) { list.add(collection.getWorkflowStep1()); } //check for workflow step 2 group - if(collection.getWorkflowStep2()!=null) - { + if (collection.getWorkflowStep2() != null) { list.add(collection.getWorkflowStep2()); } //check for workflow step 3 group - if(collection.getWorkflowStep3()!=null) - { + if (collection.getWorkflowStep3() != null) { list.add(collection.getWorkflowStep3()); } // FINAL CATCH-ALL -> Find any other groups where name begins with "COLLECTION__" // (Necessary cause XMLUI allows you to generate a 'COLLECTION__DEFAULT_READ' group) List matchingGroups = groupService.search(context, "COLLECTION\\_" + collection.getID() + "\\_"); - for(Group g : matchingGroups) - { - if(!list.contains(g)) - { + for (Group g : matchingGroups) { + if (!list.contains(g)) { list.add(g); } } - if(list.size()>0) - { + if (list.size() > 0) { return list; } } @@ -637,15 +560,13 @@ public class RoleDisseminator implements PackageDisseminator * For all other objects, null is returned. * * @param context The DSpace context - * @param object the DSpace object + * @param object the DSpace object * @return array of all associated EPerson objects * @throws SQLException if database error */ protected List findAssociatedPeople(Context context, DSpaceObject object) - throws SQLException - { - if(object.getType()==Constants.SITE) - { + throws SQLException { + if (object.getType() == Constants.SITE) { return ePersonService.findAll(context, EPerson.EMAIL); } @@ -663,10 +584,10 @@ public class RoleDisseminator implements PackageDisseminator * with this packager */ @Override - public String getParameterHelp() - { - return "* passwords=[boolean] " + - "If true, user password hashes are also exported (so that they can be later restored). If false, user passwords are not exported. (Default is false)"; + public String getParameterHelp() { + return "* passwords=[boolean] " + + "If true, user password hashes are also exported (so that they can be later restored). If false, user " + + "passwords are not exported. (Default is false)"; } } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/RoleIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/RoleIngester.java index 1d9f91e2cb..2ce3f50a3c 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/RoleIngester.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/RoleIngester.java @@ -7,6 +7,17 @@ */ package org.dspace.content.packager; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + import org.apache.commons.codec.DecoderException; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; @@ -27,29 +38,21 @@ import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.*; +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; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - /** * Create EPersons and Groups from a file of external representations. - * + * * @author mwood */ -public class RoleIngester implements PackageIngester -{ +public class RoleIngester implements PackageIngester { private static final Logger log = LoggerFactory - .getLogger(RoleIngester.class); + .getLogger(RoleIngester.class); protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); @@ -59,29 +62,24 @@ public class RoleIngester implements PackageIngester /** * Common code to ingest roles from a Document. - * - * @param context - * DSpace Context - * @param parent - * the Parent DSpaceObject - * @param document - * the XML Document - * @throws SQLException if database error + * + * @param context DSpace Context + * @param parent the Parent DSpaceObject + * @param document the XML Document + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws PackageException if packaging error + * @throws PackageException if packaging error */ void ingestDocument(Context context, DSpaceObject parent, - PackageParameters params, Document document) - throws SQLException, AuthorizeException, PackageException - { + PackageParameters params, Document document) + throws SQLException, AuthorizeException, PackageException { String myEmail = context.getCurrentUser().getEmail(); String myNetid = context.getCurrentUser().getNetid(); // Ingest users (EPersons) first so Groups can use them NodeList users = document - .getElementsByTagName(RoleDisseminator.EPERSON); - for (int i = 0; i < users.getLength(); i++) - { + .getElementsByTagName(RoleDisseminator.EPERSON); + for (int i = 0; i < users.getLength(); i++) { Element user = (Element) users.item(i); // int userID = Integer.valueOf(user.getAttribute("ID")); // FIXME // no way to set ID! @@ -92,48 +90,35 @@ public class RoleIngester implements PackageIngester String email = null; String netid = null; String identity; - if (emails.getLength() > 0) - { + if (emails.getLength() > 0) { email = emails.item(0).getTextContent(); - if (email.equals(myEmail)) - { + if (email.equals(myEmail)) { continue; // Cannot operate on my own EPerson! } identity = email; collider = ePersonService.findByEmail(context, identity); // collider = EPerson.find(context, userID); - } - else if (netids.getLength() > 0) - { + } else if (netids.getLength() > 0) { netid = netids.item(0).getTextContent(); - if (netid.equals(myNetid)) - { + if (netid.equals(myNetid)) { continue; // Cannot operate on my own EPerson! } identity = netid; collider = ePersonService.findByNetid(context, identity); - } - else - { + } else { throw new PackageException("EPerson has neither email nor netid."); } - if (null != collider) - if (params.replaceModeEnabled()) // -r -f - { + if (null != collider) { + if (params.replaceModeEnabled()) { // -r -f eperson = collider; - } - else if (params.keepExistingModeEnabled()) // -r -k - { + } else if (params.keepExistingModeEnabled()) { // -r -k log.warn("Existing EPerson {} was not restored from the package.", identity); continue; - } - else - { + } else { throw new PackageException("EPerson " + identity + " already exists."); } - else - { + } else { eperson = ePersonService.create(context); log.info("Created EPerson {}.", identity); } @@ -144,32 +129,23 @@ public class RoleIngester implements PackageIngester NodeList data; data = user.getElementsByTagName(RoleDisseminator.FIRST_NAME); - if (data.getLength() > 0) - { + if (data.getLength() > 0) { eperson.setFirstName(context, data.item(0).getTextContent()); - } - else - { + } else { eperson.setFirstName(context, null); } data = user.getElementsByTagName(RoleDisseminator.LAST_NAME); - if (data.getLength() > 0) - { + if (data.getLength() > 0) { eperson.setLastName(context, data.item(0).getTextContent()); - } - else - { + } else { eperson.setLastName(context, null); } data = user.getElementsByTagName(RoleDisseminator.LANGUAGE); - if (data.getLength() > 0) - { + if (data.getLength() > 0) { eperson.setLanguage(context, data.item(0).getTextContent()); - } - else - { + } else { eperson.setLanguage(context, null); } @@ -183,24 +159,25 @@ public class RoleIngester implements PackageIngester eperson.setSelfRegistered(data.getLength() > 0); data = user.getElementsByTagName(RoleDisseminator.PASSWORD_HASH); - if (data.getLength() > 0) - { + if (data.getLength() > 0) { Node element = data.item(0); NamedNodeMap attributes = element.getAttributes(); Node algorithm = attributes.getNamedItem(RoleDisseminator.PASSWORD_DIGEST); String algorithmText; - if (null != algorithm) + if (null != algorithm) { algorithmText = algorithm.getNodeValue(); - else + } else { algorithmText = null; + } Node salt = attributes.getNamedItem(RoleDisseminator.PASSWORD_SALT); String saltText; - if (null != salt) + if (null != salt) { saltText = salt.getNodeValue(); - else + } else { saltText = null; + } PasswordHash password; try { @@ -209,9 +186,7 @@ public class RoleIngester implements PackageIngester throw new PackageValidationException("Unable to decode hexadecimal password hash or salt", ex); } ePersonService.setPasswordHash(eperson, password); - } - else - { + } else { ePersonService.setPasswordHash(eperson, null); } @@ -225,44 +200,41 @@ public class RoleIngester implements PackageIngester NodeList groups = document.getElementsByTagName(RoleDisseminator.GROUP); // Create the groups and add their EPerson members - for (int groupx = 0; groupx < groups.getLength(); groupx++) - { + for (int groupx = 0; groupx < groups.getLength(); groupx++) { Element group = (Element) groups.item(groupx); String name = group.getAttribute(RoleDisseminator.NAME); log.debug("Processing group {}", name); - try - { + try { //Translate Group name back to internal ID format (e.g. COLLECTION__ADMIN) // TODO: is this necessary? can we leave it in format with Handle in place of ? // For now, this is necessary, because we don't want to accidentally // create a new group COLLECTION_hdl:123/34_ADMIN, which is equivalent // to an existing COLLECTION_45_ADMIN group name = PackageUtils.translateGroupNameForImport(context, name); - } - catch(PackageException pe) - { + } catch (PackageException pe) { // If an error is thrown, then this Group corresponds to a // Community or Collection that doesn't currently exist in the // system. So, log a warning & skip it for now. - log.warn("Skipping group named '" + name + "' as it seems to correspond to a Community or Collection that does not exist in the system. " + - "If you are performing an AIP restore, you can ignore this warning as the Community/Collection AIP will likely create this group once it is processed."); + log.warn( + "Skipping group named '" + name + "' as it seems to correspond to a Community or Collection that " + + "does not exist in the system. " + + "If you are performing an AIP restore, you can ignore this warning as the " + + "Community/Collection AIP will likely create this group once it is processed."); continue; } log.debug("Translated group name: {}", name); Group groupObj = null; // The group to restore Group collider = groupService.findByName(context, name); // Existing group? - if (null != collider) - { // Group already exists, so empty it - if (params.replaceModeEnabled()) // -r -f - { + if (null != collider) { // Group already exists, so empty it + + if (params.replaceModeEnabled()) { // -r -f // Get a *copy* of our group list to avoid ConcurrentModificationException // when we remove these groups from the parent Group obj List groupRemovalList = new ArrayList<>(collider.getMemberGroups()); Iterator groupIterator = groupRemovalList.iterator(); - while(groupIterator.hasNext()) - { + while (groupIterator.hasNext()) { Group member = groupIterator.next(); groupService.removeMember(context, collider, member); } @@ -271,77 +243,56 @@ public class RoleIngester implements PackageIngester // when we remove these epersons from the parent Group obj List epersonRemovalList = new ArrayList<>(collider.getMembers()); Iterator epersonIterator = epersonRemovalList.iterator(); - while(epersonIterator.hasNext()) - { + while (epersonIterator.hasNext()) { EPerson member = epersonIterator.next(); // Remove all group members *EXCEPT* we don't ever want // to remove the current user from the list of Administrators // (otherwise remainder of ingest will fail) - if(!(collider.equals(groupService.findByName(context, Group.ADMIN)) && - member.equals(context.getCurrentUser()))) - { + if (!(collider.equals(groupService.findByName(context, Group.ADMIN)) && + member.equals(context.getCurrentUser()))) { groupService.removeMember(context, collider, member); } } log.info("Existing Group {} was cleared. Its members will be replaced.", name); groupObj = collider; - } - else if (params.keepExistingModeEnabled()) // -r -k - { + } else if (params.keepExistingModeEnabled()) { // -r -k log.warn("Existing Group {} was not replaced from the package.", name); continue; - } - else - { + } else { throw new PackageException("Group " + name + " already exists"); } - } - else - { // No such group exists -- so, we'll need to create it! + } else { // No such group exists -- so, we'll need to create it! - DSpaceObjectService dsoService = ContentServiceFactory.getInstance().getDSpaceObjectService(parent); + DSpaceObjectService dsoService = ContentServiceFactory.getInstance() + .getDSpaceObjectService(parent); log.debug("Creating group for a {}", dsoService.getTypeText(parent)); // First Check if this is a "typed" group (i.e. Community or Collection associated Group) // If so, we'll create it via the Community or Collection String type = group.getAttribute(RoleDisseminator.TYPE); log.debug("Group type is {}", type); - if(type!=null && !type.isEmpty() && parent!=null) - { + if (type != null && !type.isEmpty() && parent != null) { //What type of dspace object is this group associated with - if(parent.getType()==Constants.COLLECTION) - { + if (parent.getType() == Constants.COLLECTION) { Collection collection = (Collection) parent; // Create this Collection-associated group, based on its group type - if(type.equals(RoleDisseminator.GROUP_TYPE_ADMIN)) - { + if (type.equals(RoleDisseminator.GROUP_TYPE_ADMIN)) { groupObj = collectionService.createAdministrators(context, collection); - } - else if(type.equals(RoleDisseminator.GROUP_TYPE_SUBMIT)) - { + } else if (type.equals(RoleDisseminator.GROUP_TYPE_SUBMIT)) { groupObj = collectionService.createSubmitters(context, collection); - } - else if(type.equals(RoleDisseminator.GROUP_TYPE_WORKFLOW_STEP_1)) - { + } else if (type.equals(RoleDisseminator.GROUP_TYPE_WORKFLOW_STEP_1)) { groupObj = collectionService.createWorkflowGroup(context, collection, 1); - } - else if(type.equals(RoleDisseminator.GROUP_TYPE_WORKFLOW_STEP_2)) - { + } else if (type.equals(RoleDisseminator.GROUP_TYPE_WORKFLOW_STEP_2)) { groupObj = collectionService.createWorkflowGroup(context, collection, 2); - } - else if(type.equals(RoleDisseminator.GROUP_TYPE_WORKFLOW_STEP_3)) - { + } else if (type.equals(RoleDisseminator.GROUP_TYPE_WORKFLOW_STEP_3)) { groupObj = collectionService.createWorkflowGroup(context, collection, 3); } - } - else if(parent.getType()==Constants.COMMUNITY) - { + } else if (parent.getType() == Constants.COMMUNITY) { Community community = (Community) parent; // Create this Community-associated group, based on its group type - if(type.equals(RoleDisseminator.GROUP_TYPE_ADMIN)) - { + if (type.equals(RoleDisseminator.GROUP_TYPE_ADMIN)) { groupObj = communityService.createAdministrators(context, community); } } @@ -349,8 +300,7 @@ public class RoleIngester implements PackageIngester } //If group not yet created, create it with the given name - if(groupObj==null) - { + if (groupObj == null) { groupObj = groupService.create(context); } @@ -362,16 +312,16 @@ public class RoleIngester implements PackageIngester // Add EPeople to newly created Group NodeList members = group.getElementsByTagName(RoleDisseminator.MEMBER); - for (int memberx = 0; memberx < members.getLength(); memberx++) - { + for (int memberx = 0; memberx < members.getLength(); memberx++) { Element member = (Element) members.item(memberx); String memberName = member.getAttribute(RoleDisseminator.NAME); EPerson memberEPerson = ePersonService.findByEmail(context, memberName); - if (null != memberEPerson) + if (null != memberEPerson) { groupService.addMember(context, groupObj, memberEPerson); - else + } else { throw new PackageValidationException("EPerson " + memberName - + " not found, not added to " + name); + + " not found, not added to " + name); + } } // Actually write Group info to DB @@ -382,19 +332,15 @@ public class RoleIngester implements PackageIngester } // Go back and add Group members, now that all groups exist - for (int groupx = 0; groupx < groups.getLength(); groupx++) - { + for (int groupx = 0; groupx < groups.getLength(); groupx++) { Element group = (Element) groups.item(groupx); String name = group.getAttribute(RoleDisseminator.NAME); log.debug("Processing group {}", name); - try - { + try { // Translate Group name back to internal ID format (e.g. COLLECTION__ADMIN) name = PackageUtils.translateGroupNameForImport(context, name); log.debug("Translated group name: {}", name); - } - catch(PackageException pe) - { + } catch (PackageException pe) { // If an error is thrown, then this Group corresponds to a // Community or Collection that doesn't currently exist in the // system. So,skip it for now. @@ -407,9 +353,8 @@ public class RoleIngester implements PackageIngester Group groupObj = groupService.findByName(context, name); log.debug("Looked up the group and found {}", groupObj); NodeList members = group - .getElementsByTagName(RoleDisseminator.MEMBER_GROUP); - for (int memberx = 0; memberx < members.getLength(); memberx++) - { + .getElementsByTagName(RoleDisseminator.MEMBER_GROUP); + for (int memberx = 0; memberx < members.getLength(); memberx++) { Element member = (Element) members.item(memberx); String memberName = member.getAttribute(RoleDisseminator.NAME); //Translate Group name back to internal ID format (e.g. COLLECTION__ADMIN) @@ -428,37 +373,29 @@ public class RoleIngester implements PackageIngester * Ingest roles from an InputStream. * * @param context DSpace Context - * @param parent the Parent DSpaceObject - * @param params package params - * @param stream input stream with the roles - * @throws PackageException if packaging error - * @throws SQLException if database error + * @param parent the Parent DSpaceObject + * @param params package params + * @param stream input stream with the roles + * @throws PackageException if packaging error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void ingestStream(Context context, DSpaceObject parent, - PackageParameters params, InputStream stream) - throws PackageException, SQLException, AuthorizeException - { + PackageParameters params, InputStream stream) + throws PackageException, SQLException, AuthorizeException { Document document; - try - { + try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setIgnoringComments(true); dbf.setCoalescing(true); DocumentBuilder db = dbf.newDocumentBuilder(); document = db.parse(stream); - } - catch (ParserConfigurationException e) - { + } catch (ParserConfigurationException e) { throw new PackageException(e); - } - catch (SAXException e) - { + } catch (SAXException e) { throw new PackageException(e); - } - catch (IOException e) - { + } catch (IOException e) { throw new PackageException(e); } /* @@ -469,7 +406,7 @@ public class RoleIngester implements PackageIngester /* * (non-Javadoc) - * + * * @see * org.dspace.content.packager.PackageIngester#ingest(org.dspace.core.Context * , org.dspace.content.DSpaceObject, java.io.File, @@ -477,26 +414,20 @@ public class RoleIngester implements PackageIngester */ @Override public DSpaceObject ingest(Context context, DSpaceObject parent, - File pkgFile, PackageParameters params, String license) - throws PackageException, CrosswalkException, AuthorizeException, - SQLException, IOException - { + File pkgFile, PackageParameters params, String license) + throws PackageException, CrosswalkException, AuthorizeException, + SQLException, IOException { Document document; - try - { + try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setIgnoringComments(true); dbf.setCoalescing(true); DocumentBuilder db = dbf.newDocumentBuilder(); document = db.parse(pkgFile); - } - catch (ParserConfigurationException e) - { + } catch (ParserConfigurationException e) { throw new PackageException(e); - } - catch (SAXException e) - { + } catch (SAXException e) { throw new PackageException(e); } ingestDocument(context, parent, params, document); @@ -507,7 +438,7 @@ public class RoleIngester implements PackageIngester /* * (non-Javadoc) - * + * * @see * org.dspace.content.packager.PackageIngester#ingestAll(org.dspace.core * .Context, org.dspace.content.DSpaceObject, java.io.File, @@ -515,17 +446,17 @@ public class RoleIngester implements PackageIngester */ @Override public List ingestAll(Context context, DSpaceObject parent, - File pkgFile, PackageParameters params, String license) - throws PackageException, UnsupportedOperationException, - CrosswalkException, AuthorizeException, SQLException, IOException - { + File pkgFile, PackageParameters params, String license) + throws PackageException, UnsupportedOperationException, + CrosswalkException, AuthorizeException, SQLException, IOException { throw new PackageException( - "ingestAll() is not implemented, as ingest() method already handles ingestion of all roles from an external file."); + "ingestAll() is not implemented, as ingest() method already handles ingestion of all roles from an " + + "external file."); } /* * (non-Javadoc) - * + * * @see * org.dspace.content.packager.PackageIngester#replace(org.dspace.core.Context * , org.dspace.content.DSpaceObject, java.io.File, @@ -533,17 +464,16 @@ public class RoleIngester implements PackageIngester */ @Override public DSpaceObject replace(Context context, DSpaceObject dso, - File pkgFile, PackageParameters params) throws PackageException, - UnsupportedOperationException, CrosswalkException, - AuthorizeException, SQLException, IOException - { + File pkgFile, PackageParameters params) throws PackageException, + UnsupportedOperationException, CrosswalkException, + AuthorizeException, SQLException, IOException { //Just call ingest() -- this will perform a replacement as necessary return ingest(context, dso, pkgFile, params, null); } /* * (non-Javadoc) - * + * * @see * org.dspace.content.packager.PackageIngester#replaceAll(org.dspace.core * .Context, org.dspace.content.DSpaceObject, java.io.File, @@ -551,12 +481,12 @@ public class RoleIngester implements PackageIngester */ @Override public List replaceAll(Context context, DSpaceObject dso, - File pkgFile, PackageParameters params) throws PackageException, - UnsupportedOperationException, CrosswalkException, - AuthorizeException, SQLException, IOException - { + File pkgFile, PackageParameters params) throws PackageException, + UnsupportedOperationException, CrosswalkException, + AuthorizeException, SQLException, IOException { throw new PackageException( - "replaceAll() is not implemented, as replace() method already handles replacement of all roles from an external file."); + "replaceAll() is not implemented, as replace() method already handles replacement of all roles from an " + + "external file."); } /** @@ -569,8 +499,7 @@ public class RoleIngester implements PackageIngester * with this packager */ @Override - public String getParameterHelp() - { + public String getParameterHelp() { return "No additional options available."; } } diff --git a/dspace-api/src/main/java/org/dspace/content/service/BitstreamFormatService.java b/dspace-api/src/main/java/org/dspace/content/service/BitstreamFormatService.java index e5f83243c7..19ef5c7d07 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/BitstreamFormatService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/BitstreamFormatService.java @@ -7,36 +7,33 @@ */ package org.dspace.content.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; import org.dspace.core.Context; import org.dspace.service.DSpaceCRUDService; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the BitstreamFormat object. - * The implementation of this class is responsible for all business logic calls for the BitstreamFormat object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the BitstreamFormat object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ public interface BitstreamFormatService extends DSpaceCRUDService { - /** * Find a bitstream format by its (unique) MIME type. * If more than one bitstream format has the same MIME type, the * one returned is unpredictable. * - * @param context - * DSpace context object - * @param mimeType - * MIME type value - * + * @param context DSpace context object + * @param mimeType MIME type value * @return the corresponding bitstream format, or null if - * there's no bitstream format with the given MIMEtype. + * there's no bitstream format with the given MIMEtype. * @throws SQLException if database error */ public BitstreamFormat findByMIMEType(Context context, String mimeType) throws SQLException; @@ -44,13 +41,10 @@ public interface BitstreamFormatService extends DSpaceCRUDServicenull if - * there's no bitstream format with the given short description + * there's no bitstream format with the given short description * @throws SQLException if database error */ public BitstreamFormat findByShortDescription(Context context, String desc) throws SQLException; @@ -58,23 +52,17 @@ public interface BitstreamFormatService extends DSpaceCRUDServiceUNKNOWN,KNOWN or SUPPORTED. * * @param bitstreamFormat format - * @param supportLevel - * the new support level + * @param supportLevel the new support level */ public void setSupportLevel(BitstreamFormat bitstreamFormat, int supportLevel); @@ -127,11 +112,9 @@ public interface BitstreamFormatService extends DSpaceCRUDService-1 if the action - * string is unknown + * string is unknown */ public int getSupportLevelID(String supportLevel); @@ -139,10 +122,8 @@ public interface BitstreamFormatService extends DSpaceCRUDService, DSpaceObjectLegacySupportService{ +public interface BitstreamService extends DSpaceObjectService, DSpaceObjectLegacySupportService { public List findAll(Context context) throws SQLException; public Iterator findAll(Context context, int limit, int offset) throws SQLException; + /** + * Clone the given bitstream by firstly creating a new bitstream, with a new ID. + * Then set the internal identifier, file size, checksum, and + * checksum algorithm as same as the given bitstream. + * This allows multiple bitstreams to share the same internal identifier of assets . + * An example of such a use case scenario is versioning. + * + * @param context + * DSpace context object + * @param bitstream + * Bitstream to be cloned + * @return the clone + * @throws SQLException if database error + */ + public Bitstream clone(Context context, Bitstream bitstream) throws SQLException; + /** * Create a new bitstream, with a new ID. The checksum and file size are * calculated. No authorization checks are made in this method. * The newly created bitstream has the "unknown" format. * - * @param context - * DSpace context object - * @param is - * the bits to put in the bitstream - * + * @param context DSpace context object + * @param is the bits to put in the bitstream * @return the newly created bitstream - * @throws IOException if IO error + * @throws IOException if IO error * @throws SQLException if database error */ public Bitstream create(Context context, InputStream is) throws IOException, SQLException; @@ -50,62 +69,57 @@ public interface BitstreamService extends DSpaceObjectService, DSpace * calculated. * The newly created bitstream has the "unknown" format. * - * @param context - * DSpace context object - * @param bundle - * The bundle in which our bitstream should be added. - * - * @param is - * the bits to put in the bitstream - * + * @param context DSpace context object + * @param bundle The bundle in which our bitstream should be added. + * @param is the bits to put in the bitstream * @return the newly created bitstream - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public Bitstream create(Context context, Bundle bundle, InputStream is) throws IOException, SQLException, AuthorizeException; + public Bitstream create(Context context, Bundle bundle, InputStream is) + throws IOException, SQLException, AuthorizeException; /** * Register a new bitstream, with a new ID. The checksum and file size * are calculated. The newly created bitstream has the "unknown" * format. * - * @param context DSpace context object - * @param bundle The bundle in which our bitstream should be added. - * @param assetstore corresponds to an assetstore in dspace.cfg + * @param context DSpace context object + * @param bundle The bundle in which our bitstream should be added. + * @param assetstore corresponds to an assetstore in dspace.cfg * @param bitstreamPath the path and filename relative to the assetstore - * @return the newly registered bitstream - * @throws IOException if IO error - * @throws SQLException if database error + * @return the newly registered bitstream + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Bitstream register(Context context, Bundle bundle, int assetstore, String bitstreamPath) - throws IOException, SQLException, AuthorizeException; + throws IOException, SQLException, AuthorizeException; /** * Register a new bitstream, with a new ID. The checksum and file size * are calculated. The newly created bitstream has the "unknown" * format. * - * @param context DSpace context object - * @param assetstore corresponds to an assetstore in dspace.cfg + * @param context DSpace context object + * @param assetstore corresponds to an assetstore in dspace.cfg * @param bitstreamPath the path and filename relative to the assetstore - * @return the newly registered bitstream - * @throws IOException if IO error - * @throws SQLException if database error + * @return the newly registered bitstream + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Bitstream register(Context context, int assetstore, String bitstreamPath) - throws IOException, SQLException, AuthorizeException; + throws IOException, SQLException, AuthorizeException; /** * Set the user's format description. This implies that the format of the * bitstream is uncertain, and the format is set to "unknown." * - * @param context DSpace context object - * @param bitstream DSpace bitstream - * @param desc - * the user's description of the format + * @param context DSpace context object + * @param bitstream DSpace bitstream + * @param desc the user's description of the format * @throws SQLException if database error */ public void setUserFormatDescription(Context context, Bitstream bitstream, String desc) throws SQLException; @@ -113,9 +127,9 @@ public interface BitstreamService extends DSpaceObjectService, DSpace /** * Get the description of the format - either the user's or the description * of the format defined by the system. - * - * @param context DSpace context object - * @param bitstream DSpace bitstream + * + * @param context DSpace context object + * @param bitstream DSpace bitstream * @return a description of the format. * @throws SQLException if database error */ @@ -126,11 +140,10 @@ public interface BitstreamService extends DSpaceObjectService, DSpace * description, it is cleared. Passing in null sets the type * of this bitstream to "unknown". * - * @param context DSpace context object - * @param bitstream DSpace bitstream - * @param bitstreamFormat - * the format of this bitstream, or null for - * unknown + * @param context DSpace context object + * @param bitstream DSpace bitstream + * @param bitstreamFormat the format of this bitstream, or null for + * unknown * @throws SQLException if database error */ public void setFormat(Context context, Bitstream bitstream, BitstreamFormat bitstreamFormat) throws SQLException; @@ -138,27 +151,29 @@ public interface BitstreamService extends DSpaceObjectService, DSpace /** * Retrieve the contents of the bitstream * - * @param context DSpace context object - * @param bitstream DSpace bitstream + * @param context DSpace context object + * @param bitstream DSpace bitstream * @return a stream from which the bitstream can be read. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public InputStream retrieve(Context context, Bitstream bitstream) throws IOException, SQLException, AuthorizeException; + public InputStream retrieve(Context context, Bitstream bitstream) + throws IOException, SQLException, AuthorizeException; /** * Determine if this bitstream is registered (available elsewhere on * filesystem than in assetstore). More about registered items: * https://wiki.duraspace.org/display/DSDOC3x/Registering+(not+Importing)+Bitstreams+via+Simple+Archive+Format * - * @param bitstream DSpace bitstream + * @param bitstream DSpace bitstream * @return true if the bitstream is registered, false otherwise */ public boolean isRegisteredBitstream(Bitstream bitstream); /** * Retrieve all bitstreams with the deleted flag set to true + * * @param context the dspace context * @return a list of all bitstreams that have been "deleted" * @throws SQLException if database error @@ -168,9 +183,10 @@ public interface BitstreamService extends DSpaceObjectService, DSpace /** * Remove a bitstream that has been set to "deleted" from the database - * @param context the dspace context + * + * @param context the dspace context * @param bitstream the bitstream to deleted from the database - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void expunge(Context context, Bitstream bitstream) throws SQLException, AuthorizeException; @@ -202,4 +218,6 @@ public interface BitstreamService extends DSpaceObjectService, DSpace int countBitstreamsWithoutPolicy(Context context) throws SQLException; List getNotReferencedBitstreams(Context context) throws SQLException; + + public Long getLastModified(Bitstream bitstream); } diff --git a/dspace-api/src/main/java/org/dspace/content/service/BundleService.java b/dspace-api/src/main/java/org/dspace/content/service/BundleService.java index 7d99aafe5f..e7fc0ac8f1 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/BundleService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/BundleService.java @@ -7,6 +7,11 @@ */ package org.dspace.content.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.content.Bitstream; @@ -15,30 +20,24 @@ import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.core.Context; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; - /** * Service interface class for the Bundle object. - * The implementation of this class is responsible for all business logic calls for the Bundle object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Bundle object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ -public interface BundleService extends DSpaceObjectService, DSpaceObjectLegacySupportService -{ +public interface BundleService extends DSpaceObjectService, DSpaceObjectLegacySupportService { /** * Create a new bundle, with a new ID and link it to the provided item * - * @param context - * DSpace context object - * @param item DSpace item - * @param name bundle name + * @param context DSpace context object + * @param item DSpace item + * @param name bundle name * @return the newly created bundle * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @throws SQLException if database error */ public Bundle create(Context context, Item item, String name) throws SQLException, AuthorizeException; @@ -47,15 +46,14 @@ public interface BundleService extends DSpaceObjectService, DSpaceObject /** * Add an existing bitstream to this bundle * - * @param context DSpace Context - * @param bundle the bitstream bundle - * @param bitstream - * the bitstream to add + * @param context DSpace Context + * @param bundle the bitstream bundle + * @param bitstream the bitstream to add * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @throws SQLException if database error */ public void addBitstream(Context context, Bundle bundle, Bitstream bitstream) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; /** @@ -67,48 +65,45 @@ public interface BundleService extends DSpaceObjectService, DSpaceObject * bitstream from the foreign key constraint so that the * cleanup process can run normally. * - * @param context DSpace Context - * @param bundle the bitstream bundle - * @param bitstream - * the bitstream to remove - * @throws IOException if IO error + * @param context DSpace Context + * @param bundle the bitstream bundle + * @param bitstream the bitstream to remove + * @throws IOException if IO error * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @throws SQLException if database error */ public void removeBitstream(Context context, Bundle bundle, Bitstream bitstream) throws AuthorizeException, - SQLException, IOException; + SQLException, IOException; /** * remove all policies on the bundle and its contents, and replace them with * the DEFAULT_BITSTREAM_READ policies belonging to the collection. * - * @param context DSpace Context - * @param bundle the bitstream bundle - * @param collection - * Collection - * @throws SQLException - * if an SQL error or if no default policies found. It's a bit - * draconian, but default policies must be enforced. + * @param context DSpace Context + * @param bundle the bitstream bundle + * @param collection Collection + * @throws SQLException if an SQL error or if no default policies found. It's a bit + * draconian, but default policies must be enforced. * @throws AuthorizeException if authorization error */ public void inheritCollectionDefaultPolicies(Context context, Bundle bundle, Collection collection) - throws java.sql.SQLException, AuthorizeException; + throws java.sql.SQLException, AuthorizeException; /** * remove all of the policies for the bundle and bitstream contents and replace * them with a new list of policies * - * @param context DSpace Context - * @param bundle the bitstream bundle + * @param context DSpace Context + * @param bundle the bitstream bundle * @param newpolicies - - * this will be all of the new policies for the bundle and - * bitstream contents - * @throws SQLException if database error + * this will be all of the new policies for the bundle and + * bitstream contents + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void replaceAllBitstreamPolicies(Context context, Bundle bundle, List newpolicies) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; public List getBitstreamPolicies(Context context, Bundle bundle) throws SQLException; @@ -116,10 +111,11 @@ public interface BundleService extends DSpaceObjectService, DSpaceObject /** * Changes bitstream order according to the array - * @param context DSpace Context - * @param bundle the bitstream bundle + * + * @param context DSpace Context + * @param bundle the bitstream bundle * @param bitstreamIds the identifiers in the order they are to be set - * @throws SQLException when an SQL error has occurred (querying DSpace) + * @throws SQLException when an SQL error has occurred (querying DSpace) * @throws AuthorizeException If the user can't make the changes */ public void setOrder(Context context, Bundle bundle, UUID bitstreamIds[]) throws AuthorizeException, SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java index 152e2d1ccf..f0ac1b0e4d 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java @@ -7,6 +7,13 @@ */ package org.dspace.content.service; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.MissingResourceException; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.Collection; @@ -15,60 +22,49 @@ import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.eperson.Group; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; -import java.util.MissingResourceException; - /** * Service interface class for the Collection object. - * The implementation of this class is responsible for all business logic calls for the Collection object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Collection object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ -public interface CollectionService extends DSpaceObjectService, DSpaceObjectLegacySupportService { +public interface CollectionService + extends DSpaceObjectService, DSpaceObjectLegacySupportService { /** * Create a new collection with a new ID. * Once created the collection is added to the given community * - * @param context - * DSpace context object + * @param context DSpace context object * @param community DSpace Community (parent) - * * @return the newly created collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Collection create(Context context, Community community) throws SQLException, - AuthorizeException; + AuthorizeException; /** * Create a new collection with the supplied handle and with a new ID. * Once created the collection is added to the given community * - * @param context - * DSpace context object + * @param context DSpace context object * @param community DSpace Community (parent) - * - * @param handle the pre-determined Handle to assign to the new community + * @param handle the pre-determined Handle to assign to the new community * @return the newly created collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Collection create(Context context, Community community, String handle) throws SQLException, - AuthorizeException; + AuthorizeException; /** * Get all collections in the system. These are alphabetically sorted by * collection name. * - * @param context - * DSpace context object - * + * @param context DSpace context object * @return the collections in the system * @throws SQLException if database error */ @@ -76,12 +72,10 @@ public interface CollectionService extends DSpaceObjectService, DSpa /** * Get all collections in the system. Adds support for limit and offset. - * @param context - * The relevant DSpace Context. - * @param limit - * paging limit - * @param offset - * paging offset + * + * @param context The relevant DSpace Context. + * @param limit paging limit + * @param offset paging offset * @return List of Collections * @throws SQLException if database error */ @@ -100,18 +94,16 @@ public interface CollectionService extends DSpaceObjectService, DSpa /** * Set a metadata value * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection - * @param field - * the name of the metadata field to get - * @param value - * value to set the field to - * + * @param field the name of the metadata field to get + * @param value value to set the field to * @throws MissingResourceException if resource missing - * @throws SQLException if database error + * @throws SQLException if database error */ @Deprecated - public void setMetadata(Context context, Collection collection, String field, String value) throws MissingResourceException, SQLException; + public void setMetadata(Context context, Collection collection, String field, String value) + throws MissingResourceException, SQLException; /** * Give the collection a logo. Passing in null removes any @@ -121,18 +113,17 @@ public interface CollectionService extends DSpaceObjectService, DSpa * effect. Setting a logo and not calling update later may * result in a previous logo lying around as an "orphaned" bitstream. * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection - * @param is the stream to use as the new logo - * - * @return the new logo bitstream, or null if there is no - * logo (null was passed in) + * @param is the stream to use as the new logo + * @return the new logo bitstream, or null if there is no + * logo (null was passed in) * @throws AuthorizeException if authorization error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error */ public Bitstream setLogo(Context context, Collection collection, InputStream is) throws AuthorizeException, - IOException, SQLException; + IOException, SQLException; /** * Create a workflow group for the given step if one does not already exist. @@ -141,17 +132,15 @@ public interface CollectionService extends DSpaceObjectService, DSpa * between the group and the collection is not written until * update is called. * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection - * @param step - * the step (1-3) of the workflow to create or get the group for - * + * @param step the step (1-3) of the workflow to create or get the group for * @return the workflow group associated with this collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Group createWorkflowGroup(Context context, Collection collection, int step) throws SQLException, - AuthorizeException; + AuthorizeException; /** * Set the workflow group corresponding to a particular workflow step. @@ -159,13 +148,11 @@ public interface CollectionService extends DSpaceObjectService, DSpa * group for that workflow step; any existing group is NOT deleted. * * @param collection Collection - * @param step - * the workflow step (1-3) - * @param group - * the new workflow group, or null + * @param step the workflow step (1-3) + * @param group the new workflow group, or null */ public void setWorkflowGroup(Context context, Collection collection, int step, Group group) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; /** * Get the the workflow group corresponding to a particular workflow step. @@ -173,9 +160,7 @@ public interface CollectionService extends DSpaceObjectService, DSpa * this collection for the given step. * * @param collection Collection - * @param step - * the workflow step (1-3) - * + * @param step the workflow step (1-3) * @return the group of reviewers or null */ public Group getWorkflowGroup(Collection collection, int step); @@ -186,10 +171,10 @@ public interface CollectionService extends DSpaceObjectService, DSpa * other groups may also be allowed to submit to this collection by the * authorization system. * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection * @return the default group of submitters associated with this collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Group createSubmitters(Context context, Collection collection) throws SQLException, AuthorizeException; @@ -199,9 +184,10 @@ public interface CollectionService extends DSpaceObjectService, DSpa * then return without error. This will merely dereference the current * submitters group from the collection so that it may be deleted * without violating database constraints. - * @param context DSpace Context + * + * @param context DSpace Context * @param collection Collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void removeSubmitters(Context context, Collection collection) throws SQLException, AuthorizeException; @@ -212,10 +198,10 @@ public interface CollectionService extends DSpaceObjectService, DSpa * Returns either the newly created group or the previously existing one. * Note that other groups may also be administrators. * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection * @return the default group of editors associated with this collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Group createAdministrators(Context context, Collection collection) throws SQLException, AuthorizeException; @@ -225,9 +211,10 @@ public interface CollectionService extends DSpaceObjectService, DSpa * then return without error. This will merely dereference the current * administrators group from the collection so that it may be deleted * without violating database constraints. - * @param context DSpace Context + * + * @param context DSpace Context * @param collection Collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void removeAdministrators(Context context, Collection collection) throws SQLException, AuthorizeException; @@ -256,9 +243,9 @@ public interface CollectionService extends DSpaceObjectService, DSpa * the collection after doing this, or the item will have been created but * the collection record will not refer to it. * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void createTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException; @@ -270,13 +257,14 @@ public interface CollectionService extends DSpaceObjectService, DSpa * any other changes made; in other words, this method does an * update. * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ - public void removeTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException, IOException; + public void removeTemplateItem(Context context, Collection collection) + throws SQLException, AuthorizeException, IOException; /** * Add an item to the collection. This simply adds a relationship between @@ -284,11 +272,10 @@ public interface CollectionService extends DSpaceObjectService, DSpa * remove a personal workspace item etc. This has instant effect; * update need not be called. * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection - * @param item - * item to add - * @throws SQLException if database error + * @param item item to add + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void addItem(Context context, Collection collection, Item item) throws SQLException, AuthorizeException; @@ -296,40 +283,39 @@ public interface CollectionService extends DSpaceObjectService, DSpa /** * Remove an item. If the item is then orphaned, it is deleted. * - * @param context DSpace Context + * @param context DSpace Context * @param collection Collection - * @param item - * item to remove - * @throws SQLException if database error + * @param item item to remove + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public void removeItem(Context context, Collection collection, Item item) throws SQLException, AuthorizeException, - IOException; + IOException; public boolean canEditBoolean(Context context, Collection collection) throws SQLException; - public boolean canEditBoolean(Context context, Collection collection, boolean useInheritance) throws java.sql.SQLException; + public boolean canEditBoolean(Context context, Collection collection, boolean useInheritance) + throws java.sql.SQLException; public void canEdit(Context context, Collection collection) throws SQLException, AuthorizeException; - public void canEdit(Context context, Collection collection, boolean useInheritance) throws SQLException, AuthorizeException; + public void canEdit(Context context, Collection collection, boolean useInheritance) + throws SQLException, AuthorizeException; /** * return an array of collections that user has a given permission on * (useful for trimming 'select to collection' list) or figuring out which * collections a person is an editor for. * - * @param context DSpace Context - * @param community - * (optional) restrict search to a community, else null - * @param actionID - * of the action - * + * @param context DSpace Context + * @param community (optional) restrict search to a community, else null + * @param actionID of the action * @return Collection [] of collections with matching permissions * @throws SQLException if database error */ - public List findAuthorized(Context context, Community community, int actionID) throws java.sql.SQLException; + public List findAuthorized(Context context, Community community, int actionID) + throws java.sql.SQLException; public Collection findByGroup(Context context, Group group) throws SQLException; @@ -339,6 +325,7 @@ public interface CollectionService extends DSpaceObjectService, DSpa /** * The map entry returned contains a collection as a key and sum of bitstream sizes in bytes as a value + * * @param context DSpace Context * @return List of Collections and bitstream sizes map * @throws SQLException if database error diff --git a/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java b/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java index 1e20b0470e..6284b27e25 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java @@ -7,6 +7,12 @@ */ package org.dspace.content.service; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.List; +import java.util.MissingResourceException; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.Collection; @@ -14,31 +20,23 @@ import org.dspace.content.Community; import org.dspace.core.Context; import org.dspace.eperson.Group; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.List; -import java.util.MissingResourceException; - /** * Service interface class for the Community object. - * The implementation of this class is responsible for all business logic calls for the Community object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Community object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ -public interface CommunityService extends DSpaceObjectService, DSpaceObjectLegacySupportService -{ +public interface CommunityService extends DSpaceObjectService, DSpaceObjectLegacySupportService { /** * Create a new top-level community, with a new ID. * - * @param parent parent community - * @param context - * DSpace context object - * + * @param parent parent community + * @param context DSpace context object * @return the newly created community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Community create(Community parent, Context context) throws SQLException, AuthorizeException; @@ -47,26 +45,22 @@ public interface CommunityService extends DSpaceObjectService, DSpace /** * Create a new top-level community, with a new ID. * - * @param parent parent community - * @param context - * DSpace context object - * @param handle the pre-determined Handle to assign to the new community - * + * @param parent parent community + * @param context DSpace context object + * @param handle the pre-determined Handle to assign to the new community * @return the newly created community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Community create(Community parent, Context context, String handle) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; /** * Get a list of all communities in the system. These are alphabetically * sorted by community name. * - * @param context - * DSpace context object - * + * @param context DSpace context object * @return the communities in the system * @throws SQLException if database error */ @@ -74,9 +68,10 @@ public interface CommunityService extends DSpaceObjectService, DSpace /** * Get all communities in the system. Adds support for limit and offset. + * * @param context context - * @param limit limit - * @param offset offset + * @param limit limit + * @param offset offset * @return list of communities * @throws SQLException if database error */ @@ -87,9 +82,7 @@ public interface CommunityService extends DSpaceObjectService, DSpace * alphabetically sorted by community name. A top-level community is one * without a parent community. * - * @param context - * DSpace context object - * + * @param context DSpace context object * @return the top-level communities in the system * @throws SQLException if database error */ @@ -99,13 +92,9 @@ public interface CommunityService extends DSpaceObjectService, DSpace * Get the value of a metadata field * * @param community community - * @param field - * the name of the metadata field to get - * + * @param field the name of the metadata field to get * @return the value of the metadata field - * - * @throws IllegalArgumentException - * if the requested metadata field doesn't exist + * @throws IllegalArgumentException if the requested metadata field doesn't exist * @deprecated */ @Override @@ -116,21 +105,18 @@ public interface CommunityService extends DSpaceObjectService, DSpace /** * Set a metadata value * - * @param context context + * @param context context * @param community community - * @param field - * the name of the metadata field to get - * @param value - * value to set the field to - * - * @throws IllegalArgumentException - * if the requested metadata field doesn't exist + * @param field the name of the metadata field to get + * @param value value to set the field to + * @throws IllegalArgumentException if the requested metadata field doesn't exist * @throws MissingResourceException if resource missing - * @throws SQLException if database error + * @throws SQLException if database error * @deprecated */ @Deprecated - public void setMetadata(Context context, Community community, String field, String value) throws MissingResourceException, SQLException; + public void setMetadata(Context context, Community community, String field, String value) + throws MissingResourceException, SQLException; /** * Give the community a logo. Passing in null removes any @@ -140,28 +126,27 @@ public interface CommunityService extends DSpaceObjectService, DSpace * effect. Setting a logo and not calling update later may * result in a previous logo lying around as an "orphaned" bitstream. * - * @param context context + * @param context context * @param community community - * @param is the stream to use as the new logo - * - * @return the new logo bitstream, or null if there is no - * logo (null was passed in) - * @throws IOException if IO error - * @throws SQLException if database error + * @param is the stream to use as the new logo + * @return the new logo bitstream, or null if there is no + * logo (null was passed in) + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Bitstream setLogo(Context context, Community community, InputStream is) throws AuthorizeException, - IOException, SQLException; + IOException, SQLException; /** * Create a default administrators group if one does not already exist. * Returns either the newly created group or the previously existing one. * Note that other groups may also be administrators. * - * @param context context + * @param context context * @param community community * @return the default group of editors associated with this community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Group createAdministrators(Context context, Community community) throws SQLException, AuthorizeException; @@ -171,9 +156,10 @@ public interface CommunityService extends DSpaceObjectService, DSpace * then return without error. This will merely dereference the current * administrators group from the community so that it may be deleted * without violating database constraints. - * @param context context + * + * @param context context * @param community community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void removeAdministrators(Context context, Community community) throws SQLException, AuthorizeException; @@ -182,7 +168,7 @@ public interface CommunityService extends DSpaceObjectService, DSpace * Return an array of parent communities of this community, in ascending * order. If community is top-level, return an empty array. * - * @param context context + * @param context context * @param community community * @return an array of parent communities, empty if top-level * @throws SQLException if database error @@ -192,10 +178,8 @@ public interface CommunityService extends DSpaceObjectService, DSpace /** * Return an array of parent communities of this collection. * - * @param context - * The relevant DSpace Context. - * @param collection - * collection to check + * @param context The relevant DSpace Context. + * @param collection collection to check * @return an array of parent communities * @throws SQLException if database error */ @@ -204,7 +188,7 @@ public interface CommunityService extends DSpaceObjectService, DSpace /** * Return an array of collections of this community and its subcommunities * - * @param context context + * @param context context * @param community community * @return an array of collections * @throws SQLException if database error @@ -216,89 +200,86 @@ public interface CommunityService extends DSpaceObjectService, DSpace /** * Add an exisiting collection to the community * - * @param context context - * @param community community - * @param collection - * collection to add - * @throws SQLException if database error + * @param context context + * @param community community + * @param collection collection to add + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void addCollection(Context context, Community community, Collection collection) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; /** * Create a new sub-community within this community. * - * @param context context + * @param context context * @param parentCommunity parent community * @return the new community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public Community createSubcommunity(Context context, Community parentCommunity) throws SQLException, AuthorizeException; + public Community createSubcommunity(Context context, Community parentCommunity) + throws SQLException, AuthorizeException; /** * Create a new sub-community within this community. * - * @param context context - * @param handle the pre-determined Handle to assign to the new community + * @param context context + * @param handle the pre-determined Handle to assign to the new community * @param parentCommunity parent community * @return the new community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Community createSubcommunity(Context context, Community parentCommunity, String handle) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; /** * Add an existing community as a subcommunity to the community * - * @param context context - * @param parentCommunity - * parent community to add our subcommunity to - * @param childCommunity - * subcommunity to add - * @throws SQLException if database error + * @param context context + * @param parentCommunity parent community to add our subcommunity to + * @param childCommunity subcommunity to add + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void addSubcommunity(Context context, Community parentCommunity, Community childCommunity) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; /** * Remove a collection. If it only belongs to one parent community, * then it is permanently deleted. If it has more than one parent community, * it is simply unmapped from the current community. * - * @param context context - * @param c collection to remove + * @param context context + * @param c collection to remove * @param community community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public void removeCollection(Context context, Community community, Collection c) - throws SQLException, AuthorizeException, IOException; + throws SQLException, AuthorizeException, IOException; /** * Remove a subcommunity. If it only belongs to one parent community, * then it is permanently deleted. If it has more than one parent community, * it is simply unmapped from the current community. * - * @param context context - * @param childCommunity - * subcommunity to remove + * @param context context + * @param childCommunity subcommunity to remove * @param parentCommunity parent community - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public void removeSubcommunity(Context context, Community parentCommunity, Community childCommunity) - throws SQLException, AuthorizeException, IOException; + throws SQLException, AuthorizeException, IOException; /** * return TRUE if context's user can edit community, false otherwise * - * @param context context + * @param context context * @param community community * @return boolean true = current user can edit community * @throws SQLException if database error diff --git a/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectLegacySupportService.java b/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectLegacySupportService.java index b5023f4afa..79f47400c3 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectLegacySupportService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectLegacySupportService.java @@ -7,17 +7,17 @@ */ package org.dspace.content.service; +import java.sql.SQLException; + import org.dspace.content.DSpaceObject; import org.dspace.core.Context; -import java.sql.SQLException; - /** * Service interface class that adds support to retrieve DSpaceObject by the old integer based identifier which was used * to identify DSpaceObjects prior to DSpace 6.0 * - * @author kevinvandevelde at atmire.com * @param class type + * @author kevinvandevelde at atmire.com */ public interface DSpaceObjectLegacySupportService { @@ -29,7 +29,7 @@ public interface DSpaceObjectLegacySupportService { * a pair of type number and database ID. * * @param context - the context - * @param id - the legacy id within table of type'd objects + * @param id - the legacy id within table of type'd objects * @return the object found, or null if it does not exist. * @throws java.sql.SQLException only upon failure accessing the database. */ diff --git a/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectService.java b/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectService.java index 6f111fcd86..2ab4f2b8b1 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectService.java @@ -7,37 +7,36 @@ */ package org.dspace.content.service; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.DSpaceObject; -import org.dspace.content.MetadataField; -import org.dspace.content.MetadataValue; -import org.dspace.core.Context; - import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataValue; +import org.dspace.core.Context; + /** * Service interface class for the DSpaceObject. - * All DSpaceObject service classes should implement this class since it offers some basic methods which all DSpaceObjects + * All DSpaceObject service classes should implement this class since it offers some basic methods which all + * DSpaceObjects * are required to have. * - * @author kevinvandevelde at atmire.com * @param class type + * @author kevinvandevelde at atmire.com */ public interface DSpaceObjectService { - - /** * Generic find for when the precise type of a DSO is not known, just the * a pair of type number and database ID. * * @param context - the context - * @param id - id within table of type'd objects + * @param id - id within table of type'd objects * @return the object found, or null if it does not exist. * @throws SQLException only upon failure accessing the database. */ @@ -49,15 +48,16 @@ public interface DSpaceObjectService { * * @param dso DSpaceObject * @return Name for the object, or null if it doesn't have - * one + * one */ public abstract String getName(T dso); /** * Tries to lookup all Identifiers of this DSpaceObject. + * * @param context DSpace context - * @param dso DSpaceObject + * @param dso DSpaceObject * @return An array containing all found identifiers or an array with a length of 0. */ public ArrayList getIdentifiers(Context context, T dso); @@ -71,9 +71,9 @@ public interface DSpaceObjectService { * the object self. * * @param context DSpace context - * @param dso DSpaceObject + * @param dso DSpaceObject * @return the dspace object that "own" the current object in - * the hierarchy + * the hierarchy * @throws SQLException if database error */ public DSpaceObject getParentObject(Context context, T dso) throws SQLException; @@ -87,23 +87,22 @@ public interface DSpaceObjectService { * needed. * * @param context DSpace context - * @param dso DSpaceObject - * @param action - * ID of action being attempted, from - * org.dspace.core.Constants. The ADMIN action is - * not a valid parameter for this method, an - * IllegalArgumentException should be thrown + * @param dso DSpaceObject + * @param action ID of action being attempted, from + * org.dspace.core.Constants. The ADMIN action is + * not a valid parameter for this method, an + * IllegalArgumentException should be thrown * @return the dspace object, if any, where an ADMIN action is sufficient to - * grant the original action - * @throws SQLException if database error - * @throws IllegalArgumentException - * if the ADMIN action is supplied as parameter of the method - * call + * grant the original action + * @throws SQLException if database error + * @throws IllegalArgumentException if the ADMIN action is supplied as parameter of the method + * call */ public DSpaceObject getAdminObject(Context context, T dso, int action) throws SQLException; /** * Provide the text name of the type of this DSpaceObject. It is most likely all uppercase. + * * @param dso DSpaceObject * @return Object type as text */ @@ -136,37 +135,33 @@ public interface DSpaceObjectService { * combination is significant. When retrieving with wildcards, values of a * particular element/qualifier/language combinations will be adjacent, but * the overall ordering of the combinations is indeterminate. + * * @param dSpaceObject DSpaceObject - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the element name. DSpaceObject.ANY matches any - * element. null doesn't really make sense as all - * metadata must have an element. - * @param qualifier - * the qualifier. null means unqualified, and - * DSpaceObject.ANY means any qualifier (including - * unqualified.) - * @param lang - * the ISO639 language code, optionally followed by an underscore - * and the ISO3166 country code. null means only - * values with no language are returned, and - * DSpaceObject.ANY means values with any country code or - * no country code are returned. - * + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the element name. DSpaceObject.ANY matches any + * element. null doesn't really make sense as all + * metadata must have an element. + * @param qualifier the qualifier. null means unqualified, and + * DSpaceObject.ANY means any qualifier (including + * unqualified.) + * @param lang the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means only + * values with no language are returned, and + * DSpaceObject.ANY means values with any country code or + * no country code are returned. * @return metadata fields that match the parameters */ - public List getMetadata(T dSpaceObject, String schema, String element, String qualifier, String lang); + public List getMetadata(T dSpaceObject, String schema, String element, String qualifier, + String lang); /** * Retrieve metadata field values from a given metadata string * of the form {@code .[.|.*]} * * @param dSpaceObject DSpaceObject - * @param mdString - * The metadata string of the form - * {@code .[.|.*]} + * @param mdString The metadata string of the form + * {@code .[.|.*]} * @return metadata fields that match the parameters */ public List getMetadataByMetadataString(T dSpaceObject, String mdString); @@ -176,20 +171,17 @@ public interface DSpaceObjectService { * Get the value of a metadata field * * @param dSpaceObject DSpaceObject - * @param value - * the name of the metadata field to get - * + * @param value the name of the metadata field to get * @return the value of the metadata field (or null if the column is an SQL NULL) - * - * @throws IllegalArgumentException - * if the requested metadata field doesn't exist + * @throws IllegalArgumentException if the requested metadata field doesn't exist */ public String getMetadata(T dSpaceObject, String value); public List getMetadata(T dSpaceObject, String mdString, String authority); - public List getMetadata(T dSpaceObject, String schema, String element, String qualifier, String lang, String authority); + public List getMetadata(T dSpaceObject, String schema, String element, String qualifier, String lang, + String authority); /** * Add metadata fields. These are appended to existing values. @@ -199,136 +191,116 @@ public interface DSpaceObjectService { * If metadata authority control is available, try to get authority * values. The authority confidence depends on whether authority is * required or not. - * - * @param context DSpace context - * @param dso DSpaceObject - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the metadata element name - * @param qualifier - * the metadata qualifier name, or null for - * unqualified - * @param lang - * the ISO639 language code, optionally followed by an underscore - * and the ISO3166 country code. null means the - * value has no language (for example, a date). - * @param values - * the values to add. + * + * @param context DSpace context + * @param dso DSpaceObject + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the metadata element name + * @param qualifier the metadata qualifier name, or null for + * unqualified + * @param lang the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means the + * value has no language (for example, a date). + * @param values the values to add. * @throws SQLException if database error */ - public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, List values) throws SQLException; + public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + List values) throws SQLException; /** * Add metadata fields. These are appended to existing values. * Use clearDC to remove values. The ordering of values * passed in is maintained. - * - * @param context DSpace context - * @param dso DSpaceObject - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the metadata element name - * @param qualifier - * the metadata qualifier name, or null for - * unqualified - * @param lang - * the ISO639 language code, optionally followed by an underscore - * and the ISO3166 country code. null means the - * value has no language (for example, a date). - * @param values - * the values to add. - * @param authorities - * the external authority key for this value (or null) - * @param confidences - * the authority confidence (default 0) + * + * @param context DSpace context + * @param dso DSpaceObject + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the metadata element name + * @param qualifier the metadata qualifier name, or null for + * unqualified + * @param lang the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means the + * value has no language (for example, a date). + * @param values the values to add. + * @param authorities the external authority key for this value (or null) + * @param confidences the authority confidence (default 0) * @throws SQLException if database error */ - public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, List values, List authorities, List confidences) throws SQLException; + public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + List values, List authorities, List confidences) + throws SQLException; /** * Add metadata fields. These are appended to existing values. * Use clearDC to remove values. The ordering of values * passed in is maintained. - * - * @param context DSpace context - * @param dso DSpaceObject - * @param metadataField - * the metadata field to which the value is to be set - * @param lang - * the ISO639 language code, optionally followed by an underscore - * and the ISO3166 country code. null means the - * value has no language (for example, a date). - * @param values - * the values to add. - * @param authorities - * the external authority key for this value (or null) - * @param confidences - * the authority confidence (default 0) + * + * @param context DSpace context + * @param dso DSpaceObject + * @param metadataField the metadata field to which the value is to be set + * @param lang the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means the + * value has no language (for example, a date). + * @param values the values to add. + * @param authorities the external authority key for this value (or null) + * @param confidences the authority confidence (default 0) * @throws SQLException if database error */ - public void addMetadata(Context context, T dso, MetadataField metadataField, String lang, List values, List authorities, List confidences) throws SQLException; + public void addMetadata(Context context, T dso, MetadataField metadataField, String lang, List values, + List authorities, List confidences) throws SQLException; - public void addMetadata(Context context, T dso, MetadataField metadataField, String language, String value, String authority, int confidence) throws SQLException; + public void addMetadata(Context context, T dso, MetadataField metadataField, String language, String value, + String authority, int confidence) throws SQLException; - public void addMetadata(Context context, T dso, MetadataField metadataField, String language, String value) throws SQLException; + public void addMetadata(Context context, T dso, MetadataField metadataField, String language, String value) + throws SQLException; - public void addMetadata(Context context, T dso, MetadataField metadataField, String language, List values) throws SQLException; + public void addMetadata(Context context, T dso, MetadataField metadataField, String language, List values) + throws SQLException; /** * Add a single metadata field. This is appended to existing * values. Use clearDC to remove values. * - * @param context DSpace context - * @param dso DSpaceObject - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the metadata element name - * @param qualifier - * the metadata qualifier, or null for - * unqualified - * @param lang - * the ISO639 language code, optionally followed by an underscore - * and the ISO3166 country code. null means the - * value has no language (for example, a date). - * @param value - * the value to add. + * @param context DSpace context + * @param dso DSpaceObject + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the metadata element name + * @param qualifier the metadata qualifier, or null for + * unqualified + * @param lang the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means the + * value has no language (for example, a date). + * @param value the value to add. * @throws SQLException if database error */ - public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, String value) throws SQLException; + public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + String value) throws SQLException; /** * Add a single metadata field. This is appended to existing * values. Use clearDC to remove values. * - * @param context DSpace context - * @param dso DSpaceObject - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the metadata element name - * @param qualifier - * the metadata qualifier, or null for - * unqualified - * @param lang - * the ISO639 language code, optionally followed by an underscore - * and the ISO3166 country code. null means the - * value has no language (for example, a date). - * @param value - * the value to add. - * @param authority - * the external authority key for this value (or null) - * @param confidence - * the authority confidence (default 0) + * @param context DSpace context + * @param dso DSpaceObject + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the metadata element name + * @param qualifier the metadata qualifier, or null for + * unqualified + * @param lang the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means the + * value has no language (for example, a date). + * @param value the value to add. + * @param authority the external authority key for this value (or null) + * @param confidence the authority confidence (default 0) * @throws SQLException if database error */ - public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, String value, String authority, int confidence) throws SQLException; + public void addMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + String value, String authority, int confidence) throws SQLException; /** * Clear metadata values. As with getDC above, @@ -338,53 +310,49 @@ public interface DSpaceObjectService { * Thus, dspaceobject.clearDC(Item.ANY, Item.ANY, Item.ANY) will * remove all Dublin Core metadata associated with an DSpaceObject. * - * @param context DSpace context - * @param dso DSpaceObject - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the Dublin Core element to remove, or Item.ANY - * @param qualifier - * the qualifier. null means unqualified, and - * Item.ANY means any qualifier (including - * unqualified.) - * @param lang - * the ISO639 language code, optionally followed by an underscore - * and the ISO3166 country code. null means only - * values with no language are removed, and Item.ANY - * means values with any country code or no country code are - * removed. + * @param context DSpace context + * @param dso DSpaceObject + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the Dublin Core element to remove, or Item.ANY + * @param qualifier the qualifier. null means unqualified, and + * Item.ANY means any qualifier (including + * unqualified.) + * @param lang the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means only + * values with no language are removed, and Item.ANY + * means values with any country code or no country code are + * removed. * @throws SQLException if database error */ - public void clearMetadata(Context context, T dso, String schema, String element, String qualifier, String lang) throws SQLException; + public void clearMetadata(Context context, T dso, String schema, String element, String qualifier, String lang) + throws SQLException; public void removeMetadataValues(Context context, T dso, List values) throws SQLException; public String getMetadataFirstValue(T dso, String schema, String element, String qualifier, String language); + /** * Set first metadata field value - * @param context DSpace context - * @param dso DSpaceObject - * @param schema - * the schema for the metadata field. Must match - * the name of an existing metadata schema. - * @param element - * the Dublin Core element to remove, or Item.ANY - * @param qualifier - * the qualifier. null means unqualified, and - * Item.ANY means any qualifier (including - * unqualified.) - * @param language - * the ISO639 language code, optionally followed by an underscore - * and the ISO3166 country code. null means only - * values with no language are removed, and Item.ANY - * means values with any country code or no country code are - * removed. - * @param value metadata value + * + * @param context DSpace context + * @param dso DSpaceObject + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the Dublin Core element to remove, or Item.ANY + * @param qualifier the qualifier. null means unqualified, and + * Item.ANY means any qualifier (including + * unqualified.) + * @param language the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means only + * values with no language are removed, and Item.ANY + * means values with any country code or no country code are + * removed. + * @param value metadata value * @throws SQLException if database error */ - public void setMetadataSingleValue(Context context, T dso, String schema, String element, String qualifier, String language, String value) throws SQLException; + public void setMetadataSingleValue(Context context, T dso, String schema, String element, String qualifier, + String language, String value) throws SQLException; public void updateLastModified(Context context, T dso) throws SQLException, AuthorizeException; @@ -400,4 +368,12 @@ public interface DSpaceObjectService { */ public int getSupportsTypeConstant(); + void addAndShiftRightMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + String value, String authority, int confidence, int index) throws SQLException; + + void replaceMetadata(Context context, T dso, String schema, String element, String qualifier, String lang, + String value, String authority, int confidence, int index) throws SQLException; + + void moveMetadata(Context context, T dso, String schema, String element, String qualifier, int from, int to) + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/service/InProgressSubmissionService.java b/dspace-api/src/main/java/org/dspace/content/service/InProgressSubmissionService.java index c08935bda7..4396c4ce08 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/InProgressSubmissionService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/InProgressSubmissionService.java @@ -7,37 +7,45 @@ */ package org.dspace.content.service; +import java.sql.SQLException; + +import org.dspace.app.util.DCInputsReaderException; import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Collection; import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; -import java.sql.SQLException; - /** * Service interface class for the InProgressSubmission. - * All InProgressSubmission service classes should implement this class since it offers some basic methods which all InProgressSubmissions + * All InProgressSubmission service classes should implement this class since it offers some basic methods which all + * InProgressSubmissions * are required to have. * - * @author kevinvandevelde at atmire.com * @param class type + * @author kevinvandevelde at atmire.com */ public interface InProgressSubmissionService { /** * Deletes submission wrapper, doesn't delete item contents - * @param context context + * + * @param context context * @param inProgressSubmission submission - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void deleteWrapper(Context context, T inProgressSubmission) throws SQLException, AuthorizeException; /** * Update the submission, including the unarchived item. - * @param context context + * + * @param context context * @param inProgressSubmission submission - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void update(Context context, T inProgressSubmission) throws SQLException, AuthorizeException; + + public void move(Context context, T inProgressSubmission, Collection fromCollection, Collection toCollection) + throws DCInputsReaderException; } diff --git a/dspace-api/src/main/java/org/dspace/content/service/InstallItemService.java b/dspace-api/src/main/java/org/dspace/content/service/InstallItemService.java index 3fe6e1e4f0..67ac2e2049 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/InstallItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/InstallItemService.java @@ -7,14 +7,14 @@ */ package org.dspace.content.service; +import java.io.IOException; +import java.sql.SQLException; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.InProgressSubmission; import org.dspace.content.Item; import org.dspace.core.Context; -import java.io.IOException; -import java.sql.SQLException; - /** * Support to install an Item in the archive. * @@ -27,35 +27,29 @@ public interface InstallItemService { * Take an InProgressSubmission and turn it into a fully-archived Item, * creating a new Handle. * - * @param context - * DSpace Context - * @param is - * submission to install - * + * @param context DSpace Context + * @param is submission to install * @return the fully archived Item - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Item installItem(Context context, InProgressSubmission is) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; /** * Take an InProgressSubmission and turn it into a fully-archived Item. * - * @param c current context - * @param is - * submission to install - * @param suppliedHandle - * the existing Handle to give to the installed item - * + * @param c current context + * @param is submission to install + * @param suppliedHandle the existing Handle to give to the installed item * @return the fully archived Item - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Item installItem(Context c, InProgressSubmission is, - String suppliedHandle) throws SQLException, - IOException, AuthorizeException; + String suppliedHandle) throws SQLException, + IOException, AuthorizeException; /** * Turn an InProgressSubmission into a fully-archived Item, for @@ -65,20 +59,17 @@ public interface InstallItemService { * ingest mechanism is assumed to have set all relevant technical * and administrative metadata fields. * - * @param c current context - * @param is - * submission to install - * @param suppliedHandle - * the existing Handle to give the installed item, or null - * to create a new one. - * + * @param c current context + * @param is submission to install + * @param suppliedHandle the existing Handle to give the installed item, or null + * to create a new one. * @return the fully archived Item - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Item restoreItem(Context c, InProgressSubmission is, - String suppliedHandle) throws SQLException, IOException, AuthorizeException; + String suppliedHandle) throws SQLException, IOException, AuthorizeException; /** * Generate provenance-worthy description of the bitstreams contained in an @@ -86,11 +77,10 @@ public interface InstallItemService { * * @param context context * @param myitem the item to generate description for - * * @return provenance description * @throws SQLException if database error */ public String getBitstreamProvenanceMessage(Context context, Item myitem) - throws SQLException; + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java index 75aaffda27..bfc01fbf84 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java @@ -7,13 +7,6 @@ */ package org.dspace.content.service; -import org.dspace.authorize.AuthorizeException; -import org.dspace.authorize.ResourcePolicy; -import org.dspace.content.*; -import org.dspace.core.Context; -import org.dspace.eperson.EPerson; -import org.dspace.eperson.Group; - import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; @@ -22,14 +15,28 @@ import java.util.Iterator; import java.util.List; import java.util.UUID; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.ResourcePolicy; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.Thumbnail; +import org.dspace.content.WorkspaceItem; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; + /** * Service interface class for the Item object. - * The implementation of this class is responsible for all business logic calls for the Item object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Item object and is autowired + * by spring * * @author kevinvandevelde at atmire.com */ -public interface ItemService extends DSpaceObjectService, DSpaceObjectLegacySupportService -{ +public interface ItemService extends DSpaceObjectService, DSpaceObjectLegacySupportService { public Thumbnail getThumbnail(Context context, Item item, boolean requireOriginal) throws SQLException; /** @@ -37,10 +44,10 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * since items need to be created as workspace items. Authorisation is the * responsibility of the caller. * - * @param context DSpace context object + * @param context DSpace context object * @param workspaceItem in progress workspace item * @return the newly created item - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Item create(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException; @@ -51,10 +58,10 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * the collection after doing this, or the item will have been created but * the collection record will not refer to it. * - * @param context DSpace context object + * @param context DSpace context object * @param collection Collection (parent) * @return empty template item for this collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Item createTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException; @@ -74,8 +81,8 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * set are included. The order of the list is indeterminate. * * @param context DSpace context object - * @param limit limit - * @param offset offset + * @param limit limit + * @param offset offset * @return an iterator over the items in the archive. * @throws SQLException if database error */ @@ -85,8 +92,7 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * Get all "final" items in the archive, both archived ("in archive" flag) or * withdrawn items are included. The order of the list is indeterminate. * - * @param context - * DSpace context object + * @param context DSpace context object * @return an iterator over the items in the archive. * @throws SQLException if database error */ @@ -96,32 +102,30 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * Find all the items in the archive by a given submitter. The order is * indeterminate. Only items with the "in archive" flag set are included. * - * @param context - * DSpace context object - * @param eperson - * the submitter + * @param context DSpace context object + * @param eperson the submitter * @return an iterator over the items submitted by eperson * @throws SQLException if database error */ public Iterator findBySubmitter(Context context, EPerson eperson) - throws SQLException; + throws SQLException; /** * Retrieve the list of items submitted by eperson, ordered by recently submitted, optionally limitable * * @param context DSpace context object - * @param eperson - * the submitter - * @param limit a positive integer to limit, -1 or null for unlimited + * @param eperson the submitter + * @param limit a positive integer to limit, -1 or null for unlimited * @return an iterator over the items submitted by eperson * @throws SQLException if database error */ - public Iterator findBySubmitterDateSorted(Context context, EPerson eperson, Integer limit) throws SQLException; + public Iterator findBySubmitterDateSorted(Context context, EPerson eperson, Integer limit) + throws SQLException; /** - * Get all the items in this collection. The order is indeterminate. + * Get all the archived items in this collection. The order is indeterminate. * - * @param context DSpace context object + * @param context DSpace context object * @param collection Collection (parent) * @return an iterator over the items in the collection. * @throws SQLException if database error @@ -129,32 +133,56 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega public Iterator findByCollection(Context context, Collection collection) throws SQLException; /** - * Get all the items in this collection. The order is indeterminate. + * Get all the archived items in this collection. The order is indeterminate. * - * @param context DSpace context object + * @param context DSpace context object * @param collection Collection (parent) - * @param limit limited number of items - * @param offset offset value + * @param limit limited number of items + * @param offset offset value * @return an iterator over the items in the collection. * @throws SQLException if database error */ - public Iterator findByCollection(Context context, Collection collection, Integer limit, Integer offset) throws SQLException; + public Iterator findByCollection(Context context, Collection collection, Integer limit, Integer offset) + throws SQLException; + + /** + * Get all the items (including private and withdrawn) in this collection. The order is indeterminate. + * + * @param context DSpace context object + * @param collection Collection (parent) + * @return an iterator over the items in the collection. + * @param limit limited number of items + * @param offset offset value + * @throws SQLException if database error + */ + public Iterator findAllByCollection(Context context, Collection collection, Integer limit, Integer offset) + throws SQLException; /** * Get all Items installed or withdrawn, discoverable, and modified since a Date. * * @param context DSpace context object - * @param since earliest interesting last-modified date, or null for no date test. + * @param since earliest interesting last-modified date, or null for no date test. * @return an iterator over the items in the collection. * @throws SQLException if database error */ public Iterator findInArchiveOrWithdrawnDiscoverableModifiedSince(Context context, Date since) + throws SQLException; + + /** + * Get all Items installed or withdrawn, NON-discoverable, and modified since a Date. + * @param context context + * @param since earliest interesting last-modified date, or null for no date test. + * @return an iterator over the items in the collection. + * @throws SQLException if database error + */ + public Iterator findInArchiveOrWithdrawnNonDiscoverableModifiedSince(Context context, Date since) throws SQLException; /** - * Get all the items in this collection. The order is indeterminate. + * Get all the items (including private and withdrawn) in this collection. The order is indeterminate. * - * @param context DSpace context object + * @param context DSpace context object * @param collection Collection (parent) * @return an iterator over the items in the collection. * @throws SQLException if database error @@ -164,7 +192,7 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega /** * See whether this Item is contained by a given Collection. * - * @param item item to check + * @param item item to check * @param collection Collection (parent * @return true if {@code collection} contains this Item. * @throws SQLException if database error @@ -177,7 +205,7 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * communities of the owning collections. * * @param context DSpace context object - * @param item item to check + * @param item item to check * @return the communities this item is in. * @throws SQLException if database error */ @@ -188,11 +216,9 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * Get the bundles matching a bundle name (name corresponds roughly to type) * * @param item item to check - * @param name - * name of bundle (ORIGINAL/TEXT/THUMBNAIL) - * @throws SQLException if database error - * + * @param name name of bundle (ORIGINAL/TEXT/THUMBNAIL) * @return the bundles in an unordered array + * @throws SQLException if database error */ public List getBundles(Item item, String name) throws SQLException; @@ -200,10 +226,9 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * Add an existing bundle to this item. This has immediate effect. * * @param context DSpace context object - * @param item item to add the bundle to - * @param bundle - * the bundle to add - * @throws SQLException if database error + * @param item item to add the bundle to + * @param bundle the bundle to add + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void addBundle(Context context, Item item, Bundle bundle) throws SQLException, AuthorizeException; @@ -213,26 +238,24 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * bundle is orphaned. * * @param context DSpace context object - * @param item Item - * @param bundle - * the bundle to remove - * @throws SQLException if database error + * @param item Item + * @param bundle the bundle to remove + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public void removeBundle(Context context, Item item, Bundle bundle) throws SQLException, AuthorizeException, - IOException; + IOException; /** * Remove all bundles linked to this item. This may result in the bundle being deleted, if the * bundle is orphaned. * * @param context DSpace context object - * @param item - * the item from which to remove all bundles - * @throws SQLException if database error + * @param item the item from which to remove all bundles + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public void removeAllBundles(Context context, Item item) throws AuthorizeException, SQLException, IOException; @@ -241,33 +264,30 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * method for the most common use. * * @param context DSpace context object - * @param item item to create bitstream on - * @param is - * the stream to create the new bitstream from - * @param name - * is the name of the bundle (ORIGINAL, TEXT, THUMBNAIL) + * @param item item to create bitstream on + * @param is the stream to create the new bitstream from + * @param name is the name of the bundle (ORIGINAL, TEXT, THUMBNAIL) * @return Bitstream that is created * @throws AuthorizeException if authorization error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error */ public Bitstream createSingleBitstream(Context context, InputStream is, Item item, String name) - throws AuthorizeException, IOException, SQLException; + throws AuthorizeException, IOException, SQLException; /** * Convenience method, calls createSingleBitstream() with name "ORIGINAL" * * @param context DSpace context object - * @param item item to create bitstream on - * @param is - * InputStream + * @param item item to create bitstream on + * @param is InputStream * @return created bitstream * @throws AuthorizeException if authorization error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error */ public Bitstream createSingleBitstream(Context context, InputStream is, Item item) - throws AuthorizeException, IOException, SQLException; + throws AuthorizeException, IOException, SQLException; /** * Get all non-internal bitstreams in the item. This is mainly used for @@ -275,7 +295,7 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * is indeterminate. * * @param context DSpace context object - * @param item item to check + * @param item item to check * @return non-internal bitstreams. * @throws SQLException if database error */ @@ -289,22 +309,22 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * This method is used by the org.dspace.submit.step.LicenseStep class * * @param context DSpace context object - * @param item item to remove DSpace license from - * @throws SQLException if database error + * @param item item to remove DSpace license from + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public void removeDSpaceLicense(Context context, Item item) throws SQLException, AuthorizeException, - IOException; + IOException; /** * Remove all licenses from an item - it was rejected * * @param context DSpace context object - * @param item item to remove all licenses from - * @throws SQLException if database error + * @param item item to remove all licenses from + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public void removeLicenses(Context context, Item item) throws SQLException, AuthorizeException, IOException; @@ -313,8 +333,8 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * and metadata are not deleted, but it is not publicly accessible. * * @param context DSpace context object - * @param item item to withdraw - * @throws SQLException if database error + * @param item item to withdraw + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void withdraw(Context context, Item item) throws SQLException, AuthorizeException; @@ -324,8 +344,8 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * Reinstate a withdrawn item * * @param context DSpace context object - * @param item withdrawn item to reinstate - * @throws SQLException if database error + * @param item withdrawn item to reinstate + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void reinstate(Context context, Item item) throws SQLException, AuthorizeException; @@ -333,9 +353,8 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega /** * Return true if this Collection 'owns' this item * - * @param item item to check - * @param collection - * Collection + * @param item item to check + * @param collection Collection * @return true if this Collection owns this item */ public boolean isOwningCollection(Item item, Collection collection); @@ -344,31 +363,32 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * remove all of the policies for item and replace them with a new list of * policies * - * @param context DSpace context object - * @param item item to replace policies on + * @param context DSpace context object + * @param item item to replace policies on * @param newpolicies - - * this will be all of the new policies for the item and its - * contents - * @throws SQLException if database error + * this will be all of the new policies for the item and its + * contents + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public void replaceAllItemPolicies(Context context, Item item, List newpolicies) throws SQLException, - AuthorizeException; + public void replaceAllItemPolicies(Context context, Item item, List newpolicies) + throws SQLException, + AuthorizeException; /** * remove all of the policies for item's bitstreams and bundles and replace * them with a new list of policies * - * @param context DSpace context object - * @param item item to replace policies on + * @param context DSpace context object + * @param item item to replace policies on * @param newpolicies - - * this will be all of the new policies for the bundle and - * bitstream contents - * @throws SQLException if database error + * this will be all of the new policies for the bundle and + * bitstream contents + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void replaceAllBitstreamPolicies(Context context, Item item, List newpolicies) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; /** @@ -376,10 +396,9 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * to a given Group * * @param context DSpace context object - * @param item item to remove group policies from - * @param group - * Group referenced by policies that needs to be removed - * @throws SQLException if database error + * @param item item to remove group policies from + * @param group Group referenced by policies that needs to be removed + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void removeGroupPolicies(Context context, Item item, Group group) throws SQLException, AuthorizeException; @@ -389,56 +408,59 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * the DEFAULT_ITEM_READ and DEFAULT_BITSTREAM_READ policies belonging to * the collection. * - * @param context DSpace context object - * @param item item to reset policies on - * @param collection - * Collection - * @throws SQLException if database error - * if an SQL error or if no default policies found. It's a bit - * draconian, but default policies must be enforced. + * @param context DSpace context object + * @param item item to reset policies on + * @param collection Collection + * @throws SQLException if database error + * if an SQL error or if no default policies found. It's a bit + * draconian, but default policies must be enforced. * @throws AuthorizeException if authorization error */ public void inheritCollectionDefaultPolicies(Context context, Item item, Collection collection) - throws java.sql.SQLException, AuthorizeException; + throws java.sql.SQLException, AuthorizeException; - public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection) throws SQLException, AuthorizeException; + public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection) + throws SQLException, AuthorizeException; - public void adjustItemPolicies(Context context, Item item, Collection collection) throws SQLException, AuthorizeException; + public void adjustItemPolicies(Context context, Item item, Collection collection) + throws SQLException, AuthorizeException; /** * Moves the item from one collection to another one * * @param context DSpace context object - * @param item item to move - * @param from Collection to move from - * @param to Collection to move to - * @throws SQLException if database error + * @param item item to move + * @param from Collection to move from + * @param to Collection to move to + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ - public void move(Context context, Item item, Collection from, Collection to) throws SQLException, AuthorizeException, IOException; + public void move(Context context, Item item, Collection from, Collection to) + throws SQLException, AuthorizeException, IOException; /** * Moves the item from one collection to another one * - * @param context DSpace context object - * @param item item to move - * @param from Collection to move from - * @param to Collection to move to + * @param context DSpace context object + * @param item item to move + * @param from Collection to move from + * @param to Collection to move to * @param inheritDefaultPolicies whether to inherit policies from new collection - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ - public void move(Context context, Item item, Collection from, Collection to, boolean inheritDefaultPolicies) throws SQLException, AuthorizeException, IOException; + public void move(Context context, Item item, Collection from, Collection to, boolean inheritDefaultPolicies) + throws SQLException, AuthorizeException, IOException; /** * Check the bundle ORIGINAL to see if there are any uploaded files * * @param item item to check * @return true if there is a bundle named ORIGINAL with one or more - * bitstreams inside + * bitstreams inside * @throws SQLException if database error */ public boolean hasUploadedFiles(Item item) throws SQLException; @@ -447,7 +469,7 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * Get the collections this item is not in. * * @param context DSpace context object - * @param item item to check + * @param item item to check * @return the collections this item is not in, if any. * @throws SQLException if database error */ @@ -457,71 +479,75 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * return TRUE if context's user can edit item, false otherwise * * @param context DSpace context object - * @param item item to check + * @param item item to check * @return boolean true = current user can edit item * @throws SQLException if database error */ public boolean canEdit(Context context, Item item) throws java.sql.SQLException; - + /** * return TRUE if context's user can create new version of the item, false * otherwise. + * * @param context DSpace context object - * @param item item to check + * @param item item to check * @return boolean true = current user can create new version of the item * @throws SQLException if database error */ public boolean canCreateNewVersion(Context context, Item item) throws SQLException; - + /** * Returns an iterator of Items possessing the passed metadata field, or only * those matching the passed value, if value is not Item.ANY * - * @param context DSpace context object - * @param schema metadata field schema - * @param element metadata field element + * @param context DSpace context object + * @param schema metadata field schema + * @param element metadata field element * @param qualifier metadata field qualifier - * @param value field value or Item.ANY to match any value + * @param value field value or Item.ANY to match any value * @return an iterator over the items matching that authority value - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error - * + * @throws IOException if IO error */ public Iterator findByMetadataField(Context context, String schema, String element, String qualifier, String value) - throws SQLException, AuthorizeException, IOException; + throws SQLException, AuthorizeException, IOException; - public Iterator findByMetadataQuery(Context context, List> listFieldList, List query_op, List query_val, List collectionUuids, String regexClause, int offset, int limit) - throws SQLException, AuthorizeException, IOException; + public Iterator findByMetadataQuery(Context context, List> listFieldList, + List query_op, List query_val, List collectionUuids, + String regexClause, int offset, int limit) + throws SQLException, AuthorizeException, IOException; /** * Find all the items in the archive with a given authority key value * in the indicated metadata field. * - * @param context DSpace context object - * @param schema metadata field schema - * @param element metadata field element + * @param context DSpace context object + * @param schema metadata field schema + * @param element metadata field element * @param qualifier metadata field qualifier - * @param value the value of authority key to look for + * @param value the value of authority key to look for * @return an iterator over the items matching that authority value - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ public Iterator findByAuthorityValue(Context context, String schema, String element, String qualifier, String value) - throws SQLException, AuthorizeException, IOException; + throws SQLException, AuthorizeException, IOException; - public Iterator findByMetadataFieldAuthority(Context context, String mdString, String authority) throws SQLException, AuthorizeException; + public Iterator findByMetadataFieldAuthority(Context context, String mdString, String authority) + throws SQLException, AuthorizeException; /** * Service method for knowing if this Item should be visible in the item list. * Items only show up in the "item list" if the user has READ permission * and if the Item isn't flagged as unlisted. + * * @param context DSpace context object - * @param item item + * @param item item * @return true or false */ public boolean isItemListedForUser(Context context, Item item); @@ -529,28 +555,38 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega /** * counts items in the given collection * - * @param context DSpace context object + * @param context DSpace context object * @param collection Collection * @return total items * @throws SQLException if database error */ public int countItems(Context context, Collection collection) throws SQLException; + /** + * counts all items in the given collection including withdrawn items + * + * @param context DSpace context object + * @param collection Collection + * @return total items + * @throws SQLException if database error + */ + public int countAllItems(Context context, Collection collection) throws SQLException; + /** * Find all Items modified since a Date. * * @param context DSpace context object - * @param last Earliest interesting last-modified date. + * @param last Earliest interesting last-modified date. * @return iterator over items * @throws SQLException if database error */ public Iterator findByLastModifiedSince(Context context, Date last) - throws SQLException; + throws SQLException; /** * counts items in the given community * - * @param context DSpace context object + * @param context DSpace context object * @param community Community * @return total items * @throws SQLException if database error @@ -558,7 +594,17 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega public int countItems(Context context, Community community) throws SQLException; /** - * counts all items + * counts all items in the given community including withdrawn + * + * @param context DSpace context object + * @param community Community + * @return total items + * @throws SQLException if database error + */ + public int countAllItems(Context context, Community community) throws SQLException; + + /** + * counts all items * * @param context DSpace context object * @return total items @@ -566,7 +612,7 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega */ int countTotal(Context context) throws SQLException; - /** + /** * counts all items not in archive * * @param context DSpace context object @@ -575,7 +621,7 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega */ int countNotArchivedItems(Context context) throws SQLException; - /** + /** * counts all withdrawn items * * @param context DSpace context object @@ -586,8 +632,9 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega /** * Check if the supplied item is an inprogress submission + * * @param context DSpace context object - * @param item item to check + * @param item item to check * @return true if the item is linked to a workspaceitem or workflowitem * @throws SQLException if database error */ diff --git a/dspace-api/src/main/java/org/dspace/content/service/MetadataFieldService.java b/dspace-api/src/main/java/org/dspace/content/service/MetadataFieldService.java index b94092d9d1..5bfefd1db0 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/MetadataFieldService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/MetadataFieldService.java @@ -7,19 +7,20 @@ */ package org.dspace.content.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; import org.dspace.content.NonUniqueMetadataException; import org.dspace.core.Context; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the MetadataField object. - * The implementation of this class is responsible for all business logic calls for the MetadataField object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the MetadataField object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -28,28 +29,27 @@ public interface MetadataFieldService { /** * Creates a new metadata field. * - * @param context - * DSpace context object + * @param context DSpace context object * @param metadataSchema schema - * @param scopeNote scope note - * @param element element - * @param qualifier qualifier + * @param scopeNote scope note + * @param element element + * @param qualifier qualifier * @return new MetadataField - * @throws AuthorizeException if authorization error - * @throws SQLException if database error - * @throws NonUniqueMetadataException if an existing field with an identical element and qualifier is already present + * @throws AuthorizeException if authorization error + * @throws SQLException if database error + * @throws NonUniqueMetadataException if an existing field with an identical element and qualifier is already + * present */ - public MetadataField create(Context context, MetadataSchema metadataSchema, String element, String qualifier, String scopeNote) - throws AuthorizeException, SQLException, NonUniqueMetadataException; + public MetadataField create(Context context, MetadataSchema metadataSchema, String element, String qualifier, + String scopeNote) + throws AuthorizeException, SQLException, NonUniqueMetadataException; /** * Find the field corresponding to the given numeric ID. The ID is * a database key internal to DSpace. * - * @param context - * context, in case we need to read it in from DB - * @param id - * the metadata field ID + * @param context context, in case we need to read it in from DB + * @param id the metadata field ID * @return the metadata field object * @throws SQLException if database error */ @@ -58,22 +58,23 @@ public interface MetadataFieldService { /** * Retrieves the metadata field from the database. * - * @param context dspace context + * @param context dspace context * @param metadataSchema schema - * @param element element name - * @param qualifier qualifier (may be ANY or null) + * @param element element name + * @param qualifier qualifier (may be ANY or null) * @return recalled metadata field * @throws SQLException if database error */ public MetadataField findByElement(Context context, MetadataSchema metadataSchema, String element, String qualifier) - throws SQLException; + throws SQLException; public MetadataField findByElement(Context context, String metadataSchemaName, String element, String qualifier) - throws SQLException; + throws SQLException; + + public List findFieldsByElementNameUnqualified(Context context, String metadataSchema, + String element) + throws SQLException; - public List findFieldsByElementNameUnqualified(Context context, String metadataSchema, String element) - throws SQLException; - /** * Retrieve all metadata field types from the registry * @@ -86,34 +87,35 @@ public interface MetadataFieldService { /** * Return all metadata fields that are found in a given schema. * - * @param context dspace context + * @param context dspace context * @param metadataSchema the metadata schema for which we want all our metadata fields * @return array of metadata fields * @throws SQLException if database error */ public List findAllInSchema(Context context, MetadataSchema metadataSchema) - throws SQLException; + throws SQLException; /** * Update the metadata field in the database. * - * @param context dspace context + * @param context dspace context * @param metadataField metadata field - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws NonUniqueMetadataException if an existing field with an identical element and qualifier is already present - * @throws IOException if IO error + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws NonUniqueMetadataException if an existing field with an identical element and qualifier is already + * present + * @throws IOException if IO error */ public void update(Context context, MetadataField metadataField) - throws SQLException, AuthorizeException, NonUniqueMetadataException, IOException; + throws SQLException, AuthorizeException, NonUniqueMetadataException, IOException; /** * Delete the metadata field. * - * @param context dspace context + * @param context dspace context * @param metadataField metadata field - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void delete(Context context, MetadataField metadataField) throws SQLException, AuthorizeException; diff --git a/dspace-api/src/main/java/org/dspace/content/service/MetadataSchemaService.java b/dspace-api/src/main/java/org/dspace/content/service/MetadataSchemaService.java index 0d779f1aa0..08477ea675 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/MetadataSchemaService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/MetadataSchemaService.java @@ -7,17 +7,18 @@ */ package org.dspace.content.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.MetadataSchema; import org.dspace.content.NonUniqueMetadataException; import org.dspace.core.Context; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the MetadataSchema object. - * The implementation of this class is responsible for all business logic calls for the MetadataSchema object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the MetadataSchema object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -26,21 +27,22 @@ public interface MetadataSchemaService { /** * Creates a new metadata schema in the database, using the name and namespace. * - * @param context - * DSpace context object - * @param name name + * @param context DSpace context object + * @param name name * @param namespace namespace * @return new MetadataSchema - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws NonUniqueMetadataException if an existing field with an identical element and qualifier is already present + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws NonUniqueMetadataException if an existing field with an identical element and qualifier is already + * present */ - public MetadataSchema create(Context context, String name, String namespace) throws SQLException, AuthorizeException, NonUniqueMetadataException; + public MetadataSchema create(Context context, String name, String namespace) + throws SQLException, AuthorizeException, NonUniqueMetadataException; /** * Get the schema object corresponding to this namespace URI. * - * @param context DSpace context + * @param context DSpace context * @param namespace namespace URI to match * @return metadata schema object or null if none found. * @throws SQLException if database error @@ -50,20 +52,22 @@ public interface MetadataSchemaService { /** * Update the metadata schema in the database. * - * @param context DSpace context + * @param context DSpace context * @param metadataSchema metadata schema - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws NonUniqueMetadataException if an existing field with an identical element and qualifier is already present + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws NonUniqueMetadataException if an existing field with an identical element and qualifier is already + * present */ - public void update(Context context, MetadataSchema metadataSchema) throws SQLException, AuthorizeException, NonUniqueMetadataException; + public void update(Context context, MetadataSchema metadataSchema) + throws SQLException, AuthorizeException, NonUniqueMetadataException; /** * Delete the metadata schema. * - * @param context DSpace context + * @param context DSpace context * @param metadataSchema metadata schema - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public void delete(Context context, MetadataSchema metadataSchema) throws SQLException, AuthorizeException; @@ -81,10 +85,8 @@ public interface MetadataSchemaService { * Get the schema corresponding with this numeric ID. * The ID is a database key internal to DSpace. * - * @param context - * context, in case we need to read it in from DB - * @param id - * the schema ID + * @param context context, in case we need to read it in from DB + * @param id the schema ID * @return the metadata schema object * @throws SQLException if database error */ @@ -93,10 +95,8 @@ public interface MetadataSchemaService { /** * Get the schema corresponding with this short name. * - * @param context - * context, in case we need to read it in from DB - * @param shortName - * the short name for the schema + * @param context context, in case we need to read it in from DB + * @param shortName the short name for the schema * @return the metadata schema object * @throws SQLException if database error */ diff --git a/dspace-api/src/main/java/org/dspace/content/service/MetadataValueService.java b/dspace-api/src/main/java/org/dspace/content/service/MetadataValueService.java index 2b34c74634..ce3c0094b3 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/MetadataValueService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/MetadataValueService.java @@ -7,20 +7,21 @@ */ package org.dspace.content.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; import org.dspace.core.Context; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Service interface class for the MetadataValue object. - * The implementation of this class is responsible for all business logic calls for the MetadataValue object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the MetadataValue object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -29,9 +30,8 @@ public interface MetadataValueService { /** * Creates a new metadata value. * - * @param context - * DSpace context object - * @param dso DSpaceObject + * @param context DSpace context object + * @param dso DSpaceObject * @param metadataField metadata field * @return new MetadataValue * @throws SQLException if database error @@ -44,40 +44,41 @@ public interface MetadataValueService { * @param context dspace context * @param valueId database key id of value * @return recalled metadata value - * @throws IOException if IO error + * @throws IOException if IO error * @throws SQLException if database error */ public MetadataValue find(Context context, int valueId) - throws IOException, SQLException; + throws IOException, SQLException; /** * Retrieves the metadata values for a given field from the database. * - * @param context dspace context + * @param context dspace context * @param metadataField metadata field whose values to look for * @return a collection of metadata values - * @throws IOException if IO error + * @throws IOException if IO error * @throws SQLException if database error */ public List findByField(Context context, MetadataField metadataField) - throws IOException, SQLException; + throws IOException, SQLException; /** * Update the metadata value in the database. * - * @param context dspace context + * @param context dspace context * @param metadataValue metadata value * @throws SQLException if database error */ public void update(Context context, MetadataValue metadataValue) throws SQLException; - public void update(Context context, MetadataValue metadataValue, boolean modifyParentObject) throws SQLException, AuthorizeException; + public void update(Context context, MetadataValue metadataValue, boolean modifyParentObject) + throws SQLException, AuthorizeException; /** * Delete the metadata field. * - * @param context dspace context + * @param context dspace context * @param metadataValue metadata value * @throws SQLException if database error */ @@ -90,13 +91,13 @@ public interface MetadataValueService { /** * Get the minimum value of a given metadata field across all objects. * - * @param context dspace context + * @param context dspace context * @param metadataFieldId unique identifier of the interesting field. * @return the minimum value of the metadata field * @throws SQLException if database error */ public MetadataValue getMinimum(Context context, int metadataFieldId) - throws SQLException; + throws SQLException; int countTotal(Context context) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/service/SiteService.java b/dspace-api/src/main/java/org/dspace/content/service/SiteService.java index 477900616d..9245c03729 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/SiteService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/SiteService.java @@ -7,19 +7,19 @@ */ package org.dspace.content.service; +import java.sql.SQLException; + import org.dspace.content.Site; import org.dspace.core.Context; -import java.sql.SQLException; - /** * Service interface class for the Site object. - * The implementation of this class is responsible for all business logic calls for the Site object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Site object and is autowired + * by spring * * @author kevinvandevelde at atmire.com */ -public interface SiteService extends DSpaceObjectService -{ +public interface SiteService extends DSpaceObjectService { public Site createSite(Context context) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/service/SupervisedItemService.java b/dspace-api/src/main/java/org/dspace/content/service/SupervisedItemService.java index e1a48596df..883e0f9fd2 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/SupervisedItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/SupervisedItemService.java @@ -7,26 +7,24 @@ */ package org.dspace.content.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.WorkspaceItem; import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import java.sql.SQLException; -import java.util.List; - /** * Class to handle WorkspaceItems which are being supervised. * * @author Richard Jones - * @version $Revision$ + * @version $Revision$ */ -public interface SupervisedItemService -{ +public interface SupervisedItemService { /** * Get all workspace items which are being supervised * * @param context the context this object exists in - * * @return array of SupervisedItems * @throws SQLException if database error */ @@ -36,9 +34,8 @@ public interface SupervisedItemService /** * Get items being supervised by given EPerson * - * @param ep the eperson who's items to supervise we want - * @param context the dspace context - * + * @param ep the eperson who's items to supervise we want + * @param context the dspace context * @return the items eperson is supervising in an array * @throws SQLException if database error */ diff --git a/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java b/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java index b8640d7b1e..6f85033906 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java @@ -7,6 +7,11 @@ */ package org.dspace.content.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.Item; @@ -15,28 +20,21 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflow.WorkflowItem; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; - /** * Service interface class for the WorkspaceItem object. - * The implementation of this class is responsible for all business logic calls for the WorkspaceItem object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the WorkspaceItem object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ -public interface WorkspaceItemService extends InProgressSubmissionService{ +public interface WorkspaceItemService extends InProgressSubmissionService { /** * Get a workspace item from the database. The item, collection and * submitter are loaded into memory. * - * @param context - * DSpace context object - * @param id - * ID of the workspace item - * + * @param context DSpace context object + * @param id ID of the workspace item * @return the workspace item, or null if the ID is invalid. * @throws SQLException if database error */ @@ -47,20 +45,16 @@ public interface WorkspaceItemService extends InProgressSubmissionServicetrue, the workspace item starts as a copy - * of the collection's template item - * + * @param context DSpace context object + * @param collection Collection being submitted to + * @param template if true, the workspace item starts as a copy + * of the collection's template item * @return the newly created workspace item - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public WorkspaceItem create(Context context, Collection collection, boolean template) - throws AuthorizeException, SQLException; + public WorkspaceItem create(Context context, Collection collection, boolean template) + throws AuthorizeException, SQLException; public WorkspaceItem create(Context c, WorkflowItem wfi) throws SQLException, AuthorizeException; @@ -70,46 +64,52 @@ public interface WorkspaceItemService extends InProgressSubmissionService findByEPerson(Context context, EPerson ep) - throws SQLException; + throws SQLException; + + /** + * Get a page of workspace items for a particular e-person. These are ordered by + * workspace item ID, since this should likely keep them in the order in + * which they were created. + * + * @param context the context object + * @param ep the eperson + * @param limit the max number of workspaceitems to return + * @param offset the offset + * @return the corresponding workspace items + * @throws SQLException if database error + */ + public List findByEPerson(Context context, EPerson ep, Integer limit, Integer offset) + throws SQLException; /** * Get all workspace items for a particular collection. * - * @param context - * the context object - * @param collection - * the collection - * + * @param context the context object + * @param collection the collection * @return the corresponding workspace items * @throws SQLException if database error */ public List findByCollection(Context context, Collection collection) - throws SQLException; + throws SQLException; /** * Check to see if a particular item is currently still in a user's Workspace. * If so, its WorkspaceItem is returned. If not, null is returned * - * @param context - * the context object - * @param item - * the item - * + * @param context the context object + * @param item the item * @return workflow item corresponding to the item, or null * @throws SQLException if database error */ public WorkspaceItem findByItem(Context context, Item item) - throws SQLException; + throws SQLException; public List findAllSupervisedItems(Context context) throws SQLException; @@ -118,34 +118,51 @@ public interface WorkspaceItemService extends InProgressSubmissionService findAll(Context context) throws SQLException; + /** + * Get all workspace items in the whole system, paginated. + * + * @param context the context object + * @param limit limit + * @param offset offset + * @return a page of workspace items + * @throws SQLException if database error + */ + public List findAll(Context context, Integer limit, Integer offset) throws SQLException; + + /** * Delete the workspace item. The entry in workspaceitem, the unarchived * item and its contents are all removed (multiple inclusion * notwithstanding.) - * @param context context + * + * @param context context * @param workspaceItem workspace item - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public void deleteAll(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException, IOException; + public void deleteAll(Context context, WorkspaceItem workspaceItem) + throws SQLException, AuthorizeException, IOException; int countTotal(Context context) throws SQLException; /** * The map entry returned contains stage reached as the key and count of items in that stage as a value - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. * @return the map * @throws SQLException if database error */ List> getStageReachedCounts(Context context) throws SQLException; + + + public int countByEPerson(Context context, EPerson ep) throws SQLException; + } diff --git a/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDAO.java b/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDAO.java index fcd3e05204..d4571b8463 100644 --- a/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDAO.java +++ b/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDAO.java @@ -7,16 +7,19 @@ */ package org.dspace.core; -import org.apache.commons.collections.CollectionUtils; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.criterion.Projections; - import java.sql.SQLException; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.UUID; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Root; + +import org.apache.commons.collections.CollectionUtils; +import org.hibernate.Session; /** * Hibernate implementation for generic DAO interface. Also includes additional @@ -28,8 +31,7 @@ import java.util.UUID; */ public abstract class AbstractHibernateDAO implements GenericDAO { - protected AbstractHibernateDAO() - { + protected AbstractHibernateDAO() { } @@ -44,6 +46,13 @@ public abstract class AbstractHibernateDAO implements GenericDAO { //Isn't required, is just here for other DB implementation. Hibernate auto keeps track of changes. } + /** + * The Session used to manipulate entities of this type. + * + * @param context current DSpace context. + * @return the current Session. + * @throws SQLException + */ protected Session getHibernateSession(Context context) throws SQLException { return ((Session) context.getDBConnection().getSession()); } @@ -55,20 +64,22 @@ public abstract class AbstractHibernateDAO implements GenericDAO { @Override public List findAll(Context context, Class clazz) throws SQLException { - return list(createCriteria(context, clazz)); + CriteriaQuery criteriaQuery = getCriteriaQuery(getCriteriaBuilder(context), clazz); + Root root = criteriaQuery.from(clazz); + criteriaQuery.select(root); + return executeCriteriaQuery(context, criteriaQuery, false, -1, -1); } @Override public T findUnique(Context context, String query) throws SQLException { @SuppressWarnings("unchecked") - T result = (T) createQuery(context, query).uniqueResult(); + T result = (T) createQuery(context, query).getSingleResult(); return result; } @Override public T findByID(Context context, Class clazz, UUID id) throws SQLException { - if(id == null) - { + if (id == null) { return null; } @SuppressWarnings("unchecked") @@ -86,7 +97,7 @@ public abstract class AbstractHibernateDAO implements GenericDAO { @Override public List findMany(Context context, String query) throws SQLException { @SuppressWarnings("unchecked") - List result = (List) createQuery(context, query).list(); + List result = (List) createQuery(context, query).getResultList(); return result; } @@ -102,33 +113,86 @@ public abstract class AbstractHibernateDAO implements GenericDAO { */ public List findMany(Context context, Query query) throws SQLException { @SuppressWarnings("unchecked") - List result = (List) query.list(); + List result = (List) query.getResultList(); return result; } - public Criteria createCriteria(Context context, Class persistentClass) throws SQLException { - return getHibernateSession(context).createCriteria(persistentClass); - } - - public Criteria createCriteria(Context context, Class persistentClass, String alias) throws SQLException { - return getHibernateSession(context).createCriteria(persistentClass, alias); - } - + /** + * Create a parsed query from a query expression. + * + * @param context current DSpace context. + * @param query textual form of the query. + * @return parsed form of the query. + * @throws SQLException + */ public Query createQuery(Context context, String query) throws SQLException { return getHibernateSession(context).createQuery(query); } - public List list(Criteria criteria) - { + /** + * This method will return a list with unique results, no duplicates, made by the given CriteriaQuery and parameters + * + * @param context + * The standard DSpace context object + * @param criteriaQuery + * The CriteriaQuery for which this list will be retrieved + * @param cacheable + * Whether or not this query should be cacheable + * @param clazz + * The clazz for which this CriteriaQuery will be executed on + * @param maxResults + * The maxmimum amount of results that will be returned for this CriteriaQuery + * @param offset + * The offset to be used for the CriteriaQuery + * @return A list of distinct results as depicted by the CriteriaQuery and parameters + * @throws SQLException + */ + public List list(Context context, CriteriaQuery criteriaQuery, boolean cacheable, Class clazz, int maxResults, + int offset) throws SQLException { + criteriaQuery.distinct(true); @SuppressWarnings("unchecked") - List result = (List) criteria.list(); + List result = (List) executeCriteriaQuery(context, criteriaQuery, cacheable, maxResults, offset); return result; } - public List list(Query query) - { + /** + * This method will return a list of results for the given CriteriaQuery and parameters + * + * @param context + * The standard DSpace context object + * @param criteriaQuery + * The CriteriaQuery to be used to find the list of results + * @param cacheable + * A boolean value indicating whether this query should be cached or not + * @param clazz + * The class on which the CriteriaQuery will search + * @param maxResults + * The maximum amount of results to be returned + * @param offset + * The offset to be used for the CriteriaQuery + * @param distinct + * A boolean value indicating whether this list should be distinct or not + * @return A list of results determined by the CriteriaQuery and parameters + * @throws SQLException + */ + public List list(Context context, CriteriaQuery criteriaQuery, boolean cacheable, Class clazz, int maxResults, + int offset, boolean distinct) throws SQLException { + criteriaQuery.distinct(distinct); @SuppressWarnings("unchecked") - List result = (List) query.list(); + List result = (List) executeCriteriaQuery(context, criteriaQuery, cacheable, maxResults, offset); + return result; + } + + /** + * This method will be used to return a list of results for the given query + * + * @param query + * The query for which the resulting list will be returned + * @return The list of results for the given query + */ + public List list(Query query) { + @SuppressWarnings("unchecked") + List result = (List) query.getResultList(); return result; } @@ -136,72 +200,223 @@ public abstract class AbstractHibernateDAO implements GenericDAO { * Retrieve a unique result from the query. If multiple results CAN be * retrieved an exception will be thrown, * so only use when the criteria state uniqueness in the database. - * @param criteria JPA criteria + * @param criteriaQuery JPA criteria * @return a DAO specified by the criteria */ - public T uniqueResult(Criteria criteria) - { - @SuppressWarnings("unchecked") - T result = (T) criteria.uniqueResult(); - return result; + public T uniqueResult(Context context, CriteriaQuery criteriaQuery, boolean cacheable, Class clazz, + int maxResults, int offset) throws SQLException { + List list = list(context, criteriaQuery, cacheable, clazz, maxResults, offset); + if (CollectionUtils.isNotEmpty(list)) { + if (list.size() == 1) { + return list.get(0); + } else { + throw new IllegalArgumentException("More than one result found"); + } + } else { + return null; + } } /** * Retrieve a single result from the query. Best used if you expect a * single result, but this isn't enforced on the database. - * @param criteria JPA criteria + * @param criteriaQuery JPA criteria * @return a DAO specified by the criteria */ - public T singleResult(Criteria criteria) - { - criteria.setMaxResults(1); - List list = list(criteria); - if(CollectionUtils.isNotEmpty(list)) - { - return list.get(0); - }else{ - return null; - } + public T singleResult(Context context, CriteriaQuery criteriaQuery) throws SQLException { + Query query = this.getHibernateSession(context).createQuery(criteriaQuery); + return singleResult(query); } + /** + * This method will return the first result from the given query or null if no results were found + * + * @param query + * The query that is to be executed + * @return One result from the given query or null if none was found + */ public T singleResult(final Query query) { query.setMaxResults(1); List list = list(query); - if(CollectionUtils.isNotEmpty(list)) - { + if (CollectionUtils.isNotEmpty(list)) { return list.get(0); - }else{ + } else { return null; } + } - public T uniqueResult(Query query) - { + /** + * This method will return a singular result for the given query + * + * @param query + * The query for which a single result will be given + * @return The single result for this query + */ + public T uniqueResult(Query query) { @SuppressWarnings("unchecked") - T result = (T) query.uniqueResult(); + T result = (T) query.getSingleResult(); return result; } - public Iterator iterate(Query query) - { + /** + * This method will return an Iterator for the given Query + * + * @param query + * The query for which an Iterator will be made + * @return The Iterator for the results of this query + */ + public Iterator iterate(Query query) { @SuppressWarnings("unchecked") - Iterator result = (Iterator) query.iterate(); + Iterator result = (Iterator) query.getResultList().iterator(); return result; } - public int count(Criteria criteria) - { - return ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue(); + /** + * This method will return the amount of results that would be generated for this CriteriaQuery as an integer + * + * @param context + * The standard DSpace Context object + * @param criteriaQuery + * The CriteriaQuery for which this result will be retrieved + * @param criteriaBuilder + * The CriteriaBuilder that accompagnies the CriteriaQuery + * @param root + * The root that'll determine on which class object we need to calculate the result + * @return The amount of results that would be found by this CriteriaQuery as an integer value + * @throws SQLException + */ + public int count(Context context, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder, Root root) + throws SQLException { + return Math.toIntExact(countLong(context, criteriaQuery, criteriaBuilder, root)); } - public int count(Query query) - { - return ((Long) query.uniqueResult()).intValue(); + /** + * This method will return the count of items for this query as an integer + * This query needs to already be in a formate that'll return one record that contains the amount + * + * @param query + * The query for which the amount of results will be returned. + * @return The amount of results + */ + public int count(Query query) { + return ((Long) query.getSingleResult()).intValue(); } - public long countLong(Criteria criteria) - { - return (Long) criteria.setProjection(Projections.rowCount()).uniqueResult(); + /** + * This method will return the count of items for this query as a long + * + * @param context + * The standard DSpace Context object + * @param criteriaQuery + * The CriteriaQuery for which the amount of results will be retrieved + * @param criteriaBuilder + * The CriteriaBuilder that goes along with this CriteriaQuery + * @param root + * The root created for a DSpace class on which this query will search + * @return A long value that depicts the amount of results this query has found + * @throws SQLException + */ + public long countLong(Context context, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder, Root root) + throws SQLException { + Expression countExpression = criteriaBuilder.countDistinct(root); + criteriaQuery.select(countExpression); + return (Long) this.getHibernateSession(context).createQuery(criteriaQuery).getSingleResult(); } + + /** + * This method should always be used in order to retrieve the CriteriaQuery in order to + * start creating a query that has to be executed + * + * @param criteriaBuilder + * The CriteriaBuilder for which this CriteriaQuery will be constructed + * @param clazz + * The class that this CriteriaQuery will be constructed for + * @return A CriteriaQuery on which a query can be built + */ + public CriteriaQuery getCriteriaQuery(CriteriaBuilder criteriaBuilder, Class clazz) { + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(clazz); + return criteriaQuery; + } + + /** + * This method should always be used in order to retrieve a CriteriaBuilder for the given context + * + * @param context + * The standard DSpace Context class for which a CriteriaBuilder will be made + * @return A CriteriaBuilder that can be used to create the query + * @throws SQLException + */ + public CriteriaBuilder getCriteriaBuilder(Context context) throws SQLException { + return this.getHibernateSession(context).getCriteriaBuilder(); + } + + /** + * This method will return a list of objects to be returned that match the given criteriaQuery and parameters. + * The maxResults and offSet can be circumvented by entering the value -1 for them. + * + * @param context + * The standard context DSpace object + * @param criteriaQuery + * The CriteriaQuery that will be used for executing the query + * @param cacheable + * Whether or not this query is able to be cached + * @param maxResults + * The maximum amount of results that this query will return + * This can be circumvented by passing along -1 as the value + * @param offset + * The offset to be used in this query + * This can be circumvented by passing along -1 as the value + * @return This will return a list of objects that conform to the made query + * @throws SQLException + */ + public List executeCriteriaQuery(Context context, CriteriaQuery criteriaQuery, boolean cacheable, + int maxResults, int offset) throws SQLException { + Query query = this.getHibernateSession(context).createQuery(criteriaQuery); + + query.setHint("org.hibernate.cacheable", cacheable); + if (maxResults != -1) { + query.setMaxResults(maxResults); + } + if (offset != -1) { + query.setFirstResult(offset); + } + return query.getResultList(); + + } + + /** + * This method can be used to construct a query for which there needs to be a bunch of equal properties + * These properties can be passed along in the equals hashmap + * + * @param context + * The standard DSpace context object + * @param clazz + * The class on which the criteriaQuery will be built + * @param equals + * A hashmap that can be used to store the String representation of the column + * and the value that should match that in the DB + * @param cacheable + * A boolean indicating whether this query should be cacheable or not + * @param maxResults + * The max amount of results to be returned by this query + * @param offset + * The offset to be used in this query + * @return Will return a list of objects that correspond with the constructed query and parameters + * @throws SQLException + */ + public List findByX(Context context, Class clazz, Map equals, boolean cacheable, int maxResults, + int offset) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteria = getCriteriaQuery(criteriaBuilder, clazz); + Root root = criteria.from(clazz); + criteria.select(root); + + for (Map.Entry entry : equals.entrySet()) { + criteria.where(criteriaBuilder.equal(root.get(entry.getKey()), entry.getValue())); + } + return executeCriteriaQuery(context, criteria, cacheable, maxResults, offset); + } + } diff --git a/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDSODAO.java b/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDSODAO.java index 423f12a50f..232431cac7 100644 --- a/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDSODAO.java +++ b/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDSODAO.java @@ -7,87 +7,97 @@ */ package org.dspace.core; +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.ListUtils; import org.apache.commons.lang3.StringUtils; import org.dspace.content.DSpaceObject; import org.dspace.content.MetadataField; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.Collection; -import java.util.List; /** - * Hibernate implementation used by DSO Database Access Objects , includes commonly used methods - * Each DSO Database Access Objects should extend this class to prevent code duplication. + * Hibernate implementation used by DSpaceObject Database Access Objects. + * Includes commonly used methods. + * + *

    + * Each DSO Database Access Object should extend this class to prevent code duplication. * * @author kevinvandevelde at atmire.com - * @param class type + * @param type of DSO represented. */ -public abstract class AbstractHibernateDSODAO extends AbstractHibernateDAO -{ - public T findByLegacyId(Context context, int legacyId, Class clazz) throws SQLException - { - Criteria criteria = createCriteria(context, clazz); - criteria.add(Restrictions.eq("legacyId", legacyId)); - return uniqueResult(criteria); +public abstract class AbstractHibernateDSODAO extends AbstractHibernateDAO { + /** + * Find a DSO by its "legacy ID". Former versions of DSpace used integer + * record IDs, and these may still be found in external records such as AIPs. + * All DSOs now have UUID primary keys, and those should be used when available. + * Each type derived from DSpaceObject had its own stream of record IDs, so + * it is also necessary to know the specific type. + * @param context current DSpace context. + * @param legacyId the old integer record identifier. + * @param clazz DSO subtype of record identified by {@link legacyId}. + * @return + * @throws SQLException + */ + public T findByLegacyId(Context context, int legacyId, Class clazz) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, clazz); + Root root = criteriaQuery.from(clazz); + criteriaQuery.where(criteriaBuilder.equal(root.get("legacyId"), legacyId)); + return uniqueResult(context, criteriaQuery, false, clazz, -1, -1); } - /** * Add left outer join on all metadata fields which are passed to this function. * The identifier of the join will be the toString() representation of the metadata field. - * The joineded metadata fields can then be used to query or sort. - * @param query - * partial SQL query (to be appended) - * @param tableIdentifier - * DB table to join with - * @param metadataFields - * a collection of metadata fields + * The joined metadata fields can then be used to query or sort. + * @param query the query string being built. + * @param tableIdentifier name of the table to be joined. + * @param metadataFields names of the desired fields. */ - protected void addMetadataLeftJoin(StringBuilder query, String tableIdentifier, Collection metadataFields) - { + protected void addMetadataLeftJoin(StringBuilder query, String tableIdentifier, + Collection metadataFields) { for (MetadataField metadataField : metadataFields) { query.append(" left join ").append(tableIdentifier).append(".metadata ").append(metadataField.toString()); - query.append(" WITH ").append(metadataField.toString()).append(".metadataField.id").append(" = :").append(metadataField.toString()); + query.append(" WITH ").append(metadataField.toString()).append(".metadataField.id").append(" = :") + .append(metadataField.toString()); } } /** - * Using the metadata tables mapped in the leftJoin, this function creates a where query which can check the values - * Values can be checked using a like or an "=" query, this is determined by the "operator" parameter + * Using the metadata tables mapped in the leftJoin, this function creates a where query which can check the values. + * Values can be checked using a like or an "=" query, as determined by the "operator" parameter. * When creating a query, the "queryParam" string can be used set as parameter for the query. * * @param query the already existing query builder, all changes will be appended - * @param metadataFields the metadatafields who's metadata value should be queried + * @param metadataFields the metadata fields whose metadata value should be queried * @param operator can either be "=" or "like" * @param additionalWhere additional where query */ - protected void addMetadataValueWhereQuery(StringBuilder query, List metadataFields, String operator, String additionalWhere) - { + protected void addMetadataValueWhereQuery(StringBuilder query, List metadataFields, String operator, + String additionalWhere) { if (CollectionUtils.isNotEmpty(metadataFields) || StringUtils.isNotBlank(additionalWhere)) { //Add the where query on metadata query.append(" WHERE "); for (int i = 0; i < metadataFields.size(); i++) { MetadataField metadataField = metadataFields.get(i); - if (StringUtils.isNotBlank(operator)) - { + if (StringUtils.isNotBlank(operator)) { query.append(" ("); - query.append("lower(STR(" + metadataField.toString()).append(".value)) ").append(operator).append(" lower(:queryParam)"); + query.append("lower(STR(" + metadataField.toString()).append(".value)) ").append(operator) + .append(" lower(:queryParam)"); query.append(")"); - if (i < metadataFields.size() - 1) - { + if (i < metadataFields.size() - 1) { query.append(" OR "); } } } - if (StringUtils.isNotBlank(additionalWhere)) - { - if (CollectionUtils.isNotEmpty(metadataFields)) - { + if (StringUtils.isNotBlank(additionalWhere)) { + if (CollectionUtils.isNotEmpty(metadataFields)) { query.append(" OR "); } query.append(additionalWhere); @@ -96,11 +106,27 @@ public abstract class AbstractHibernateDSODAO extends Ab } } - protected void addMetadataSortQuery(StringBuilder query, List metadataSortFields, List columnSortFields) { + /** + * Append ORDER BY clause based on metadata fields or column names. + * All fields will be in ascending order. + * @param query the query being built. + * @param metadataSortFields fields on which to sort -- use this OR columnSortFields. + * @param columnSortFields columns on which to sort -- use this OR metadataSortFields. + */ + protected void addMetadataSortQuery(StringBuilder query, List metadataSortFields, + List columnSortFields) { addMetadataSortQuery(query, metadataSortFields, columnSortFields, ListUtils.EMPTY_LIST); } - protected void addMetadataSortQuery(StringBuilder query, List metadataSortFields, List columnSortFields, List direction) - { + + /** + * Append ORDER BY clause based on metadata fields or column names. + * @param query the query being built. + * @param metadataSortFields fields on which to sort -- use this OR columnSortFields. + * @param columnSortFields columns on which to sort -- use this OR metadataSortFields. + * @param direction ASC or DESC for each field. Unspecified fields will be ASC. + */ + protected void addMetadataSortQuery(StringBuilder query, List metadataSortFields, + List columnSortFields, List direction) { if (CollectionUtils.isNotEmpty(metadataSortFields)) { query.append(" ORDER BY "); @@ -109,19 +135,16 @@ public abstract class AbstractHibernateDSODAO extends Ab query.append("STR(").append(metadataField.toString()).append(".value)"); String dir = direction.size() > i ? " " + direction.get(i) : ""; query.append(dir); - if(i != metadataSortFields.size() -1) - { + if (i != metadataSortFields.size() - 1) { query.append(","); } } - } else if (CollectionUtils.isNotEmpty(columnSortFields)) - { + } else if (CollectionUtils.isNotEmpty(columnSortFields)) { query.append(" ORDER BY "); for (int i = 0; i < columnSortFields.size(); i++) { String sortField = columnSortFields.get(i); query.append(sortField); - if (i != columnSortFields.size() -1) - { + if (i != columnSortFields.size() - 1) { query.append(","); } } diff --git a/dspace-api/src/main/java/org/dspace/core/ConfigurationManager.java b/dspace-api/src/main/java/org/dspace/core/ConfigurationManager.java index 6c573cf96d..30d6cf800a 100644 --- a/dspace-api/src/main/java/org/dspace/core/ConfigurationManager.java +++ b/dspace-api/src/main/java/org/dspace/core/ConfigurationManager.java @@ -9,9 +9,9 @@ package org.dspace.core; import java.util.Enumeration; import java.util.Properties; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationConverter; - import org.apache.log4j.Logger; import org.dspace.services.factory.DSpaceServicesFactory; @@ -25,7 +25,6 @@ import org.dspace.services.factory.DSpaceServicesFactory; * Other configuration files are read from the config directory * of the DSpace installation directory. * - * * @author Robert Tansley * @author Larry Stone - Interpolated values. * @author Mark Diggory - General Improvements to detection, logging and loading. @@ -33,22 +32,22 @@ import org.dspace.services.factory.DSpaceServicesFactory; * @version $Revision$ * @deprecated Please use org.dspace.services.ConfigurationService. See examples below. */ -public class ConfigurationManager -{ - /** log4j category */ +public class ConfigurationManager { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(ConfigurationManager.class); - protected ConfigurationManager() - { + protected ConfigurationManager() { } /** * Identify if DSpace is properly configured + * * @return boolean true if configured, false otherwise */ - public static boolean isConfigured() - { + public static boolean isConfigured() { return DSpaceServicesFactory.getInstance().getConfigurationService() != null; } @@ -57,22 +56,20 @@ public class ConfigurationManager * * @return properties - all non-modular properties */ - public static Properties getProperties() - { + public static Properties getProperties() { return DSpaceServicesFactory.getInstance().getConfigurationService().getProperties(); } /** * Returns all properties for a given module * - * @param module - * the name of the module + * @param module the name of the module * @return properties - all module's properties */ - public static Properties getProperties(String module) - { + public static Properties getProperties(String module) { // Find subset of Configurations which have been prefixed with the module name - Configuration subset = DSpaceServicesFactory.getInstance().getConfigurationService().getConfiguration().subset(module); + Configuration subset = DSpaceServicesFactory.getInstance().getConfigurationService().getConfiguration() + .subset(module); // Convert to a Properties object and return it return ConfigurationConverter.getProperties(subset); @@ -81,33 +78,25 @@ public class ConfigurationManager /** * Get a configuration property * - * @param property - * the name of the property - * + * @param property the name of the property * @return the value of the property, or null if the property - * does not exist. + * does not exist. */ - public static String getProperty(String property) - { + public static String getProperty(String property) { return DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(property); } /** * Get a module configuration property value. * - * @param module - * the name of the module, or null for regular configuration - * property - * @param property - * the name (key) of the property - * @return - * the value of the property, or null if the - * property does not exist + * @param module the name of the module, or null for regular configuration + * property + * @param property the name (key) of the property + * @return the value of the property, or null if the + * property does not exist */ - public static String getProperty(String module, String property) - { - if (module == null) - { + public static String getProperty(String module, String property) { + if (module == null) { return getProperty(property); } @@ -118,35 +107,26 @@ public class ConfigurationManager /** * Get a configuration property as an integer * - * @param property - * the name of the property - * + * @param property the name of the property * @return the value of the property. 0 is returned if the - * property does not exist. To differentiate between this case and - * when the property actually is zero, use getProperty. + * property does not exist. To differentiate between this case and + * when the property actually is zero, use getProperty. */ - public static int getIntProperty(String property) - { + public static int getIntProperty(String property) { return DSpaceServicesFactory.getInstance().getConfigurationService().getIntProperty(property); } /** * Get a module configuration property as an integer * - * @param module - * the name of the module - * - * @param property - * the name of the property - * + * @param module the name of the module + * @param property the name of the property * @return the value of the property. 0 is returned if the - * property does not exist. To differentiate between this case and - * when the property actually is zero, use getProperty. + * property does not exist. To differentiate between this case and + * when the property actually is zero, use getProperty. */ - public static int getIntProperty(String module, String property) - { - if (module == null) - { + public static int getIntProperty(String module, String property) { + if (module == null) { return getIntProperty(property); } @@ -157,43 +137,30 @@ public class ConfigurationManager /** * Get a configuration property as an integer, with default * - * @param property - * the name of the property - * - * @param defaultValue - * value to return if property is not found or is not an Integer. - * + * @param property the name of the property + * @param defaultValue value to return if property is not found or is not an Integer. * @return the value of the property. default is returned if - * the property does not exist or is not an Integer. To differentiate between this case - * and when the property actually is false, use - * getProperty. + * the property does not exist or is not an Integer. To differentiate between this case + * and when the property actually is false, use + * getProperty. */ - public static int getIntProperty(String property, int defaultValue) - { + public static int getIntProperty(String property, int defaultValue) { return DSpaceServicesFactory.getInstance().getConfigurationService().getIntProperty(property, defaultValue); } /** * Get a module configuration property as an integer, with default * - * @param module - * the name of the module - * - * @param property - * the name of the property - * - * @param defaultValue - * value to return if property is not found or is not an Integer. - * + * @param module the name of the module + * @param property the name of the property + * @param defaultValue value to return if property is not found or is not an Integer. * @return the value of the property. default is returned if - * the property does not exist or is not an Integer. To differentiate between this case - * and when the property actually is false, use - * getProperty. + * the property does not exist or is not an Integer. To differentiate between this case + * and when the property actually is false, use + * getProperty. */ - public static int getIntProperty(String module, String property, int defaultValue) - { - if (module == null) - { + public static int getIntProperty(String module, String property, int defaultValue) { + if (module == null) { return getIntProperty(property, defaultValue); } @@ -204,34 +171,26 @@ public class ConfigurationManager /** * Get a configuration property as a long * - * @param property - * the name of the property - * + * @param property the name of the property * @return the value of the property. 0 is returned if the - * property does not exist. To differentiate between this case and - * when the property actually is zero, use getProperty. + * property does not exist. To differentiate between this case and + * when the property actually is zero, use getProperty. */ - public static long getLongProperty(String property) - { + public static long getLongProperty(String property) { return DSpaceServicesFactory.getInstance().getConfigurationService().getLongProperty(property); } /** * Get a module configuration property as a long * - * @param module - * the name of the module - * @param property - * the name of the property - * + * @param module the name of the module + * @param property the name of the property * @return the value of the property. 0 is returned if the - * property does not exist. To differentiate between this case and - * when the property actually is zero, use getProperty. + * property does not exist. To differentiate between this case and + * when the property actually is zero, use getProperty. */ - public static long getLongProperty(String module, String property) - { - if (module == null) - { + public static long getLongProperty(String module, String property) { + if (module == null) { return getLongProperty(property); } @@ -239,46 +198,33 @@ public class ConfigurationManager return getLongProperty(module + "." + property); } - /** + /** * Get a configuration property as an long, with default * - * - * @param property - * the name of the property - * - * @param defaultValue - * value to return if property is not found or is not a Long. - * + * @param property the name of the property + * @param defaultValue value to return if property is not found or is not a Long. * @return the value of the property. default is returned if - * the property does not exist or is not an Integer. To differentiate between this case - * and when the property actually is false, use - * getProperty. + * the property does not exist or is not an Integer. To differentiate between this case + * and when the property actually is false, use + * getProperty. */ - public static long getLongProperty(String property, int defaultValue) - { + public static long getLongProperty(String property, int defaultValue) { return DSpaceServicesFactory.getInstance().getConfigurationService().getLongProperty(property, defaultValue); } /** * Get a configuration property as an long, with default * - * @param module the module, or null for regular property - * - * @param property - * the name of the property - * - * @param defaultValue - * value to return if property is not found or is not a Long. - * + * @param module the module, or null for regular property + * @param property the name of the property + * @param defaultValue value to return if property is not found or is not a Long. * @return the value of the property. default is returned if - * the property does not exist or is not an Integer. To differentiate between this case - * and when the property actually is false, use - * getProperty. + * the property does not exist or is not an Integer. To differentiate between this case + * and when the property actually is false, use + * getProperty. */ - public static long getLongProperty(String module, String property, int defaultValue) - { - if (module == null) - { + public static long getLongProperty(String module, String property, int defaultValue) { + if (module == null) { return getLongProperty(property, defaultValue); } @@ -291,16 +237,13 @@ public class ConfigurationManager * of the property is TRUE or YES (case * insensitive.) * - * @param property - * the name of the property - * + * @param property the name of the property * @return the value of the property. false is returned if - * the property does not exist. To differentiate between this case - * and when the property actually is false, use - * getProperty. + * the property does not exist. To differentiate between this case + * and when the property actually is false, use + * getProperty. */ - public static boolean getBooleanProperty(String property) - { + public static boolean getBooleanProperty(String property) { return DSpaceServicesFactory.getInstance().getConfigurationService().getBooleanProperty(property); } @@ -309,20 +252,15 @@ public class ConfigurationManager * the value of the property is TRUE or YES (case * insensitive.) * - * @param module the module, or null for regular property - * - * @param property - * the name of the property - * + * @param module the module, or null for regular property + * @param property the name of the property * @return the value of the property. false is returned if - * the property does not exist. To differentiate between this case - * and when the property actually is false, use - * getProperty. + * the property does not exist. To differentiate between this case + * and when the property actually is false, use + * getProperty. */ - public static boolean getBooleanProperty(String module, String property) - { - if (module == null) - { + public static boolean getBooleanProperty(String module, String property) { + if (module == null) { return getBooleanProperty(property); } @@ -330,25 +268,20 @@ public class ConfigurationManager return getBooleanProperty(module + "." + property); } - /** + /** * Get a configuration property as a boolean, with default. * True is indicated if the value * of the property is TRUE or YES (case * insensitive.) * - * @param property - * the name of the property - * - * @param defaultValue - * value to return if property is not found. - * + * @param property the name of the property + * @param defaultValue value to return if property is not found. * @return the value of the property. default is returned if - * the property does not exist. To differentiate between this case - * and when the property actually is false, use - * getProperty. + * the property does not exist. To differentiate between this case + * and when the property actually is false, use + * getProperty. */ - public static boolean getBooleanProperty(String property, boolean defaultValue) - { + public static boolean getBooleanProperty(String property, boolean defaultValue) { return DSpaceServicesFactory.getInstance().getConfigurationService().getBooleanProperty(property, defaultValue); } @@ -358,23 +291,16 @@ public class ConfigurationManager * of the property is TRUE or YES (case * insensitive.) * - * @param module module, or null for regular property - * - * @param property - * the name of the property - * - * @param defaultValue - * value to return if property is not found. - * + * @param module module, or null for regular property + * @param property the name of the property + * @param defaultValue value to return if property is not found. * @return the value of the property. default is returned if - * the property does not exist. To differentiate between this case - * and when the property actually is false, use - * getProperty. + * the property does not exist. To differentiate between this case + * and when the property actually is false, use + * getProperty. */ - public static boolean getBooleanProperty(String module, String property, boolean defaultValue) - { - if (module == null) - { + public static boolean getBooleanProperty(String module, String property, boolean defaultValue) { + if (module == null) { return getBooleanProperty(property, defaultValue); } @@ -390,10 +316,10 @@ public class ConfigurationManager * * @return an enumeration of all the keys in the DSpace configuration */ - public static Enumeration propertyNames() - { + public static Enumeration propertyNames() { // Get a list of all property keys, and convert into an Enumeration - return java.util.Collections.enumeration(DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys()); + return java.util.Collections + .enumeration(DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys()); } /** @@ -401,15 +327,14 @@ public class ConfigurationManager *

    * As ConfigurationManager is now deprecated, older code using this method * should consider using ConfigurationService.getPropertyKeys(String prefix) directly. - * - * @param module module, or null for regular property * + * @param module module, or null for regular property * @return an enumeration of all the keys in the module configuration, - * or null if the module does not exist. + * or null if the module does not exist. */ - public static Enumeration propertyNames(String module) - { + public static Enumeration propertyNames(String module) { // Get property keys beginning with this prefix, and convert into an Enumeration - return java.util.Collections.enumeration(DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys(module)); + return java.util.Collections + .enumeration(DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys(module)); } } diff --git a/dspace-api/src/main/java/org/dspace/core/Constants.java b/dspace-api/src/main/java/org/dspace/core/Constants.java index e221bb7ac0..8f5073f731 100644 --- a/dspace-api/src/main/java/org/dspace/core/Constants.java +++ b/dspace-api/src/main/java/org/dspace/core/Constants.java @@ -10,50 +10,69 @@ package org.dspace.core; /** * Class with constants and matching strings, for DSpace types. These numbers * must never be changed!! - * + * * @author David Stuve * @version $Revision$ */ -public class Constants -{ - /** Type of bitstream objects */ +public class Constants { + /** + * Type of bitstream objects + */ public static final int BITSTREAM = 0; - /** Type of bundle objects */ + /** + * Type of bundle objects + */ public static final int BUNDLE = 1; - /** Type of item objects */ + /** + * Type of item objects + */ public static final int ITEM = 2; - /** Type of collection objects */ + /** + * Type of collection objects + */ public static final int COLLECTION = 3; - /** Type of community objects */ + /** + * Type of community objects + */ public static final int COMMUNITY = 4; - /** DSpace site type */ + /** + * DSpace site type + */ public static final int SITE = 5; - /** Type of eperson groups */ + /** + * Type of eperson groups + */ public static final int GROUP = 6; - /** Type of individual eperson objects */ + /** + * Type of individual eperson objects + */ public static final int EPERSON = 7; /** * lets you look up type names from the type IDs */ - public static final String[] typeText = { "BITSTREAM", "BUNDLE", "ITEM", - "COLLECTION", "COMMUNITY", "SITE", "GROUP", "EPERSON" }; + public static final String[] typeText = {"BITSTREAM", "BUNDLE", "ITEM", + "COLLECTION", "COMMUNITY", "SITE", "GROUP", "EPERSON"}; /** * Special Bundle and Bitstream Names: */ - /** Magic name of item license, as bitstream in LICENSE_BUNDLE_NAME */ + /** + * Magic name of item license, as bitstream in LICENSE_BUNDLE_NAME + */ public static final String LICENSE_BITSTREAM_NAME = "license.txt"; - /** Magic name of bundle containing item license */ + /** + * Magic name of bundle containing item license + */ public static final String LICENSE_BUNDLE_NAME = "LICENSE"; /** @@ -67,20 +86,26 @@ public class Constants */ public static final String CONTENT_BUNDLE_NAME = "ORIGINAL"; - /** Bundle name for structured metadata bitstreams. */ + /** + * Bundle name for structured metadata bitstreams. + */ public static final String METADATA_BUNDLE_NAME = "METADATA"; - /** Action of reading, viewing or downloading something */ + /** + * Action of reading, viewing or downloading something + */ public static final int READ = 0; - /** Action of modifying something */ + /** + * Action of modifying something + */ public static final int WRITE = 1; /** * Action of deleting something. Different from removing something from a * container. (DELETE is now obsolete) - * + * * @see #REMOVE */ public static final int DELETE = 2; @@ -94,27 +119,39 @@ public class Constants /** * Action of removing something from a container. Different from deletion. - * + * * @see #DELETE */ public static final int REMOVE = 4; - /** Action of performing workflow step 1 */ + /** + * Action of performing workflow step 1 + */ public static final int WORKFLOW_STEP_1 = 5; - /** Action of performing workflow step 2 */ + /** + * Action of performing workflow step 2 + */ public static final int WORKFLOW_STEP_2 = 6; - /** Action of performing workflow step 3 */ + /** + * Action of performing workflow step 3 + */ public static final int WORKFLOW_STEP_3 = 7; - /** Action of performing a workflow */ + /** + * Action of performing a workflow + */ public static final int WORKFLOW_ABORT = 8; - /** Default Read policies for Bitstreams submitted to container */ + /** + * Default Read policies for Bitstreams submitted to container + */ public static final int DEFAULT_BITSTREAM_READ = 9; - /** Default Read policies for Items submitted to container */ + /** + * Default Read policies for Items submitted to container + */ public static final int DEFAULT_ITEM_READ = 10; /** @@ -126,22 +163,26 @@ public class Constants * Administrative actions - System Admin, Community Admin, Collection Admin */ public static final int ADMIN = 11; - + public static final int WITHDRAWN_READ = 12; - - /** Position of front page news item -- top box */ + + /** + * Position of front page news item -- top box + */ public static final int NEWS_TOP = 0; - /** Position of front page news item -- sidebar */ + /** + * Position of front page news item -- sidebar + */ public static final int NEWS_SIDE = 1; /** * lets you look up action names from the action IDs */ - public static final String[] actionText = { "READ", "WRITE", - "OBSOLETE (DELETE)", "ADD", "REMOVE", "WORKFLOW_STEP_1", - "WORKFLOW_STEP_2", "WORKFLOW_STEP_3", "WORKFLOW_ABORT", - "DEFAULT_BITSTREAM_READ", "DEFAULT_ITEM_READ", "ADMIN", "WITHDRAWN_READ" }; + public static final String[] actionText = {"READ", "WRITE", + "OBSOLETE (DELETE)", "ADD", "REMOVE", "WORKFLOW_STEP_1", + "WORKFLOW_STEP_2", "WORKFLOW_STEP_3", "WORKFLOW_ABORT", + "DEFAULT_BITSTREAM_READ", "DEFAULT_ITEM_READ", "ADMIN", "WITHDRAWN_READ"}; /** * generating constants for the relevance array dynamically is simple: just @@ -165,39 +206,39 @@ public class Constants * test actionTypeRelevance[READ] | RCOMMUNITY, 0 = irrelevant) */ public static final int[] actionTypeRelevance = { - RBITSTREAM | RBUNDLE | RITEM | RCOLLECTION | RCOMMUNITY, // 0 - READ - RBITSTREAM | RBUNDLE | RITEM | RCOLLECTION | RCOMMUNITY, // 1 - - // WRITE - 0, // 2 - DELETE (obsolete) - RBUNDLE | RITEM | RCOLLECTION | RCOMMUNITY, // 3 - ADD - RBUNDLE | RITEM | RCOLLECTION | RCOMMUNITY, // 4 - REMOVE - 0, // 5 - WORKFLOW_STEP_1 - 0, // 6 - WORKFLOW_STEP_2 - 0, // 7 - WORKFLOW_STEP_3 - 0, // 8 - WORKFLOW_ABORT - RCOLLECTION, // 9 - DEFAULT_BITSTREAM_READ - RCOLLECTION, // 10 - DEFAULT_ITEM_READ - RITEM | RCOLLECTION | RCOMMUNITY, // 11 - ADMIN - RBITSTREAM | RBUNDLE | RITEM // 12 - WITHDRAWN_READ + RBITSTREAM | RBUNDLE | RITEM | RCOLLECTION | RCOMMUNITY, // 0 - READ + RBITSTREAM | RBUNDLE | RITEM | RCOLLECTION | RCOMMUNITY, // 1 - + // WRITE + 0, // 2 - DELETE (obsolete) + RBUNDLE | RITEM | RCOLLECTION | RCOMMUNITY, // 3 - ADD + RBUNDLE | RITEM | RCOLLECTION | RCOMMUNITY, // 4 - REMOVE + 0, // 5 - WORKFLOW_STEP_1 + 0, // 6 - WORKFLOW_STEP_2 + 0, // 7 - WORKFLOW_STEP_3 + 0, // 8 - WORKFLOW_ABORT + RCOLLECTION, // 9 - DEFAULT_BITSTREAM_READ + RCOLLECTION, // 10 - DEFAULT_ITEM_READ + RITEM | RCOLLECTION | RCOMMUNITY, // 11 - ADMIN + RBITSTREAM | RBUNDLE | RITEM // 12 - WITHDRAWN_READ }; public static final String DEFAULT_ENCODING = "UTF-8"; /** - * If you know the type string, look up the corresponding type ID constant. - * - * @param type - * String with the name of the type (must be exact match) - * - * @return the corresponding type ID, or -1 if the type - * string is unknown + * Default constructor */ - public static int getTypeID(String type) - { - for (int i = 0; i < typeText.length; i++) - { - if (typeText[i].equals(type)) - { + private Constants() { } + + /** + * If you know the type string, look up the corresponding type ID constant. + * + * @param type String with the name of the type (must be exact match) + * @return the corresponding type ID, or -1 if the type + * string is unknown + */ + public static int getTypeID(String type) { + for (int i = 0; i < typeText.length; i++) { + if (typeText[i].equals(type)) { return i; } } @@ -208,19 +249,14 @@ public class Constants /** * If you know the action string, look up the corresponding type ID * constant. - * - * @param action - * String with the name of the action (must be exact match) - * + * + * @param action String with the name of the action (must be exact match) * @return the corresponding action ID, or -1 if the action - * string is unknown + * string is unknown */ - public static int getActionID(String action) - { - for (int i = 0; i < actionText.length; i++) - { - if (actionText[i].equals(action)) - { + public static int getActionID(String action) { + for (int i = 0; i < actionText.length; i++) { + if (actionText[i].equals(action)) { return i; } } diff --git a/dspace-api/src/main/java/org/dspace/core/Context.java b/dspace-api/src/main/java/org/dspace/core/Context.java index 7d16f51a43..fac882c715 100644 --- a/dspace-api/src/main/java/org/dspace/core/Context.java +++ b/dspace-api/src/main/java/org/dspace/core/Context.java @@ -7,6 +7,17 @@ */ package org.dspace.core; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.EmptyStackException; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.Stack; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + import org.apache.log4j.Logger; import org.dspace.authorize.ResourcePolicy; import org.dspace.content.DSpaceObject; @@ -22,9 +33,6 @@ import org.dspace.storage.rdbms.DatabaseUtils; import org.dspace.utils.DSpace; import org.springframework.util.CollectionUtils; -import java.sql.SQLException; -import java.util.*; - /** * Class representing the context of a particular DSpace operation. This stores * information such as the current authenticated user and the database @@ -38,27 +46,36 @@ import java.util.*; * changes and free up the resources. *

    * The context object is also used as a cache for CM API objects. - * - * + * * @version $Revision$ */ -public class Context -{ +public class Context implements AutoCloseable { private static final Logger log = Logger.getLogger(Context.class); + protected static final AtomicBoolean databaseUpdated = new AtomicBoolean(false); - /** Current user - null means anonymous access */ + /** + * Current user - null means anonymous access + */ private EPerson currentUser; - /** Current Locale */ + /** + * Current Locale + */ private Locale currentLocale; - /** Extra log info */ + /** + * Extra log info + */ private String extraLogInfo; - /** Indicates whether authorisation subsystem should be ignored */ + /** + * Indicates whether authorisation subsystem should be ignored + */ private boolean ignoreAuth; - /** A stack with the history of authorisation system check modify */ + /** + * A stack with the history of authorisation system check modify + */ private Stack authStateChangeHistory; /** @@ -67,19 +84,29 @@ public class Context */ private Stack authStateClassCallHistory; - /** Group IDs of special groups user is a member of */ + /** + * Group IDs of special groups user is a member of + */ private List specialGroups; - /** Content events */ + /** + * Content events + */ private LinkedList events = null; - /** Event dispatcher name */ + /** + * Event dispatcher name + */ private String dispName = null; - /** Context mode */ + /** + * Context mode + */ private Mode mode = Mode.READ_WRITE; - /** Cache that is only used the context is in READ_ONLY mode */ + /** + * Cache that is only used the context is in READ_ONLY mode + */ private ContextReadOnlyCache readOnlyCache = new ContextReadOnlyCache(); protected EventService eventService; @@ -92,22 +119,7 @@ public class Context BATCH_EDIT } - static - { - // Before initializing a Context object, we need to ensure the database - // is up-to-date. This ensures any outstanding Flyway migrations are run - // PRIOR to Hibernate initializing (occurs when DBConnection is loaded in init() below). - try - { - DatabaseUtils.updateDatabase(); - } - catch(SQLException sqle) - { - log.fatal("Cannot initialize database via Flyway!", sqle); - } - } - - protected Context(EventService eventService, DBConnection dbConnection) { + protected Context(EventService eventService, DBConnection dbConnection) { this.mode = Mode.READ_WRITE; this.eventService = eventService; this.dbConnection = dbConnection; @@ -119,8 +131,7 @@ public class Context * Construct a new context object with default options. A database connection is opened. * No user is authenticated. */ - public Context() - { + public Context() { this.mode = Mode.READ_WRITE; init(); } @@ -128,36 +139,32 @@ public class Context /** * Construct a new context object with the given mode enabled. A database connection is opened. * No user is authenticated. - * - * @param mode The mode to use when opening the context. + * + * @param mode The mode to use when opening the context. */ - public Context(Mode mode) - { + public Context(Mode mode) { this.mode = mode; init(); } /** - * Initializes a new context object. + * Initializes a new context object. * - * @throws SQLException - * if there was an error obtaining a database connection + * @throws SQLException if there was an error obtaining a database connection */ - private void init() - { - if(eventService == null) - { + protected void init() { + updateDatabase(); + + if (eventService == null) { eventService = EventServiceFactory.getInstance().getEventService(); } - if(dbConnection == null) - { + if (dbConnection == null) { // Obtain a non-auto-committing connection dbConnection = new DSpace().getServiceManager() - .getServiceByName(null, DBConnection.class); - if(dbConnection == null) - { + .getServiceByName(null, DBConnection.class); + if (dbConnection == null) { log.fatal("Cannot obtain the bean which provides a database connection. " + - "Check previous entries in the dspace.log to find why the db failed to initialize."); + "Check previous entries in the dspace.log to find why the db failed to initialize."); } } @@ -168,83 +175,92 @@ public class Context specialGroups = new ArrayList<>(); - authStateChangeHistory = new Stack(); - authStateClassCallHistory = new Stack(); + authStateChangeHistory = new Stack<>(); + authStateClassCallHistory = new Stack<>(); setMode(this.mode); } + public static boolean updateDatabase() { + //If the database has not been updated yet, update it and remember that. + if (databaseUpdated.compareAndSet(false, true)) { + + // Before initializing a Context object, we need to ensure the database + // is up-to-date. This ensures any outstanding Flyway migrations are run + // PRIOR to Hibernate initializing (occurs when DBConnection is loaded in calling init() method). + try { + DatabaseUtils.updateDatabase(); + } catch (SQLException sqle) { + log.fatal("Cannot initialize database via Flyway!", sqle); + databaseUpdated.set(false); + } + } + + return databaseUpdated.get(); + } + /** * Get the database connection associated with the context - * + * * @return the database connection */ - DBConnection getDBConnection() - { + DBConnection getDBConnection() { return dbConnection; } - public DatabaseConfigVO getDBConfig() throws SQLException - { + public DatabaseConfigVO getDBConfig() throws SQLException { return dbConnection.getDatabaseConfig(); } - public String getDbType(){ + public String getDbType() { return dbConnection.getType(); } /** * Set the current user. Authentication must have been performed by the * caller - this call does not attempt any authentication. - * - * @param user - * the new current user, or null if no user is - * authenticated + * + * @param user the new current user, or null if no user is + * authenticated */ - public void setCurrentUser(EPerson user) - { + public void setCurrentUser(EPerson user) { currentUser = user; } /** * Get the current (authenticated) user - * + * * @return the current user, or null if no user is - * authenticated + * authenticated */ - public EPerson getCurrentUser() - { + public EPerson getCurrentUser() { return currentUser; } /** * Gets the current Locale - * + * * @return Locale the current Locale */ - public Locale getCurrentLocale() - { + public Locale getCurrentLocale() { return currentLocale; } /** * set the current Locale - * - * @param locale - * the current Locale + * + * @param locale the current Locale */ - public void setCurrentLocale(Locale locale) - { + public void setCurrentLocale(Locale locale) { currentLocale = locale; } /** * Find out if the authorisation system should be ignored for this context. - * + * * @return true if authorisation should be ignored for this - * session. + * session. */ - public boolean ignoreAuthorization() - { + public boolean ignoreAuthorization() { return ignoreAuth; } @@ -252,11 +268,9 @@ public class Context * Turn Off the Authorisation System for this context and store this change * in a history for future use. */ - public void turnOffAuthorisationSystem() - { + public void turnOffAuthorisationSystem() { authStateChangeHistory.push(ignoreAuth); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { Thread currThread = Thread.currentThread(); StackTraceElement[] stackTrace = currThread.getStackTrace(); String caller = stackTrace[stackTrace.length - 1].getClassName(); @@ -270,28 +284,23 @@ public class Context * Restore the previous Authorisation System State. If the state was not * changed by the current caller a warning will be displayed in log. Use: * - * mycontext.turnOffAuthorisationSystem(); - * some java code that require no authorisation check - * mycontext.restoreAuthSystemState(); - * If Context debug is enabled, the correct sequence calling will be + * mycontext.turnOffAuthorisationSystem(); + * some java code that require no authorisation check + * mycontext.restoreAuthSystemState(); + * If Context debug is enabled, the correct sequence calling will be * checked and a warning will be displayed if not. */ - public void restoreAuthSystemState() - { + public void restoreAuthSystemState() { Boolean previousState; - try - { + try { previousState = authStateChangeHistory.pop(); - } - catch (EmptyStackException ex) - { + } catch (EmptyStackException ex) { log.warn(LogManager.getHeader(this, "restore_auth_sys_state", - "not previous state info available " - + ex.getLocalizedMessage())); + "not previous state info available " + + ex.getLocalizedMessage())); previousState = Boolean.FALSE; } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { Thread currThread = Thread.currentThread(); StackTraceElement[] stackTrace = currThread.getStackTrace(); String caller = stackTrace[stackTrace.length - 1].getClassName(); @@ -299,17 +308,16 @@ public class Context String previousCaller = (String) authStateClassCallHistory.pop(); // if previousCaller is not the current caller *only* log a warning - if (!previousCaller.equals(caller)) - { + if (!previousCaller.equals(caller)) { log - .warn(LogManager - .getHeader( - this, - "restore_auth_sys_state", - "Class: " - + caller - + " call restore but previous state change made by " - + previousCaller)); + .warn(LogManager + .getHeader( + this, + "restore_auth_sys_state", + "Class: " + + caller + + " call restore but previous state change made by " + + previousCaller)); } } ignoreAuth = previousState.booleanValue(); @@ -321,23 +329,20 @@ public class Context * current Web user's session: *

    * setExtraLogInfo("session_id="+request.getSession().getId()); - * - * @param info - * the extra information to log + * + * @param info the extra information to log */ - public void setExtraLogInfo(String info) - { + public void setExtraLogInfo(String info) { extraLogInfo = info; } /** * Get extra information to be logged with message logged in the scope of * this context. - * + * * @return the extra log info - guaranteed non- null */ - public String getExtraLogInfo() - { + public String getExtraLogInfo() { return extraLogInfo; } @@ -348,32 +353,27 @@ public class Context *

    * Calling complete() on a Context which is no longer valid (isValid()==false), * is a no-op. - * - * @throws SQLException - * if there was an error completing the database transaction - * or closing the connection + * + * @throws SQLException if there was an error completing the database transaction + * or closing the connection */ - public void complete() throws SQLException - { + public void complete() throws SQLException { // If Context is no longer open/valid, just note that it has already been closed - if(!isValid()) + if (!isValid()) { log.info("complete() was called on a closed Context object. No changes to commit."); + } - try - { + try { // As long as we have a valid, writeable database connection, // rollback any changes if we are in read-only mode, // otherwise, commit any changes made as part of the transaction - if(isReadOnly()) { + if (isReadOnly()) { abort(); } else { commit(); } - } - finally - { - if(dbConnection != null) - { + } finally { + if (dbConnection != null) { // Free the DB connection dbConnection.closeDBConnection(); dbConnection = null; @@ -391,34 +391,32 @@ public class Context * * @throws SQLException When committing the transaction in the database fails. */ - public void commit() throws SQLException - { + public void commit() throws SQLException { // If Context is no longer open/valid, just note that it has already been closed - if(!isValid()) { + if (!isValid()) { log.info("commit() was called on a closed Context object. No changes to commit."); } - if(isReadOnly()) { + if (isReadOnly()) { throw new UnsupportedOperationException("You cannot commit a read-only context"); } // Our DB Connection (Hibernate) will decide if an actual commit is required or not - try - { + try { // As long as we have a valid, writeable database connection, // commit any changes made as part of the transaction - if (isValid()) - { + if (isValid()) { + // Dispatch events before committing changes to the database, + // as the consumers may change something too dispatchEvents(); } } finally { - if(log.isDebugEnabled()) { + if (log.isDebugEnabled()) { log.debug("Cache size on commit is " + getCacheSize()); } - if(dbConnection != null) - { + if (dbConnection != null) { //Commit our changes dbConnection.commit(); reloadContextBoundEntities(); @@ -427,8 +425,7 @@ public class Context } - public void dispatchEvents() - { + public void dispatchEvents() { // Commit any changes made as part of the transaction Dispatcher dispatcher = null; @@ -452,37 +449,31 @@ public class Context /** * Select an event dispatcher, null selects the default - * + * * @param dispatcher dispatcher */ - public void setDispatcher(String dispatcher) - { - if (log.isDebugEnabled()) - { + public void setDispatcher(String dispatcher) { + if (log.isDebugEnabled()) { log.debug(this.toString() + ": setDispatcher(\"" + dispatcher - + "\")"); + + "\")"); } dispName = dispatcher; } /** * Add an event to be dispatched when this context is committed. - * - * @param event - * event to be dispatched + * + * @param event event to be dispatched */ - public void addEvent(Event event) - { - /* + public void addEvent(Event event) { + /* * invalid condition if in read-only mode: events - which * indicate mutation - are firing: no recourse but to bail */ - if (isReadOnly()) - { + if (isReadOnly()) { throw new IllegalStateException("Attempt to mutate object in read-only context"); } - if (events == null) - { + if (events == null) { events = new LinkedList(); } @@ -492,29 +483,26 @@ public class Context /** * Get the current event list. If there is a separate list of events from * already-committed operations combine that with current list. - * + * * @return List of all available events. */ - public LinkedList getEvents() - { + public LinkedList getEvents() { return events; } - public boolean hasEvents() - { + public boolean hasEvents() { return !CollectionUtils.isEmpty(events); } /** * Retrieves the first element in the events list and removes it from the list of events once retrieved + * * @return The first event of the list or null if the list is empty */ - public Event pollEvent() - { - if(hasEvents()) - { + public Event pollEvent() { + if (hasEvents()) { return events.poll(); - }else{ + } else { return null; } } @@ -529,68 +517,61 @@ public class Context * Calling abort() on a Context which is no longer valid (isValid()==false), * is a no-op. */ - public void abort() - { + public void abort() { // If Context is no longer open/valid, just note that it has already been closed - if(!isValid()) + if (!isValid()) { log.info("abort() was called on a closed Context object. No changes to abort."); + } - try - { - // Rollback if we have a database connection, and it is NOT Read Only - if (isValid()) - { + try { + // Rollback ONLY if we have a database connection, and it is NOT Read Only + if (isValid() && !isReadOnly()) { dbConnection.rollback(); } - } - catch (SQLException se) - { + } catch (SQLException se) { log.error(se.getMessage(), se); - } - finally - { - try - { - if (!dbConnection.isSessionAlive()) - { + } finally { + try { + if (!dbConnection.isSessionAlive()) { dbConnection.closeDBConnection(); } - } - catch (Exception ex) - { + } catch (Exception ex) { log.error("Exception aborting context", ex); } events = null; } } + @Override + public void close() { + if (isValid()) { + abort(); + } + } + /** - * * Find out if this context is valid. Returns false if this * context has been aborted or completed. - * + * * @return true if the context is still valid, otherwise - * false + * false */ - public boolean isValid() - { + public boolean isValid() { // Only return true if our DB connection is live return dbConnection != null && dbConnection.isTransActionAlive(); } /** * Reports whether context supports updating DSpaceObjects, or only reading. - * + * * @return true if the context is read-only, otherwise - * false + * false */ - public boolean isReadOnly() - { + public boolean isReadOnly() { return mode != null && mode == Mode.READ_ONLY; } - public void setSpecialGroup(UUID groupID) - { + public void setSpecialGroup(UUID groupID) { specialGroups.add(groupID); // System.out.println("Added " + groupID); @@ -598,15 +579,12 @@ public class Context /** * test if member of special group - * - * @param groupID - * ID of special group to test + * + * @param groupID ID of special group to test * @return true if member */ - public boolean inSpecialGroup(UUID groupID) - { - if (specialGroups.contains(groupID)) - { + public boolean inSpecialGroup(UUID groupID) { + if (specialGroups.contains(groupID)) { // System.out.println("Contains " + groupID); return true; } @@ -617,14 +595,13 @@ public class Context /** * Get an array of all of the special groups that current user is a member * of. + * * @return list of groups * @throws SQLException if database error */ - public List getSpecialGroups() throws SQLException - { + public List getSpecialGroups() throws SQLException { List myGroups = new ArrayList(); - for (UUID groupId : specialGroups) - { + for (UUID groupId : specialGroups) { myGroups.add(EPersonServiceFactory.getInstance().getGroupService().find(this, groupId)); } @@ -632,14 +609,12 @@ public class Context } @Override - protected void finalize() throws Throwable - { + protected void finalize() throws Throwable { /* * If a context is garbage-collected, we roll back and free up the * database connection if there is one. */ - if (dbConnection != null && dbConnection.isTransActionAlive()) - { + if (dbConnection != null && dbConnection.isTransActionAlive()) { abort(); } @@ -654,7 +629,8 @@ public class Context /** * Returns the size of the cache of all object that have been read from the database so far. A larger number * means that more memory is consumed by the cache. This also has a negative impact on the query performance. In - * that case you should consider uncaching entities when they are no longer needed (see {@link Context#uncacheEntity(ReloadableEntity)} () uncacheEntity}). + * that case you should consider uncaching entities when they are no longer needed (see + * {@link Context#uncacheEntity(ReloadableEntity)} () uncacheEntity}). * * @throws SQLException When connecting to the active cache fails. */ @@ -671,7 +647,8 @@ public class Context * READ_ONLY: READ ONLY mode will tell the database we are nog going to do any updates. This means it can disable * optimalisations for delaying or grouping updates. * - * READ_WRITE: This is the default mode and enables the normal database behaviour. This behaviour is optimal for querying and updating a + * READ_WRITE: This is the default mode and enables the normal database behaviour. This behaviour is optimal for + * querying and updating a * small number of records. * * @param newMode The mode to put this context in @@ -693,12 +670,12 @@ public class Context log.warn("New context mode detected that has nog been configured."); break; } - } catch(SQLException ex) { + } catch (SQLException ex) { log.warn("Unable to set database connection mode", ex); } //Always clear the cache, except when going from READ_ONLY to READ_ONLY - if(mode != Mode.READ_ONLY || newMode != Mode.READ_ONLY) { + if (mode != Mode.READ_ONLY || newMode != Mode.READ_ONLY) { //clear our read-only cache to prevent any inconsistencies readOnlyCache.clear(); } @@ -709,6 +686,7 @@ public class Context /** * The current database mode of this context. + * * @return The current mode */ public Mode getCurrentMode() { @@ -729,7 +707,7 @@ public class Context */ @Deprecated public void enableBatchMode(boolean batchModeEnabled) throws SQLException { - if(batchModeEnabled) { + if (batchModeEnabled) { setMode(Mode.BATCH_EDIT); } else { setMode(Mode.READ_WRITE); @@ -738,6 +716,7 @@ public class Context /** * Check if "batch processing mode" is enabled for this context. + * * @return True if batch processing mode is enabled, false otherwise. */ @Deprecated @@ -750,7 +729,7 @@ public class Context * entity. This means changes to the entity will be tracked and persisted to the database. * * @param entity The entity to reload - * @param The class of the enity. The entity must implement the {@link ReloadableEntity} interface. + * @param The class of the enity. The entity must implement the {@link ReloadableEntity} interface. * @return A (possibly) NEW reference to the entity that should be used for further processing. * @throws SQLException When reloading the entity from the database fails. */ @@ -763,7 +742,7 @@ public class Context * Remove an entity from the cache. This is necessary when batch processing a large number of items. * * @param entity The entity to reload - * @param The class of the enity. The entity must implement the {@link ReloadableEntity} interface. + * @param The class of the enity. The entity must implement the {@link ReloadableEntity} interface. * @throws SQLException When reloading the entity from the database fails. */ @SuppressWarnings("unchecked") @@ -772,15 +751,16 @@ public class Context } public Boolean getCachedAuthorizationResult(DSpaceObject dspaceObject, int action, EPerson eperson) { - if(isReadOnly()) { + if (isReadOnly()) { return readOnlyCache.getCachedAuthorizationResult(dspaceObject, action, eperson); } else { return null; } } - public void cacheAuthorizedAction(DSpaceObject dspaceObject, int action, EPerson eperson, Boolean result, ResourcePolicy rp) { - if(isReadOnly()) { + public void cacheAuthorizedAction(DSpaceObject dspaceObject, int action, EPerson eperson, Boolean result, + ResourcePolicy rp) { + if (isReadOnly()) { readOnlyCache.cacheAuthorizedAction(dspaceObject, action, eperson, result); try { uncacheEntity(rp); @@ -791,7 +771,7 @@ public class Context } public Boolean getCachedGroupMembership(Group group, EPerson eperson) { - if(isReadOnly()) { + if (isReadOnly()) { return readOnlyCache.getCachedGroupMembership(group, eperson); } else { return null; @@ -799,19 +779,19 @@ public class Context } public void cacheGroupMembership(Group group, EPerson eperson, Boolean isMember) { - if(isReadOnly()) { + if (isReadOnly()) { readOnlyCache.cacheGroupMembership(group, eperson, isMember); } } public void cacheAllMemberGroupsSet(EPerson ePerson, Set groups) { - if(isReadOnly()) { + if (isReadOnly()) { readOnlyCache.cacheAllMemberGroupsSet(ePerson, groups); } } public Set getCachedAllMemberGroupsSet(EPerson ePerson) { - if(isReadOnly()) { + if (isReadOnly()) { return readOnlyCache.getCachedAllMemberGroupsSet(ePerson); } else { return null; @@ -820,6 +800,7 @@ public class Context /** * Reload all entities related to this context. + * * @throws SQLException When reloading one of the entities fails. */ private void reloadContextBoundEntities() throws SQLException { diff --git a/dspace-api/src/main/java/org/dspace/core/ContextReadOnlyCache.java b/dspace-api/src/main/java/org/dspace/core/ContextReadOnlyCache.java index 4eba1b1b1f..fff84c7424 100644 --- a/dspace-api/src/main/java/org/dspace/core/ContextReadOnlyCache.java +++ b/dspace-api/src/main/java/org/dspace/core/ContextReadOnlyCache.java @@ -7,6 +7,9 @@ */ package org.dspace.core; +import java.util.HashMap; +import java.util.Set; + import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.commons.lang3.tuple.Pair; @@ -16,9 +19,6 @@ import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.springframework.util.CollectionUtils; -import java.util.HashMap; -import java.util.Set; - /** * Object that manages the read-only caches for the Context class */ @@ -69,7 +69,7 @@ public class ContextReadOnlyCache { public void cacheAllMemberGroupsSet(EPerson ePerson, Set groups) { allMemberGroupsCache.put(buildAllMembersGroupKey(ePerson), - groups); + groups); //clear the individual groupMembershipCache as we have all memberships now. groupMembershipCache.clear(); @@ -89,15 +89,16 @@ public class ContextReadOnlyCache { return ePerson == null ? "" : ePerson.getID().toString(); } - private ImmutableTriple buildAuthorizedActionKey(DSpaceObject dspaceObject, int action, EPerson eperson) { + private ImmutableTriple buildAuthorizedActionKey(DSpaceObject dspaceObject, int action, + EPerson eperson) { return new ImmutableTriple<>(dspaceObject == null ? "" : dspaceObject.getID().toString(), - Integer.valueOf(action), - eperson == null ? "" : eperson.getID().toString()); + Integer.valueOf(action), + eperson == null ? "" : eperson.getID().toString()); } private Pair buildGroupMembershipKey(Group group, EPerson eperson) { return new ImmutablePair<>(group == null ? "" : group.getName(), - eperson == null ? "" : eperson.getID().toString()); + eperson == null ? "" : eperson.getID().toString()); } } diff --git a/dspace-api/src/main/java/org/dspace/core/DBConnection.java b/dspace-api/src/main/java/org/dspace/core/DBConnection.java index 26ea5a86b2..cb5825eec1 100644 --- a/dspace-api/src/main/java/org/dspace/core/DBConnection.java +++ b/dspace-api/src/main/java/org/dspace/core/DBConnection.java @@ -7,61 +7,145 @@ */ package org.dspace.core; +import java.sql.SQLException; +import javax.sql.DataSource; + import org.dspace.storage.rdbms.DatabaseConfigVO; -import javax.sql.DataSource; -import java.sql.SQLException; - /** - * Interface representing a Database connection, this class should only be access by the context object. + * Interface representing a persistence provider "session". + * Implementations will wrap something like a JPA EntityManager or a Hibernate + * Session. The terms "database" and "connection" are historic and have no + * direct relationship to a JDBC Connection or even a connection pool. * + *

    This class should only be accessed by an enclosing {@link Context} object. + * + *

    Note that the user's HTTPSession is an unrelated concept. + * + * @param type of the persistence provider's session object. * @author kevinvandevelde at atmire.com - * @param class type */ public interface DBConnection { + /** + * Access to the underlying persistence provider's session object. + * + * @return the provider's session object for this connection. + * @throws SQLException passed through. + */ public T getSession() throws SQLException; + /** + * @return true if this session has an uncommitted transaction. + */ public boolean isTransActionAlive(); + /** + * @return true if the session is open, false if it has been closed. + */ public boolean isSessionAlive(); - public void rollback() throws SQLException; - - public void closeDBConnection() throws SQLException; - + /** + * Commit the open transaction. + * + * @throws SQLException passed through. + */ public void commit() throws SQLException; + /** + * Roll back the open transaction. + * + * @throws SQLException passed through. + */ + public void rollback() throws SQLException; + + /** + * Close this session: close DBMS connection(s) and clean up resources. + * + * @throws SQLException passed through. + */ + public void closeDBConnection() throws SQLException; + + /** + * Close all sessions. Release all associated resources (cache, DBMS + * connections, etc.) To be used only when exiting the application. + */ public void shutdown(); + /** + * Some description of the DBMS used to persist entities. + * + * @return Brand, version, dialect, etc. Implementation specific. + */ public String getType(); + /** + * The JDBC DataSource used by this session. Think carefully before using. + * + * @return the source of DBMS connections. + */ public DataSource getDataSource(); + /** + * Identify certain characteristics of the DBMS being used to support persistence. + * + * @return a collection of DBMS, database and connection information. + * @throws SQLException passed through. + */ public DatabaseConfigVO getDatabaseConfig() throws SQLException; - + + /** + * Configure the connection for special uses. + * + * @param batchOptimized if true, optimize for batch use. Typically this + * means suppressing automatic flushing of updates, thus requiring manual + * flushing at appropriate points in the process. + * @param readOnlyOptimized if true, optimize for read-only use. Typically + * this suppresses all updating. + * @throws SQLException + */ public void setConnectionMode(boolean batchOptimized, boolean readOnlyOptimized) throws SQLException; + /** + * Has this session been configured for large batches? Typically this means + * that automatic flushing of updates to the database is suppressed, and + * thus one must take care to flush manually (or commit) at appropriate times. + * + * @return true if configured for batch. + */ public boolean isOptimizedForBatchProcessing(); + /** + * How many entities are cached in this session? + * + * @return number of cached entities. + * @throws SQLException passed through. + */ public long getCacheSize() throws SQLException; /** - * Reload a DSpace object from the database. This will make sure the object is valid and stored in the cache. - * @param the type of entity. + * Reload a DSpace object from the database. This will make sure the object + * is valid and stored in the cache. The returned object should be used + * henceforth instead of the passed object. + * + * @param type of {@link entity} * @param entity The DSpace object to reload * @return the reloaded entity. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws java.sql.SQLException passed through. */ public E reloadEntity(E entity) throws SQLException; /** - * Remove a DSpace object from the cache when batch processing a large number of objects. - * @param the type of entity. - * @param entity The DSpace object to reload - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * Remove a DSpace object from the session cache when batch processing a + * large number of objects. + * + *

    Objects removed from cache are not saved in any way. Therefore, if you + * have modified an object, you should be sure to {@link commit()} changes + * before calling this method. + * + * @param Type of {@link entity} + * @param entity The DSpace object to decache. + * @throws java.sql.SQLException passed through. */ - public void uncacheEntity(E entity) throws SQLException ; + public void uncacheEntity(E entity) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/core/Email.java b/dspace-api/src/main/java/org/dspace/core/Email.java index e3a1bc57b2..0ce631e6b8 100644 --- a/dspace-api/src/main/java/org/dspace/core/Email.java +++ b/dspace-api/src/main/java/org/dspace/core/Email.java @@ -36,6 +36,7 @@ import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; + import org.apache.log4j.Logger; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; @@ -99,33 +100,43 @@ import org.dspace.services.factory.DSpaceServicesFactory; * of the e-mail; they won't get filled out. *

    * - * * @author Robert Tansley * @author Jim Downing - added attachment handling code * @author Adan Roman Ruiz at arvo.es - added inputstream attachment handling code * @version $Revision: 5844 $ */ -public class Email -{ - /** The content of the message */ +public class Email { + /** + * The content of the message + */ private String content; - /** The subject of the message */ + /** + * The subject of the message + */ private String subject; - /** The arguments to fill out */ + /** + * The arguments to fill out + */ private List arguments; - /** The recipients */ + /** + * The recipients + */ private List recipients; - /** Reply to field, if any */ + /** + * Reply to field, if any + */ private String replyTo; private List attachments; private List moreAttachments; - /** The character set this message will be sent in */ + /** + * The character set this message will be sent in + */ private String charset; private static final Logger log = Logger.getLogger(Email.class); @@ -133,8 +144,7 @@ public class Email /** * Create a new email message. */ - public Email() - { + public Email() { arguments = new ArrayList(50); recipients = new ArrayList(50); attachments = new ArrayList(10); @@ -148,11 +158,9 @@ public class Email /** * Add a recipient * - * @param email - * the recipient's email address + * @param email the recipient's email address */ - public void addRecipient(String email) - { + public void addRecipient(String email) { recipients.add(email); } @@ -161,11 +169,9 @@ public class Email * formatting -addArgument will start. Comments and any * "Subject:" line must be stripped. * - * @param cnt - * the content of the message + * @param cnt the content of the message */ - public void setContent(String cnt) - { + public void setContent(String cnt) { content = cnt; arguments = new ArrayList(); } @@ -173,47 +179,39 @@ public class Email /** * Set the subject of the message * - * @param s - * the subject of the message + * @param s the subject of the message */ - public void setSubject(String s) - { + public void setSubject(String s) { subject = s; } /** * Set the reply-to email address * - * @param email - * the reply-to email address + * @param email the reply-to email address */ - public void setReplyTo(String email) - { + public void setReplyTo(String email) { replyTo = email; } /** * Fill out the next argument in the template * - * @param arg - * the value for the next argument + * @param arg the value for the next argument */ - public void addArgument(Object arg) - { + public void addArgument(Object arg) { arguments.add(arg); } - public void addAttachment(File f, String name) - { + public void addAttachment(File f, String name) { attachments.add(new FileAttachment(f, name)); } - public void addAttachment(InputStream is, String name,String mimetype) - { - moreAttachments.add(new InputStreamAttachment(is, name,mimetype)); + + public void addAttachment(InputStream is, String name, String mimetype) { + moreAttachments.add(new InputStreamAttachment(is, name, mimetype)); } - public void setCharset(String cs) - { + public void setCharset(String cs) { charset = cs; } @@ -221,8 +219,7 @@ public class Email * "Reset" the message. Clears the arguments and recipients, but leaves the * subject and content intact. */ - public void reset() - { + public void reset() { arguments = new ArrayList(50); recipients = new ArrayList(50); attachments = new ArrayList(10); @@ -234,12 +231,10 @@ public class Email /** * Sends the email. * - * @throws MessagingException - * if there was a problem sending the mail. - * @throws IOException if IO error + * @throws MessagingException if there was a problem sending the mail. + * @throws IOException if IO error */ - public void send() throws MessagingException, IOException - { + public void send() throws MessagingException, IOException { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); // Get the mail configuration properties @@ -247,8 +242,7 @@ public class Email boolean disabled = config.getBooleanProperty("mail.server.disabled", false); // If no character set specified, attempt to retrieve a default - if (charset == null) - { + if (charset == null) { charset = config.getProperty("mail.charset"); } @@ -261,10 +255,9 @@ public class Email // Set the recipients of the message Iterator i = recipients.iterator(); - while (i.hasNext()) - { + while (i.hasNext()) { message.addRecipient(Message.RecipientType.TO, new InternetAddress( - i.next())); + i.next())); } // Format the mail message @@ -277,182 +270,152 @@ public class Email // Set the subject of the email (may contain parameters) String fullSubject = MessageFormat.format(subject, args); - if (charset != null) - { + if (charset != null) { message.setSubject(fullSubject, charset); - } - else - { + } else { message.setSubject(fullSubject); } // Add attachments - if (attachments.isEmpty() && moreAttachments.isEmpty()) - { + if (attachments.isEmpty() && moreAttachments.isEmpty()) { // If a character set has been specified, or a default exists - if (charset != null) - { + if (charset != null) { message.setText(fullMessage, charset); - } - else - { + } else { message.setText(fullMessage); } - } - else - { - Multipart multipart = new MimeMultipart(); - // create the first part of the email - BodyPart messageBodyPart = new MimeBodyPart(); - messageBodyPart.setText(fullMessage); - multipart.addBodyPart(messageBodyPart); - if (!attachments.isEmpty()) { - for (Iterator iter = attachments.iterator(); iter.hasNext();) - { + } else { + Multipart multipart = new MimeMultipart(); + // create the first part of the email + BodyPart messageBodyPart = new MimeBodyPart(); + messageBodyPart.setText(fullMessage); + multipart.addBodyPart(messageBodyPart); + if (!attachments.isEmpty()) { + for (Iterator iter = attachments.iterator(); iter.hasNext(); ) { FileAttachment f = iter.next(); // add the file messageBodyPart = new MimeBodyPart(); messageBodyPart.setDataHandler(new DataHandler( - new FileDataSource(f.file))); + new FileDataSource(f.file))); messageBodyPart.setFileName(f.name); multipart.addBodyPart(messageBodyPart); } message.setContent(multipart); - } - if (!moreAttachments.isEmpty()) { - for (Iterator iter = moreAttachments.iterator(); iter.hasNext();) - { - InputStreamAttachment isa = iter.next(); - // add the stream - messageBodyPart = new MimeBodyPart(); - messageBodyPart.setDataHandler( - new DataHandler(new InputStreamDataSource( - isa.name, - isa.mimetype, - isa.is) - ) - ); - messageBodyPart.setFileName(isa.name); - multipart.addBodyPart(messageBodyPart); - } - message.setContent(multipart); - } + } + if (!moreAttachments.isEmpty()) { + for (Iterator iter = moreAttachments.iterator(); iter.hasNext(); ) { + InputStreamAttachment isa = iter.next(); + // add the stream + messageBodyPart = new MimeBodyPart(); + messageBodyPart.setDataHandler( + new DataHandler(new InputStreamDataSource( + isa.name, + isa.mimetype, + isa.is) + ) + ); + messageBodyPart.setFileName(isa.name); + multipart.addBodyPart(messageBodyPart); + } + message.setContent(multipart); + } } - if (replyTo != null) - { + if (replyTo != null) { Address[] replyToAddr = new Address[1]; replyToAddr[0] = new InternetAddress(replyTo); message.setReplyTo(replyToAddr); } - if (disabled) - { + if (disabled) { StringBuffer text = new StringBuffer( "Message not sent due to mail.server.disabled:\n"); Enumeration headers = message.getAllHeaderLines(); - while (headers.hasMoreElements()) + while (headers.hasMoreElements()) { text.append(headers.nextElement()).append('\n'); + } - if (!attachments.isEmpty()) - { + if (!attachments.isEmpty()) { text.append("\nAttachments:\n"); - for (FileAttachment f : attachments) + for (FileAttachment f : attachments) { text.append(f.name).append('\n'); + } text.append('\n'); } text.append('\n').append(fullMessage); log.info(text); - } - else + } else { Transport.send(message); + } } /** * Get the template for an email message. The message is suitable for * inserting values using java.text.MessageFormat. * - * @param emailFile - * full name for the email template, for example "/dspace/config/emails/register". - * + * @param emailFile full name for the email template, for example "/dspace/config/emails/register". * @return the email object, with the content and subject filled out from - * the template - * + * the template * @throws IOException if IO error - * if the template couldn't be found, or there was some other - * error reading the template + * if the template couldn't be found, or there was some other + * error reading the template */ public static Email getEmail(String emailFile) - throws IOException - { + throws IOException { String charset = null; String subject = ""; StringBuilder contentBuffer = new StringBuilder(); InputStream is = null; InputStreamReader ir = null; BufferedReader reader = null; - try - { + try { is = new FileInputStream(emailFile); ir = new InputStreamReader(is, "UTF-8"); reader = new BufferedReader(ir); boolean more = true; - while (more) - { + while (more) { String line = reader.readLine(); - if (line == null) - { + if (line == null) { more = false; - } - else if (line.toLowerCase().startsWith("subject:")) - { + } else if (line.toLowerCase().startsWith("subject:")) { subject = line.substring(8).trim(); - } - else if (line.toLowerCase().startsWith("charset:")) - { + } else if (line.toLowerCase().startsWith("charset:")) { charset = line.substring(8).trim(); - } - else if (!line.startsWith("#")) - { + } else if (!line.startsWith("#")) { contentBuffer.append(line); contentBuffer.append("\n"); } } - } finally - { - if (reader != null) - { + } finally { + if (reader != null) { try { reader.close(); - } catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } - if (ir != null) - { + if (ir != null) { try { ir.close(); - } catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } - if (is != null) - { + if (is != null) { try { is.close(); - } catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } Email email = new Email(); email.setSubject(subject); email.setContent(contentBuffer.toString()); - if (charset != null) - { + if (charset != null) { email.setCharset(charset); } return email; @@ -472,8 +435,7 @@ public class Email * * @param args the command line arguments given */ - public static void main(String[] args) - { + public static void main(String[] args) { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); String to = config.getProperty("mail.admin"); String subject = "DSpace test email"; @@ -488,10 +450,8 @@ public class Email System.out.println(" - Subject: " + subject); System.out.println(" - Server: " + server); boolean disabled = config.getBooleanProperty("mail.server.disabled", false); - try - { - if (disabled) - { + try { + if (disabled) { System.err.println("\nError sending email:"); System.err.println(" - Error: cannot test email because mail.server.disabled is set to true"); System.err.println("\nPlease see the DSpace documentation for assistance.\n"); @@ -500,17 +460,13 @@ public class Email return; } e.send(); - } - catch (MessagingException me) - { + } catch (MessagingException me) { System.err.println("\nError sending email:"); System.err.println(" - Error: " + me); System.err.println("\nPlease see the DSpace documentation for assistance.\n"); System.err.println("\n"); System.exit(1); - } - catch (IOException e1) - { + } catch (IOException e1) { System.err.println("\nError sending email:"); System.err.println(" - Error: " + e1); System.err.println("\nPlease see the DSpace documentation for assistance.\n"); @@ -524,12 +480,9 @@ public class Email * Utility struct class for handling file attachments. * * @author ojd20 - * */ - private static class FileAttachment - { - public FileAttachment(File f, String n) - { + private static class FileAttachment { + public FileAttachment(File f, String n) { this.file = f; this.name = n; } @@ -541,14 +494,11 @@ public class Email /** * Utility struct class for handling file attachments. - * + * * @author Adán Román Ruiz at arvo.es - * */ - private static class InputStreamAttachment - { - public InputStreamAttachment(InputStream is, String name, String mimetype) - { + private static class InputStreamAttachment { + public InputStreamAttachment(InputStream is, String name, String mimetype) { this.is = is; this.name = name; this.mimetype = mimetype; @@ -558,46 +508,45 @@ public class Email String mimetype; String name; } - + /** - * - * @author arnaldo - */ - public class InputStreamDataSource implements DataSource { - private String name; - private String contentType; - private ByteArrayOutputStream baos; - - InputStreamDataSource(String name, String contentType, InputStream inputStream) throws IOException { - this.name = name; - this.contentType = contentType; - baos = new ByteArrayOutputStream(); - int read; - byte[] buff = new byte[256]; - while((read = inputStream.read(buff)) != -1) { - baos.write(buff, 0, read); - } - } + * @author arnaldo + */ + public class InputStreamDataSource implements DataSource { + private String name; + private String contentType; + private ByteArrayOutputStream baos; - @Override - public String getContentType() { - return contentType; - } - - @Override - public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(baos.toByteArray()); - } - - @Override - public String getName() { - return name; - } + InputStreamDataSource(String name, String contentType, InputStream inputStream) throws IOException { + this.name = name; + this.contentType = contentType; + baos = new ByteArrayOutputStream(); + int read; + byte[] buff = new byte[256]; + while ((read = inputStream.read(buff)) != -1) { + baos.write(buff, 0, read); + } + } - @Override - public OutputStream getOutputStream() throws IOException { - throw new IOException("Cannot write to this read-only resource"); - } - } + @Override + public String getContentType() { + return contentType; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(baos.toByteArray()); + } + + @Override + public String getName() { + return name; + } + + @Override + public OutputStream getOutputStream() throws IOException { + throw new IOException("Cannot write to this read-only resource"); + } + } } diff --git a/dspace-api/src/main/java/org/dspace/core/GenericDAO.java b/dspace-api/src/main/java/org/dspace/core/GenericDAO.java index 20a03f039e..ba17499a67 100644 --- a/dspace-api/src/main/java/org/dspace/core/GenericDAO.java +++ b/dspace-api/src/main/java/org/dspace/core/GenericDAO.java @@ -7,8 +7,6 @@ */ package org.dspace.core; -import org.dspace.content.DSpaceObject; - import java.sql.SQLException; import java.util.List; import java.util.UUID; @@ -16,25 +14,45 @@ import java.util.UUID; /** * Generic Database Access Object interface class that should be implemented by all DAOs. * It offers up a lot of general methods so these don't need to be declared again in each DAO. - * The default hibernate implementation offers up a class that implements all these methods. + * The default Hibernate implementation offers up a class that implements all these methods. * + * @param type which is accessed by this DAO, for example Item. * @author kevinvandevelde at atmire.com - * @param class type */ -public interface GenericDAO -{ +public interface GenericDAO { + /** + * Create a new instance of this type in the database. + * + * @param context current DSpace context. + * @param t type to be created. + * @return entity tracking the created instance. + * @throws SQLException + */ public T create(Context context, T t) throws SQLException; + /** + * Persist this instance in the database. + * + * @param context current DSpace context. + * @param t type created here. + * @throws SQLException passed through. + */ public void save(Context context, T t) throws SQLException; + /** + * Remove an instance from the database. + * + * @param context current DSpace context. + * @param t type of the instance to be removed. + * @throws SQLException passed through. + */ public void delete(Context context, T t) throws SQLException; /** * Fetch all persisted instances of a given object type. * - * @param context - * The relevant DSpace Context. - * @param clazz the desired type. + * @param context The relevant DSpace Context. + * @param clazz the desired type. * @return list of DAOs of the same type as clazz * @throws SQLException if database error */ @@ -43,24 +61,40 @@ public interface GenericDAO /** * Execute a JPQL query returning a unique result. * - * @param context - * The relevant DSpace Context. - * @param query JPQL query string + * @param context The relevant DSpace Context. + * @param query JPQL query string * @return a DAO specified by the query string * @throws SQLException if database error */ public T findUnique(Context context, String query) throws SQLException; + /** + * Fetch the entity identified by its legacy database identifier. + * + * @param context current DSpace context. + * @param clazz class of entity to be found. + * @param id legacy database record ID. + * @return the found entity. + * @throws SQLException passed through. + */ public T findByID(Context context, Class clazz, int id) throws SQLException; + /** + * Fetch the entity identified by its UUID primary key. + * + * @param context current DSpace context. + * @param clazz class of entity to be found. + * @param id primary key of the database record. + * @return the found entity. + * @throws SQLException + */ public T findByID(Context context, Class clazz, UUID id) throws SQLException; /** * Execute a JPQL query and return a collection of results. * - * @param context - * The relevant DSpace Context. - * @param query JPQL query string + * @param context The relevant DSpace Context. + * @param query JPQL query string * @return list of DAOs specified by the query string * @throws SQLException if database error */ diff --git a/dspace-api/src/main/java/org/dspace/core/HibernateDBConnection.java b/dspace-api/src/main/java/org/dspace/core/HibernateDBConnection.java index b81cddff01..c88cd0c1cd 100644 --- a/dspace-api/src/main/java/org/dspace/core/HibernateDBConnection.java +++ b/dspace-api/src/main/java/org/dspace/core/HibernateDBConnection.java @@ -7,11 +7,25 @@ */ package org.dspace.core; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import javax.sql.DataSource; + import org.dspace.authorize.ResourcePolicy; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.handle.Handle; import org.dspace.storage.rdbms.DatabaseConfigVO; -import org.hibernate.*; +import org.hibernate.FlushMode; +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.proxy.HibernateProxyHelper; import org.hibernate.resource.transaction.spi.TransactionStatus; @@ -19,13 +33,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.orm.hibernate5.SessionFactoryUtils; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.SQLException; - /** - * Hibernate implementation of the DBConnection + * Hibernate implementation of the DBConnection. * * @author kevinvandevelde at atmire.com */ @@ -34,13 +43,13 @@ public class HibernateDBConnection implements DBConnection { @Autowired(required = true) @Qualifier("sessionFactory") private SessionFactory sessionFactory; - + private boolean batchModeEnabled = false; private boolean readOnlyEnabled = false; @Override public Session getSession() throws SQLException { - if(!isTransActionAlive()){ + if (!isTransActionAlive()) { sessionFactory.getCurrentSession().beginTransaction(); configureDatabaseMode(); } @@ -59,28 +68,29 @@ public class HibernateDBConnection implements DBConnection { @Override public boolean isSessionAlive() { - return sessionFactory.getCurrentSession() != null && sessionFactory.getCurrentSession().getTransaction() != null && sessionFactory.getCurrentSession().getTransaction().getStatus().isOneOf(TransactionStatus.ACTIVE); + return sessionFactory.getCurrentSession() != null && sessionFactory.getCurrentSession() + .getTransaction() != null && sessionFactory + .getCurrentSession().getTransaction().getStatus().isOneOf(TransactionStatus.ACTIVE); } @Override public void rollback() throws SQLException { - if(isTransActionAlive()){ + if (isTransActionAlive()) { getTransaction().rollback(); } } @Override public void closeDBConnection() throws SQLException { - if(sessionFactory.getCurrentSession() != null && sessionFactory.getCurrentSession().isOpen()) - { + if (sessionFactory.getCurrentSession() != null && sessionFactory.getCurrentSession().isOpen()) { sessionFactory.getCurrentSession().close(); } } @Override public void commit() throws SQLException { - if(isTransActionAlive() && !getTransaction().getStatus().isOneOf(TransactionStatus.MARKED_ROLLBACK, TransactionStatus.ROLLING_BACK)) - { + if (isTransActionAlive() && !getTransaction().getStatus().isOneOf(TransactionStatus.MARKED_ROLLBACK, + TransactionStatus.ROLLING_BACK)) { getSession().flush(); getTransaction().commit(); } @@ -125,9 +135,9 @@ public class HibernateDBConnection implements DBConnection { @Override @SuppressWarnings("unchecked") public E reloadEntity(final E entity) throws SQLException { - if(entity == null) { + if (entity == null) { return null; - } else if(getSession().contains(entity)) { + } else if (getSession().contains(entity)) { return entity; } else { return (E) getSession().get(HibernateProxyHelper.getClassWithoutInitializingProxy(entity), entity.getID()); @@ -147,9 +157,9 @@ public class HibernateDBConnection implements DBConnection { } private void configureDatabaseMode() throws SQLException { - if(batchModeEnabled) { + if (batchModeEnabled) { getSession().setHibernateFlushMode(FlushMode.ALWAYS); - } else if(readOnlyEnabled) { + } else if (readOnlyEnabled) { getSession().setHibernateFlushMode(FlushMode.MANUAL); } else { getSession().setHibernateFlushMode(FlushMode.AUTO); @@ -160,88 +170,91 @@ public class HibernateDBConnection implements DBConnection { * Evict an entity from the hibernate cache. This is necessary when batch processing a large number of items. * * @param entity The entity to reload - * @param The class of the enity. The entity must implement the {@link ReloadableEntity} interface. + * @param The class of the enity. The entity must implement the {@link ReloadableEntity} interface. * @throws SQLException When reloading the entity from the database fails. */ @Override public void uncacheEntity(E entity) throws SQLException { - if(entity != null) { + if (entity != null) { if (entity instanceof DSpaceObject) { DSpaceObject dso = (DSpaceObject) entity; // The metadatavalue relation has CascadeType.ALL, so they are evicted automatically // and we don' need to uncache the values explicitly. - if(Hibernate.isInitialized(dso.getHandles())) { + if (Hibernate.isInitialized(dso.getHandles())) { for (Handle handle : Utils.emptyIfNull(dso.getHandles())) { uncacheEntity(handle); } } - if(Hibernate.isInitialized(dso.getResourcePolicies())) { + if (Hibernate.isInitialized(dso.getResourcePolicies())) { for (ResourcePolicy policy : Utils.emptyIfNull(dso.getResourcePolicies())) { uncacheEntity(policy); } } } + // ITEM if (entity instanceof Item) { Item item = (Item) entity; - if(Hibernate.isInitialized(item.getSubmitter())) { - uncacheEntity(item.getSubmitter()); - } - if(Hibernate.isInitialized(item.getBundles())) { + //DO NOT uncache the submitter. This could be the current eperson. Uncaching could lead to + //LazyInitializationExceptions (see DS-3648) + + if (Hibernate.isInitialized(item.getBundles())) { for (Bundle bundle : Utils.emptyIfNull(item.getBundles())) { uncacheEntity(bundle); } } + // BUNDLE } else if (entity instanceof Bundle) { Bundle bundle = (Bundle) entity; - if(Hibernate.isInitialized(bundle.getBitstreams())) { + if (Hibernate.isInitialized(bundle.getBitstreams())) { for (Bitstream bitstream : Utils.emptyIfNull(bundle.getBitstreams())) { uncacheEntity(bitstream); } } - //} else if(entity instanceof Bitstream) { - // Bitstream bitstream = (Bitstream) entity; - // No specific child entities to decache + // BITSTREAM + // No specific child entities to decache + + // COMMUNITY } else if (entity instanceof Community) { Community community = (Community) entity; - if(Hibernate.isInitialized(community.getAdministrators())) { - uncacheEntity(community.getAdministrators()); - } - if(Hibernate.isInitialized(community.getLogo())) { + // We don't uncache groups as they might still be referenced from the Context object + + if (Hibernate.isInitialized(community.getLogo())) { uncacheEntity(community.getLogo()); } + + // COLLECTION } else if (entity instanceof Collection) { Collection collection = (Collection) entity; - if(Hibernate.isInitialized(collection.getLogo())) { + + //We don't uncache groups as they might still be referenced from the Context object + + if (Hibernate.isInitialized(collection.getLogo())) { uncacheEntity(collection.getLogo()); } - if(Hibernate.isInitialized(collection.getAdministrators())) { - uncacheEntity(collection.getAdministrators()); - } - if(Hibernate.isInitialized(collection.getSubmitters())) { - uncacheEntity(collection.getSubmitters()); - } - if(Hibernate.isInitialized(collection.getTemplateItem())) { + if (Hibernate.isInitialized(collection.getTemplateItem())) { uncacheEntity(collection.getTemplateItem()); } - if(Hibernate.isInitialized(collection.getWorkflowStep1())) { - uncacheEntity(collection.getWorkflowStep1()); - } - if(Hibernate.isInitialized(collection.getWorkflowStep2())) { - uncacheEntity(collection.getWorkflowStep2()); - } - if(Hibernate.isInitialized(collection.getWorkflowStep3())) { - uncacheEntity(collection.getWorkflowStep3()); - } } - getSession().evict(entity); + // Unless this object exists in the session, we won't do anything + if (getSession().contains(entity)) { + + // If our Session has unsaved changes (dirty) and not READ-ONLY + if (!readOnlyEnabled && getSession().isDirty()) { + // write changes to database (don't worry if transaction fails, flushed changes will be rolled back) + getSession().flush(); + } + + // Remove object from Session + getSession().evict(entity); + } } } } diff --git a/dspace-api/src/main/java/org/dspace/core/I18nUtil.java b/dspace-api/src/main/java/org/dspace/core/I18nUtil.java index aba0bff4e3..b8aeb959b4 100644 --- a/dspace-api/src/main/java/org/dspace/core/I18nUtil.java +++ b/dspace-api/src/main/java/org/dspace/core/I18nUtil.java @@ -7,22 +7,21 @@ */ package org.dspace.core; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.dspace.eperson.EPerson; - import java.io.File; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.StringTokenizer; -import java.util.List; -import java.util.ArrayList; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.dspace.eperson.EPerson; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; - /** * I18nUtil.java * @@ -31,42 +30,41 @@ import org.dspace.services.factory.DSpaceServicesFactory; * - getting all supported Locales for this DSpace Instance * - getting email template, help file, input forms for a given Locale * - * * @author Bernadette Schlonsok and Claudia Juergen - * * @version 1.0 */ -public class I18nUtil -{ +public class I18nUtil { private static final Logger log = Logger.getLogger(I18nUtil.class); - + // the default Locale of this DSpace Instance public static final Locale DEFAULTLOCALE = getDefaultLocale(); // delimiters between elements of UNIX/POSIX locale spec, e.g. en_US.UTF-8 private static final String LOCALE_DELIMITERS = " _."; + /** + * Default constructor + */ + private I18nUtil() { } + /** * Gets the default locale as defined in dspace.cfg If no default locale is * defined, the Locale of the JVM is used * * @return defaultLocale - * the default Locale for this DSpace instance + * the default Locale for this DSpace instance */ - public static Locale getDefaultLocale() - { + public static Locale getDefaultLocale() { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); // First, try configured default locale Locale defaultLocale = null; - if (config.hasProperty("default.locale")) - { + if (config.hasProperty("default.locale")) { defaultLocale = makeLocale(config.getProperty("default.locale")); } // Finally, get the Locale of the JVM - if (defaultLocale == null) - { + if (defaultLocale == null) { defaultLocale = Locale.getDefault(); } @@ -76,21 +74,20 @@ public class I18nUtil // Translate a string locale specification (e.g. "en_US.UTF-8") into Locale // This is needed because Locale constructor expects args for // language, territory, and variant to be separated already. - private static Locale makeLocale(String localeSpec) - { + private static Locale makeLocale(String localeSpec) { StringTokenizer st = new StringTokenizer(localeSpec, LOCALE_DELIMITERS); int countTokens = st.countTokens(); - switch (countTokens) - { - case 1: - return new Locale(st.nextToken().trim()); - case 2: - return new Locale(st.nextToken().trim(), st.nextToken().trim()); - case 3: - return new Locale(st.nextToken().trim(), st.nextToken().trim(), - st.nextToken().trim()); + switch (countTokens) { + case 1: + return new Locale(st.nextToken().trim()); + case 2: + return new Locale(st.nextToken().trim(), st.nextToken().trim()); + case 3: + return new Locale(st.nextToken().trim(), st.nextToken().trim(), + st.nextToken().trim()); + default: + return null; } - return null; } /** @@ -100,18 +97,15 @@ public class I18nUtil * @param ep Eperson * @return Locale */ - public static Locale getEPersonLocale(EPerson ep) - { - if (ep == null) - { + public static Locale getEPersonLocale(EPerson ep) { + if (ep == null) { log.error("No EPerson specified, returning default locale"); return I18nUtil.getDefaultLocale(); } String lang = ep.getLanguage(); - - if (StringUtils.isBlank(lang)) - { + + if (StringUtils.isBlank(lang)) { log.error("No language specified for EPerson " + ep.getID()); return I18nUtil.getDefaultLocale(); } @@ -125,19 +119,15 @@ public class I18nUtil * * @return an array of supported Locales or null */ - public static Locale[] getSupportedLocales() - { + public static Locale[] getSupportedLocales() { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); String[] locales = config.getArrayProperty("webui.supported.locales"); - if (locales != null && locales.length>0) - { + if (locales != null && locales.length > 0) { return parseLocales(locales); - } - else - { + } else { Locale[] availableLocales = new Locale[1]; - availableLocales[0] = DEFAULTLOCALE; + availableLocales[0] = DEFAULTLOCALE; return availableLocales; } } @@ -146,33 +136,25 @@ public class I18nUtil * Gets the appropriate supported Locale according for a given Locale If * no appropriate supported locale is found, the DEFAULTLOCALE is used * - * @param locale - * Locale to find the corresponding Locale + * @param locale Locale to find the corresponding Locale * @return supportedLocale - * Locale for session according to locales supported by this DSpace instance as set in dspace.cfg + * Locale for session according to locales supported by this DSpace instance as set in dspace.cfg */ - - public static Locale getSupportedLocale(Locale locale) - { + + public static Locale getSupportedLocale(Locale locale) { Locale[] availableLocales = getSupportedLocales(); boolean isSupported = false; Locale supportedLocale = null; String testLocale = ""; - if (availableLocales == null) - { + if (availableLocales == null) { supportedLocale = DEFAULTLOCALE; - } - else - { - if (!locale.getVariant().equals("")) - { + } else { + if (!locale.getVariant().equals("")) { testLocale = locale.toString(); - for (int i = 0; i < availableLocales.length; i++) - { + for (int i = 0; i < availableLocales.length; i++) { if (testLocale.equalsIgnoreCase(availableLocales[i] - .toString())) - { + .toString())) { isSupported = true; supportedLocale = availableLocales[i]; } @@ -180,39 +162,32 @@ public class I18nUtil } } - if (!(isSupported && locale.getCountry().equals(""))) - { + if (!(isSupported && locale.getCountry().equals(""))) { testLocale = locale.getLanguage() + "_" - + locale.getCountry(); + + locale.getCountry(); - for (int i = 0; i < availableLocales.length; i++) - { + for (int i = 0; i < availableLocales.length; i++) { if (testLocale.equalsIgnoreCase(availableLocales[i] - .toString())) - { + .toString())) { isSupported = true; supportedLocale = availableLocales[i]; } } } - if (!isSupported) - { + if (!isSupported) { testLocale = locale.getLanguage(); - for (int i = 0; i < availableLocales.length; i++) - { + for (int i = 0; i < availableLocales.length; i++) { if (testLocale.equalsIgnoreCase(availableLocales[i] - .toString())) - { + .toString())) { isSupported = true; supportedLocale = availableLocales[i]; } } } - if (!isSupported) - { + if (!isSupported) { supportedLocale = DEFAULTLOCALE; } } @@ -220,63 +195,49 @@ public class I18nUtil } - - - /** - * Get the appropriate localized version of input-forms.xml according to language settings + * Get the appropriate localized version of submission-forms.xml according to language settings * - * @param locale - * Locale, the local to get the input-forms.xml for - * @return String - localized filename for input-forms.xml + * @param locale Locale, the local to get the submission-forms.xml for + * @return String - localized filename for submission-forms.xml */ - public static String getInputFormsFileName(Locale locale) - { + public static String getInputFormsFileName(Locale locale) { /** Name of the form definition XML file */ String fileName = ""; - final String FORM_DEF_FILE = "input-forms"; + final String FORM_DEF_FILE = "submission-forms"; final String FILE_TYPE = ".xml"; String defsFilename = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") - + File.separator + "config" + File.separator + FORM_DEF_FILE; - fileName = getFilename(locale, defsFilename, FILE_TYPE); + + File.separator + "config" + File.separator + FORM_DEF_FILE; + fileName = getFilename(locale, defsFilename, FILE_TYPE); return fileName; } + /** * Get the i18n message string for a given key and use the default Locale. * - * @param key - * String - name of the key to get the message for - * + * @param key String - name of the key to get the message for * @return message - * String of the message - * - * + * String of the message */ - public static String getMessage(String key) - { + public static String getMessage(String key) { return getMessage(key.trim(), DEFAULTLOCALE); } - + /** * Get the i18n message string for a given key and locale * - * @param key - * String - name of the key to get the message for - * @param locale - * Locale, to get the message for - * + * @param key String - name of the key to get the message for + * @param locale Locale, to get the message for * @return message - * String of the message + * String of the message */ - public static String getMessage(String key, Locale locale) - { - if (locale == null) - { + public static String getMessage(String key, Locale locale) { + if (locale == null) { locale = DEFAULTLOCALE; } - ResourceBundle.Control control = + ResourceBundle.Control control = ResourceBundle.Control.getNoFallbackControl( - ResourceBundle.Control.FORMAT_DEFAULT); + ResourceBundle.Control.FORMAT_DEFAULT); ResourceBundle messages = ResourceBundle.getBundle("Messages", locale, control); try { @@ -284,68 +245,56 @@ public class I18nUtil return message; } catch (MissingResourceException e) { log.error("'" + key + "' translation undefined in locale '" - + locale.toString() + "'"); + + locale.toString() + "'"); return key; } } - + /** * Get the i18n message string for a given key and context * - * @param key - * String - name of the key to get the message for - * @param c - * Context having the desired Locale - * + * @param key String - name of the key to get the message for + * @param c Context having the desired Locale * @return message - * String of the message - * - * + * String of the message */ - public static String getMessage(String key, Context c) - { + public static String getMessage(String key, Context c) { return getMessage(key.trim(), c.getCurrentLocale()); } - /** * Get the appropriate localized version of the default.license according to language settings * - * @param context - * the current DSpace context + * @param context the current DSpace context * @return fileName - * String - localized filename for default.license + * String - localized filename for default.license */ - public static String getDefaultLicense(Context context) - { + public static String getDefaultLicense(Context context) { Locale locale = context.getCurrentLocale(); String fileName = ""; /** Name of the default license */ final String DEF_LIC_FILE = "default"; final String FILE_TYPE = ".license"; String defsFilename = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") - + File.separator + "config" + File.separator + DEF_LIC_FILE; - + + File.separator + "config" + File.separator + DEF_LIC_FILE; + fileName = getFilename(locale, defsFilename, FILE_TYPE); - + return fileName; } + /** * Get the appropriate localized version of a file according to language settings * e. g. help files in jsp/help/ * - * @param locale - * Locale to get the file for - * @param fileName - * String fileName, to get the localized file for - * @param fileType - * String file extension + * @param locale Locale to get the file for + * @param fileName String fileName, to get the localized file for + * @param fileType String file extension * @return localizedFileName - * String - localized filename + * String - localized filename */ - private static String getFilename(Locale locale, String fileName, String fileType) - { + private static String getFilename(Locale locale, String fileName, String fileType) { String localizedFileName = null; boolean fileFound = false; // with Language, Country, Variant @@ -356,77 +305,63 @@ public class I18nUtil String fileNameL = null; fileNameL = fileName + "_" + locale.getLanguage(); - if (fileType == null) - { + if (fileType == null) { fileType = ""; } - if (!("".equals(locale.getCountry()))) - { + if (!("".equals(locale.getCountry()))) { fileNameLC = fileName + "_" + locale.getLanguage() + "_" - + locale.getCountry(); + + locale.getCountry(); - if (!("".equals(locale.getVariant()))) - { + if (!("".equals(locale.getVariant()))) { fileNameLCV = fileName + "_" + locale.getLanguage() + "_" - + locale.getCountry() + "_" + locale.getVariant(); + + locale.getCountry() + "_" + locale.getVariant(); } } - if (fileNameLCV != null && !fileFound) - { + if (fileNameLCV != null && !fileFound) { File fileTmp = new File(fileNameLCV + fileType); - if (fileTmp.exists()) - { + if (fileTmp.exists()) { fileFound = true; - localizedFileName = fileNameLCV + fileType; + localizedFileName = fileNameLCV + fileType; } } - if (fileNameLC != null && !fileFound) - { + if (fileNameLC != null && !fileFound) { File fileTmp = new File(fileNameLC + fileType); - if (fileTmp.exists()) - { + if (fileTmp.exists()) { fileFound = true; localizedFileName = fileNameLC + fileType; } } - if (fileNameL != null && !fileFound) - { + if (fileNameL != null && !fileFound) { File fileTmp = new File(fileNameL + fileType); - if (fileTmp.exists()) - { + if (fileTmp.exists()) { fileFound = true; - localizedFileName = fileNameL + fileType; + localizedFileName = fileNameL + fileType; } } - if (!fileFound) - { + if (!fileFound) { localizedFileName = fileName + fileType; } return localizedFileName; } - - + /** * Get the appropriate localized version of an email template according to language settings * - * @param locale - * Locale for this request - * @param name - * String - base name of the email template + * @param locale Locale for this request + * @param name String - base name of the email template * @return templateName - * String - localized filename of an email template + * String - localized filename of an email template */ - public static String getEmailFilename(Locale locale, String name) - { + public static String getEmailFilename(Locale locale, String name) { String templateName = ""; String templateFile = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") - + File.separator + "config" + File.separator + "emails" - + File.separator + name; + + File.separator + "config" + File.separator + "emails" + + File.separator + name; templateName = getFilename(locale, templateFile, ""); return templateName; @@ -435,17 +370,15 @@ public class I18nUtil /** * Creates array of Locales from text list of locale-specifications. * Used to parse lists in DSpace configuration properties. + * * @param locales locale string array * @return array of locale results, possibly empty */ - public static Locale[] parseLocales(String[] locales) - { + public static Locale[] parseLocales(String[] locales) { List resultList = new ArrayList(); - for (String ls : locales) - { + for (String ls : locales) { Locale lc = makeLocale(ls); - if (lc != null) - { + if (lc != null) { resultList.add(lc); } } diff --git a/dspace-api/src/main/java/org/dspace/core/LegacyPluginServiceImpl.java b/dspace-api/src/main/java/org/dspace/core/LegacyPluginServiceImpl.java index eb80542bbe..477143a04a 100644 --- a/dspace-api/src/main/java/org/dspace/core/LegacyPluginServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/core/LegacyPluginServiceImpl.java @@ -17,6 +17,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; + import org.apache.log4j.Logger; import org.dspace.core.service.PluginService; import org.dspace.services.ConfigurationService; @@ -36,38 +37,39 @@ import org.springframework.beans.factory.annotation.Autowired; * (usage patterns) of plugins: *

    *
      - *
    1. Singleton Plugin
      - * There is only one implementation class for the plugin. It is indicated - * in the configuration. This type of plugin chooses an implementations of - * a service, for the entire system, at configuration time. Your - * application just fetches the plugin for that interface and gets the - * configured-in choice.
    2. + *
    3. Singleton Plugin
      + * There is only one implementation class for the plugin. It is indicated + * in the configuration. This type of plugin chooses an implementations of + * a service, for the entire system, at configuration time. Your + * application just fetches the plugin for that interface and gets the + * configured-in choice.
    4. * - *
    5. Sequence Plugins
      - * You need a sequence or series of plugins, to implement a mechanism like - * StackableAuthenticationMethods or a pipeline, where each plugin is - * called in order to contribute its implementation of a process to the - * whole.
    6. - *
    7. Named Plugins
      - * Use a named plugin when the application has to choose one plugin - * implementation out of many available ones. Each implementation is bound - * to one or more names (symbolic identifiers) in the configuration.
    8. - *
    - *

    - * The name is just a String to be associated with the - * combination of implementation class and interface. It may contain - * any characters except for comma (,) and equals (=). It may contain - * embedded spaces. Comma is a special character used to separate - * names in the configuration entry. - *

    + *
  • Sequence Plugins
    + * You need a sequence or series of plugins, to implement a mechanism like + * StackableAuthenticationMethods or a pipeline, where each plugin is + * called in order to contribute its implementation of a process to the + * whole.
  • + *
  • Named Plugins
    + * Use a named plugin when the application has to choose one plugin + * implementation out of many available ones. Each implementation is bound + * to one or more names (symbolic identifiers) in the configuration.
  • + * + *

    + * The name is just a String to be associated with the + * combination of implementation class and interface. It may contain + * any characters except for comma (,) and equals (=). It may contain + * embedded spaces. Comma is a special character used to separate + * names in the configuration entry. + *

    * * @author Larry Stone * @author Tim Donohue (turned old PluginManager into a PluginService) * @see SelfNamedPlugin */ -public class LegacyPluginServiceImpl implements PluginService -{ - /** log4j category */ +public class LegacyPluginServiceImpl implements PluginService { + /** + * log4j category + */ private static Logger log = Logger.getLogger(LegacyPluginServiceImpl.class); /** @@ -78,7 +80,9 @@ public class LegacyPluginServiceImpl implements PluginService private static final String NAMED_PREFIX = "plugin.named."; private static final String SELFNAMED_PREFIX = "plugin.selfnamed."; - /** Configuration name of paths to search for third-party plugins. */ + /** + * Configuration name of paths to search for third-party plugins. + */ private static final String CLASSPATH = "plugin.classpath"; // Separator character (from perl $;) to make "two dimensional" @@ -86,10 +90,14 @@ public class LegacyPluginServiceImpl implements PluginService // this character separates the words. private static final String SEP = "\034"; - /** Paths to search for third-party plugins. */ + /** + * Paths to search for third-party plugins. + */ private String[] classPath; - /** Custom class loader to search for third-party plugins. */ + /** + * Custom class loader to search for third-party plugins. + */ private PathsClassLoader loader; @Autowired(required = true) @@ -104,13 +112,13 @@ public class LegacyPluginServiceImpl implements PluginService * plugin classpath info from config. * Called by "init-method" in Spring config. */ - void init() - { + void init() { String path = configurationService.getProperty(CLASSPATH); - if (null == path) + if (null == path) { classPath = new String[0]; - else + } else { classPath = path.split(":"); + } loader = new PathsClassLoader(LegacyPluginServiceImpl.class.getClassLoader(), classPath); } @@ -131,22 +139,18 @@ public class LegacyPluginServiceImpl implements PluginService */ @Override public Object getSinglePlugin(Class interfaceClass) - throws PluginConfigurationError, PluginInstantiationException - { + throws PluginConfigurationError, PluginInstantiationException { String iname = interfaceClass.getName(); // NOTE: module name is ignored, as single plugins ALWAYS begin with SINGLE_PREFIX - String key = SINGLE_PREFIX+iname; + String key = SINGLE_PREFIX + iname; // configuration format is prefix. = String classname = configurationService.getProperty(key); - if (classname != null) - { + if (classname != null) { return getAnonymousPlugin(classname.trim()); - } - else - { - throw new PluginConfigurationError("No Single Plugin configured for interface \""+iname+"\""); + } else { + throw new PluginConfigurationError("No Single Plugin configured for interface \"" + iname + "\""); } } @@ -160,12 +164,11 @@ public class LegacyPluginServiceImpl implements PluginService * * @param interfaceClass interface for which to find plugins. * @return an array of plugin instances; if none are - * available an empty array is returned. + * available an empty array is returned. */ @Override public Object[] getPluginSequence(Class interfaceClass) - throws PluginInstantiationException - { + throws PluginInstantiationException { // cache of config data for Sequence Plugins; format its // -> [ .. ] (value is Array) Map sequenceConfig = new HashMap(); @@ -174,28 +177,23 @@ public class LegacyPluginServiceImpl implements PluginService // format is prefix. = String iname = interfaceClass.getName(); String[] classname = null; - if (!sequenceConfig.containsKey(iname)) - { + if (!sequenceConfig.containsKey(iname)) { // NOTE: module name is ignored, as sequence plugins ALWAYS begin with SEQUENCE_PREFIX - String key = SEQUENCE_PREFIX+iname; + String key = SEQUENCE_PREFIX + iname; classname = configurationService.getArrayProperty(key); - if (classname == null || classname.length==0) - { - log.warn("No Configuration entry found for Sequence Plugin interface="+iname); + if (classname == null || classname.length == 0) { + log.warn("No Configuration entry found for Sequence Plugin interface=" + iname); return (Object[]) Array.newInstance(interfaceClass, 0); } sequenceConfig.put(iname, classname); - } - else - { + } else { classname = sequenceConfig.get(iname); } - Object result[] = (Object[])Array.newInstance(interfaceClass, classname.length); - for (int i = 0; i < classname.length; ++i) - { - log.debug("Adding Sequence plugin for interface= "+iname+", class="+classname[i]); + Object result[] = (Object[]) Array.newInstance(interfaceClass, classname.length); + for (int i = 0; i < classname.length; ++i) { + log.debug("Adding Sequence plugin for interface= " + iname + ", class=" + classname[i]); result[i] = getAnonymousPlugin(classname[i]); } return result; @@ -204,20 +202,14 @@ public class LegacyPluginServiceImpl implements PluginService // Get possibly-cached plugin instance for un-named plugin, // this is shared by Single and Sequence plugins. private Object getAnonymousPlugin(String classname) - throws PluginInstantiationException - { - try - { + throws PluginInstantiationException { + try { Class pluginClass = Class.forName(classname, true, loader); return pluginClass.newInstance(); - } - catch (ClassNotFoundException e) - { + } catch (ClassNotFoundException e) { throw new PluginInstantiationException("Cannot load plugin class: " + - e.toString(), e); - } - catch (InstantiationException|IllegalAccessException e) - { + e.toString(), e); + } catch (InstantiationException | IllegalAccessException e) { throw new PluginInstantiationException(e); } } @@ -231,8 +223,7 @@ public class LegacyPluginServiceImpl implements PluginService // load and cache configuration data for the given interface. private void configureNamedPlugin(String iname) - throws ClassNotFoundException - { + throws ClassNotFoundException { int found = 0; /** @@ -241,34 +232,28 @@ public class LegacyPluginServiceImpl implements PluginService * There is ALSO a "marker key" of "intfc" by itself to show we * loaded this intfc's configuration. */ - if (!namedPluginClasses.containsKey(iname)) - { + if (!namedPluginClasses.containsKey(iname)) { // 1. Get classes named by the configuration. format is: // plugin.named. = = \, [,] \ // = \, [ ... ] // NOTE: module name is ignored, as named plugins ALWAYS begin with NAMED_PREFIX - String key = NAMED_PREFIX+iname; + String key = NAMED_PREFIX + iname; String[] namedVals = configurationService.getArrayProperty(key); - if (namedVals != null && namedVals.length>0) - { + if (namedVals != null && namedVals.length > 0) { String prevClassName = null; - for(String namedVal : namedVals) - { + for (String namedVal : namedVals) { String[] valSplit = namedVal.trim().split("\\s*=\\s*"); String className = null; String name = null; - + // If there's no "=" separator in this value, assume it's // just a "name" that belongs with previous class. // (This may occur if there's an unescaped comma between names) - if (prevClassName!=null && valSplit.length==1) - { + if (prevClassName != null && valSplit.length == 1) { className = prevClassName; name = valSplit[0]; - } - else - { + } else { // first part is class name className = valSplit[0]; prevClassName = className; @@ -286,39 +271,31 @@ public class LegacyPluginServiceImpl implements PluginService // 2. Get Self-named config entries: // format is plugin.selfnamed. = , .. // NOTE: module name is ignored, as self-named plugins ALWAYS begin with SELFNAMED_PREFIX - key = SELFNAMED_PREFIX+iname; + key = SELFNAMED_PREFIX + iname; String[] selfNamedVals = configurationService.getArrayProperty(key); - if (selfNamedVals != null && selfNamedVals.length>0) - { - for (String classname : selfNamedVals) - { - try - { + if (selfNamedVals != null && selfNamedVals.length > 0) { + for (String classname : selfNamedVals) { + try { Class pluginClass = Class.forName(classname, true, loader); - String names[] = (String[])pluginClass.getMethod("getPluginNames"). - invoke(null); - if (names == null || names.length == 0) - { - log.error("Self-named plugin class \"" + classname + "\" returned null or empty name list!"); - } - else - { + String names[] = (String[]) pluginClass.getMethod("getPluginNames"). + invoke(null); + if (names == null || names.length == 0) { + log.error( + "Self-named plugin class \"" + classname + "\" returned null or empty name list!"); + } else { found += installNamedConfigs(iname, classname, names); } - } - catch (NoSuchMethodException e) - { - log.error("Implementation Class \""+classname+"\" is not a subclass of SelfNamedPlugin, it has no getPluginNames() method."); - } - catch (Exception e) - { + } catch (NoSuchMethodException e) { + log.error( + "Implementation Class \"" + classname + "\" is not a subclass of SelfNamedPlugin, it has " + + "no getPluginNames() method."); + } catch (Exception e) { log.error("Error while configuring self-named plugin", e); } } } namedPluginClasses.put(iname, "org.dspace.core.marker"); - if (found == 0) - { + if (found == 0) { log.error("No named plugins found for interface=" + iname); } } @@ -326,22 +303,17 @@ public class LegacyPluginServiceImpl implements PluginService // add info for a named plugin to cache, under all its names. private int installNamedConfigs(String iname, String classname, String names[]) - throws ClassNotFoundException - { + throws ClassNotFoundException { int found = 0; - for (int i = 0; i < names.length; ++i) - { - String key = iname+SEP+names[i]; - if (namedPluginClasses.containsKey(key)) - { + for (int i = 0; i < names.length; ++i) { + String key = iname + SEP + names[i]; + if (namedPluginClasses.containsKey(key)) { log.error("Name collision in named plugin, implementation class=\"" + classname + - "\", name=\"" + names[i] + "\""); - } - else - { + "\", name=\"" + names[i] + "\""); + } else { namedPluginClasses.put(key, classname); } - log.debug("Got Named Plugin, intfc="+iname+", name="+names[i]+", class="+classname); + log.debug("Got Named Plugin, intfc=" + iname + ", name=" + names[i] + ", class=" + classname); ++found; } return found; @@ -354,44 +326,34 @@ public class LegacyPluginServiceImpl implements PluginService * String.equals(). * * @param interfaceClass the interface class of the plugin - * @param name under which the plugin implementation is configured. + * @param name under which the plugin implementation is configured. * @return instance of plugin implementation, or null if there is no match or an error. */ @Override public Object getNamedPlugin(Class interfaceClass, String name) - throws PluginInstantiationException - { - try - { + throws PluginInstantiationException { + try { String iname = interfaceClass.getName(); configureNamedPlugin(iname); String key = iname + SEP + name; String cname = namedPluginClasses.get(key); - if (cname == null) - { + if (cname == null) { log.warn("Cannot find named plugin for interface=" + iname + ", name=\"" + name + "\""); - } - else - { + } else { Class pluginClass = Class.forName(cname, true, loader); log.debug("Creating instance of: " + cname + " for interface=" + iname + - " pluginName=" + name ); + " pluginName=" + name); Object result = pluginClass.newInstance(); - if (result instanceof SelfNamedPlugin) - { + if (result instanceof SelfNamedPlugin) { ((SelfNamedPlugin) result).setPluginInstanceName(name); } return result; } - } - catch (ClassNotFoundException e) - { + } catch (ClassNotFoundException e) { throw new PluginInstantiationException("Cannot load plugin class: " + - e.toString(), e); - } - catch (InstantiationException|IllegalAccessException e) - { + e.toString(), e); + } catch (InstantiationException | IllegalAccessException e) { throw new PluginInstantiationException(e); } @@ -404,24 +366,20 @@ public class LegacyPluginServiceImpl implements PluginService * return true. If there is no matching plugin, return false. * * @param interfaceClass the interface class of the plugin - * @param name under which the plugin implementation is configured. + * @param name under which the plugin implementation is configured. * @return true if plugin was found to be configured, false otherwise */ @Override public boolean hasNamedPlugin(Class interfaceClass, String name) - throws PluginInstantiationException - { - try - { + throws PluginInstantiationException { + try { String iname = interfaceClass.getName(); configureNamedPlugin(iname); String key = iname + SEP + name; return namedPluginClasses.get(key) != null; - } - catch (ClassNotFoundException e) - { + } catch (ClassNotFoundException e) { throw new PluginInstantiationException("Cannot load plugin class: " + - e.toString(), e); + e.toString(), e); } } @@ -436,34 +394,27 @@ public class LegacyPluginServiceImpl implements PluginService * * @param interfaceClass plugin interface for which to return names. * @return an array of strings with every name; if none are - * available an empty array is returned. + * available an empty array is returned. */ @Override - public String[] getAllPluginNames(Class interfaceClass) - { - try - { + public String[] getAllPluginNames(Class interfaceClass) { + try { String iname = interfaceClass.getName(); configureNamedPlugin(iname); String prefix = iname + SEP; ArrayList result = new ArrayList(); - for (String key : namedPluginClasses.keySet()) - { - if (key.startsWith(prefix)) - { + for (String key : namedPluginClasses.keySet()) { + if (key.startsWith(prefix)) { result.add(key.substring(prefix.length())); } } - if (result.size() == 0) - { + if (result.size() == 0) { log.error("Cannot find any names for named plugin, interface=" + iname); } return result.toArray(new String[result.size()]); - } - catch (ClassNotFoundException e) - { + } catch (ClassNotFoundException e) { return new String[0]; } } @@ -474,74 +425,54 @@ public class LegacyPluginServiceImpl implements PluginService */ // true if classname is valid and loadable. - private boolean checkClassname(String iname, String msg) - { - try - { - if (Class.forName(iname, true, loader) != null) - { + private boolean checkClassname(String iname, String msg) { + try { + if (Class.forName(iname, true, loader) != null) { return true; } - } - catch (ClassNotFoundException ce) - { - log.error("No class definition found for "+msg+": \""+iname+"\""); + } catch (ClassNotFoundException ce) { + log.error("No class definition found for " + msg + ": \"" + iname + "\""); } return false; } // true if classname is loadable AND is subclass of SelfNamedPlugin - private boolean checkSelfNamed(String iname) - { - try - { - if (!checkSelfNamed(Class.forName(iname, true, loader))) - { + private boolean checkSelfNamed(String iname) { + try { + if (!checkSelfNamed(Class.forName(iname, true, loader))) { log.error("The class \"" + iname + "\" is NOT a subclass of SelfNamedPlugin but it should be!"); } - } - catch (ClassNotFoundException ce) - { - log.error("No class definition found for self-named class interface: \""+iname+"\""); + } catch (ClassNotFoundException ce) { + log.error("No class definition found for self-named class interface: \"" + iname + "\""); } return false; } // recursively climb superclass stack until we find SelfNamedPlugin - private boolean checkSelfNamed(Class cls) - { + private boolean checkSelfNamed(Class cls) { Class sup = cls.getSuperclass(); - if (sup == null) - { + if (sup == null) { return false; - } - else if (sup.equals(SelfNamedPlugin.class)) - { + } else if (sup.equals(SelfNamedPlugin.class)) { return true; - } - else - { + } else { return checkSelfNamed(sup); } } // check named-plugin names by interface -- call the usual // configuration and let it find missing or duplicate names. - private void checkNames(String iname) - { - try - { + private void checkNames(String iname) { + try { configureNamedPlugin(iname); - } - catch (ClassNotFoundException ce) - { + } catch (ClassNotFoundException ce) { // bogus classname should be old news by now. } } /** * Validate the entries in the DSpace Configuration relevant to - LegacyPluginServiceImpl. Look for inconsistencies, illegal syntax, etc. + * LegacyPluginServiceImpl. Look for inconsistencies, illegal syntax, etc. * Announce violations with "log.error" so they appear in the log * or in the standard error stream if this is run interactively. *
      @@ -553,11 +484,11 @@ public class LegacyPluginServiceImpl implements PluginService *
    • Implementations of named plugin have no name collisions. *
    • Named plugin entries lacking names. *
    + * * @throws IOException if IO error */ public void checkConfiguration() - throws IOException - { + throws IOException { FileReader fr = null; BufferedReader cr = null; @@ -574,26 +505,16 @@ public class LegacyPluginServiceImpl implements PluginService // Find all property keys starting with "plugin." List keys = configurationService.getPropertyKeys("plugin."); - for(String key : keys) - { - if (key.startsWith(SINGLE_PREFIX)) - { + for (String key : keys) { + if (key.startsWith(SINGLE_PREFIX)) { singleKey.put(key.substring(SINGLE_PREFIX.length()), key); - } - else if (key.startsWith(SEQUENCE_PREFIX)) - { + } else if (key.startsWith(SEQUENCE_PREFIX)) { sequenceKey.put(key.substring(SEQUENCE_PREFIX.length()), key); - } - else if (key.startsWith(NAMED_PREFIX)) - { + } else if (key.startsWith(NAMED_PREFIX)) { namedKey.put(key.substring(NAMED_PREFIX.length()), key); - } - else if (key.startsWith(SELFNAMED_PREFIX)) - { + } else if (key.startsWith(SELFNAMED_PREFIX)) { selfnamedKey.put(key.substring(SELFNAMED_PREFIX.length()), key); - } - else - { + } else { log.error("Key with unknown prefix \"" + key + "\" in DSpace configuration"); } } @@ -603,12 +524,11 @@ public class LegacyPluginServiceImpl implements PluginService // since either one will work for the Plugin Manager. ArrayList allInterfaces = new ArrayList(); allInterfaces.addAll(singleKey.keySet()); - allInterfaces.addAll(sequenceKey .keySet()); + allInterfaces.addAll(sequenceKey.keySet()); allInterfaces.addAll(namedKey.keySet()); allInterfaces.addAll(selfnamedKey.keySet()); Iterator ii = allInterfaces.iterator(); - while (ii.hasNext()) - { + while (ii.hasNext()) { checkClassname(ii.next(), "key interface or class"); } @@ -620,19 +540,14 @@ public class LegacyPluginServiceImpl implements PluginService // single plugins - just check that it has a valid impl. class ii = singleKey.keySet().iterator(); - while (ii.hasNext()) - { + while (ii.hasNext()) { String key = ii.next(); - String val = configurationService.getProperty(SINGLE_PREFIX+key); - if (val == null) - { + String val = configurationService.getProperty(SINGLE_PREFIX + key); + if (val == null) { log.error("Single plugin config not found for: " + SINGLE_PREFIX + key); - } - else - { + } else { val = val.trim(); - if (checkClassname(val, "implementation class")) - { + if (checkClassname(val, "implementation class")) { allImpls.put(val, val); } } @@ -640,20 +555,14 @@ public class LegacyPluginServiceImpl implements PluginService // sequence plugins - all values must be classes ii = sequenceKey.keySet().iterator(); - while (ii.hasNext()) - { + while (ii.hasNext()) { String key = ii.next(); - String[] vals = configurationService.getArrayProperty(SEQUENCE_PREFIX+key); - if (vals == null || vals.length==0) - { + String[] vals = configurationService.getArrayProperty(SEQUENCE_PREFIX + key); + if (vals == null || vals.length == 0) { log.error("Sequence plugin config not found for: " + SEQUENCE_PREFIX + key); - } - else - { - for (String val : vals) - { - if (checkClassname(val, "implementation class")) - { + } else { + for (String val : vals) { + if (checkClassname(val, "implementation class")) { allImpls.put(val, val); } } @@ -663,20 +572,14 @@ public class LegacyPluginServiceImpl implements PluginService // 3. self-named plugins - grab and check all values // then make sure it is a subclass of SelfNamedPlugin ii = selfnamedKey.keySet().iterator(); - while (ii.hasNext()) - { + while (ii.hasNext()) { String key = ii.next(); - String[] vals = configurationService.getArrayProperty(SELFNAMED_PREFIX+key); - if (vals == null || vals.length==0) - { + String[] vals = configurationService.getArrayProperty(SELFNAMED_PREFIX + key); + if (vals == null || vals.length == 0) { log.error("Selfnamed plugin config not found for: " + SELFNAMED_PREFIX + key); - } - else - { - for (String val : vals) - { - if (checkClassname(val, "selfnamed implementation class")) - { + } else { + for (String val : vals) { + if (checkClassname(val, "selfnamed implementation class")) { allImpls.put(val, val); checkSelfNamed(val); } @@ -688,25 +591,19 @@ public class LegacyPluginServiceImpl implements PluginService // 4. named plugins - extract the classnames and treat same as sequence. // use named plugin config mechanism to test for duplicates, unnamed. ii = namedKey.keySet().iterator(); - while (ii.hasNext()) - { + while (ii.hasNext()) { String key = ii.next(); - String[] vals = configurationService.getArrayProperty(NAMED_PREFIX+key); - if (vals == null || vals.length==0) - { + String[] vals = configurationService.getArrayProperty(NAMED_PREFIX + key); + if (vals == null || vals.length == 0) { log.error("Named plugin config not found for: " + NAMED_PREFIX + key); - } - else - { + } else { checkNames(key); - for (String val : vals) - { + for (String val : vals) { // each named plugin has two parts to the value, format: // [classname] = [plugin-name] String val_split[] = val.split("\\s*=\\s*"); String classname = val_split[0]; - if (checkClassname(classname, "implementation class")) - { + if (checkClassname(classname, "implementation class")) { allImpls.put(classname, classname); } } @@ -722,8 +619,7 @@ public class LegacyPluginServiceImpl implements PluginService * @param argv the command line arguments given * @throws Exception if error */ - public void main(String[] argv) throws Exception - { + public void main(String[] argv) throws Exception { checkConfiguration(); } diff --git a/dspace-api/src/main/java/org/dspace/core/LicenseServiceImpl.java b/dspace-api/src/main/java/org/dspace/core/LicenseServiceImpl.java index b58fa76c7a..8324105a30 100644 --- a/dspace-api/src/main/java/org/dspace/core/LicenseServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/core/LicenseServiceImpl.java @@ -28,85 +28,70 @@ import org.slf4j.LoggerFactory; * * @author mhwood */ -public class LicenseServiceImpl implements LicenseService -{ +public class LicenseServiceImpl implements LicenseService { private final Logger log = LoggerFactory.getLogger(LicenseServiceImpl.class); - /** The default license */ + /** + * The default license + */ protected String license; - protected LicenseServiceImpl() - { + protected LicenseServiceImpl() { } @Override public void writeLicenseFile(String licenseFile, - String newLicense) - { - try - { + String newLicense) { + try { FileOutputStream fos = new FileOutputStream(licenseFile); OutputStreamWriter osr = new OutputStreamWriter(fos, "UTF-8"); PrintWriter out = new PrintWriter(osr); out.print(newLicense); out.close(); - } catch (IOException e) - { + } catch (IOException e) { log.warn("license_write: " + e.getLocalizedMessage()); } license = newLicense; } @Override - public String getLicenseText(String licenseFile) - { + public String getLicenseText(String licenseFile) { InputStream is = null; InputStreamReader ir = null; BufferedReader br = null; - try - { + try { is = new FileInputStream(licenseFile); ir = new InputStreamReader(is, "UTF-8"); br = new BufferedReader(ir); String lineIn; license = ""; - while ((lineIn = br.readLine()) != null) - { + while ((lineIn = br.readLine()) != null) { license = license + lineIn + '\n'; } - } catch (IOException e) - { + } catch (IOException e) { log.error("Can't load configuration", e); throw new IllegalStateException("Failed to read default license.", e); - } finally - { - if (br != null) - { - try - { + } finally { + if (br != null) { + try { br.close(); - } catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } - if (ir != null) - { - try - { + if (ir != null) { + try { ir.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } - if (is != null) - { - try - { + if (is != null) { + try { is.close(); - } catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } @@ -119,10 +104,8 @@ public class LicenseServiceImpl implements LicenseService * @return the default license */ @Override - public String getDefaultSubmissionLicense() - { - if (null == license) - { + public String getDefaultSubmissionLicense() { + if (null == license) { init(); } return license; @@ -131,16 +114,15 @@ public class LicenseServiceImpl implements LicenseService /** * Load in the default license. */ - protected void init() - { - File licenseFile = new File(DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") + protected void init() { + File licenseFile = new File( + DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") + File.separator + "config" + File.separator + "default.license"); - FileInputStream fir = null; + FileInputStream fir = null; InputStreamReader ir = null; BufferedReader br = null; - try - { + try { fir = new FileInputStream(licenseFile); ir = new InputStreamReader(fir, "UTF-8"); @@ -148,55 +130,41 @@ public class LicenseServiceImpl implements LicenseService String lineIn; license = ""; - while ((lineIn = br.readLine()) != null) - { + while ((lineIn = br.readLine()) != null) { license = license + lineIn + '\n'; } br.close(); - } - catch (IOException e) - { - log.error("Can't load license: " + licenseFile.toString() , e); + } catch (IOException e) { + log.error("Can't load license: " + licenseFile.toString(), e); // FIXME: Maybe something more graceful here, but with the // configuration we can't do anything throw new IllegalStateException("Cannot load license: " - + licenseFile.toString(),e); - } - finally - { - if (br != null) - { - try - { + + licenseFile.toString(), e); + } finally { + if (br != null) { + try { br.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } - if (ir != null) - { - try - { + if (ir != null) { + try { ir.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } - if (fir != null) - { - try - { + if (fir != null) { + try { fir.close(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { + // ignore } } } diff --git a/dspace-api/src/main/java/org/dspace/core/LogManager.java b/dspace-api/src/main/java/org/dspace/core/LogManager.java index bb4441c2ba..c8988ca997 100644 --- a/dspace-api/src/main/java/org/dspace/core/LogManager.java +++ b/dspace-api/src/main/java/org/dspace/core/LogManager.java @@ -11,89 +11,82 @@ import org.dspace.eperson.EPerson; /** * Class for generating standard log header - * + * * @author David Stuve * @author Robert Tansley * @version $Revision$ */ -public class LogManager -{ +public class LogManager { + + /** + * Default constructor + */ + private LogManager() { } + /** * Generate the log header - * - * @param context - * the current Context - safe to pass in null - * @param action - * string describing the action - * @param extrainfo - * string with extra information, like parameters - * + * + * @param context the current Context - safe to pass in null + * @param action string describing the action + * @param extrainfo string with extra information, like parameters * @return the filled out log header */ public static String getHeader(Context context, String action, - String extrainfo) - { + String extrainfo) { String email = "anonymous"; String contextExtraInfo; - if (context != null) - { + if (context != null) { EPerson e = context.getCurrentUser(); - if (e != null) - { + if (e != null) { email = e.getEmail(); } contextExtraInfo = context.getExtraLogInfo(); - } - else - { + } else { contextExtraInfo = "no_context"; } - + StringBuilder result = new StringBuilder(); // Escape everthing but the extra context info because for some crazy reason two fields - // are generated inside this entry one for the session id, and another for the ip + // are generated inside this entry one for the session id, and another for the ip // address. Everything else should be escaped. - result.append(escapeLogField(email)).append(":").append(contextExtraInfo).append(":").append(escapeLogField(action)).append(":").append(escapeLogField(extrainfo)); + result.append(escapeLogField(email)).append(":").append(contextExtraInfo).append(":") + .append(escapeLogField(action)).append(":").append(escapeLogField(extrainfo)); return result.toString(); } - - + + /** - * If any string within the log line contains a field separator (:) they need to be escaped so as the + * If any string within the log line contains a field separator (:) they need to be escaped so as the * line may be parsed and analysed later. This method will escape a log field. - * + * * Single slashes and colons will be escaped so that colons no longer appear in the logs - * + * * @param field The unescaped log field * @return An escaped log field */ - public static String escapeLogField(String field) - { - if (field != null) - { - field = field.replaceAll("\\\\", "\\\\\\\\;"); - field = field.replaceAll(":","\\\\colon;"); + public static String escapeLogField(String field) { + if (field != null) { + field = field.replaceAll("\\\\", "\\\\\\\\;"); + field = field.replaceAll(":", "\\\\colon;"); } return field; } - + /** * Unescape a log field. - * + * * @param field The escaped log field * @return the original log field */ - public static String unescapeLogField(String field) - { - - if (field != null) - { - field = field.replaceAll("\\\\colon;", ":"); - field = field.replaceAll("\\\\\\\\;","\\\\"); + public static String unescapeLogField(String field) { + + if (field != null) { + field = field.replaceAll("\\\\colon;", ":"); + field = field.replaceAll("\\\\\\\\;", "\\\\"); } return field; } diff --git a/dspace-api/src/main/java/org/dspace/core/LoggerServiceImpl.java b/dspace-api/src/main/java/org/dspace/core/LoggerServiceImpl.java index 6ba8bd81d0..47875d345a 100644 --- a/dspace-api/src/main/java/org/dspace/core/LoggerServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/core/LoggerServiceImpl.java @@ -14,6 +14,7 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.util.Enumeration; import java.util.Properties; + import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.DOMConfigurator; @@ -26,9 +27,10 @@ import org.dspace.services.factory.DSpaceServicesFactory; * * @author Tim Donohue */ -public class LoggerServiceImpl implements KernelStartupCallbackService -{ - /** log4j category */ +public class LoggerServiceImpl implements KernelStartupCallbackService { + /** + * log4j category + */ private static Logger log = Logger.getLogger(LoggerServiceImpl.class); // System property which will disable DSpace's log4j setup @@ -42,10 +44,8 @@ public class LoggerServiceImpl implements KernelStartupCallbackService * in our ConfigurationService. */ @Override - public void executeCallback() - { - try - { + public void executeCallback() { + try { /* * Initialize Logging once ConfigurationManager is initialized. * @@ -70,109 +70,89 @@ public class LoggerServiceImpl implements KernelStartupCallbackService ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); String dsLogConfiguration = config.getProperty(LOG_CONFIG_PROPERTY); - if (dsLogConfiguration == null || System.getProperty(LOG_DISABLE_PROPERTY) != null) - { + if (dsLogConfiguration == null || System.getProperty(LOG_DISABLE_PROPERTY) != null) { /* * Do nothing if log config not set in dspace.cfg or "dspace.log.init.disable" * system property set. Leave it upto log4j to properly init its logging * via classpath or system properties. */ info("Using default log4j provided log configuration." + - " If unintended, check your dspace.cfg for (" +LOG_CONFIG_PROPERTY+ ")"); - } - else - { - info("Using dspace provided log configuration (" +LOG_CONFIG_PROPERTY+ ")"); + " If unintended, check your dspace.cfg for (" + LOG_CONFIG_PROPERTY + ")"); + } else { + info("Using dspace provided log configuration (" + LOG_CONFIG_PROPERTY + ")"); File logConfigFile = new File(dsLogConfiguration); - if(logConfigFile.exists()) - { + if (logConfigFile.exists()) { info("Loading: " + dsLogConfiguration); // Check if we have an XML config - if(logConfigFile.getName().endsWith(".xml")) - { + if (logConfigFile.getName().endsWith(".xml")) { // Configure log4j via the DOMConfigurator DOMConfigurator.configure(logConfigFile.toURI().toURL()); - } - else // Otherwise, assume a Properties file - { + } else { + // Otherwise, assume a Properties file + // Parse our log4j properties file Properties log4jProps = new Properties(); - try(InputStream fis = new FileInputStream(logConfigFile)) - { + try (InputStream fis = new FileInputStream(logConfigFile)) { log4jProps.load(fis); - } - catch(IOException e) - { - fatal("Can't load dspace provided log4j configuration from " + logConfigFile.getAbsolutePath(), e); + } catch (IOException e) { + fatal("Can't load dspace provided log4j configuration from " + logConfigFile + .getAbsolutePath(), e); } // Configure log4j based on all its properties PropertyConfigurator.configure(log4jProps); } - } - else - { + } else { info("File does not exist: " + dsLogConfiguration); } } - } - catch (MalformedURLException e) - { + } catch (MalformedURLException e) { fatal("Can't load dspace provided log4j configuration", e); - throw new IllegalStateException("Cannot load dspace provided log4j configuration",e); + throw new IllegalStateException("Cannot load dspace provided log4j configuration", e); } } /** * Attempt to log an INFO statement. If Log4j is not yet setup, send to System OUT + * * @param string */ - private void info(String string) - { - if (!isLog4jConfigured()) - { + private void info(String string) { + if (!isLog4jConfigured()) { System.out.println("INFO: " + string); - } - else - { + } else { log.info(string); } } /** * Attempt to log a WARN statement. If Log4j is not yet setup, send to System OUT + * * @param string */ - private void warn(String string) - { - if (!isLog4jConfigured()) - { + private void warn(String string) { + if (!isLog4jConfigured()) { System.out.println("WARN: " + string); - } - else - { + } else { log.warn(string); } } /** * Attempt to log a FATAL statement. If Log4j is not yet setup, send to System ERR + * * @param string * @param e */ - private void fatal(String string, Exception e) - { - if (!isLog4jConfigured()) - { + private void fatal(String string, Exception e) { + if (!isLog4jConfigured()) { System.err.println("FATAL: " + string); e.printStackTrace(System.err); - } - else - { + } else { log.fatal(string, e); } } @@ -182,23 +162,17 @@ public class LoggerServiceImpl implements KernelStartupCallbackService *

    * Based on samples here: http://wiki.apache.org/logging-log4j/UsefulCode */ - private boolean isLog4jConfigured() - { + private boolean isLog4jConfigured() { Enumeration appenders = org.apache.log4j.LogManager.getRootLogger() - .getAllAppenders(); + .getAllAppenders(); - if (!(appenders instanceof org.apache.log4j.helpers.NullEnumeration)) - { + if (!(appenders instanceof org.apache.log4j.helpers.NullEnumeration)) { return true; - } - else - { + } else { Enumeration loggers = org.apache.log4j.LogManager.getCurrentLoggers(); - while (loggers.hasMoreElements()) - { + while (loggers.hasMoreElements()) { Logger c = (Logger) loggers.nextElement(); - if (!(c.getAllAppenders() instanceof org.apache.log4j.helpers.NullEnumeration)) - { + if (!(c.getAllAppenders() instanceof org.apache.log4j.helpers.NullEnumeration)) { return true; } } diff --git a/dspace-api/src/main/java/org/dspace/core/NewsServiceImpl.java b/dspace-api/src/main/java/org/dspace/core/NewsServiceImpl.java index 8a0c5a89e5..d2bdf787f8 100644 --- a/dspace-api/src/main/java/org/dspace/core/NewsServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/core/NewsServiceImpl.java @@ -31,21 +31,20 @@ import org.springframework.beans.factory.annotation.Autowired; * * @author mhwood */ -public class NewsServiceImpl implements NewsService -{ +public class NewsServiceImpl implements NewsService { private final Logger log = LoggerFactory.getLogger(NewsServiceImpl.class); private List acceptableFilenames; @Autowired(required = true) private ConfigurationService configurationService; - + public void setAcceptableFilenames(List acceptableFilenames) { this.acceptableFilenames = addLocalesToAcceptableFilenames(acceptableFilenames); } protected List addLocalesToAcceptableFilenames(List acceptableFilenames) { - String [] locales = configurationService.getArrayProperty("webui.supported.locales"); + String[] locales = configurationService.getArrayProperty("webui.supported.locales"); List newAcceptableFilenames = new ArrayList<>(); newAcceptableFilenames.addAll(acceptableFilenames); for (String local : locales) { @@ -62,12 +61,14 @@ public class NewsServiceImpl implements NewsService } - /** Not instantiable. */ - protected NewsServiceImpl() {} + /** + * Not instantiable. + */ + protected NewsServiceImpl() { + } @Override - public String readNewsFile(String newsFile) - { + public String readNewsFile(String newsFile) { if (!validate(newsFile)) { throw new IllegalArgumentException("The file " + newsFile + " is not a valid news file"); } @@ -77,8 +78,7 @@ public class NewsServiceImpl implements NewsService StringBuilder text = new StringBuilder(); - try - { + try { // retrieve existing news from file FileInputStream fir = new FileInputStream(fileName); InputStreamReader ir = new InputStreamReader(fir, "UTF-8"); @@ -86,17 +86,14 @@ public class NewsServiceImpl implements NewsService String lineIn; - while ((lineIn = br.readLine()) != null) - { + while ((lineIn = br.readLine()) != null) { text.append(lineIn); } br.close(); ir.close(); fir.close(); - } - catch (IOException e) - { + } catch (IOException e) { log.warn("news_read: " + e.getLocalizedMessage()); } @@ -104,26 +101,22 @@ public class NewsServiceImpl implements NewsService } @Override - public String writeNewsFile(String newsFile, String news) - { + public String writeNewsFile(String newsFile, String news) { if (!validate(newsFile)) { - throw new IllegalArgumentException("The file "+ newsFile + " is not a valid news file"); + throw new IllegalArgumentException("The file " + newsFile + " is not a valid news file"); } String fileName = getNewsFilePath(); fileName += newsFile; - try - { + try { // write the news out to the appropriate file FileOutputStream fos = new FileOutputStream(fileName); OutputStreamWriter osr = new OutputStreamWriter(fos, "UTF-8"); PrintWriter out = new PrintWriter(osr); out.print(news); out.close(); - } - catch (IOException e) - { + } catch (IOException e) { log.warn("news_write: " + e.getLocalizedMessage()); } @@ -131,13 +124,12 @@ public class NewsServiceImpl implements NewsService } @Override - public String getNewsFilePath() - { + public String getNewsFilePath() { String filePath = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") - + File.separator + "config" + File.separator; + + File.separator + "config" + File.separator; return filePath; } - + @Override public boolean validate(String newsName) { if (acceptableFilenames != null) { diff --git a/dspace-api/src/main/java/org/dspace/core/PathsClassLoader.java b/dspace-api/src/main/java/org/dspace/core/PathsClassLoader.java index f0f736e7b9..e52fe412b4 100644 --- a/dspace-api/src/main/java/org/dspace/core/PathsClassLoader.java +++ b/dspace-api/src/main/java/org/dspace/core/PathsClassLoader.java @@ -29,84 +29,69 @@ import java.util.jar.JarFile; * @author Mark H. Wood */ public class PathsClassLoader - extends ClassLoader -{ - /** Filesystem paths to be searched. */ + extends ClassLoader { + /** + * Filesystem paths to be searched. + */ private final String[] classpath; /** * Instantiate to use a custom class path. * - * @param parent delegate to this ClassLoader first. + * @param parent delegate to this ClassLoader first. * @param classpath filesystem paths to be searched for classes and JARs. */ - PathsClassLoader(ClassLoader parent, String[] classpath) - { + PathsClassLoader(ClassLoader parent, String[] classpath) { super(parent); this.classpath = classpath; } @Override - protected Class findClass(String name) throws ClassNotFoundException - { + protected Class findClass(String name) throws ClassNotFoundException { Class found = null; - for (String aPath : classpath) - { + for (String aPath : classpath) { String bodyPath = name.replace('.', '/'); File pathFile = new File(aPath); - if (pathFile.isDirectory()) - { + if (pathFile.isDirectory()) { byte[] body; int bodySize; File bodyFile = new File(pathFile, bodyPath + ".class"); - if (!bodyFile.exists()) - { + if (!bodyFile.exists()) { continue; } bodySize = (int) bodyFile.length(); body = new byte[bodySize]; FileInputStream bodyStream = null; - try - { + try { bodyStream = new FileInputStream(bodyFile); int pos = 0; int len; - do - { + do { len = bodyStream.read(body, pos, bodySize); pos += len; } while (pos < bodySize); - } catch (IOException e) - { + } catch (IOException e) { throw new ClassNotFoundException("Class body not read", e); - } finally - { - if (null != bodyStream) - { - try - { + } finally { + if (null != bodyStream) { + try { bodyStream.close(); - } catch (IOException ex) - { + } catch (IOException ex) { /* don't care */ } } } found = defineClass(name, body, 0, bodySize); break; - } - else if (pathFile.isFile()) - { + } else if (pathFile.isFile()) { byte[] body; int bodySize; InputStream bodyStream = null; JarFile jar = null; - try - { + try { jar = new JarFile(pathFile); JarEntry entry = jar.getJarEntry(bodyPath + ".class"); - if (null == entry) - { + if (null == entry) { continue; } bodyStream = jar.getInputStream(entry); @@ -114,51 +99,37 @@ public class PathsClassLoader body = new byte[bodySize]; int pos = 0; int len; - do - { + do { len = bodyStream.read(body, pos, bodySize); pos += len; } while (pos < bodySize); - } catch (IOException e) - { + } catch (IOException e) { throw new ClassNotFoundException("Class body not read", e); - } finally - { - if (null != bodyStream) - { - try - { + } finally { + if (null != bodyStream) { + try { bodyStream.close(); - } catch (IOException e) - { + } catch (IOException e) { /* don't care */ } } - if (null != jar) - { - try - { + if (null != jar) { + try { jar.close(); - } catch (IOException e) - { + } catch (IOException e) { /* don't care */ } } } found = defineClass(name, body, 0, bodySize); break; - } - else - { + } else { // Just skip this path element -- probably just file not found here. } } - if (null == found) - { + if (null == found) { throw new ClassNotFoundException(name); - } - else - { + } else { resolveClass(found); return found; } diff --git a/dspace-api/src/main/java/org/dspace/core/PluginConfigurationError.java b/dspace-api/src/main/java/org/dspace/core/PluginConfigurationError.java index 7e02c05f85..e5f40ab06c 100644 --- a/dspace-api/src/main/java/org/dspace/core/PluginConfigurationError.java +++ b/dspace-api/src/main/java/org/dspace/core/PluginConfigurationError.java @@ -19,13 +19,11 @@ package org.dspace.core; * @see org.dspace.core.service.PluginService */ -public class PluginConfigurationError extends Error -{ +public class PluginConfigurationError extends Error { /** * @param msg Error message text. */ - public PluginConfigurationError(String msg) - { + public PluginConfigurationError(String msg) { super(msg); } } diff --git a/dspace-api/src/main/java/org/dspace/core/PluginInstantiationException.java b/dspace-api/src/main/java/org/dspace/core/PluginInstantiationException.java index 2d498cd7be..99e5eb23f8 100644 --- a/dspace-api/src/main/java/org/dspace/core/PluginInstantiationException.java +++ b/dspace-api/src/main/java/org/dspace/core/PluginInstantiationException.java @@ -22,30 +22,26 @@ package org.dspace.core; * @see org.dspace.core.service.PluginService */ -public class PluginInstantiationException extends RuntimeException -{ +public class PluginInstantiationException extends RuntimeException { /** * @param msg Error message text. */ - public PluginInstantiationException(String msg) - { + public PluginInstantiationException(String msg) { super(msg); } /** - * @param msg Error message text. + * @param msg Error message text. * @param cause other exception that this one is wrapping. */ - public PluginInstantiationException(String msg, Throwable cause) - { + public PluginInstantiationException(String msg, Throwable cause) { super(msg, cause); } /** * @param cause other exception that this one is wrapping. */ - public PluginInstantiationException(Throwable cause) - { + public PluginInstantiationException(Throwable cause) { super(cause); } } diff --git a/dspace-api/src/main/java/org/dspace/core/ReloadableEntity.java b/dspace-api/src/main/java/org/dspace/core/ReloadableEntity.java index 87ee88bf5f..76139ff173 100644 --- a/dspace-api/src/main/java/org/dspace/core/ReloadableEntity.java +++ b/dspace-api/src/main/java/org/dspace/core/ReloadableEntity.java @@ -10,11 +10,16 @@ package org.dspace.core; import java.io.Serializable; /** - * Interface that has to be implemented by all entities that can be reloaded by the Context - * (see {@link org.dspace.core.Context#reloadEntity(ReloadableEntity)} ])} + * Implemented by all entities that can be reloaded by the {@link Context}. + * + * @param type of this entity's primary key. + * @see org.dspace.core.Context#reloadEntity(ReloadableEntity) */ public interface ReloadableEntity { - + /** + * The unique identifier of this entity instance. + * + * @return the value of the primary key for this instance. + */ T getID(); - } diff --git a/dspace-api/src/main/java/org/dspace/core/SelfNamedPlugin.java b/dspace-api/src/main/java/org/dspace/core/SelfNamedPlugin.java index e9a1002f8e..2bdcf830e7 100644 --- a/dspace-api/src/main/java/org/dspace/core/SelfNamedPlugin.java +++ b/dspace-api/src/main/java/org/dspace/core/SelfNamedPlugin.java @@ -28,8 +28,7 @@ package org.dspace.core; * @version $Revision$ * @see org.dspace.core.service.PluginService */ -public abstract class SelfNamedPlugin -{ +public abstract class SelfNamedPlugin { // the specific alias used to find the class that created this instance. private String myName = null; @@ -49,8 +48,7 @@ public abstract class SelfNamedPlugin * * @return array of names of this plugin */ - public static String[] getPluginNames() - { + public static String[] getPluginNames() { return null; } @@ -65,8 +63,7 @@ public abstract class SelfNamedPlugin * * @return name or null if not available. */ - public String getPluginInstanceName() - { + public String getPluginInstanceName() { return myName; } @@ -78,8 +75,7 @@ public abstract class SelfNamedPlugin * * @param name -- name used to select this class. */ - protected void setPluginInstanceName(String name) - { + protected void setPluginInstanceName(String name) { myName = name; } } diff --git a/dspace-api/src/main/java/org/dspace/core/Utils.java b/dspace-api/src/main/java/org/dspace/core/Utils.java index 02708bf17a..a7e59a2e46 100644 --- a/dspace-api/src/main/java/org/dspace/core/Utils.java +++ b/dspace-api/src/main/java/org/dspace/core/Utils.java @@ -16,28 +16,36 @@ import java.math.BigInteger; import java.rmi.dgc.VMID; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Random; +import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.text.SimpleDateFormat; -import java.text.ParseException; + import com.coverity.security.Escape; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; /** * Utility functions for DSpace. - * + * * @author Peter Breton * @version $Revision$ */ -public final class Utils -{ - /** log4j logger */ +public final class Utils { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(Utils.class); private static final Pattern DURATION_PATTERN = Pattern - .compile("(\\d+)([smhdwy])"); + .compile("(\\d+)([smhdwy])"); private static final long MS_IN_SECOND = 1000L; @@ -58,15 +66,13 @@ public final class Utils private static VMID vmid = new VMID(); // for parseISO8601Date - private static SimpleDateFormat parseFmt[] = - { + private static SimpleDateFormat parseFmt[] = { // first try at parsing, has milliseconds (note General time zone) new SimpleDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSz"), // second try at parsing, no milliseconds (note General time zone) new SimpleDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ssz"), - // finally, try without any timezone (defaults to current TZ) new SimpleDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSS"), @@ -82,52 +88,44 @@ public final class Utils private static Calendar outCal = GregorianCalendar.getInstance(); - /** Private Constructor */ - private Utils() - { - } + /** + * Private constructor + */ + private Utils() { } /** * Return an MD5 checksum for data in hex format. - * - * @param data - * The data to checksum. + * + * @param data The data to checksum. * @return MD5 checksum for the data in hex format. */ - public static String getMD5(String data) - { + public static String getMD5(String data) { return getMD5(data.getBytes()); } /** * Return an MD5 checksum for data in hex format. - * - * @param data - * The data to checksum. + * + * @param data The data to checksum. * @return MD5 checksum for the data in hex format. */ - public static String getMD5(byte[] data) - { + public static String getMD5(byte[] data) { return toHex(getMD5Bytes(data)); } /** * Return an MD5 checksum for data as a byte array. - * - * @param data - * The data to checksum. + * + * @param data The data to checksum. * @return MD5 checksum for the data as a byte array. */ - public static byte[] getMD5Bytes(byte[] data) - { - try - { + public static byte[] getMD5Bytes(byte[] data) { + try { MessageDigest digest = MessageDigest.getInstance("MD5"); return digest.digest(data); - } - catch (NoSuchAlgorithmException nsae) - { + } catch (NoSuchAlgorithmException nsae) { + // ignore } // Should never happen @@ -136,23 +134,19 @@ public final class Utils /** * Return a hex representation of the byte array - * - * @param data - * The data to transform. + * + * @param data The data to transform. * @return A hex representation of the data. */ - public static String toHex(byte[] data) - { - if ((data == null) || (data.length == 0)) - { + public static String toHex(byte[] data) { + if ((data == null) || (data.length == 0)) { return null; } StringBuffer result = new StringBuffer(); // This is far from the most efficient way to do things... - for (int i = 0; i < data.length; i++) - { + for (int i = 0; i < data.length; i++) { int low = (int) (data[i] & 0x0F); int high = (int) (data[i] & 0xF0); @@ -166,38 +160,35 @@ public final class Utils /** * Generate a unique key. The key is a long (length 38 to 40) sequence of * digits. - * + * * @return A unique key as a long sequence of base-10 digits. */ - public static String generateKey() - { + public static String generateKey() { return new BigInteger(generateBytesKey()).abs().toString(); } /** * Generate a unique key. The key is a 32-character long sequence of hex * digits. - * + * * @return A unique key as a long sequence of hex digits. */ - public static String generateHexKey() - { + public static String generateHexKey() { return toHex(generateBytesKey()); } /** * Generate a unique key as a byte array. - * + * * @return A unique key as a byte array. */ - public static synchronized byte[] generateBytesKey() - { + public static synchronized byte[] generateBytesKey() { byte[] junk = new byte[16]; random.nextBytes(junk); String input = new StringBuffer().append(vmid).append( - new java.util.Date()).append(Arrays.toString(junk)).append(counter++).toString(); + new java.util.Date()).append(Arrays.toString(junk)).append(counter++).toString(); return getMD5Bytes(input.getBytes()); } @@ -209,25 +200,20 @@ public final class Utils * flush or close the streams, as to do so would require making non-portable * assumptions about the streams' origin and further use. If you wish to * perform a buffered copy, use {@link #bufferedCopy}. - * - * @param input - * The InputStream to obtain data from. - * @param output - * The OutputStream to copy data to. + * + * @param input The InputStream to obtain data from. + * @param output The OutputStream to copy data to. * @throws IOException if IO error */ public static void copy(final InputStream input, final OutputStream output) - throws IOException - { + throws IOException { final int BUFFER_SIZE = 1024 * 4; final byte[] buffer = new byte[BUFFER_SIZE]; - while (true) - { + while (true) { final int count = input.read(buffer, 0, BUFFER_SIZE); - if (-1 == count) - { + if (-1 == count) { break; } @@ -246,19 +232,16 @@ public final class Utils * java.io.BufferedOutputStream to {@link #copy}, and * flushing the output stream afterwards. The streams are not closed after * the copy. - * - * @param source - * The InputStream to obtain data from. - * @param destination - * The OutputStream to copy data to. + * + * @param source The InputStream to obtain data from. + * @param destination The OutputStream to copy data to. * @throws IOException if IO error */ public static void bufferedCopy(final InputStream source, - final OutputStream destination) throws IOException - { + final OutputStream destination) throws IOException { final BufferedInputStream input = new BufferedInputStream(source); final BufferedOutputStream output = new BufferedOutputStream( - destination); + destination); copy(input, output); output.flush(); } @@ -269,71 +252,49 @@ public final class Utils * any metadata fields that could contain the characters {@code "<", ">", "&", "'"}, * and double quotation marks. This will effectively disable HTML links * in metadata. - * - * @param value - * the metadata value to be scrubbed for display - * + * + * @param value the metadata value to be scrubbed for display * @return the passed-in string, with html special characters replaced with - * entities. + * entities. */ - public static String addEntities(String value) - { + public static String addEntities(String value) { return Escape.html(value); } /** * Utility method to parse durations defined as {@code \d+[smhdwy]} (seconds, * minutes, hours, days, weeks, years) - * - * @param duration - * specified duration - * + * + * @param duration specified duration * @return number of milliseconds equivalent to duration. - * - * @throws ParseException - * if the duration is of incorrect format + * @throws ParseException if the duration is of incorrect format */ - public static long parseDuration(String duration) throws ParseException - { + public static long parseDuration(String duration) throws ParseException { Matcher m = DURATION_PATTERN.matcher(duration.trim()); - if (!m.matches()) - { + if (!m.matches()) { throw new ParseException("'" + duration - + "' is not a valid duration definition", 0); + + "' is not a valid duration definition", 0); } String units = m.group(2); long multiplier = MS_IN_SECOND; - if ("s".equals(units)) - { + if ("s".equals(units)) { multiplier = MS_IN_SECOND; - } - else if ("m".equals(units)) - { + } else if ("m".equals(units)) { multiplier = MS_IN_MINUTE; - } - else if ("h".equals(units)) - { + } else if ("h".equals(units)) { multiplier = MS_IN_HOUR; - } - else if ("d".equals(units)) - { + } else if ("d".equals(units)) { multiplier = MS_IN_DAY; - } - else if ("w".equals(units)) - { + } else if ("w".equals(units)) { multiplier = MS_IN_WEEK; - } - else if ("y".equals(units)) - { + } else if ("y".equals(units)) { multiplier = MS_IN_YEAR; - } - else - { + } else { throw new ParseException(units - + " is not a valid time unit (must be 'y', " - + "'w', 'd', 'h', 'm' or 's')", duration.indexOf(units)); + + " is not a valid time unit (must be 'y', " + + "'w', 'd', 'h', 'm' or 's')", duration.indexOf(units)); } long qint = Long.parseLong(m.group(1)); @@ -350,37 +311,27 @@ public final class Utils * @param s the input string * @return Date object, or null if there is a problem translating. */ - public static synchronized Date parseISO8601Date(String s) - { + public static synchronized Date parseISO8601Date(String s) { // attempt to normalize the timezone to something we can parse; // SimpleDateFormat can't handle "Z" - char tzSign = s.charAt(s.length()-6); - if (s.endsWith("Z")) - { + char tzSign = s.charAt(s.length() - 6); + if (s.endsWith("Z")) { s = s.substring(0, s.length() - 1) + "GMT+00:00"; - } - - // check for trailing timezone - else if (tzSign == '-' || tzSign == '+') - { + } else if (tzSign == '-' || tzSign == '+') { + // check for trailing timezone s = s.substring(0, s.length() - 6) + "GMT" + s.substring(s.length() - 6); } // try to parse without milliseconds ParseException lastError = null; - for (int i = 0; i < parseFmt.length; ++i) - { - try - { + for (int i = 0; i < parseFmt.length; ++i) { + try { return parseFmt[i].parse(s); - } - catch (ParseException e) - { + } catch (ParseException e) { lastError = e; } } - if (lastError != null) - { + if (lastError != null) { log.error("Error parsing date:", lastError); } return null; @@ -395,23 +346,66 @@ public final class Utils * @param d the input Date * @return String containing formatted date. */ - public static synchronized String formatISO8601Date(Date d) - { + public static synchronized String formatISO8601Date(Date d) { String result; outCal.setTime(d); - if (outCal.get(Calendar.MILLISECOND) == 0) - { + if (outCal.get(Calendar.MILLISECOND) == 0) { result = outFmtSecond.format(d); - } - else - { + } else { result = outFmtMillisec.format(d); } int rl = result.length(); - return result.substring(0, rl-2) + ":" + result.substring(rl-2); + return result.substring(0, rl - 2) + ":" + result.substring(rl - 2); } - public static Collection emptyIfNull(Collection collection) { + public static java.util.Collection emptyIfNull(java.util.Collection collection) { return collection == null ? Collections.emptyList() : collection; } + + /** + * Utility method to extract schema, element, qualifier from the metadata field key + * Keep in mind that this method try to auto discover the common separator used in DSpace ("_" or ".") + * + * Return an array of token with size 3 which contains: + * schema = tokens[0]; + * element = tokens[1]; + * qualifier = tokens[2]; //it can be empty string + * + * @param metadata (the field in the form dc.title or dc_title) + * @return array of tokens + */ + public static String[] tokenize(String metadata) { + String separator = metadata.contains("_") ? "_" : "."; + StringTokenizer dcf = new StringTokenizer(metadata, separator); + + String[] tokens = {"", "", ""}; + int i = 0; + while (dcf.hasMoreTokens()) { + tokens[i] = dcf.nextToken().trim(); + i++; + } + // Tokens contains: + // schema = tokens[0]; + // element = tokens[1]; + // qualifier = tokens[2]; + return tokens; + + } + + /** + * Make the metadata field key using the separator. + * + * @param schema + * @param element + * @param qualifier + * @param separator (DSpace common separator are "_" or ".") + * @return metadata field key + */ + public static String standardize(String schema, String element, String qualifier, String separator) { + if (StringUtils.isBlank(qualifier)) { + return schema + separator + element; + } else { + return schema + separator + element + separator + qualifier; + } + } } diff --git a/dspace-api/src/main/java/org/dspace/core/factory/CoreServiceFactory.java b/dspace-api/src/main/java/org/dspace/core/factory/CoreServiceFactory.java index 7e5d1efd7e..888cd21764 100644 --- a/dspace-api/src/main/java/org/dspace/core/factory/CoreServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/core/factory/CoreServiceFactory.java @@ -13,7 +13,8 @@ import org.dspace.core.service.PluginService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the core package, use CoreServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the core package, use CoreServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -25,8 +26,8 @@ public abstract class CoreServiceFactory { public abstract PluginService getPluginService(); - public static CoreServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("coreServiceFactory", CoreServiceFactory.class); + public static CoreServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("coreServiceFactory", CoreServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/core/factory/CoreServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/core/factory/CoreServiceFactoryImpl.java index 83c13d1cab..4beb47f2c0 100644 --- a/dspace-api/src/main/java/org/dspace/core/factory/CoreServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/core/factory/CoreServiceFactoryImpl.java @@ -13,7 +13,8 @@ import org.dspace.core.service.PluginService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the core package, use CoreServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the core package, use CoreServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/core/service/LicenseService.java b/dspace-api/src/main/java/org/dspace/core/service/LicenseService.java index 732fe93b53..b0226ebcfe 100644 --- a/dspace-api/src/main/java/org/dspace/core/service/LicenseService.java +++ b/dspace-api/src/main/java/org/dspace/core/service/LicenseService.java @@ -17,23 +17,18 @@ public interface LicenseService { /** * Writes license to a text file. * - * @param licenseFile - * name for the file into which license will be written, - * relative to the current directory. - * @param newLicense new license + * @param licenseFile name for the file into which license will be written, + * relative to the current directory. + * @param newLicense new license */ public void writeLicenseFile(String licenseFile, - String newLicense); + String newLicense); /** * Get the License * - * @param - * licenseFile file name - * - * @return - * license text - * + * @param licenseFile file name + * @return license text */ public String getLicenseText(String licenseFile); diff --git a/dspace-api/src/main/java/org/dspace/core/service/NewsService.java b/dspace-api/src/main/java/org/dspace/core/service/NewsService.java index a9f9f04e5e..ff67aa7f41 100644 --- a/dspace-api/src/main/java/org/dspace/core/service/NewsService.java +++ b/dspace-api/src/main/java/org/dspace/core/service/NewsService.java @@ -17,8 +17,7 @@ public interface NewsService { /** * Reads news from a text file. * - * @param newsFile - * name of the news file to read in, relative to the news file path. + * @param newsFile name of the news file to read in, relative to the news file path. * @return contents */ public String readNewsFile(String newsFile); @@ -26,10 +25,8 @@ public interface NewsService { /** * Writes news to a text file. * - * @param newsFile - * name of the news file to read in, relative to the news file path. - * @param news - * the text to be written to the file. + * @param newsFile name of the news file to read in, relative to the news file path. + * @param news the text to be written to the file. * @return string */ public String writeNewsFile(String newsFile, String news); @@ -43,11 +40,10 @@ public interface NewsService { /** * Check if the newsName is an acceptable file name - * - * @param newsName - * news name - * @return true - * if the newsName is valid + * + * @param newsName news name + * @return true + * if the newsName is valid */ public boolean validate(String newsName); } diff --git a/dspace-api/src/main/java/org/dspace/core/service/PluginService.java b/dspace-api/src/main/java/org/dspace/core/service/PluginService.java index ef8cd3393c..0bd7fdb0f6 100644 --- a/dspace-api/src/main/java/org/dspace/core/service/PluginService.java +++ b/dspace-api/src/main/java/org/dspace/core/service/PluginService.java @@ -17,8 +17,7 @@ package org.dspace.core.service; * * @author Tim Donohue */ -public interface PluginService -{ +public interface PluginService { /** * Returns all of the names under which a named plugin implementing * the interface can be requested (with getNamedPlugin()). @@ -30,7 +29,7 @@ public interface PluginService * * @param interfaceClass plugin interface for which to return names. * @return an array of strings with every name; if none are - * available an empty array is returned. + * available an empty array is returned. */ public String[] getAllPluginNames(Class interfaceClass); @@ -41,7 +40,7 @@ public interface PluginService * String.equals(). * * @param interfaceClass the interface class of the plugin - * @param name under which the plugin implementation is configured. + * @param name under which the plugin implementation is configured. * @return instance of plugin implementation, or null if there is no match or an error. */ public Object getNamedPlugin(Class interfaceClass, String name); @@ -52,7 +51,7 @@ public interface PluginService * return true. If there is no matching plugin, return false. * * @param interfaceClass the interface class of the plugin - * @param name under which the plugin implementation is configured. + * @param name under which the plugin implementation is configured. * @return true if plugin was found to be configured, false otherwise */ public boolean hasNamedPlugin(Class interfaceClass, String name); @@ -67,7 +66,7 @@ public interface PluginService * * @param interfaceClass interface for which to find plugins. * @return an array of plugin instances; if none are - * available an empty array is returned. + * available an empty array is returned. */ public Object[] getPluginSequence(Class interfaceClass); diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/AbstractTranslator.java b/dspace-api/src/main/java/org/dspace/ctask/general/AbstractTranslator.java index c80f37ebd6..6cc4e59204 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/AbstractTranslator.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/AbstractTranslator.java @@ -7,20 +7,20 @@ */ package org.dspace.ctask.general; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + import org.apache.log4j.Logger; -import org.dspace.content.MetadataValue; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.curate.AbstractCurationTask; import org.dspace.curate.Curator; import org.dspace.curate.Distributive; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - /** * MicrosoftTranslator translates stuff @@ -28,8 +28,7 @@ import java.util.List; * @author Kim Shepherd */ @Distributive -public abstract class AbstractTranslator extends AbstractCurationTask -{ +public abstract class AbstractTranslator extends AbstractCurationTask { protected int status = Curator.CURATE_UNSET; @@ -44,14 +43,13 @@ public abstract class AbstractTranslator extends AbstractCurationTask private static Logger log = Logger.getLogger(AbstractTranslator.class); protected List results = new ArrayList(); - + private final transient ConfigurationService configurationService - = DSpaceServicesFactory.getInstance().getConfigurationService(); + = DSpaceServicesFactory.getInstance().getConfigurationService(); @Override - public void init(Curator curator, String taskId) throws IOException - { + public void init(Curator curator, String taskId) throws IOException { super.init(curator, taskId); // Load configuration @@ -60,8 +58,7 @@ public abstract class AbstractTranslator extends AbstractCurationTask String[] toTranslate = configurationService.getArrayProperty(PLUGIN_PREFIX + ".field.targets"); String[] langs = configurationService.getArrayProperty(PLUGIN_PREFIX + ".language.targets"); - if(!(toTranslate.length > 0 && langs.length > 0)) - { + if (!(toTranslate.length > 0 && langs.length > 0)) { status = Curator.CURATE_ERROR; results.add("Configuration error"); setResult(results.toString()); @@ -75,11 +72,9 @@ public abstract class AbstractTranslator extends AbstractCurationTask } @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { - if(dso instanceof Item) - { + if (dso instanceof Item) { Item item = (Item) dso; /* @@ -93,30 +88,27 @@ public abstract class AbstractTranslator extends AbstractCurationTask log.debug("Translating metadata for " + handle); List authLangs = itemService.getMetadataByMetadataString(item, authLangField); - if(authLangs.size() > 0) - { + if (authLangs.size() > 0) { /* Assume the first... multiple "authoritative" languages won't work */ authLang = authLangs.get(0).getValue(); log.debug("Authoritative language for " + handle + " is " + authLang); } - for(String lang : langs) - { + for (String lang : langs) { lang = lang.trim(); - for(String field : toTranslate) - { + for (String field : toTranslate) { boolean translated = false; field = field.trim(); String[] fieldSegments = field.split("\\."); List fieldMetadata = null; - - if(fieldSegments.length > 2) { + + if (fieldSegments.length > 2) { // First, check to see if we've already got this in the target language - List checkMetadata = itemService.getMetadata(item, fieldSegments[0], fieldSegments[1], fieldSegments[2], lang); - if(checkMetadata.size() > 0) - { + List checkMetadata = itemService + .getMetadata(item, fieldSegments[0], fieldSegments[1], fieldSegments[2], lang); + if (checkMetadata.size() > 0) { // We've already translated this, move along log.debug(handle + "already has " + field + " in " + lang + ", skipping"); results.add(handle + ": Skipping " + lang + " translation " + "(" + field + ")"); @@ -124,14 +116,14 @@ public abstract class AbstractTranslator extends AbstractCurationTask } // Let's carry on and get the authoritative version, then - fieldMetadata = itemService.getMetadata(item, fieldSegments[0], fieldSegments[1], fieldSegments[2], authLang); + fieldMetadata = itemService + .getMetadata(item, fieldSegments[0], fieldSegments[1], fieldSegments[2], authLang); - } - else { + } else { // First, check to see if we've already got this in the target language - List checkMetadata = itemService.getMetadata(item, fieldSegments[0], fieldSegments[1], null, lang); - if(checkMetadata.size() > 0) - { + List checkMetadata = itemService + .getMetadata(item, fieldSegments[0], fieldSegments[1], null, lang); + if (checkMetadata.size() > 0) { // We've already translated this, move along log.debug(handle + "already has " + field + " in " + lang + ", skipping"); results.add(handle + ": Skipping " + lang + " translation " + "(" + field + ")"); @@ -139,38 +131,39 @@ public abstract class AbstractTranslator extends AbstractCurationTask } // Let's carry on and get the authoritative version, then - fieldMetadata = itemService.getMetadata(item, fieldSegments[0], fieldSegments[1], null, authLang); + fieldMetadata = itemService + .getMetadata(item, fieldSegments[0], fieldSegments[1], null, authLang); } - if(!translated && fieldMetadata.size() > 0) - { - for(MetadataValue metadataValue : fieldMetadata) { + if (!translated && fieldMetadata.size() > 0) { + for (MetadataValue metadataValue : fieldMetadata) { String value = metadataValue.getValue(); String translatedText = translateText(authLang, lang, value); - if(translatedText != null && !"".equals(translatedText)) - { + if (translatedText != null && !"".equals(translatedText)) { try { // Add the new metadata - if(fieldSegments.length > 2) { - itemService.addMetadata(Curator.curationContext(), item, fieldSegments[0], fieldSegments[1], fieldSegments[2], lang, translatedText); - } - else { - itemService.addMetadata(Curator.curationContext(), item, fieldSegments[0], fieldSegments[1], null, lang, translatedText); + if (fieldSegments.length > 2) { + itemService.addMetadata(Curator.curationContext(), item, fieldSegments[0], + fieldSegments[1], fieldSegments[2], lang, + translatedText); + } else { + itemService.addMetadata(Curator.curationContext(), item, fieldSegments[0], + fieldSegments[1], null, lang, translatedText); } itemService.update(Curator.curationContext(), item); - results.add(handle + ": Translated " + authLang + " -> " + lang + " (" + field + ")"); - } - catch(Exception e) { + results + .add(handle + ": Translated " + authLang + " -> " + lang + " (" + field + ")"); + } catch (Exception e) { log.info(e.getLocalizedMessage()); status = Curator.CURATE_ERROR; } - } - else { - results.add(handle + ": Failed translation of " + authLang + " -> " + lang + "(" + field + ")"); + } else { + results.add( + handle + ": Failed translation of " + authLang + " -> " + lang + "(" + field + ")"); } } } @@ -198,12 +191,10 @@ public abstract class AbstractTranslator extends AbstractCurationTask return null; } - private void processResults() throws IOException - { + private void processResults() throws IOException { StringBuilder sb = new StringBuilder(); sb.append("Translation report: \n----------------\n"); - for(String result : results) - { + for (String result : results) { sb.append(result).append("\n"); } setResult(sb.toString()); diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/BasicLinkChecker.java b/dspace-api/src/main/java/org/dspace/ctask/general/BasicLinkChecker.java index b216b75ba1..dc59292afe 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/BasicLinkChecker.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/BasicLinkChecker.java @@ -7,19 +7,19 @@ */ package org.dspace.ctask.general; -import org.apache.log4j.Logger; -import org.dspace.content.MetadataValue; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; -import org.dspace.curate.AbstractCurationTask; -import org.dspace.curate.Curator; - import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; +import org.apache.log4j.Logger; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.curate.AbstractCurationTask; +import org.dspace.curate.Curator; + /** * A basic link checker that is designed to be extended. By default this link checker * will check that all links stored in anyschema.anyelement.uri metadata fields return @@ -31,8 +31,7 @@ import java.util.List; * @author Stuart Lewis */ -public class BasicLinkChecker extends AbstractCurationTask -{ +public class BasicLinkChecker extends AbstractCurationTask { // The status of the link checking of this item private int status = Curator.CURATE_UNSET; @@ -52,16 +51,14 @@ public class BasicLinkChecker extends AbstractCurationTask * @throws java.io.IOException THrown if something went wrong */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { // The results that we'll return StringBuilder results = new StringBuilder(); // Unless this is an item, we'll skip this item status = Curator.CURATE_SKIP; - if (dso instanceof Item) - { - Item item = (Item)dso; + if (dso instanceof Item) { + Item item = (Item) dso; // Get the URLs List urls = getURLs(item); @@ -71,16 +68,12 @@ public class BasicLinkChecker extends AbstractCurationTask results.append("Item: ").append(getItemHandle(item)).append("\n"); // Check the URLs - for (String url : urls) - { + for (String url : urls) { boolean ok = checkURL(url, results); - if(ok) - { + if (ok) { status = Curator.CURATE_SUCCESS; - } - else - { + } else { status = Curator.CURATE_FAIL; } } @@ -98,13 +91,11 @@ public class BasicLinkChecker extends AbstractCurationTask * @param item The item to extract URLs from * @return An array of URL Strings */ - protected List getURLs(Item item) - { + protected List getURLs(Item item) { // Get URIs from anyschema.anyelement.uri.* List urls = itemService.getMetadata(item, Item.ANY, Item.ANY, "uri", Item.ANY); ArrayList theURLs = new ArrayList(); - for (MetadataValue url : urls) - { + for (MetadataValue url : urls) { theURLs.add(url.getValue()); } return theURLs; @@ -113,24 +104,18 @@ public class BasicLinkChecker extends AbstractCurationTask /** * Check the URL and perform appropriate reporting * - * @param url - * The URL to check - * @param results - * Result string with HTTP status codes + * @param url The URL to check + * @param results Result string with HTTP status codes * @return If the URL was OK or not */ - protected boolean checkURL(String url, StringBuilder results) - { + protected boolean checkURL(String url, StringBuilder results) { // Link check the URL int httpStatus = getResponseStatus(url); - if ((httpStatus >= 200) && (httpStatus < 300)) - { + if ((httpStatus >= 200) && (httpStatus < 300)) { results.append(" - " + url + " = " + httpStatus + " - OK\n"); return true; - } - else - { + } else { results.append(" - " + url + " = " + httpStatus + " - FAILED\n"); return false; } @@ -143,19 +128,16 @@ public class BasicLinkChecker extends AbstractCurationTask * @param url The url to open * @return The HTTP response code (e.g. 200 / 301 / 404 / 500) */ - protected int getResponseStatus(String url) - { - try - { + protected int getResponseStatus(String url) { + try { URL theURL = new URL(url); - HttpURLConnection connection = (HttpURLConnection)theURL.openConnection(); + HttpURLConnection connection = (HttpURLConnection) theURL.openConnection(); int code = connection.getResponseCode(); connection.disconnect(); return code; - } catch (IOException ioe) - { + } catch (IOException ioe) { // Must be a bad URL log.debug("Bad link: " + ioe.getMessage()); return 0; @@ -168,10 +150,9 @@ public class BasicLinkChecker extends AbstractCurationTask * @param item The item to get a description of * @return The handle, or in workflow */ - protected String getItemHandle(Item item) - { + protected String getItemHandle(Item item) { String handle = item.getHandle(); - return (handle != null) ? handle: " in workflow"; + return (handle != null) ? handle : " in workflow"; } } diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/BitstreamsIntoMetadata.java b/dspace-api/src/main/java/org/dspace/ctask/general/BitstreamsIntoMetadata.java index daae192b4b..79da1eff90 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/BitstreamsIntoMetadata.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/BitstreamsIntoMetadata.java @@ -7,22 +7,24 @@ */ package org.dspace.ctask.general; -import org.apache.log4j.Logger; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; -import org.dspace.curate.AbstractCurationTask; -import org.dspace.curate.Curator; - import java.sql.SQLException; import java.util.List; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.curate.AbstractCurationTask; +import org.dspace.curate.Curator; + /** * A curation job to take bitstream URLs and place them into metadata elements. * * @author Stuart Lewis */ -public class BitstreamsIntoMetadata extends AbstractCurationTask -{ +public class BitstreamsIntoMetadata extends AbstractCurationTask { // The status of this item protected int status = Curator.CURATE_UNSET; @@ -41,8 +43,7 @@ public class BitstreamsIntoMetadata extends AbstractCurationTask * @return The curation task status of the checking */ @Override - public int perform(DSpaceObject dso) - { + public int perform(DSpaceObject dso) { // The results that we'll return StringBuilder results = new StringBuilder(); @@ -50,10 +51,9 @@ public class BitstreamsIntoMetadata extends AbstractCurationTask status = Curator.CURATE_SKIP; boolean changed = false; logDebugMessage("The target dso is " + dso.getName()); - if (dso instanceof Item) - { + if (dso instanceof Item) { try { - Item item = (Item)dso; + Item item = (Item) dso; itemService.clearMetadata(Curator.curationContext(), item, "dc", "format", Item.ANY, Item.ANY); for (Bundle bundle : item.getBundles()) { if ("ORIGINAL".equals(bundle.getName())) { @@ -99,10 +99,8 @@ public class BitstreamsIntoMetadata extends AbstractCurationTask * * @param message The message to log */ - protected void logDebugMessage(String message) - { - if (log.isDebugEnabled()) - { + protected void logDebugMessage(String message) { + if (log.isDebugEnabled()) { log.debug(message); } } @@ -110,16 +108,15 @@ public class BitstreamsIntoMetadata extends AbstractCurationTask /** * Add the bitstream metadata to the item * - * @param item The item + * @param item The item * @param bitstream The bitstream - * @param type The type of bitstream - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param type The type of bitstream + * @throws SQLException An exception that provides information on a database access error or other errors. */ protected void addMetadata(Item item, Bitstream bitstream, String type) throws SQLException { String value = bitstream.getFormat(Curator.curationContext()).getMIMEType() + "##"; value += bitstream.getName() + "##"; - value += bitstream.getSize() + "##"; + value += bitstream.getSizeBytes() + "##"; value += item.getHandle() + "##"; value += bitstream.getSequenceID() + "##"; value += bitstream.getChecksum() + "##"; diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/ClamScan.java b/dspace-api/src/main/java/org/dspace/ctask/general/ClamScan.java index a074600794..d1fa70565d 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/ClamScan.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/ClamScan.java @@ -20,7 +20,10 @@ import java.util.ArrayList; import java.util.List; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.curate.AbstractCurationTask; @@ -29,7 +32,8 @@ import org.dspace.curate.Suspendable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** ClamScan.java +/** + * ClamScan.java * * A set of methods to scan using the * clamav daemon. @@ -39,13 +43,12 @@ import org.slf4j.LoggerFactory; * @author wbossons */ -@Suspendable(invoked= Curator.Invoked.INTERACTIVE) -public class ClamScan extends AbstractCurationTask -{ +@Suspendable(invoked = Curator.Invoked.INTERACTIVE) +public class ClamScan extends AbstractCurationTask { protected final int DEFAULT_CHUNK_SIZE = 4096;//2048 - protected final byte[] INSTREAM = "zINSTREAM\0".getBytes(); - protected final byte[] PING = "zPING\0".getBytes(); - protected final byte[] STATS = "nSTATS\n".getBytes();//prefix with z + protected final byte[] INSTREAM = "zINSTREAM\0".getBytes(); + protected final byte[] PING = "zPING\0".getBytes(); + protected final byte[] STATS = "nSTATS\n".getBytes();//prefix with z protected final byte[] IDSESSION = "zIDSESSION\0".getBytes(); protected final byte[] END = "zEND\0".getBytes(); protected final String PLUGIN_PREFIX = "clamav"; @@ -56,12 +59,12 @@ public class ClamScan extends AbstractCurationTask protected final String NEW_ITEM_HANDLE = "in workflow"; private static final Logger log = LoggerFactory.getLogger(ClamScan.class); - + protected String host = null; - protected int port = 0; + protected int port = 0; protected int timeout = 0; protected boolean failfast = true; - + protected int status = Curator.CURATE_UNSET; protected List results = null; @@ -70,8 +73,7 @@ public class ClamScan extends AbstractCurationTask protected BitstreamService bitstreamService; @Override - public void init(Curator curator, String taskId) throws IOException - { + public void init(Curator curator, String taskId) throws IOException { super.init(curator, taskId); host = configurationService.getProperty(PLUGIN_PREFIX + ".service.host"); port = configurationService.getIntProperty(PLUGIN_PREFIX + ".service.port"); @@ -81,285 +83,217 @@ public class ClamScan extends AbstractCurationTask } @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { status = Curator.CURATE_SKIP; logDebugMessage("The target dso is " + dso.getName()); - if (dso instanceof Item) - { + if (dso instanceof Item) { status = Curator.CURATE_SUCCESS; - Item item = (Item)dso; - try - { + Item item = (Item) dso; + try { openSession(); - } - catch (IOException ioE) - { + } catch (IOException ioE) { // no point going further - set result and error out closeSession(); setResult(CONNECT_FAIL_MESSAGE); return Curator.CURATE_ERROR; } - - try - { + + try { Bundle bundle = itemService.getBundles(item, "ORIGINAL").get(0); results = new ArrayList(); - for (Bitstream bitstream : bundle.getBitstreams()) - { + for (Bitstream bitstream : bundle.getBitstreams()) { InputStream inputstream = bitstreamService.retrieve(Curator.curationContext(), bitstream); logDebugMessage("Scanning " + bitstream.getName() + " . . . "); int bstatus = scan(bitstream, inputstream, getItemHandle(item)); inputstream.close(); - if (bstatus == Curator.CURATE_ERROR) - { + if (bstatus == Curator.CURATE_ERROR) { // no point going further - set result and error out setResult(SCAN_FAIL_MESSAGE); - status = bstatus; - break; - } - if (failfast && bstatus == Curator.CURATE_FAIL) - { status = bstatus; break; } - else if (bstatus == Curator.CURATE_FAIL && - status == Curator.CURATE_SUCCESS) - { + if (failfast && bstatus == Curator.CURATE_FAIL) { + status = bstatus; + break; + } else if (bstatus == Curator.CURATE_FAIL && + status == Curator.CURATE_SUCCESS) { status = bstatus; } - - } - } - catch (AuthorizeException authE) - { + + } + } catch (AuthorizeException authE) { throw new IOException(authE.getMessage(), authE); - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE.getMessage(), sqlE); - } - finally - { + } finally { closeSession(); } - - if (status != Curator.CURATE_ERROR) - { + + if (status != Curator.CURATE_ERROR) { formatResults(item); } } return status; } - - /** openSession + + /** + * openSession * * This method opens a session. * - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ - protected void openSession() throws IOException - { + protected void openSession() throws IOException { socket = new Socket(); - try - { + try { logDebugMessage("Connecting to " + host + ":" + port); socket.connect(new InetSocketAddress(host, port)); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Failed to connect to clamd . . .", e); throw (e); } - try - { + try { socket.setSoTimeout(timeout); - } - catch (SocketException e) - { + } catch (SocketException e) { log.error("Could not set socket timeout . . . " + timeout + "ms", e); throw (new IOException(e)); } - try - { + try { dataOutputStream = new DataOutputStream(socket.getOutputStream()); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Failed to open OutputStream . . . ", e); throw (e); } - try - { + try { dataOutputStream.write(IDSESSION); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Error initiating session with IDSESSION command . . . ", e); throw (e); } } - /** closeSession + /** + * closeSession * * Close the IDSESSION in CLAMD - * - * */ - protected void closeSession() - { - if (dataOutputStream != null) - { - try - { + protected void closeSession() { + if (dataOutputStream != null) { + try { dataOutputStream.write(END); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Exception closing dataOutputStream", e); } } - try - { + try { logDebugMessage("Closing the socket for ClamAv daemon . . . "); socket.close(); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Exception closing socket", e); } } - /** A buffer to hold chunks of an input stream to be scanned for viruses. */ + /** + * A buffer to hold chunks of an input stream to be scanned for viruses. + */ final byte[] buffer = new byte[DEFAULT_CHUNK_SIZE]; /** * Issue the INSTREAM command and return the response to * and from the clamav daemon. * - * @param bitstream the bitstream for reporting results + * @param bitstream the bitstream for reporting results * @param inputstream the InputStream to read - * @param itemHandle the item handle for reporting results + * @param itemHandle the item handle for reporting results * @return a ScanResult representing the server response */ - protected int scan(Bitstream bitstream, InputStream inputstream, String itemHandle) - { - try - { + protected int scan(Bitstream bitstream, InputStream inputstream, String itemHandle) { + try { dataOutputStream.write(INSTREAM); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Error writing INSTREAM command", e); return Curator.CURATE_ERROR; } int read = DEFAULT_CHUNK_SIZE; - while (read == DEFAULT_CHUNK_SIZE) - { - try - { + while (read == DEFAULT_CHUNK_SIZE) { + try { read = inputstream.read(buffer); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Failed attempting to read the InputStream", e); return Curator.CURATE_ERROR; } - if (read == -1) - { + if (read == -1) { break; } - try - { + try { dataOutputStream.writeInt(read); dataOutputStream.write(buffer, 0, read); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Could not write to the socket", e); return Curator.CURATE_ERROR; } } - try - { + try { dataOutputStream.writeInt(0); dataOutputStream.flush(); - } - catch (IOException e) - { - log.error("Error writing zero-length chunk to socket", e) ; + } catch (IOException e) { + log.error("Error writing zero-length chunk to socket", e); return Curator.CURATE_ERROR; } - try - { + try { read = socket.getInputStream().read(buffer); - } - catch (IOException e) - { - log.error( "Error reading result from socket", e); + } catch (IOException e) { + log.error("Error reading result from socket", e); return Curator.CURATE_ERROR; } - - if (read > 0) - { + + if (read > 0) { String response = new String(buffer, 0, read); logDebugMessage("Response: " + response); - if (response.contains("FOUND")) - { + if (response.contains("FOUND")) { String itemMsg = "item - " + itemHandle + ": "; String bsMsg = "bitstream - " + bitstream.getName() + - ": SequenceId - " + bitstream.getSequenceID() + ": infected"; + ": SequenceId - " + bitstream.getSequenceID() + ": infected"; report(itemMsg + bsMsg); results.add(bsMsg); return Curator.CURATE_FAIL; - } - else - { + } else { return Curator.CURATE_SUCCESS; } - } - return Curator.CURATE_ERROR; + } + return Curator.CURATE_ERROR; } - protected void formatResults(Item item) throws IOException - { + protected void formatResults(Item item) throws IOException { StringBuilder sb = new StringBuilder(); sb.append("Item: ").append(getItemHandle(item)).append(" "); - if (status == Curator.CURATE_FAIL) - { + if (status == Curator.CURATE_FAIL) { sb.append(INFECTED_MESSAGE); int count = 0; - for (String scanresult : results) - { + for (String scanresult : results) { sb.append("\n").append(scanresult).append("\n"); count++; } sb.append(count).append(" virus(es) found. ") - .append(" failfast: ").append(failfast); - } - else - { + .append(" failfast: ").append(failfast); + } else { sb.append(CLEAN_MESSAGE); } setResult(sb.toString()); } - protected String getItemHandle(Item item) - { + protected String getItemHandle(Item item) { String handle = item.getHandle(); - return (handle != null) ? handle: NEW_ITEM_HANDLE; + return (handle != null) ? handle : NEW_ITEM_HANDLE; } - protected void logDebugMessage(String message) - { - if (log.isDebugEnabled()) - { + protected void logDebugMessage(String message) { + if (log.isDebugEnabled()) { log.debug(message); } } diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/MetadataValueLinkChecker.java b/dspace-api/src/main/java/org/dspace/ctask/general/MetadataValueLinkChecker.java index cb1ca9c303..11213b56f5 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/MetadataValueLinkChecker.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/MetadataValueLinkChecker.java @@ -7,12 +7,12 @@ */ package org.dspace.ctask.general; -import org.dspace.content.MetadataValue; -import org.dspace.content.Item; - import java.util.ArrayList; import java.util.List; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; + /** * A link checker that builds upon the BasicLinkChecker to check URLs that * appear in all metadata fields where the field starts with http:// or https:// @@ -24,15 +24,12 @@ import java.util.List; public class MetadataValueLinkChecker extends BasicLinkChecker { @Override - protected List getURLs(Item item) - { + protected List getURLs(Item item) { // Get all metadata elements that start with http:// or https:// List urls = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); ArrayList theURLs = new ArrayList(); - for (MetadataValue url : urls) - { - if ((url.getValue().startsWith("http://")) || (url.getValue().startsWith("https://"))) - { + for (MetadataValue url : urls) { + if ((url.getValue().startsWith("http://")) || (url.getValue().startsWith("https://"))) { theURLs.add(url.getValue()); } } diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebService.java b/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebService.java index c71c24c730..9b49105c36 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebService.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebService.java @@ -7,8 +7,8 @@ */ package org.dspace.ctask.general; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; @@ -17,16 +17,15 @@ import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; - +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.namespace.NamespaceContext; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import javax.xml.XMLConstants; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -35,46 +34,43 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.log4j.Logger; - -import org.dspace.content.MetadataValue; -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import org.xml.sax.SAXException; - import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.core.Constants; import org.dspace.curate.AbstractCurationTask; import org.dspace.curate.Curator; import org.dspace.curate.Mutative; import org.dspace.curate.Suspendable; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; /** * MetadataWebService task calls a web service using metadata from * passed item to obtain data. Depending on configuration, this * data may be assigned to item metadata fields, or just recorded in the - * task result string. Task succeeds if web service call succeeds and + * task result string. Task succeeds if web service call succeeds and * configured updates occur, fails if task user not authorized or item * lacks metadata to call service, and returns error in all other cases * (except skip status for non-item objects). * Intended use: cataloging tool in workflow and general curation. * The task uses a URL 'template' to compose the service call, e.g. - * + * * {@code http://www.sherpa.ac.uk/romeo/api29.php?issn=\{dc.identifier.issn\}} - * + * * Task will substitute the value of the passed item's metadata field * in the {parameter} position. If multiple values are present in the * item field, the first value is used. - * + * * The task uses another property (the datamap) to determine what data * to extract from the service response and how to use it, e.g. - * + * * {@code //publisher/name=>dc.publisher,//romeocolour} - * + * * Task will evaluate the left-hand side (or entire token) of each * comma-separated token in the property as an XPath 1.0 expression into * the response document, and if there is a mapping symbol (e.g. {@code '=>'}) and @@ -82,114 +78,116 @@ import org.dspace.curate.Suspendable; * metadata field in the passed item. If the response document contains * multiple values, they will all be assigned to the item field. The * mapping symbol governs the nature of metadata field assignment: - * + * * {@code '->'} mapping will add to any existing values in the item field * {@code '=>'} mapping will replace any existing values in the item field * {@code '~>'} mapping will add *only* if item field has no existing values - * + * * Unmapped data (without a mapping symbol) will simply be added to the task * result string, prepended by the XPath expression (a little prettified). - * Each label/value pair in the result string is separated by a space, + * Each label/value pair in the result string is separated by a space, * unless the optional 'separator' property is defined. - * + * * A very rudimentary facility for transformation of data is supported, e.g. - * + * * {@code http://www.crossref.org/openurl/?id=\{doi:dc.relation.isversionof\}&format=unixref} * * The 'doi:' prefix will cause the task to look for a 'transform' with that * name, which is applied to the metadata value before parameter substitution * occurs. Transforms are defined in a task property such as the following: - * + * * {@code transform.doi = match 10. trunc 60} - * + * * This means exclude the value string up to the occurrence of '10.', then * truncate after 60 characters. The only transform functions currently defined: - * + * * {@code 'cut' } = remove number leading characters * {@code 'trunc' } = remove trailing characters after number length * {@code 'match' } = start match at pattern * {@code 'text' } = append literal characters (enclose in ' ' when whitespace needed) - * + * * If the transform results in an invalid state (e.g. cutting more characters - * than are in the value), the condition will be logged and the + * than are in the value), the condition will be logged and the * un-transformed value used. * * Transforms may also be used in datamaps, e.g. - * + * * {@code //publisher/name=>shorten:dc.publisher,//romeocolour} - * + * * which would apply the 'shorten' transform to the service response value(s) * prior to metadata field assignment. * * An optional property 'headers' may be defined to stipulate any HTTP headers * required in the service call. The property syntax is double-pipe separated headers: - * + * * {@code Accept: text/xml||Cache-Control: no-cache} - * + * * @author richardrodgers */ @Mutative @Suspendable -public class MetadataWebService extends AbstractCurationTask implements NamespaceContext -{ - /** log4j category */ +public class MetadataWebService extends AbstractCurationTask implements NamespaceContext { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(MetadataWebService.class); // transform token parsing pattern - protected Pattern ttPattern = Pattern.compile("\'([^\']*)\'|(\\S+)"); + protected Pattern ttPattern = Pattern.compile("\'([^\']*)\'|(\\S+)"); // URL of web service with template parameters - protected String urlTemplate = null; + protected String urlTemplate = null; // template parameter - protected String templateParam = null; + protected String templateParam = null; // Item metadata field to use in service call - protected String lookupField = null; + protected String lookupField = null; // Optional transformation of lookupField - protected String lookupTransform = null; + protected String lookupTransform = null; // response data to map/record - protected List dataList = null; + protected List dataList = null; // response document parsing tools - protected DocumentBuilder docBuilder = null; + protected DocumentBuilder docBuilder = null; // language for metadata fields assigned - protected String lang = null; + protected String lang = null; // field separator in result string - protected String fieldSeparator = null; + protected String fieldSeparator = null; // optional XML namespace map - protected Map nsMap = new HashMap(); + protected Map nsMap = new HashMap(); // optional HTTP headers - protected Map headers = new HashMap(); - + protected Map headers = new HashMap(); + /** * Initializes task - * @param curator Curator object performing this task - * @param taskId the configured local name of the task + * + * @param curator Curator object performing this task + * @param taskId the configured local name of the task */ @Override public void init(Curator curator, String taskId) throws IOException { - super.init(curator, taskId); - lang = configurationService.getProperty("default.language"); + super.init(curator, taskId); + lang = configurationService.getProperty("default.language"); String fldSep = taskProperty("separator"); fieldSeparator = (fldSep != null) ? fldSep : " "; - urlTemplate = taskProperty("template"); - templateParam = urlTemplate.substring(urlTemplate.indexOf("{") + 1, - urlTemplate.indexOf("}")); - String[] parsed = parseTransform(templateParam); - lookupField = parsed[0]; - lookupTransform = parsed[1]; - dataList = new ArrayList<>(); - for (String entry : taskArrayProperty("datamap")) { - entry = entry.trim(); - String src = entry; - String mapping = null; - String field = null; - int mapIdx = getMapIndex(entry); - if (mapIdx > 0) { - src = entry.substring(0, mapIdx); - mapping = entry.substring(mapIdx, mapIdx + 2); - field = entry.substring(mapIdx + 2); - } - int slIdx = src.lastIndexOf("/"); - String label = (slIdx > 0) ? src.substring(slIdx + 1) : src; - dataList.add(new MetadataWebServiceDataInfo(this, src, label, mapping, field)); - } + urlTemplate = taskProperty("template"); + templateParam = urlTemplate.substring(urlTemplate.indexOf("{") + 1, + urlTemplate.indexOf("}")); + String[] parsed = parseTransform(templateParam); + lookupField = parsed[0]; + lookupTransform = parsed[1]; + dataList = new ArrayList<>(); + for (String entry : taskArrayProperty("datamap")) { + entry = entry.trim(); + String src = entry; + String mapping = null; + String field = null; + int mapIdx = getMapIndex(entry); + if (mapIdx > 0) { + src = entry.substring(0, mapIdx); + mapping = entry.substring(mapIdx, mapIdx + 2); + field = entry.substring(mapIdx + 2); + } + int slIdx = src.lastIndexOf("/"); + String label = (slIdx > 0) ? src.substring(slIdx + 1) : src; + dataList.add(new MetadataWebServiceDataInfo(this, src, label, mapping, field)); + } String hdrs = taskProperty("headers"); if (hdrs != null) { for (String header : hdrs.split("\\|\\|")) { @@ -197,18 +195,18 @@ public class MetadataWebService extends AbstractCurationTask implements Namespac headers.put(header.substring(0, split).trim(), header.substring(split + 1).trim()); } } - // initialize response document parser - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - try { - docBuilder = factory.newDocumentBuilder(); - } catch (ParserConfigurationException pcE) { - log.error("caught exception: " + pcE); - // no point in continuing - throw new IOException(pcE.getMessage(), pcE); - } + // initialize response document parser + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + try { + docBuilder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException pcE) { + log.error("caught exception: " + pcE); + // no point in continuing + throw new IOException(pcE.getMessage(), pcE); + } } - + /** * Perform the curation task upon passed DSO * @@ -216,235 +214,240 @@ public class MetadataWebService extends AbstractCurationTask implements Namespac * @throws IOException if IO error */ @Override - public int perform(DSpaceObject dso) throws IOException { - - int status = Curator.CURATE_SKIP; - StringBuilder resultSb = new StringBuilder(); - + public int perform(DSpaceObject dso) throws IOException { + + int status = Curator.CURATE_SKIP; + StringBuilder resultSb = new StringBuilder(); + if (dso.getType() == Constants.ITEM) { - Item item = (Item)dso; + Item item = (Item) dso; String itemId = item.getHandle(); if (itemId == null) { - // we are still in workflow - no handle assigned - try title - List titleDc = itemService.getMetadata(item, "dc", "title", null, Item.ANY); - String title = (titleDc.size() > 0) ? titleDc.get(0).getValue() : "untitled - dbId: " + item.getID(); - itemId = "Workflow item: " + title; + // we are still in workflow - no handle assigned - try title + List titleDc = itemService.getMetadata(item, "dc", "title", null, Item.ANY); + String title = (titleDc.size() > 0) ? titleDc.get(0).getValue() : "untitled - dbId: " + item.getID(); + itemId = "Workflow item: " + title; } else { itemId = "handle: " + itemId; } resultSb.append(itemId); // Only proceed if item has a value for service template parameter - List dcVals = itemService.getMetadataByMetadataString(item, lookupField); + List dcVals = itemService.getMetadataByMetadataString(item, lookupField); if (dcVals.size() > 0 && dcVals.get(0).getValue().length() > 0) { - String value = transform(dcVals.get(0).getValue(), lookupTransform); - status = callService(value, item, resultSb); + String value = transform(dcVals.get(0).getValue(), lookupTransform); + status = callService(value, item, resultSb); } else { - resultSb.append(" lacks metadata value required for service: ").append(lookupField); - status = Curator.CURATE_FAIL; + resultSb.append(" lacks metadata value required for service: ").append(lookupField); + status = Curator.CURATE_FAIL; } } else { - resultSb.append("Object skipped"); + resultSb.append("Object skipped"); } report(resultSb.toString()); setResult(resultSb.toString()); return status; } - - protected int callService(String value, Item item, StringBuilder resultSb) throws IOException { - - String callUrl = urlTemplate.replaceAll("\\{" + templateParam + "\\}", value); - HttpClient client = new DefaultHttpClient(); - HttpGet req = new HttpGet(callUrl); + + protected int callService(String value, Item item, StringBuilder resultSb) throws IOException { + + String callUrl = urlTemplate.replaceAll("\\{" + templateParam + "\\}", value); + HttpClient client = new DefaultHttpClient(); + HttpGet req = new HttpGet(callUrl); for (Map.Entry entry : headers.entrySet()) { req.addHeader(entry.getKey(), entry.getValue()); } - HttpResponse resp = client.execute(req); - int status = Curator.CURATE_ERROR; - int statusCode = resp.getStatusLine().getStatusCode(); - if (statusCode == HttpStatus.SC_OK) { - HttpEntity entity = resp.getEntity(); - if (entity != null) { - // boiler-plate handling taken from Apache 4.1 javadoc - InputStream instream = entity.getContent(); + HttpResponse resp = client.execute(req); + int status = Curator.CURATE_ERROR; + int statusCode = resp.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + HttpEntity entity = resp.getEntity(); + if (entity != null) { + // boiler-plate handling taken from Apache 4.1 javadoc + InputStream instream = entity.getContent(); try { - Document doc = docBuilder.parse(instream); - status = processResponse(doc, item, resultSb); - } catch (SAXException saxE) { - log.error("caught exception: " + saxE); - resultSb.append(" unable to read response document"); + Document doc = docBuilder.parse(instream); + status = processResponse(doc, item, resultSb); + } catch (SAXException saxE) { + log.error("caught exception: " + saxE); + resultSb.append(" unable to read response document"); } catch (RuntimeException ex) { - // In case of an unexpected exception you may want to abort - // the HTTP request in order to shut down the underlying - // connection and release it back to the connection manager. - req.abort(); - log.error("caught exception: " + ex); - throw ex; + // In case of an unexpected exception you may want to abort + // the HTTP request in order to shut down the underlying + // connection and release it back to the connection manager. + req.abort(); + log.error("caught exception: " + ex); + throw ex; } finally { - // Closing the input stream will trigger connection release - instream.close(); + // Closing the input stream will trigger connection release + instream.close(); } // When HttpClient instance is no longer needed, // shut down the connection manager to ensure // immediate deallocation of all system resources client.getConnectionManager().shutdown(); - } else { - log.error(" obtained no valid service response"); - resultSb.append("no service response"); - } - } else { - log.error("service returned non-OK status: " + statusCode); - resultSb.append("no service response"); - } - return status; - } - - protected int processResponse(Document doc, Item item, StringBuilder resultSb) throws IOException { - boolean update = false; - int status = Curator.CURATE_ERROR; - List values = new ArrayList(); - checkNamespaces(doc); - try { - for (MetadataWebServiceDataInfo info : dataList) { - NodeList nodes = (NodeList)info.getExpr().evaluate(doc, XPathConstants.NODESET); - values.clear(); - // if data found and we are mapping, check assignment policy - if (nodes.getLength() > 0 && info.getMapping() != null) { - if ("=>".equals(info.getMapping())) { - itemService.clearMetadata(Curator.curationContext(), item, info.getSchema(), info.getElement(), info.getQualifier(), Item.ANY); - } else if ("~>".equals(info.getMapping())) { - if (itemService.getMetadata(item, info.getSchema(), info.getElement(), info.getQualifier(), Item.ANY).size() > 0) { - // there are values, so don't overwrite - continue; - } - } else { - for (MetadataValue dcVal : itemService.getMetadata(item, info.getSchema(), info.getElement(), info.getQualifier(), Item.ANY)) { - values.add(dcVal.getValue()); - } - } - } - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - String tvalue = transform(node.getFirstChild().getNodeValue(), info.getTransform()); - // assign to metadata field if mapped && not present - if (info.getMapping() != null && ! values.contains(tvalue)) { - itemService.addMetadata(Curator.curationContext(), item, info.getSchema(), info.getElement(), info.getQualifier(), lang, tvalue); - update = true; - } - // add to result string in any case - resultSb.append(fieldSeparator).append(info.getLabel()).append(": ").append(tvalue); - } - } - // update Item if it has changed - if (update) { - itemService.update(Curator.curationContext(), item); - } - status = Curator.CURATE_SUCCESS; - } catch (AuthorizeException authE) { - log.error("caught exception: " + authE); - resultSb.append(" not authorized to update"); - status = Curator.CURATE_FAIL; - } catch (SQLException sqlE) { - log.error("caught exception: " + sqlE); - resultSb.append(" error updating metadata"); - } catch (XPathExpressionException xpeE) { - log.error("caught exception: " + xpeE); - resultSb.append(" error reading response document"); - } + } else { + log.error(" obtained no valid service response"); + resultSb.append("no service response"); + } + } else { + log.error("service returned non-OK status: " + statusCode); + resultSb.append("no service response"); + } return status; } - - protected String transform(String value, String transDef) { - if (transDef == null) { - return value; - } - String[] tokens = tokenize(transDef); - String retValue = value; - for (int i = 0; i < tokens.length; i+= 2) { - if ("cut".equals(tokens[i]) || "trunc".equals(tokens[i])) { - int index = Integer.parseInt(tokens[i+1]); - if (retValue.length() > index) { - if ("cut".equals(tokens[i])) { - retValue = retValue.substring(index); - } else { - retValue = retValue.substring(0, index); - } - } else if ("cut".equals(tokens[i])) { - log.error("requested cut: " + index + " exceeds value length"); - return value; - } - } else if ("match".equals(tokens[i])) { - int index2 = retValue.indexOf(tokens[i+1]); - if (index2 > 0) { - retValue = retValue.substring(index2); - } else { - log.error("requested match: " + tokens[i+1] + " failed"); - return value; - } - } else if ("text".equals(tokens[i])) { - retValue = retValue + tokens[i+1]; - } else { - log.error(" unknown transform operation: " + tokens[i]); - return value; - } - } - return retValue; + + protected int processResponse(Document doc, Item item, StringBuilder resultSb) throws IOException { + boolean update = false; + int status = Curator.CURATE_ERROR; + List values = new ArrayList(); + checkNamespaces(doc); + try { + for (MetadataWebServiceDataInfo info : dataList) { + NodeList nodes = (NodeList) info.getExpr().evaluate(doc, XPathConstants.NODESET); + values.clear(); + // if data found and we are mapping, check assignment policy + if (nodes.getLength() > 0 && info.getMapping() != null) { + if ("=>".equals(info.getMapping())) { + itemService.clearMetadata(Curator.curationContext(), item, info.getSchema(), info.getElement(), + info.getQualifier(), Item.ANY); + } else if ("~>".equals(info.getMapping())) { + if (itemService + .getMetadata(item, info.getSchema(), info.getElement(), info.getQualifier(), Item.ANY) + .size() > 0) { + // there are values, so don't overwrite + continue; + } + } else { + for (MetadataValue dcVal : itemService + .getMetadata(item, info.getSchema(), info.getElement(), info.getQualifier(), Item.ANY)) { + values.add(dcVal.getValue()); + } + } + } + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + String tvalue = transform(node.getFirstChild().getNodeValue(), info.getTransform()); + // assign to metadata field if mapped && not present + if (info.getMapping() != null && !values.contains(tvalue)) { + itemService.addMetadata(Curator.curationContext(), item, info.getSchema(), info.getElement(), + info.getQualifier(), lang, tvalue); + update = true; + } + // add to result string in any case + resultSb.append(fieldSeparator).append(info.getLabel()).append(": ").append(tvalue); + } + } + // update Item if it has changed + if (update) { + itemService.update(Curator.curationContext(), item); + } + status = Curator.CURATE_SUCCESS; + } catch (AuthorizeException authE) { + log.error("caught exception: " + authE); + resultSb.append(" not authorized to update"); + status = Curator.CURATE_FAIL; + } catch (SQLException sqlE) { + log.error("caught exception: " + sqlE); + resultSb.append(" error updating metadata"); + } catch (XPathExpressionException xpeE) { + log.error("caught exception: " + xpeE); + resultSb.append(" error reading response document"); + } + return status; } - - protected String[] tokenize(String text) { - List list = new ArrayList(); - Matcher m = ttPattern.matcher(text); - while (m.find()) { - if (m.group(1) != null) { - list.add(m.group(1)); + + protected String transform(String value, String transDef) { + if (transDef == null) { + return value; + } + String[] tokens = tokenize(transDef); + String retValue = value; + for (int i = 0; i < tokens.length; i += 2) { + if ("cut".equals(tokens[i]) || "trunc".equals(tokens[i])) { + int index = Integer.parseInt(tokens[i + 1]); + if (retValue.length() > index) { + if ("cut".equals(tokens[i])) { + retValue = retValue.substring(index); + } else { + retValue = retValue.substring(0, index); + } + } else if ("cut".equals(tokens[i])) { + log.error("requested cut: " + index + " exceeds value length"); + return value; + } + } else if ("match".equals(tokens[i])) { + int index2 = retValue.indexOf(tokens[i + 1]); + if (index2 > 0) { + retValue = retValue.substring(index2); + } else { + log.error("requested match: " + tokens[i + 1] + " failed"); + return value; + } + } else if ("text".equals(tokens[i])) { + retValue = retValue + tokens[i + 1]; + } else { + log.error(" unknown transform operation: " + tokens[i]); + return value; + } + } + return retValue; + } + + protected String[] tokenize(String text) { + List list = new ArrayList(); + Matcher m = ttPattern.matcher(text); + while (m.find()) { + if (m.group(1) != null) { + list.add(m.group(1)); } else if (m.group(2) != null) { list.add(m.group(2)); } } return list.toArray(new String[0]); } - - protected int getMapIndex(String mapping) { - int index = mapping.indexOf("->"); - if (index == -1) { - index = mapping.indexOf("=>"); - } - if (index == -1) { - index = mapping.indexOf("~>"); - } - return index; + + protected int getMapIndex(String mapping) { + int index = mapping.indexOf("->"); + if (index == -1) { + index = mapping.indexOf("=>"); + } + if (index == -1) { + index = mapping.indexOf("~>"); + } + return index; } - protected String[] parseTransform(String field) { - String[] parsed = new String[2]; - parsed[0] = field; - int txIdx = field.indexOf(":"); - if (txIdx > 0) { - // transform specified - String txName = field.substring(0, txIdx); - parsed[1] = taskProperty("transform." + txName); - if (parsed[1] == null) { - log.error("no transform found for: " + txName); - } - parsed[0] = field.substring(txIdx + 1); - } - return parsed; + protected String[] parseTransform(String field) { + String[] parsed = new String[2]; + parsed[0] = field; + int txIdx = field.indexOf(":"); + if (txIdx > 0) { + // transform specified + String txName = field.substring(0, txIdx); + parsed[1] = taskProperty("transform." + txName); + if (parsed[1] == null) { + log.error("no transform found for: " + txName); + } + parsed[0] = field.substring(txIdx + 1); + } + return parsed; } - protected void checkNamespaces(Document document) throws IOException { - // skip if already done - if (dataList.get(0).getExpr() != null) { - return; - } - try { - XPath xpath = XPathFactory.newInstance().newXPath(); - String prefix = null; + protected void checkNamespaces(Document document) throws IOException { + // skip if already done + if (dataList.get(0).getExpr() != null) { + return; + } + try { + XPath xpath = XPathFactory.newInstance().newXPath(); + String prefix = null; NamedNodeMap attrs = document.getDocumentElement().getAttributes(); - for (int i = 0; i < attrs.getLength(); i++) { - Node n = attrs.item(i); + for (int i = 0; i < attrs.getLength(); i++) { + Node n = attrs.item(i); String name = n.getNodeName(); // remember if a namespace if (name.startsWith("xmlns")) { - if (! "xmlns".equals(name)) { + if (!"xmlns".equals(name)) { // it is a declared (non-default) namespace - capture prefix nsMap.put(name.substring(name.indexOf(":") + 1), n.getNodeValue()); } else { @@ -455,64 +458,64 @@ public class MetadataWebService extends AbstractCurationTask implements Namespac } } if (nsMap.size() > 0) { - xpath.setNamespaceContext(this); + xpath.setNamespaceContext(this); } - // now compile the XPath expressions - for (MetadataWebServiceDataInfo info : dataList) { - info.setExpr(xpath.compile(mangleExpr(info.getXpsrc(), prefix))); - } - } catch (XPathExpressionException xpeE) { - log.error("caught exception: " + xpeE); - // no point in continuing - throw new IOException(xpeE.getMessage(), xpeE); - } + // now compile the XPath expressions + for (MetadataWebServiceDataInfo info : dataList) { + info.setExpr(xpath.compile(mangleExpr(info.getXpsrc(), prefix))); + } + } catch (XPathExpressionException xpeE) { + log.error("caught exception: " + xpeE); + // no point in continuing + throw new IOException(xpeE.getMessage(), xpeE); + } } - + protected String mangleExpr(String expr, String prefix) { - if (prefix == null) { - return expr; - } - // OK the drill is to prepend all node names with the prefix - // *unless* the node name already has a prefix. - StringBuilder sb = new StringBuilder(); - int i = 0; - while (i < expr.length()) { - if (expr.charAt(i) == '/') { - sb.append("/"); - i++; - } else { - int next = expr.indexOf("/", i); - String token = (next > 0) ? expr.substring(i, next) : expr.substring(i); - if (! token.startsWith("@") && token.indexOf(":") < 0) { - sb.append(prefix).append(":"); - } - sb.append(token); - i += token.length(); - } - } - return sb.toString(); - } - - // ---- NamespaceContext methods ---- // - - @Override - public String getNamespaceURI(String prefix) { if (prefix == null) { - throw new NullPointerException("Null prefix"); + return expr; + } + // OK the drill is to prepend all node names with the prefix + // *unless* the node name already has a prefix. + StringBuilder sb = new StringBuilder(); + int i = 0; + while (i < expr.length()) { + if (expr.charAt(i) == '/') { + sb.append("/"); + i++; + } else { + int next = expr.indexOf("/", i); + String token = (next > 0) ? expr.substring(i, next) : expr.substring(i); + if (!token.startsWith("@") && token.indexOf(":") < 0) { + sb.append(prefix).append(":"); + } + sb.append(token); + i += token.length(); + } + } + return sb.toString(); + } + + // ---- NamespaceContext methods ---- // + + @Override + public String getNamespaceURI(String prefix) { + if (prefix == null) { + throw new NullPointerException("Null prefix"); } else if ("xml".equals(prefix)) { - return XMLConstants.XML_NS_URI; + return XMLConstants.XML_NS_URI; } String nsURI = nsMap.get(prefix); return (nsURI != null) ? nsURI : XMLConstants.NULL_NS_URI; } @Override - public String getPrefix(String uri) { + public String getPrefix(String uri) { throw new UnsupportedOperationException(); } @Override - public Iterator getPrefixes(String uri) { + public Iterator getPrefixes(String uri) { throw new UnsupportedOperationException(); } } diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebServiceDataInfo.java b/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebServiceDataInfo.java index e21aa66da2..fad1661613 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebServiceDataInfo.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebServiceDataInfo.java @@ -11,31 +11,31 @@ import javax.xml.xpath.XPathExpression; /** * @author kevinvandevelde at atmire.com - * */ public class MetadataWebServiceDataInfo { private XPathExpression expr; // compiled XPath espression for data - private String xpsrc; // uncompiled XPath expression - private String label; // label for data in result string - private String mapping; // data mapping symbol: ->,=>,~>, or null = unmapped - private String schema; // item metadata field mapping target, null = unmapped - private String element; // item metadata field mapping target, null = unmapped - private String qualifier; // item metadata field mapping target, null = unmapped - private String transform; // optional transformation of data before field assignment + private String xpsrc; // uncompiled XPath expression + private String label; // label for data in result string + private String mapping; // data mapping symbol: ->,=>,~>, or null = unmapped + private String schema; // item metadata field mapping target, null = unmapped + private String element; // item metadata field mapping target, null = unmapped + private String qualifier; // item metadata field mapping target, null = unmapped + private String transform; // optional transformation of data before field assignment - public MetadataWebServiceDataInfo(MetadataWebService metadataWebService, String xpsrc, String label, String mapping, String field) { - this.xpsrc = xpsrc; - this.label = label; - this.mapping = mapping; - if (field != null) { - String[] parsed = metadataWebService.parseTransform(field); - String[] parts = parsed[0].split("\\."); - this.schema = parts[0]; - this.element = parts[1]; - this.qualifier = (parts.length == 3) ? parts[2] : null; - this.transform = parsed[1]; - } - } + public MetadataWebServiceDataInfo(MetadataWebService metadataWebService, String xpsrc, String label, String mapping, + String field) { + this.xpsrc = xpsrc; + this.label = label; + this.mapping = mapping; + if (field != null) { + String[] parsed = metadataWebService.parseTransform(field); + String[] parts = parsed[0].split("\\."); + this.schema = parts[0]; + this.element = parts[1]; + this.qualifier = (parts.length == 3) ? parts[2] : null; + this.transform = parsed[1]; + } + } public XPathExpression getExpr() { diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/MicrosoftTranslator.java b/dspace-api/src/main/java/org/dspace/ctask/general/MicrosoftTranslator.java index 9af3ccf9ce..88700be299 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/MicrosoftTranslator.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/MicrosoftTranslator.java @@ -10,6 +10,7 @@ package org.dspace.ctask.general; import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; + import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; @@ -22,15 +23,14 @@ import org.dspace.core.ConfigurationManager; * MicrosoftTranslator translates metadata fields using Microsoft Translation API v2 * * Requirements: A valid Bing App ID/Key - * More information: http://www.bing.com/developers + * More information: http://www.bing.com/developers * - * This key, and other custom configuration, goes in [dspace]/modules/translator.cfg + * This key, and other custom configuration, goes in [dspace]/modules/translator.cfg * * @author Kim Shepherd */ -public class MicrosoftTranslator extends AbstractTranslator -{ +public class MicrosoftTranslator extends AbstractTranslator { protected final String PLUGIN_PREFIX = "translator"; @@ -41,7 +41,7 @@ public class MicrosoftTranslator extends AbstractTranslator @Override protected void initApi() { - apiKey = ConfigurationManager.getProperty(PLUGIN_PREFIX, "api.key.microsoft"); + apiKey = ConfigurationManager.getProperty(PLUGIN_PREFIX, "api.key.microsoft"); } @Override @@ -61,10 +61,11 @@ public class MicrosoftTranslator extends AbstractTranslator HttpResponse httpResponse = client.execute(hm); log.debug("Response code from API call is " + httpResponse); - if(httpResponse.getStatusLine().getStatusCode() == 200) { + if (httpResponse.getStatusLine().getStatusCode() == 200) { String response = IOUtils.toString(httpResponse.getEntity().getContent(), StandardCharsets.ISO_8859_1); - response = response.replaceAll("",""); - response = response.replaceAll("",""); + response = response + .replaceAll("", ""); + response = response.replaceAll("", ""); translatedText = response; } diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/NoOpCurationTask.java b/dspace-api/src/main/java/org/dspace/ctask/general/NoOpCurationTask.java index 9396081667..1d03ec0d4e 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/NoOpCurationTask.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/NoOpCurationTask.java @@ -7,33 +7,30 @@ */ package org.dspace.ctask.general; +import java.io.IOException; + import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.curate.AbstractCurationTask; import org.dspace.curate.Curator; -import java.io.IOException; - -public class NoOpCurationTask extends AbstractCurationTask -{ +public class NoOpCurationTask extends AbstractCurationTask { protected int status = Curator.CURATE_UNSET; protected String result = null; @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { - if (dso instanceof Item) - { - Item item = (Item)dso; + if (dso instanceof Item) { + Item item = (Item) dso; status = Curator.CURATE_SUCCESS; result = "No operation performed on " + item.getHandle(); - + setResult(result); report(result); - } - + } + return status; } diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/ProfileFormats.java b/dspace-api/src/main/java/org/dspace/ctask/general/ProfileFormats.java index 1bcda07851..76471b1f9f 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/ProfileFormats.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/ProfileFormats.java @@ -12,7 +12,11 @@ import java.sql.SQLException; import java.util.HashMap; import java.util.Map; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; import org.dspace.curate.AbstractCurationTask; @@ -20,17 +24,17 @@ import org.dspace.curate.Curator; import org.dspace.curate.Distributive; /** - * ProfileFormats is a task that creates a distribution table of Bitstream + * ProfileFormats is a task that creates a distribution table of Bitstream * formats for it's passed object. Primarily a curation task demonstrator. * * @author richardrodgers */ @Distributive -public class ProfileFormats extends AbstractCurationTask -{ +public class ProfileFormats extends AbstractCurationTask { // map of formats to occurrences protected Map fmtTable = new HashMap(); - protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); /** * Perform the curation task upon passed DSO @@ -39,53 +43,41 @@ public class ProfileFormats extends AbstractCurationTask * @throws IOException if IO error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { fmtTable.clear(); distribute(dso); formatResults(); return Curator.CURATE_SUCCESS; } - + @Override - protected void performItem(Item item) throws SQLException, IOException - { - for (Bundle bundle : item.getBundles()) - { - for (Bitstream bs : bundle.getBitstreams()) - { + protected void performItem(Item item) throws SQLException, IOException { + for (Bundle bundle : item.getBundles()) { + for (Bitstream bs : bundle.getBitstreams()) { String fmt = bs.getFormat(Curator.curationContext()).getShortDescription(); Integer count = fmtTable.get(fmt); - if (count == null) - { + if (count == null) { count = 1; - } - else - { + } else { count += 1; } fmtTable.put(fmt, count); - } + } } } - - private void formatResults() throws IOException - { - try - { + + private void formatResults() throws IOException { + try { StringBuilder sb = new StringBuilder(); - for (String fmt : fmtTable.keySet()) - { + for (String fmt : fmtTable.keySet()) { BitstreamFormat bsf = bitstreamFormatService.findByShortDescription(Curator.curationContext(), fmt); sb.append(String.format("%6d", fmtTable.get(fmt))).append(" ("). - append(bitstreamFormatService.getSupportLevelText(bsf).charAt(0)).append(") "). - append(bsf.getDescription()).append("\n"); + append(bitstreamFormatService.getSupportLevelText(bsf).charAt(0)).append(") "). + append(bsf.getDescription()).append("\n"); } report(sb.toString()); setResult(sb.toString()); - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE.getMessage(), sqlE); } } diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/RequiredMetadata.java b/dspace-api/src/main/java/org/dspace/ctask/general/RequiredMetadata.java index 1168b7156f..07bfed5fe5 100644 --- a/dspace-api/src/main/java/org/dspace/ctask/general/RequiredMetadata.java +++ b/dspace-api/src/main/java/org/dspace/ctask/general/RequiredMetadata.java @@ -17,40 +17,35 @@ import org.dspace.app.util.DCInput; import org.dspace.app.util.DCInputSet; import org.dspace.app.util.DCInputsReader; import org.dspace.app.util.DCInputsReaderException; -import org.dspace.content.MetadataValue; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.core.Constants; import org.dspace.curate.AbstractCurationTask; import org.dspace.curate.Curator; import org.dspace.curate.Suspendable; /** - * RequiredMetadata task compares item metadata with fields - * marked as required in input-forms.xml. The task succeeds if all + * RequiredMetadata task compares item metadata with fields + * marked as required in submission-forms.xml. The task succeeds if all * required fields are present in the item metadata, otherwise it fails. * Primarily a curation task demonstrator. * * @author richardrodgers */ @Suspendable -public class RequiredMetadata extends AbstractCurationTask -{ +public class RequiredMetadata extends AbstractCurationTask { // map of DCInputSets protected DCInputsReader reader = null; // map of required fields protected Map> reqMap = new HashMap>(); - - @Override - public void init(Curator curator, String taskId) throws IOException - { + + @Override + public void init(Curator curator, String taskId) throws IOException { super.init(curator, taskId); - try - { + try { reader = new DCInputsReader(); - } - catch (DCInputsReaderException dcrE) - { + } catch (DCInputsReaderException dcrE) { throw new IOException(dcrE.getMessage(), dcrE); } } @@ -62,82 +57,66 @@ public class RequiredMetadata extends AbstractCurationTask * @throws IOException if IO error */ @Override - public int perform(DSpaceObject dso) throws IOException - { - if (dso.getType() == Constants.ITEM) - { - Item item = (Item)dso; + public int perform(DSpaceObject dso) throws IOException { + if (dso.getType() == Constants.ITEM) { + Item item = (Item) dso; int count = 0; - try - { + try { StringBuilder sb = new StringBuilder(); String handle = item.getHandle(); - if (handle == null) - { + if (handle == null) { // we are still in workflow - no handle assigned handle = "in workflow"; } sb.append("Item: ").append(handle); - for (String req : getReqList(item.getOwningCollection().getHandle())) - { + for (String req : getReqList(item.getOwningCollection().getHandle())) { List vals = itemService.getMetadataByMetadataString(item, req); - if (vals.size() == 0) - { + if (vals.size() == 0) { sb.append(" missing required field: ").append(req); count++; } } - if (count == 0) - { + if (count == 0) { sb.append(" has all required fields"); } report(sb.toString()); setResult(sb.toString()); - } - catch (DCInputsReaderException dcrE) - { + } catch (DCInputsReaderException dcrE) { throw new IOException(dcrE.getMessage(), dcrE); } return (count == 0) ? Curator.CURATE_SUCCESS : Curator.CURATE_FAIL; - } - else - { - setResult("Object skipped"); - return Curator.CURATE_SKIP; + } else { + setResult("Object skipped"); + return Curator.CURATE_SKIP; } } - - protected List getReqList(String handle) throws DCInputsReaderException - { + + protected List getReqList(String handle) throws DCInputsReaderException { List reqList = reqMap.get(handle); - if (reqList == null) - { + if (reqList == null) { reqList = reqMap.get("default"); } - if (reqList == null) - { + if (reqList == null) { reqList = new ArrayList(); - DCInputSet inputs = reader.getInputs(handle); - for (int i = 0; i < inputs.getNumberPages(); i++) - { - for (DCInput input : inputs.getPageRows(i, true, true)) - { - if (input.isRequired()) - { - StringBuilder sb = new StringBuilder(); - sb.append(input.getSchema()).append("."); - sb.append(input.getElement()).append("."); - String qual = input.getQualifier(); - if (qual == null) - { - qual = ""; + List inputSet = reader.getInputsByCollectionHandle(handle); + for (DCInputSet inputs : inputSet) { + for (DCInput[] row : inputs.getFields()) { + for (DCInput input : row) { + if (input.isRequired()) { + StringBuilder sb = new StringBuilder(); + sb.append(input.getSchema()).append("."); + sb.append(input.getElement()).append("."); + String qual = input.getQualifier(); + if (qual == null) { + qual = ""; + } + sb.append(qual); + reqList.add(sb.toString()); } - sb.append(qual); - reqList.add(sb.toString()); } } + reqMap.put(inputs.getFormName(), reqList); } - reqMap.put(inputs.getFormName(), reqList); } return reqList; } diff --git a/dspace-api/src/main/java/org/dspace/curate/AbstractCurationTask.java b/dspace-api/src/main/java/org/dspace/curate/AbstractCurationTask.java index 986332c4f6..cf9c9fe9de 100644 --- a/dspace-api/src/main/java/org/dspace/curate/AbstractCurationTask.java +++ b/dspace-api/src/main/java/org/dspace/curate/AbstractCurationTask.java @@ -14,7 +14,6 @@ import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; - import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; @@ -32,11 +31,10 @@ import org.dspace.services.factory.DSpaceServicesFactory; /** * AbstractCurationTask encapsulates a few common patterns of task use, * resources, and convenience methods. - * + * * @author richardrodgers */ -public abstract class AbstractCurationTask implements CurationTask -{ +public abstract class AbstractCurationTask implements CurationTask { // invoking curator protected Curator curator = null; // curator-assigned taskId @@ -49,8 +47,7 @@ public abstract class AbstractCurationTask implements CurationTask protected ConfigurationService configurationService; @Override - public void init(Curator curator, String taskId) throws IOException - { + public void init(Curator curator, String taskId) throws IOException { this.curator = curator; this.taskId = taskId; communityService = ContentServiceFactory.getInstance().getCommunityService(); @@ -61,97 +58,84 @@ public abstract class AbstractCurationTask implements CurationTask @Override public abstract int perform(DSpaceObject dso) throws IOException; - + /** * Distributes a task through a DSpace container - a convenience method - * for tasks declaring the @Distributive property. + * for tasks declaring the @Distributive property. *

    * This method invokes the 'performObject()' method on the current DSO, and * then recursively invokes the 'performObject()' method on all DSOs contained * within the current DSO. For example: if a Community is passed in, then - * 'performObject()' will be called on that Community object, as well as + * 'performObject()' will be called on that Community object, as well as * on all SubCommunities/Collections/Items contained in that Community. *

    * Individual tasks MUST override either the performObject method or * the performItem method to ensure the task is run on either all * DSOs or just all Items, respectively. - * + * * @param dso current DSpaceObject * @throws IOException if IO error */ - protected void distribute(DSpaceObject dso) throws IOException - { - try - { + protected void distribute(DSpaceObject dso) throws IOException { + try { //perform task on this current object performObject(dso); - + //next, we'll try to distribute to all child objects, based on container type int type = dso.getType(); - if (Constants.COLLECTION == type) - { + if (Constants.COLLECTION == type) { Iterator iter = itemService.findByCollection(Curator.curationContext(), (Collection) dso); - while (iter.hasNext()) - { - performObject(iter.next()); + while (iter.hasNext()) { + Item item = iter.next(); + performObject(item); + Curator.curationContext().uncacheEntity(item); } - } - else if (Constants.COMMUNITY == type) - { - Community comm = (Community)dso; - for (Community subcomm : comm.getSubcommunities()) - { + } else if (Constants.COMMUNITY == type) { + Community comm = (Community) dso; + for (Community subcomm : comm.getSubcommunities()) { distribute(subcomm); } - for (Collection coll : comm.getCollections()) - { + for (Collection coll : comm.getCollections()) { distribute(coll); } - } - else if (Constants.SITE == type) - { + } else if (Constants.SITE == type) { List topComm = communityService.findAllTop(Curator.curationContext()); - for (Community comm : topComm) - { + for (Community comm : topComm) { distribute(comm); } } - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE.getMessage(), sqlE); - } + } } - + /** * Performs task upon a single DSpaceObject. Used in conjunction with the * distribute method to run a single task across multiple DSpaceObjects. *

    * By default, this method just wraps a call to performItem - * for each Item Object. + * for each Item Object. *

    * You should override this method if you want to use * distribute to run your task across multiple DSpace Objects. *

    - * Either this method or performItem should be overridden if + * Either this method or performItem should be overridden if * distribute method is used. - * + * * @param dso the DSpaceObject * @throws SQLException if database error - * @throws IOException if IO error + * @throws IOException if IO error */ - protected void performObject(DSpaceObject dso) throws SQLException, IOException - { - // By default this method only performs tasks on Items + protected void performObject(DSpaceObject dso) throws SQLException, IOException { + // By default this method only performs tasks on Items // (You should override this method if you want to perform task on all objects) - if(dso.getType()==Constants.ITEM) - { - performItem((Item)dso); - } - + if (dso.getType() == Constants.ITEM) { + performItem((Item) dso); + } + //no-op for all other types of DSpace Objects } - + /** * Performs task upon a single DSpace Item. Used in conjunction with the * distribute method to run a single task across multiple Items. @@ -159,187 +143,145 @@ public abstract class AbstractCurationTask implements CurationTask * You should override this method if you want to use * distribute to run your task across multiple DSpace Items. *

    - * Either this method or performObject should be overridden if + * Either this method or performObject should be overridden if * distribute method is used. - * + * * @param item the DSpace Item * @throws SQLException if database error - * @throws IOException if IO error + * @throws IOException if IO error */ - protected void performItem(Item item) throws SQLException, IOException - { + protected void performItem(Item item) throws SQLException, IOException { // no-op - override when using 'distribute' method } @Override - public int perform(Context ctx, String id) throws IOException - { + public int perform(Context ctx, String id) throws IOException { DSpaceObject dso = dereference(ctx, id); return (dso != null) ? perform(dso) : Curator.CURATE_FAIL; } - + /** * Returns a DSpaceObject for passed identifier, if it exists - * - * @param ctx - * DSpace context - * @param id - * canonical id of object + * + * @param ctx DSpace context + * @param id canonical id of object * @return dso - * DSpace object, or null if no object with id exists + * DSpace object, or null if no object with id exists * @throws IOException if IO error */ - protected DSpaceObject dereference(Context ctx, String id) throws IOException - { - try - { + protected DSpaceObject dereference(Context ctx, String id) throws IOException { + try { return handleService.resolveToObject(ctx, id); - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE.getMessage(), sqlE); } } /** * Sends message to the reporting stream - * - * @param message - * the message to stream + * + * @param message the message to stream */ - protected void report(String message) - { + protected void report(String message) { curator.report(message); } /** * Assigns the result of the task performance - * - * @param result - * the result string + * + * @param result the result string */ - protected void setResult(String result) - { + protected void setResult(String result) { curator.setResult(taskId, result); } - + /** * Returns task configuration property value for passed name, else * null if no properties defined or no value for passed key. - * - * @param name - * the property name + * + * @param name the property name * @return value - * the property value, or null - * + * the property value, or null */ - protected String taskProperty(String name) - { + protected String taskProperty(String name) { // If a taskID/Name is specified, prepend it on the configuration name - if(StringUtils.isNotBlank(taskId)) - { + if (StringUtils.isNotBlank(taskId)) { return configurationService.getProperty(taskId + "." + name); - } - else - { + } else { return configurationService.getProperty(name); } } - + /** * Returns task configuration integer property value for passed name, else * passed default value if no properties defined or no value for passed key. - * - * @param name - * the property name + * + * @param name the property name * @param defaultValue value - * the default value + * the default value * @return value - * the property value, or default value - * + * the property value, or default value */ - protected int taskIntProperty(String name, int defaultValue) - { + protected int taskIntProperty(String name, int defaultValue) { // If a taskID/Name is specified, prepend it on the configuration name - if(StringUtils.isNotBlank(taskId)) - { + if (StringUtils.isNotBlank(taskId)) { return configurationService.getIntProperty(taskId + "." + name, defaultValue); - } - else - { + } else { return configurationService.getIntProperty(name, defaultValue); } - } - + } + /** * Returns task configuration long property value for passed name, else * passed default value if no properties defined or no value for passed key. - * - * @param name - * the property name + * + * @param name the property name * @param defaultValue value - * the default value + * the default value * @return value - * the property value, or default - * + * the property value, or default */ - protected long taskLongProperty(String name, long defaultValue) - { + protected long taskLongProperty(String name, long defaultValue) { // If a taskID/Name is specified, prepend it on the configuration name - if(StringUtils.isNotBlank(taskId)) - { + if (StringUtils.isNotBlank(taskId)) { return configurationService.getLongProperty(taskId + "." + name, defaultValue); - } - else - { + } else { return configurationService.getLongProperty(name, defaultValue); } - } - + } + /** * Returns task configuration boolean property value for passed name, else * passed default value if no properties defined or no value for passed key. - * - * @param name - * the property name + * + * @param name the property name * @param defaultValue value - * the default value + * the default value * @return value - * the property value, or default - * + * the property value, or default */ - protected boolean taskBooleanProperty(String name, boolean defaultValue) - { + protected boolean taskBooleanProperty(String name, boolean defaultValue) { // If a taskID/Name is specified, prepend it on the configuration name - if(StringUtils.isNotBlank(taskId)) - { + if (StringUtils.isNotBlank(taskId)) { return configurationService.getBooleanProperty(taskId + "." + name, defaultValue); - } - else - { + } else { return configurationService.getBooleanProperty(name, defaultValue); } } - + /** * Returns task configuration Array property value for passed name, else * null if no properties defined or no value for passed key. - * - * @param name - * the property name + * + * @param name the property name * @return value - * the property value, or null - * + * the property value, or null */ - protected String[] taskArrayProperty(String name) - { + protected String[] taskArrayProperty(String name) { // If a taskID/Name is specified, prepend it on the configuration name - if(StringUtils.isNotBlank(taskId)) - { + if (StringUtils.isNotBlank(taskId)) { return configurationService.getArrayProperty(taskId + "." + name); - } - else - { + } else { return configurationService.getArrayProperty(name); } } diff --git a/dspace-api/src/main/java/org/dspace/curate/CitationPage.java b/dspace-api/src/main/java/org/dspace/curate/CitationPage.java index 6c5ae56d34..8634eeb5bb 100644 --- a/dspace-api/src/main/java/org/dspace/curate/CitationPage.java +++ b/dspace-api/src/main/java/org/dspace/curate/CitationPage.java @@ -7,18 +7,6 @@ */ package org.dspace.curate; -import org.apache.log4j.Logger; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.BitstreamService; -import org.dspace.content.service.BundleService; -import org.dspace.core.Context; -import org.dspace.disseminate.factory.DisseminateServiceFactory; -import org.dspace.disseminate.service.CitationDocumentService; - -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; @@ -27,6 +15,21 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.BundleService; +import org.dspace.core.Context; +import org.dspace.disseminate.factory.DisseminateServiceFactory; +import org.dspace.disseminate.service.CitationDocumentService; + /** * CitationPage * @@ -53,8 +56,6 @@ public class CitationPage extends AbstractCurationTask { protected StringBuilder resBuilder; - - /** * The name to give the bundle we add the cited pages to. */ @@ -70,6 +71,7 @@ public class CitationPage extends AbstractCurationTask { /** * {@inheritDoc} + * * @see CurationTask#perform(DSpaceObject) */ @Override @@ -87,6 +89,7 @@ public class CitationPage extends AbstractCurationTask { /** * {@inheritDoc} + * * @see AbstractCurationTask#performItem(Item) */ @Override @@ -96,10 +99,10 @@ public class CitationPage extends AbstractCurationTask { Bundle dBundle = null; if (dBundles == null || dBundles.size() == 0) { try { - dBundle = bundleService.create(Curator.curationContext(), item ,CitationPage.DISPLAY_BUNDLE_NAME); + dBundle = bundleService.create(Curator.curationContext(), item, CitationPage.DISPLAY_BUNDLE_NAME); } catch (AuthorizeException e) { log.error("User not authroized to create bundle on item \"" - + item.getName() + "\": " + e.getMessage()); + + item.getName() + "\": " + e.getMessage()); } } else { dBundle = dBundles.get(0); @@ -107,7 +110,7 @@ public class CitationPage extends AbstractCurationTask { //Create a map of the bitstreams in the displayBundle. This is used to //check if the bundle being cited is already in the display bundle. - Map displayMap = new HashMap(); + Map displayMap = new HashMap(); for (Bitstream bs : dBundle.getBitstreams()) { displayMap.put(bs.getName(), bs); } @@ -127,7 +130,7 @@ public class CitationPage extends AbstractCurationTask { pBundle = bundleService.create(Curator.curationContext(), item, CitationPage.PRESERVATION_BUNDLE_NAME); } catch (AuthorizeException e) { log.error("User not authroized to create bundle on item \"" - + item.getName() + "\": " + e.getMessage()); + + item.getName() + "\": " + e.getMessage()); } bundles = itemService.getBundles(item, "ORIGINAL"); } @@ -143,17 +146,19 @@ public class CitationPage extends AbstractCurationTask { BitstreamFormat format = bitstream.getFormat(Curator.curationContext()); //If bitstream is a PDF document then it is citable. - CitationDocumentService citationDocument = DisseminateServiceFactory.getInstance().getCitationDocumentService(); + CitationDocumentService citationDocument = DisseminateServiceFactory.getInstance() + .getCitationDocumentService(); - if(citationDocument.canGenerateCitationVersion(Curator.curationContext(), bitstream)) { + if (citationDocument.canGenerateCitationVersion(Curator.curationContext(), bitstream)) { this.resBuilder.append(item.getHandle() + " - " - + bitstream.getName() + " is citable."); + + bitstream.getName() + " is citable."); try { //Create the cited document - File citedDocument = citationDocument.makeCitedDocument(Curator.curationContext(), bitstream); + Pair citedDocument = + citationDocument.makeCitedDocument(Curator.curationContext(), bitstream); //Add the cited document to the approiate bundle - this.addCitedPageToItem(citedDocument, bundle, pBundle, - dBundle, displayMap, item, bitstream); + this.addCitedPageToItem(citedDocument.getLeft(), bundle, pBundle, + dBundle, displayMap, item, bitstream); } catch (Exception e) { //Could be many things, but nothing that should be //expected. @@ -176,7 +181,7 @@ public class CitationPage extends AbstractCurationTask { } else { //bitstream is not a document this.resBuilder.append(item.getHandle() + " - " - + bitstream.getName() + " is not citable.\n"); + + bitstream.getName() + " is not citable.\n"); this.status = Curator.CURATE_SUCCESS; } } @@ -187,22 +192,22 @@ public class CitationPage extends AbstractCurationTask { * A helper function for {@link CitationPage#performItem(Item)}. This function takes in the * cited document as a File and adds it to DSpace properly. * - * @param citedTemp The temporary File that is the cited document. + * @param citedDoc The inputstream that is the cited document. * @param bundle The bundle the cited file is from. * @param pBundle The preservation bundle. The original document should be * put in here if it is not already. * @param dBundle The display bundle. The cited document gets put in here. * @param displayMap The map of bitstream names to bitstreams in the display - * bundle. - * @param item The item containing the bundles being used. - * @param bitstream The original source bitstream. - * @throws SQLException if database error + * bundle. + * @param item The item containing the bundles being used. + * @param bitstream The original source bitstream. + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ - protected void addCitedPageToItem(File citedTemp, Bundle bundle, Bundle pBundle, - Bundle dBundle, Map displayMap, Item item, - Bitstream bitstream) throws SQLException, AuthorizeException, IOException { + protected void addCitedPageToItem(InputStream citedDoc, Bundle bundle, Bundle pBundle, + Bundle dBundle, Map displayMap, Item item, + Bitstream bitstream) throws SQLException, AuthorizeException, IOException { //If we are modifying a file that is not in the //preservation bundle then we have to move it there. Context context = Curator.curationContext(); @@ -218,12 +223,11 @@ public class CitationPage extends AbstractCurationTask { //Create an input stream form the temporary file //that is the cited document and create a //bitstream from it. - InputStream inp = new FileInputStream(citedTemp); if (displayMap.containsKey(bitstream.getName())) { bundleService.removeBitstream(context, dBundle, displayMap.get(bitstream.getName())); } - Bitstream citedBitstream = bitstreamService.create(context, dBundle, inp); - inp.close(); //Close up the temporary InputStream + Bitstream citedBitstream = bitstreamService.create(context, dBundle, citedDoc); + citedDoc.close(); //Close up the temporary InputStream //Setup a good name for our bitstream and make //it the same format as the source document. @@ -232,8 +236,8 @@ public class CitationPage extends AbstractCurationTask { citedBitstream.setDescription(context, bitstream.getDescription()); this.resBuilder.append(" Added " - + citedBitstream.getName() - + " to the " + CitationPage.DISPLAY_BUNDLE_NAME + " bundle.\n"); + + citedBitstream.getName() + + " to the " + CitationPage.DISPLAY_BUNDLE_NAME + " bundle.\n"); //Run update to propagate changes to the //database. diff --git a/dspace-api/src/main/java/org/dspace/curate/CurationCli.java b/dspace-api/src/main/java/org/dspace/curate/CurationCli.java index 48f0855e12..c0b206abfc 100644 --- a/dspace-api/src/main/java/org/dspace/curate/CurationCli.java +++ b/dspace-api/src/main/java/org/dspace/curate/CurationCli.java @@ -7,7 +7,15 @@ */ package org.dspace.curate; -import org.apache.commons.cli.*; +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.Iterator; + +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.content.factory.ContentServiceFactory; import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; @@ -16,40 +24,41 @@ import org.dspace.eperson.EPerson; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; -import java.io.BufferedReader; -import java.io.FileReader; -import java.util.Iterator; - /** * CurationCli provides command-line access to Curation tools and processes. - * + * * @author richardrodgers */ -public class CurationCli -{ - public static void main(String[] args) throws Exception - { - // create an options object and populate it +public class CurationCli { + + /** + * Default constructor + */ + private CurationCli() { } + + public static void main(String[] args) throws Exception { + // create an options object and populate it CommandLineParser parser = new PosixParser(); Options options = new Options(); options.addOption("t", "task", true, - "curation task name"); + "curation task name"); options.addOption("T", "taskfile", true, - "file containing curation task names"); + "file containing curation task names"); options.addOption("i", "id", true, - "Id (handle) of object to perform task on, or 'all' to perform on whole repository"); + "Id (handle) of object to perform task on, or 'all' to perform on whole repository"); options.addOption("q", "queue", true, - "name of task queue to process"); + "name of task queue to process"); options.addOption("e", "eperson", true, - "email address of curating eperson"); + "email address of curating eperson"); options.addOption("r", "reporter", true, - "reporter to manage results - use '-' to report to console. If absent, no reporting"); + "reporter to manage results - use '-' to report to console. If absent, no reporting"); options.addOption("s", "scope", true, - "transaction scope to impose: use 'object', 'curation', or 'open'. If absent, 'open' applies"); + "transaction scope to impose: use 'object', 'curation', or 'open'. If absent, 'open' " + + "applies"); options.addOption("v", "verbose", false, - "report activity to stdout"); + "report activity to stdout"); options.addOption("h", "help", false, "help"); CommandLine line = parser.parse(options, args); @@ -63,212 +72,168 @@ public class CurationCli String scope = null; boolean verbose = false; - if (line.hasOption('h')) - { + if (line.hasOption('h')) { HelpFormatter help = new HelpFormatter(); help.printHelp("CurationCli\n", options); System.out - .println("\nwhole repo: CurationCli -t estimate -i all"); + .println("\nwhole repo: CurationCli -t estimate -i all"); System.out - .println("single item: CurationCli -t generate -i itemId"); + .println("single item: CurationCli -t generate -i itemId"); System.out - .println("task queue: CurationCli -q monthly"); + .println("task queue: CurationCli -q monthly"); System.exit(0); } - if (line.hasOption('t')) - { // task + if (line.hasOption('t')) { // task taskName = line.getOptionValue('t'); } - if (line.hasOption('T')) - { // task file + if (line.hasOption('T')) { // task file taskFileName = line.getOptionValue('T'); } - if (line.hasOption('i')) - { // id + if (line.hasOption('i')) { // id idName = line.getOptionValue('i'); } - if (line.hasOption('q')) - { // task queue + if (line.hasOption('q')) { // task queue taskQueueName = line.getOptionValue('q'); } - if (line.hasOption('e')) - { // eperson + if (line.hasOption('e')) { // eperson ePersonName = line.getOptionValue('e'); } - if (line.hasOption('r')) - { // report file + if (line.hasOption('r')) { // report file reporterName = line.getOptionValue('r'); } - - if (line.hasOption('s')) - { // transaction scope + + if (line.hasOption('s')) { // transaction scope scope = line.getOptionValue('s'); } - if (line.hasOption('v')) - { // verbose + if (line.hasOption('v')) { // verbose verbose = true; } // now validate the args - if (idName == null && taskQueueName == null) - { + if (idName == null && taskQueueName == null) { System.out.println("Id must be specified: a handle, 'all', or a task queue (-h for help)"); System.exit(1); } - if (taskName == null && taskFileName == null && taskQueueName == null) - { + if (taskName == null && taskFileName == null && taskQueueName == null) { System.out.println("A curation task or queue must be specified (-h for help)"); System.exit(1); } - - if (scope != null && Curator.TxScope.valueOf(scope.toUpperCase()) == null) - { - System.out.println("Bad transaction scope '" + scope + "': only 'object', 'curation' or 'open' recognized"); - System.exit(1); - } + + if (scope != null && Curator.TxScope.valueOf(scope.toUpperCase()) == null) { + System.out.println("Bad transaction scope '" + scope + "': only 'object', 'curation' or 'open' recognized"); + System.exit(1); + } EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); Context c = new Context(Context.Mode.BATCH_EDIT); - if (ePersonName != null) - { + if (ePersonName != null) { EPerson ePerson = ePersonService.findByEmail(c, ePersonName); - if (ePerson == null) - { + if (ePerson == null) { System.out.println("EPerson not found: " + ePersonName); System.exit(1); } c.setCurrentUser(ePerson); - } - else - { + } else { c.turnOffAuthorisationSystem(); } Curator curator = new Curator(); - if (reporterName != null) - { + if (reporterName != null) { curator.setReporter(reporterName); } - if (scope != null) - { - Curator.TxScope txScope = Curator.TxScope.valueOf(scope.toUpperCase()); - curator.setTransactionScope(txScope); + if (scope != null) { + Curator.TxScope txScope = Curator.TxScope.valueOf(scope.toUpperCase()); + curator.setTransactionScope(txScope); } // we are operating in batch mode, if anyone cares. curator.setInvoked(Curator.Invoked.BATCH); // load curation tasks - if (taskName != null) - { - if (verbose) - { + if (taskName != null) { + if (verbose) { System.out.println("Adding task: " + taskName); } curator.addTask(taskName); - if (verbose && ! curator.hasTask(taskName)) - { + if (verbose && !curator.hasTask(taskName)) { System.out.println("Task: " + taskName + " not resolved"); } - } - else if (taskQueueName == null) - { + } else if (taskQueueName == null) { // load taskFile BufferedReader reader = null; - try - { + try { reader = new BufferedReader(new FileReader(taskFileName)); - while ((taskName = reader.readLine()) != null) - { - if (verbose) - { + while ((taskName = reader.readLine()) != null) { + if (verbose) { System.out.println("Adding task: " + taskName); } curator.addTask(taskName); } - } - finally - { - if (reader != null) - { - reader.close(); + } finally { + if (reader != null) { + reader.close(); } } } // run tasks against object long start = System.currentTimeMillis(); - if (verbose) - { + if (verbose) { System.out.println("Starting curation"); } - if (idName != null) - { - if (verbose) - { - System.out.println("Curating id: " + idName); + if (idName != null) { + if (verbose) { + System.out.println("Curating id: " + idName); } - if ("all".equals(idName)) - { - // run on whole Site - curator.curate(c, ContentServiceFactory.getInstance().getSiteService().findSite(c).getHandle()); - } - else - { + if ("all".equals(idName)) { + // run on whole Site + curator.curate(c, ContentServiceFactory.getInstance().getSiteService().findSite(c).getHandle()); + } else { curator.curate(c, idName); } - } - else - { + } else { // process the task queue - TaskQueue queue = (TaskQueue) CoreServiceFactory.getInstance().getPluginService().getSinglePlugin(TaskQueue.class); - if (queue == null) - { + TaskQueue queue = (TaskQueue) CoreServiceFactory.getInstance().getPluginService() + .getSinglePlugin(TaskQueue.class); + if (queue == null) { System.out.println("No implementation configured for queue"); throw new UnsupportedOperationException("No queue service available"); } // use current time as our reader 'ticket' long ticket = System.currentTimeMillis(); Iterator entryIter = queue.dequeue(taskQueueName, ticket).iterator(); - while (entryIter.hasNext()) - { + while (entryIter.hasNext()) { TaskQueueEntry entry = entryIter.next(); - if (verbose) - { + if (verbose) { System.out.println("Curating id: " + entry.getObjectId()); } curator.clear(); // does entry relate to a DSO or workflow object? - if (entry.getObjectId().indexOf("/") > 0) - { - for (String task : entry.getTaskNames()) - { + if (entry.getObjectId().indexOf("/") > 0) { + for (String task : entry.getTaskNames()) { curator.addTask(task); } curator.curate(c, entry.getObjectId()); - } - else - { + } else { // make eperson who queued task the effective user EPerson agent = ePersonService.findByEmail(c, entry.getEpersonId()); - if (agent != null) - { + if (agent != null) { c.setCurrentUser(agent); } - CurateServiceFactory.getInstance().getWorkflowCuratorService().curate(curator, c, entry.getObjectId()); + CurateServiceFactory.getInstance().getWorkflowCuratorService() + .curate(curator, c, entry.getObjectId()); } } queue.release(taskQueueName, ticket, true); } c.complete(); - if (verbose) - { + if (verbose) { long elapsed = System.currentTimeMillis() - start; System.out.println("Ending curation. Elapsed time: " + elapsed); } diff --git a/dspace-api/src/main/java/org/dspace/curate/CurationTask.java b/dspace-api/src/main/java/org/dspace/curate/CurationTask.java index 77ab483cbf..328fd25bf2 100644 --- a/dspace-api/src/main/java/org/dspace/curate/CurationTask.java +++ b/dspace-api/src/main/java/org/dspace/curate/CurationTask.java @@ -18,15 +18,14 @@ import org.dspace.core.Context; * * @author richardrodgers */ -public interface CurationTask -{ +public interface CurationTask { /** * Initialize task - parameters inform the task of it's invoking curator. * Since the curator can provide services to the task, this represents * curation DI. - * + * * @param curator the Curator controlling this task - * @param taskId identifier task should use in invoking services + * @param taskId identifier task should use in invoking services * @throws IOException if error */ void init(Curator curator, String taskId) throws IOException; @@ -42,9 +41,9 @@ public interface CurationTask /** * Perform the curation task for passed id - * + * * @param ctx DSpace context object - * @param id persistent ID for DSpace object + * @param id persistent ID for DSpace object * @return status code * @throws IOException if error */ diff --git a/dspace-api/src/main/java/org/dspace/curate/Curator.java b/dspace-api/src/main/java/org/dspace/curate/Curator.java index 91152fc8aa..55d9843cb3 100644 --- a/dspace-api/src/main/java/org/dspace/curate/Curator.java +++ b/dspace-api/src/main/java/org/dspace/curate/Curator.java @@ -9,12 +9,18 @@ package org.dspace.curate; import java.io.IOException; import java.sql.SQLException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import org.apache.log4j.Logger; - -import org.dspace.content.*; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.Site; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; @@ -28,34 +34,54 @@ import org.dspace.handle.service.HandleService; * Curator orchestrates and manages the application of a one or more curation * tasks to a DSpace object. It provides common services and runtime * environment to the tasks. - * + * * @author richardrodgers */ -public class Curator -{ +public class Curator { // status code values - /** Curator unable to find requested task */ + /** + * Curator unable to find requested task + */ public static final int CURATE_NOTASK = -3; - /** no assigned status code - typically because task not yet performed */ + /** + * no assigned status code - typically because task not yet performed + */ public static final int CURATE_UNSET = -2; - /** task encountered an error in processing */ + /** + * task encountered an error in processing + */ public static final int CURATE_ERROR = -1; - /** task completed successfully */ + /** + * task completed successfully + */ public static final int CURATE_SUCCESS = 0; - /** task failed */ + /** + * task failed + */ public static final int CURATE_FAIL = 1; - /** task was not applicable to passed object */ + /** + * task was not applicable to passed object + */ public static final int CURATE_SKIP = 2; - + // invocation modes - used by Suspendable tasks - public static enum Invoked { INTERACTIVE, BATCH, ANY }; + public static enum Invoked { + INTERACTIVE, BATCH, ANY + } + + ; + // transaction scopes - public static enum TxScope { OBJECT, CURATION, OPEN }; + public static enum TxScope { + OBJECT, CURATION, OPEN + } + + ; private static final Logger log = Logger.getLogger(Curator.class); - + protected static final ThreadLocal curationCtx = new ThreadLocal<>(); - + protected Map trMap = new HashMap<>(); protected List perfList = new ArrayList<>(); protected TaskQueue taskQ = null; @@ -70,8 +96,7 @@ public class Curator /** * No-arg constructor */ - public Curator() - { + public Curator() { communityService = ContentServiceFactory.getInstance().getCommunityService(); itemService = ContentServiceFactory.getInstance().getItemService(); handleService = HandleServiceFactory.getInstance().getHandleService(); @@ -80,83 +105,72 @@ public class Curator /** * Add a task to the set to be performed. Caller should make no assumptions * on execution ordering. - * + * * @param taskName - logical name of task * @return this curator - to support concatenating invocation style */ - public Curator addTask(String taskName) - { + public Curator addTask(String taskName) { ResolvedTask task = resolver.resolveTask(taskName); - if (task != null) - { - try - { + if (task != null) { + try { task.init(this); trMap.put(taskName, new TaskRunner(task)); // performance order currently FIFO - to be revisited perfList.add(taskName); + } catch (IOException ioE) { + log.error("Task: '" + taskName + "' initialization failure: " + ioE.getMessage()); } - catch (IOException ioE) - { - log.error("Task: '" + taskName + "' initialization failure: " + ioE.getMessage()); - } - } - else - { + } else { log.error("Task: '" + taskName + "' does not resolve"); } return this; } - + /** * Returns whether this curator has the specified task - * + * * @param taskName - logical name of the task * @return true if task has been configured, else false */ - public boolean hasTask(String taskName) - { - return perfList.contains(taskName); - } - + public boolean hasTask(String taskName) { + return perfList.contains(taskName); + } + /** * Removes a task from the set to be performed. - * + * * @param taskName - logical name of the task * @return this curator - to support concatenating invocation style */ - public Curator removeTask(String taskName) - { + public Curator removeTask(String taskName) { trMap.remove(taskName); perfList.remove(taskName); return this; } - + /** * Assigns invocation mode. - * + * * @param mode one of INTERACTIVE, BATCH, ANY * @return the Curator instance. */ - public Curator setInvoked(Invoked mode) - { + public Curator setInvoked(Invoked mode) { iMode = mode; return this; } /** * Sets the reporting stream for this curator. - * + * * @param reporter name of reporting stream. The name '-' - * causes reporting to standard out. + * causes reporting to standard out. * @return return self (Curator instance) with reporter set */ - public Curator setReporter(String reporter) - { + public Curator setReporter(String reporter) { this.reporter = reporter; return this; } - + /** * Defines the transactional scope of curator executions. @@ -170,8 +184,7 @@ public class Curator * @param scope transactional scope * @return return self (Curator instance) with given scope set */ - public Curator setTransactionScope(TxScope scope) - { + public Curator setTransactionScope(TxScope scope) { txScope = scope; return this; } @@ -185,54 +198,42 @@ public class Curator * Note: this method has the side-effect of setting this instance's Context * reference. The setting is retained on return. * - * @param c a DSpace context + * @param c a DSpace context * @param id an object identifier * @throws IOException if IO error */ - public void curate(Context c, String id) throws IOException - { - if (id == null) - { - throw new IOException("Cannot perform curation task(s) on a null object identifier!"); + public void curate(Context c, String id) throws IOException { + if (id == null) { + throw new IOException("Cannot perform curation task(s) on a null object identifier!"); } - try - { + try { //Save the context on current execution thread curationCtx.set(c); - + DSpaceObject dso = handleService.resolveToObject(c, id); - if (dso != null) - { + if (dso != null) { curate(dso); - } - else - { - for (String taskName : perfList) - { + } else { + for (String taskName : perfList) { trMap.get(taskName).run(c, id); } } // if curation scoped, commit transaction if (txScope.equals(TxScope.CURATION)) { Context ctx = curationCtx.get(); - if (ctx != null) - { + if (ctx != null) { ctx.complete(); } } - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE.getMessage(), sqlE); - } - finally - { + } finally { curationCtx.remove(); } } /** - * Performs all configured tasks upon DSpace object + * Performs all configured tasks upon DSpace object * (Community, Collection or Item). *

    * Note: Site-wide tasks will default to running as @@ -244,32 +245,22 @@ public class Curator * @param dso the DSpace object * @throws IOException if IO error */ - public void curate(DSpaceObject dso) throws IOException - { - if (dso == null) - { + public void curate(DSpaceObject dso) throws IOException { + if (dso == null) { throw new IOException("Cannot perform curation task(s) on a null DSpaceObject!"); } int type = dso.getType(); - for (String taskName : perfList) - { + for (String taskName : perfList) { TaskRunner tr = trMap.get(taskName); // do we need to iterate over the object ? - if (type == Constants.ITEM || tr.task.isDistributive()) - { + if (type == Constants.ITEM || tr.task.isDistributive()) { tr.run(dso); - } - else if (type == Constants.COLLECTION) - { - doCollection(tr, (Collection)dso); - } - else if (type == Constants.COMMUNITY) - { - doCommunity(tr, (Community)dso); - } - else if (type == Constants.SITE) - { - doSite(tr, (Site) dso); + } else if (type == Constants.COLLECTION) { + doCollection(tr, (Collection) dso); + } else if (type == Constants.COMMUNITY) { + doCommunity(tr, (Community) dso); + } else if (type == Constants.SITE) { + doSite(tr, (Site) dso); } } } @@ -282,13 +273,12 @@ public class Curator * Note: this method has the side-effect of setting this instance's Context * reference. The setting is retained on return. * - * @param c session context in which curation takes place. + * @param c session context in which curation takes place. * @param dso the single object to be curated. * @throws java.io.IOException passed through. */ public void curate(Context c, DSpaceObject dso) - throws IOException - { + throws IOException { curationCtx.set(c); curate(dso); } @@ -296,201 +286,175 @@ public class Curator /** * Places a curation request for the object identified by id on a * managed queue named by the queueId. - * - * @param c A DSpace context - * @param id an object Id + * + * @param c A DSpace context + * @param id an object Id * @param queueId name of a queue. If queue does not exist, it will * be created automatically. * @throws IOException if IO error */ - public void queue(Context c, String id, String queueId) throws IOException - { - if (taskQ == null) - { + public void queue(Context c, String id, String queueId) throws IOException { + if (taskQ == null) { taskQ = (TaskQueue) CoreServiceFactory.getInstance().getPluginService().getSinglePlugin(TaskQueue.class); } - if (taskQ != null) - { + if (taskQ != null) { taskQ.enqueue(queueId, new TaskQueueEntry(c.getCurrentUser().getName(), - System.currentTimeMillis(), perfList, id)); - } - else - { + System.currentTimeMillis(), perfList, id)); + } else { log.error("curate - no TaskQueue implemented"); } } - + /** * Removes all configured tasks from the Curator. */ - public void clear() - { + public void clear() { trMap.clear(); perfList.clear(); } /** * Adds a message to the configured reporting stream. - * + * * @param message the message to output to the reporting stream. */ - public void report(String message) - { + public void report(String message) { // Stub for now - if ("-".equals(reporter)) - { + if ("-".equals(reporter)) { System.out.println(message); } } /** * Returns the status code for the latest performance of the named task. - * + * * @param taskName the task name * @return the status code - one of CURATE_ values */ - public int getStatus(String taskName) - { + public int getStatus(String taskName) { TaskRunner tr = trMap.get(taskName); return (tr != null) ? tr.statusCode : CURATE_NOTASK; } /** * Returns the result string for the latest performance of the named task. - * + * * @param taskName the task name * @return the result string, or null if task has not set it. */ - public String getResult(String taskName) - { + public String getResult(String taskName) { TaskRunner tr = trMap.get(taskName); return (tr != null) ? tr.result : null; } /** * Assigns a result to the performance of the named task. - * + * * @param taskName the task name - * @param result a string indicating results of performing task. + * @param result a string indicating results of performing task. */ - public void setResult(String taskName, String result) - { + public void setResult(String taskName, String result) { TaskRunner tr = trMap.get(taskName); - if (tr != null) - { + if (tr != null) { tr.setResult(result); } } - + /** * Returns the context object used in the current curation thread. * This is primarily a utility method to allow tasks access to the context when necessary. *

    * If the context is null or not set, then this just returns * a brand new Context object representing an Anonymous User. - * + * * @return curation thread's Context object (or a new, anonymous Context if no curation Context exists) - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ - public static Context curationContext() throws SQLException - { + public static Context curationContext() throws SQLException { // Return curation context or new context if undefined/invalid Context curCtx = curationCtx.get(); - - if (curCtx==null || !curCtx.isValid()) - { + + if (curCtx == null || !curCtx.isValid()) { //Create a new context (represents an Anonymous User) curCtx = new Context(); //Save it to current execution thread curationCtx.set(curCtx); - } + } return curCtx; } /** * Returns whether a given DSO is a 'container' - collection or community + * * @param dso a DSpace object * @return true if a container, false otherwise */ - public static boolean isContainer(DSpaceObject dso) - { + public static boolean isContainer(DSpaceObject dso) { return (dso.getType() == Constants.COMMUNITY || - dso.getType() == Constants.COLLECTION); + dso.getType() == Constants.COLLECTION); } /** * Run task for entire Site (including all Communities, Collections and Items) - * @param tr TaskRunner + * + * @param tr TaskRunner * @param site DSpace Site object * @return true if successful, false otherwise * @throws IOException if IO error */ - protected boolean doSite(TaskRunner tr, Site site) throws IOException - { + protected boolean doSite(TaskRunner tr, Site site) throws IOException { Context ctx = null; - try - { + try { //get access to the curation thread's current context ctx = curationContext(); - + // Site-wide Tasks really should have an EPerson performer associated with them, // otherwise they are run as an "anonymous" user with limited access rights. - if (ctx.getCurrentUser()==null && !ctx.ignoreAuthorization()) - { + if (ctx.getCurrentUser() == null && !ctx.ignoreAuthorization()) { log.warn("You are running one or more Site-Wide curation tasks in ANONYMOUS USER mode," + - " as there is no EPerson 'performer' associated with this task. To associate an EPerson 'performer' " + - " you should ensure tasks are called via the Curator.curate(Context, ID) method."); + " as there is no EPerson 'performer' associated with this task. To associate an EPerson " + + "'performer' " + + " you should ensure tasks are called via the Curator.curate(Context, ID) method."); } - + //Run task for the Site object itself - if (! tr.run(site)) - { + if (!tr.run(site)) { return false; } - + //Then, perform this task for all Top-Level Communities in the Site // (this will recursively perform task for all objects in DSpace) - for (Community subcomm : communityService.findAllTop(ctx)) - { - if (! doCommunity(tr, subcomm)) - { + for (Community subcomm : communityService.findAllTop(ctx)) { + if (!doCommunity(tr, subcomm)) { return false; } } - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE); } return true; } - + /** * Run task for Community along with all sub-communities and collections. - * @param tr TaskRunner + * + * @param tr TaskRunner * @param comm Community * @return true if successful, false otherwise * @throws IOException if IO error */ - protected boolean doCommunity(TaskRunner tr, Community comm) throws IOException - { - if (! tr.run(comm)) - { + protected boolean doCommunity(TaskRunner tr, Community comm) throws IOException { + if (!tr.run(comm)) { return false; } - for (Community subcomm : comm.getSubcommunities()) - { - if (! doCommunity(tr, subcomm)) - { + for (Community subcomm : comm.getSubcommunities()) { + if (!doCommunity(tr, subcomm)) { return false; } } - for (Collection coll : comm.getCollections()) - { - if (! doCollection(tr, coll)) - { + for (Collection coll : comm.getCollections()) { + if (!doCollection(tr, coll)) { return false; } } @@ -499,146 +463,119 @@ public class Curator /** * Run task for Collection along with all Items in that collection. - * @param tr TaskRunner + * + * @param tr TaskRunner * @param coll Collection * @return true if successful, false otherwise * @throws IOException if IO error */ - protected boolean doCollection(TaskRunner tr, Collection coll) throws IOException - { - try - { - if (! tr.run(coll)) - { + protected boolean doCollection(TaskRunner tr, Collection coll) throws IOException { + try { + if (!tr.run(coll)) { return false; } Context context = curationContext(); Iterator iter = itemService.findByCollection(context, coll); - while (iter.hasNext()) - { + while (iter.hasNext()) { Item item = iter.next(); boolean shouldContinue = tr.run(item); context.uncacheEntity(item); - if (!shouldContinue) - { + if (!shouldContinue) { return false; } } - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE.getMessage(), sqlE); } return true; } - + /** * Record a 'visit' to a DSpace object and enforce any policies set * on this curator. + * * @param dso the DSpace object - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ - protected void visit(DSpaceObject dso) throws IOException - { + protected void visit(DSpaceObject dso) throws IOException { Context curCtx = curationCtx.get(); - if (curCtx != null) - { - if (txScope.equals(TxScope.OBJECT)) - { + if (curCtx != null) { + if (txScope.equals(TxScope.OBJECT)) { curCtx.dispatchEvents(); } } } - protected class TaskRunner - { + protected class TaskRunner { ResolvedTask task = null; int statusCode = CURATE_UNSET; String result = null; - public TaskRunner(ResolvedTask task) - { + public TaskRunner(ResolvedTask task) { this.task = task; } - - public boolean run(DSpaceObject dso) throws IOException - { - try - { - if (dso == null) - { + + public boolean run(DSpaceObject dso) throws IOException { + try { + if (dso == null) { throw new IOException("DSpaceObject is null"); } statusCode = task.perform(dso); String id = (dso.getHandle() != null) ? dso.getHandle() : "workflow item: " + dso.getID(); log.info(logMessage(id)); visit(dso); - return ! suspend(statusCode); - } - catch (IOException ioe) - { - //log error & pass exception upwards - log.error("Error executing curation task '" + task.getName() + "'", ioe); - throw ioe; - } - } - - public boolean run(Context c, String id) throws IOException - { - try - { - if (c == null || id == null) - { - throw new IOException("Context or identifier is null"); - } - statusCode = task.perform(c, id); - log.info(logMessage(id)); - visit(null); - return ! suspend(statusCode); - } - catch (IOException ioe) - { + return !suspend(statusCode); + } catch (IOException ioe) { //log error & pass exception upwards log.error("Error executing curation task '" + task.getName() + "'", ioe); throw ioe; } } - public void setResult(String result) - { + public boolean run(Context c, String id) throws IOException { + try { + if (c == null || id == null) { + throw new IOException("Context or identifier is null"); + } + statusCode = task.perform(c, id); + log.info(logMessage(id)); + visit(null); + return !suspend(statusCode); + } catch (IOException ioe) { + //log error & pass exception upwards + log.error("Error executing curation task '" + task.getName() + "'", ioe); + throw ioe; + } + } + + public void setResult(String result) { this.result = result; } - - protected boolean suspend(int code) - { + + protected boolean suspend(int code) { Invoked mode = task.getMode(); - if (mode != null && (mode.equals(Invoked.ANY) || mode.equals(iMode))) - { - for (int i : task.getCodes()) - { - if (code == i) - { + if (mode != null && (mode.equals(Invoked.ANY) || mode.equals(iMode))) { + for (int i : task.getCodes()) { + if (code == i) { return true; } } } return false; } - + /** * Builds a useful log message for a curation task. + * * @param id ID of DSpace Object * @return log message text */ - protected String logMessage(String id) - { + protected String logMessage(String id) { StringBuilder mb = new StringBuilder(); mb.append("Curation task: ").append(task.getName()). - append(" performed on: ").append(id). - append(" with status: ").append(statusCode); - if (result != null) - { + append(" performed on: ").append(id). + append(" with status: ").append(statusCode); + if (result != null) { mb.append(". Result: '").append(result).append("'"); } return mb.toString(); diff --git a/dspace-api/src/main/java/org/dspace/curate/Distributive.java b/dspace-api/src/main/java/org/dspace/curate/Distributive.java index d3988fbda4..a3c9cd34cc 100644 --- a/dspace-api/src/main/java/org/dspace/curate/Distributive.java +++ b/dspace-api/src/main/java/org/dspace/curate/Distributive.java @@ -15,11 +15,10 @@ import java.lang.annotation.RetentionPolicy; * Annotation type for CurationTasks. A task is distributive if it * distributes its performance to the component parts of it's target object. * This usually implies container iteration. - * + * * @author richardrodgers */ @Documented @Retention(RetentionPolicy.RUNTIME) -public @interface Distributive -{ +public @interface Distributive { } diff --git a/dspace-api/src/main/java/org/dspace/curate/FileTaskQueue.java b/dspace-api/src/main/java/org/dspace/curate/FileTaskQueue.java index 48831bd26e..fc665bcf2c 100644 --- a/dspace-api/src/main/java/org/dspace/curate/FileTaskQueue.java +++ b/dspace-api/src/main/java/org/dspace/curate/FileTaskQueue.java @@ -25,13 +25,12 @@ import org.dspace.services.factory.DSpaceServicesFactory; /** * FileTaskQueue provides a TaskQueue implementation based on flat files - * for the queues and semaphores. + * for the queues and semaphores. * * @author richardrodgers */ -public class FileTaskQueue implements TaskQueue -{ - private static Logger log = Logger.getLogger(TaskQueue.class); +public class FileTaskQueue implements TaskQueue { + private static Logger log = Logger.getLogger(TaskQueue.class); // base directory for curation task queues protected String tqDir; @@ -40,21 +39,18 @@ public class FileTaskQueue implements TaskQueue // list of queues owned by reader protected List readList = new ArrayList(); - public FileTaskQueue() - { + public FileTaskQueue() { tqDir = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("curate.taskqueue.dir"); } - + @Override - public String[] queueNames() - { + public String[] queueNames() { return new File(tqDir).list(); } - + @Override public synchronized void enqueue(String queueName, TaskQueueEntry entry) - throws IOException - { + throws IOException { Set entrySet = new HashSet(); entrySet.add(entry); enqueue(queueName, entrySet); @@ -62,42 +58,33 @@ public class FileTaskQueue implements TaskQueue @Override public synchronized void enqueue(String queueName, Set entrySet) - throws IOException - { + throws IOException { // don't block or fail - iterate until an unlocked queue found/created int queueIdx = 0; File qDir = ensureQueue(queueName); - while (true) - { + while (true) { File lock = new File(qDir, "lock" + Integer.toString(queueIdx)); // Check for lock, and create one if it doesn't exist. // If the lock file already exists, this will return false - if (lock.createNewFile()) - { + if (lock.createNewFile()) { // append set contents to queue BufferedWriter writer = null; - try - { + try { File queue = new File(qDir, "queue" + Integer.toString(queueIdx)); writer = new BufferedWriter(new FileWriter(queue, true)); Iterator iter = entrySet.iterator(); - while (iter.hasNext()) - { + while (iter.hasNext()) { writer.write(iter.next().toString()); writer.newLine(); } - } - finally - { - if (writer != null) - { + } finally { + if (writer != null) { writer.close(); } } // remove lock - if (!lock.delete()) - { + if (!lock.delete()) { log.error("Unable to remove lock: " + lock.getName()); } break; @@ -108,18 +95,15 @@ public class FileTaskQueue implements TaskQueue @Override public synchronized Set dequeue(String queueName, long ticket) - throws IOException - { + throws IOException { Set entrySet = new HashSet(); - if (readTicket == -1L) - { + if (readTicket == -1L) { // hold the ticket & copy all Ids available, locking queues // stop when no more queues or one found locked File qDir = ensureQueue(queueName); readTicket = ticket; int queueIdx = 0; - while (true) - { + while (true) { File queue = new File(qDir, "queue" + Integer.toString(queueIdx)); File lock = new File(qDir, "lock" + Integer.toString(queueIdx)); @@ -128,30 +112,22 @@ public class FileTaskQueue implements TaskQueue if (queue.exists() && lock.createNewFile()) { // read contents from file BufferedReader reader = null; - try - { + try { reader = new BufferedReader(new FileReader(queue)); String entryStr = null; - while ((entryStr = reader.readLine()) != null) - { + while ((entryStr = reader.readLine()) != null) { entryStr = entryStr.trim(); - if (entryStr.length() > 0) - { + if (entryStr.length() > 0) { entrySet.add(new TaskQueueEntry(entryStr)); } } - } - finally - { - if (reader != null) - { - reader.close(); + } finally { + if (reader != null) { + reader.close(); } } readList.add(queueIdx); - } - else - { + } else { break; } queueIdx++; @@ -159,42 +135,34 @@ public class FileTaskQueue implements TaskQueue } return entrySet; } - + @Override - public synchronized void release(String queueName, long ticket, boolean remove) - { - if (ticket == readTicket) - { + public synchronized void release(String queueName, long ticket, boolean remove) { + if (ticket == readTicket) { readTicket = -1L; File qDir = ensureQueue(queueName); // remove locks & queues (if flag true) - for (Integer queueIdx : readList) - { + for (Integer queueIdx : readList) { File lock = new File(qDir, "lock" + Integer.toString(queueIdx)); - if (remove) - { + if (remove) { File queue = new File(qDir, "queue" + Integer.toString(queueIdx)); - if (!queue.delete()) - { + if (!queue.delete()) { log.error("Unable to delete queue file: " + queue.getName()); } } - if (!lock.delete()) - { + if (!lock.delete()) { log.error("Unable to delete lock file: " + lock.getName()); } } readList.clear(); } } - - protected File ensureQueue(String queueName) - { + + protected File ensureQueue(String queueName) { // create directory structures as needed File baseDir = new File(tqDir, queueName); - if (!baseDir.exists() && !baseDir.mkdirs()) - { + if (!baseDir.exists() && !baseDir.mkdirs()) { throw new IllegalStateException("Unable to create directories"); } diff --git a/dspace-api/src/main/java/org/dspace/curate/Mutative.java b/dspace-api/src/main/java/org/dspace/curate/Mutative.java index 919cd8aa17..e815bee891 100644 --- a/dspace-api/src/main/java/org/dspace/curate/Mutative.java +++ b/dspace-api/src/main/java/org/dspace/curate/Mutative.java @@ -14,11 +14,10 @@ import java.lang.annotation.RetentionPolicy; /** * Annotation type for CurationTasks. A task is mutative if it * alters (transforms, mutates) it's target object. - * + * * @author richardrodgers */ @Documented @Retention(RetentionPolicy.RUNTIME) -public @interface Mutative -{ +public @interface Mutative { } diff --git a/dspace-api/src/main/java/org/dspace/curate/ResolvedTask.java b/dspace-api/src/main/java/org/dspace/curate/ResolvedTask.java index 177f5fab88..89e92609f0 100644 --- a/dspace-api/src/main/java/org/dspace/curate/ResolvedTask.java +++ b/dspace-api/src/main/java/org/dspace/curate/ResolvedTask.java @@ -19,61 +19,53 @@ import org.dspace.core.Context; * * @author richardrodgers */ -public class ResolvedTask -{ - // wrapped objects - private CurationTask cTask; - private ScriptedTask sTask; - // local name of task - private String taskName; - // annotation data - private boolean distributive = false; - private boolean mutative = false; - private Curator.Invoked mode = null; +public class ResolvedTask { + // wrapped objects + private CurationTask cTask; + private ScriptedTask sTask; + // local name of task + private String taskName; + // annotation data + private boolean distributive = false; + private boolean mutative = false; + private Curator.Invoked mode = null; private int[] codes = null; - - - protected ResolvedTask(String taskName, CurationTask cTask) - { - this.taskName = taskName; - this.cTask = cTask; - // process annotations - Class ctClass = cTask.getClass(); - distributive = ctClass.isAnnotationPresent(Distributive.class); - mutative = ctClass.isAnnotationPresent(Mutative.class); - Suspendable suspendAnno = (Suspendable)ctClass.getAnnotation(Suspendable.class); - if (suspendAnno != null) - { + + + protected ResolvedTask(String taskName, CurationTask cTask) { + this.taskName = taskName; + this.cTask = cTask; + // process annotations + Class ctClass = cTask.getClass(); + distributive = ctClass.isAnnotationPresent(Distributive.class); + mutative = ctClass.isAnnotationPresent(Mutative.class); + Suspendable suspendAnno = (Suspendable) ctClass.getAnnotation(Suspendable.class); + if (suspendAnno != null) { mode = suspendAnno.invoked(); codes = suspendAnno.statusCodes(); } - } - - protected ResolvedTask(String taskName, ScriptedTask sTask) - { - this.taskName = taskName; - this.sTask = sTask; - // annotation processing TBD - } - + } + + protected ResolvedTask(String taskName, ScriptedTask sTask) { + this.taskName = taskName; + this.sTask = sTask; + // annotation processing TBD + } + /** * Initialize task - parameters inform the task of it's invoking curator. * Since the curator can provide services to the task, this represents * curation DI. - * + * * @param curator the Curator controlling this task * @throws IOException if IO error */ - public void init(Curator curator) throws IOException - { - if (unscripted()) - { - cTask.init(curator, taskName); - } - else - { - sTask.init(curator, taskName); - } + public void init(Curator curator) throws IOException { + if (unscripted()) { + cTask.init(curator, taskName); + } else { + sTask.init(curator, taskName); + } } /** @@ -83,71 +75,64 @@ public class ResolvedTask * @return status code * @throws IOException if error */ - public int perform(DSpaceObject dso) throws IOException - { - return (unscripted()) ? cTask.perform(dso) : sTask.performDso(dso); + public int perform(DSpaceObject dso) throws IOException { + return (unscripted()) ? cTask.perform(dso) : sTask.performDso(dso); } /** * Perform the curation task for passed id - * + * * @param ctx DSpace context object - * @param id persistent ID for DSpace object + * @param id persistent ID for DSpace object * @return status code * @throws IOException if error */ - public int perform(Context ctx, String id) throws IOException - { - return (unscripted()) ? cTask.perform(ctx, id) : sTask.performId(ctx, id); + public int perform(Context ctx, String id) throws IOException { + return (unscripted()) ? cTask.perform(ctx, id) : sTask.performId(ctx, id); } - + /** * Returns local name of task + * * @return name - * the local name of the task + * the local name of the task */ - public String getName() - { - return taskName; + public String getName() { + return taskName; } - + /** * Returns whether task should be distributed through containers - * + * * @return whether task should be distributed through containers */ - public boolean isDistributive() - { - return distributive; + public boolean isDistributive() { + return distributive; } - + /** * Returns whether task alters (mutates) it's target objects - * + * * @return whether task alters (mutates) it's target objects */ - public boolean isMutative() - { - return mutative; + public boolean isMutative() { + return mutative; } - - public Curator.Invoked getMode() - { - return mode; + + public Curator.Invoked getMode() { + return mode; } - - public int[] getCodes() - { - return codes; + + public int[] getCodes() { + return codes; } - + /** * Returns whether task is not scripted (curation task) - * + * * @return true if this task is not scripted */ - private boolean unscripted() - { - return sTask == null; + private boolean unscripted() { + return sTask == null; } } diff --git a/dspace-api/src/main/java/org/dspace/curate/ScriptedTask.java b/dspace-api/src/main/java/org/dspace/curate/ScriptedTask.java index 0e1d3ba8f9..7f63cb76dd 100644 --- a/dspace-api/src/main/java/org/dspace/curate/ScriptedTask.java +++ b/dspace-api/src/main/java/org/dspace/curate/ScriptedTask.java @@ -21,15 +21,14 @@ import org.dspace.core.Context; * * @author richardrodgers */ -public interface ScriptedTask -{ +public interface ScriptedTask { /** * Initialize task - parameters inform the task of it's invoking curator. * Since the curator can provide services to the task, this represents * curation DI. - * + * * @param curator the Curator controlling this task - * @param taskId identifier task should use in invoking services + * @param taskId identifier task should use in invoking services * @throws IOException if IO error */ public void init(Curator curator, String taskId) throws IOException; @@ -45,9 +44,9 @@ public interface ScriptedTask /** * Perform the curation task for passed id - * + * * @param ctx DSpace context object - * @param id persistent ID for DSpace object + * @param id persistent ID for DSpace object * @return status code * @throws IOException if IO error */ diff --git a/dspace-api/src/main/java/org/dspace/curate/Suspendable.java b/dspace-api/src/main/java/org/dspace/curate/Suspendable.java index 653eff4de2..20a0fd87d9 100644 --- a/dspace-api/src/main/java/org/dspace/curate/Suspendable.java +++ b/dspace-api/src/main/java/org/dspace/curate/Suspendable.java @@ -20,15 +20,15 @@ import java.lang.annotation.RetentionPolicy; * Thus, it effectively means that if a task is iterating over a collection, * the first error, or failure will halt the process. * This ensures that the status code and result of the failure are preserved. - * + * * @author richardrodgers */ @Documented @Retention(RetentionPolicy.RUNTIME) -public @interface Suspendable -{ +public @interface Suspendable { // by default, suspension occurs however task is invoked Curator.Invoked invoked() default Curator.Invoked.ANY; + // by default, either ERROR or FAILURE status codes trigger suspension int[] statusCodes() default {-1, 1}; } diff --git a/dspace-api/src/main/java/org/dspace/curate/TaskQueue.java b/dspace-api/src/main/java/org/dspace/curate/TaskQueue.java index e383aa6947..0423dbbfa5 100644 --- a/dspace-api/src/main/java/org/dspace/curate/TaskQueue.java +++ b/dspace-api/src/main/java/org/dspace/curate/TaskQueue.java @@ -21,49 +21,43 @@ import java.util.Set; * @author richardrodgers */ public interface TaskQueue { - + /** * Returns list of queue names. - * + * * @return queues - * the list of names of active queues + * the list of names of active queues */ String[] queueNames(); /** * Queues a single entry to a named queue. - * - * @param queueName - * the name of the queue on which to write - * @param entry - * the task entry + * + * @param queueName the name of the queue on which to write + * @param entry the task entry * @throws IOException if IO error */ void enqueue(String queueName, TaskQueueEntry entry) throws IOException; /** * Queues a set of task entries to a named queue. - * - * @param queueName - * the name of the queue on which to write - * @param entrySet - * the set of task entries + * + * @param queueName the name of the queue on which to write + * @param entrySet the set of task entries * @throws IOException if IO error */ void enqueue(String queueName, Set entrySet) throws IOException; - + /** * Returns the set of task entries from the named queue. The operation locks * the queue from any further enqueue or dequeue operations until a * release is called. The ticket may be any number, but a * timestamp should guarantee sufficient uniqueness. - * - * @param queueName - * the name of the queue to read - * @param ticket - * a token which must be presented to release the queue + * + * @param queueName the name of the queue to read + * @param ticket a token which must be presented to release the queue * @return set - * the current set of queued task entries + * the current set of queued task entries * @throws IOException if IO error */ Set dequeue(String queueName, long ticket) throws IOException; @@ -71,13 +65,10 @@ public interface TaskQueue { /** * Releases the lock upon the named queue, deleting it if removeEntries * is set to true. - * - * @param queueName - * the name of the queue to release - * @param ticket - * a token that was presented when queue was dequeued. - * @param removeEntries - * flag to indicate whether entries may be deleted + * + * @param queueName the name of the queue to release + * @param ticket a token that was presented when queue was dequeued. + * @param removeEntries flag to indicate whether entries may be deleted */ void release(String queueName, long ticket, boolean removeEntries); } diff --git a/dspace-api/src/main/java/org/dspace/curate/TaskQueueEntry.java b/dspace-api/src/main/java/org/dspace/curate/TaskQueueEntry.java index dcdf8374ca..f32816a1a9 100644 --- a/dspace-api/src/main/java/org/dspace/curate/TaskQueueEntry.java +++ b/dspace-api/src/main/java/org/dspace/curate/TaskQueueEntry.java @@ -13,107 +13,96 @@ import java.util.List; /** * TaskQueueEntry defines the record or entry in the named task queues. * Regular immutable value object class. - * + * * @author richardrodgers */ -public final class TaskQueueEntry -{ +public final class TaskQueueEntry { private final String epersonId; private final String submitTime; private final String tasks; private final String objId; - + /** * TaskQueueEntry constructor with enumerated field values. - * - * @param epersonId - * task owner - * @param submitTime - * time the task was submitted (System.currentTimeMillis()) - * @param taskNames - * list of task names - * @param objId - * usually a handle or workflow id + * + * @param epersonId task owner + * @param submitTime time the task was submitted (System.currentTimeMillis()) + * @param taskNames list of task names + * @param objId usually a handle or workflow id */ public TaskQueueEntry(String epersonId, long submitTime, - List taskNames, String objId) - { + List taskNames, String objId) { this.epersonId = epersonId; this.submitTime = Long.toString(submitTime); StringBuilder sb = new StringBuilder(); - for (String tName : taskNames) - { + for (String tName : taskNames) { sb.append(tName).append(","); } this.tasks = sb.substring(0, sb.length() - 1); this.objId = objId; } - + /** * Constructor with a pipe-separated list of field values. - * - * @param entry - * list of field values separated by '|'s + * + * @param entry list of field values separated by '|'s */ - public TaskQueueEntry(String entry) - { + public TaskQueueEntry(String entry) { String[] tokens = entry.split("\\|"); epersonId = tokens[0]; submitTime = tokens[1]; tasks = tokens[2]; objId = tokens[3]; } - + /** * Returns the epersonId (email) of the agent who enqueued this task entry. - * + * * @return epersonId - * name of EPerson (email) or 'unknown' if none recorded. + * name of EPerson (email) or 'unknown' if none recorded. */ - public String getEpersonId() - { + public String getEpersonId() { return epersonId; } - + /** * Returns the timestamp of when this entry was enqueued. - * + * * @return time - * Submission timestamp + * Submission timestamp */ - public long getSubmitTime() - { + public long getSubmitTime() { return Long.valueOf(submitTime); } - + /** * Return the list of tasks associated with this entry. - * + * * @return tasks - * the list of task names (Plugin names) + * the list of task names (Plugin names) */ - public List getTaskNames() - { + public List getTaskNames() { return Arrays.asList(tasks.split(",")); } - + /** * Returns the object identifier. + * * @return objId - * usually a handle or workflow id + * usually a handle or workflow id */ - public String getObjectId() - { + public String getObjectId() { return objId; } + /** * Returns a string representation of the entry + * * @return string - * pipe-separated field values + * pipe-separated field values */ @Override - public String toString() - { + public String toString() { return epersonId + "|" + submitTime + "|" + tasks + "|" + objId; } } diff --git a/dspace-api/src/main/java/org/dspace/curate/TaskResolver.java b/dspace-api/src/main/java/org/dspace/curate/TaskResolver.java index b640b5b8dd..706992093b 100644 --- a/dspace-api/src/main/java/org/dspace/curate/TaskResolver.java +++ b/dspace-api/src/main/java/org/dspace/curate/TaskResolver.java @@ -7,27 +7,25 @@ */ package org.dspace.curate; -import java.io.File; import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Properties; - import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.apache.log4j.Logger; - import org.dspace.core.factory.CoreServiceFactory; import org.dspace.services.factory.DSpaceServicesFactory; /** - * TaskResolver takes a logical name of a curation task and attempts to deliver + * TaskResolver takes a logical name of a curation task and attempts to deliver * a suitable implementation object. Supported implementation types include: * (1) Classpath-local Java classes configured and loaded via PluginService. * (2) Local script-based tasks, viz. coded in any scripting language whose @@ -43,238 +41,184 @@ import org.dspace.services.factory.DSpaceServicesFactory; * Each task has a 'descriptor' property with value syntax: * {@code ||} * An example property: - * + * * {@code linkchecker = ruby|rubytask.rb|LinkChecker.new} - * + * * This descriptor means that a 'ruby' script engine will be created, * a script file named 'rubytask.rb' in the directory {@code } will be - * loaded and the resolver will expect an evaluation of 'LinkChecker.new' will + * loaded and the resolver will expect an evaluation of 'LinkChecker.new' will * provide a correct implementation object. - * + * * Script files may embed their descriptors to facilitate deployment. * To accomplish this, a script must include the descriptor string with syntax: * {@code $td=} somewhere on a comment line. for example: - * + * * {@code My descriptor $td=ruby|rubytask.rb|LinkChecker.new} - * + * * For portability, the {@code } component may be omitted in this context. * Thus, {@code $td=ruby||LinkChecker.new} will be expanded to a descriptor * with the name of the embedding file. - * + * * @author richardrodgers */ -public class TaskResolver -{ - // logging service - private static Logger log = Logger.getLogger(TaskResolver.class); - - // base directory of task scripts & catalog name - protected static final String CATALOG = "task.catalog"; - protected final String scriptDir; - - // catalog of script tasks - protected Properties catalog; - - public TaskResolver() - { - scriptDir = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("curate.script.dir"); - } - - /** - * Installs a task script. Succeeds only if script: - * (1) exists in the configured script directory and - * (2) contains a recognizable descriptor in a comment line. - * If script lacks a descriptor, it may still be installed - * by manually invoking addDescriptor. - * - * @param taskName - * logical name of task to associate with script - * @param fileName - * name of file containing task script - * @return true if script installed, false if installation failed - */ - public boolean installScript(String taskName, String fileName) - { - // Can we locate the file in the script directory? - File script = new File(scriptDir, fileName); - if (script.exists()) - { - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(script)); - String line = null; - while((line = reader.readLine()) != null) - { - if (line.startsWith("#") && line.indexOf("$td=") > 0) - { - String desc = line.substring(line.indexOf("$td=") + 4); - // insert relFilePath if missing - String[] tokens = desc.split("\\|"); - if (tokens[1].length() == 0) - { - desc = tokens[0] + "|" + fileName + "|" + tokens[2]; - } - addDescriptor(taskName, desc); - return true; - } - } - } - catch(IOException ioE) - { - log.error("Error reading task script: " + fileName); - } - finally - { - if (reader != null) - { - try - { - reader.close(); - } - catch(IOException ioE) - { - log.error("Error closing task script: " + fileName); - } - } - } - } - else - { - log.error("Task script: " + fileName + "not found in: " + scriptDir); - } - return false; - } - - /** - * Adds a task descriptor property and flushes catalog to disk. - * - * @param taskName - * logical task name - * @param descriptor - * descriptor for task - */ - public void addDescriptor(String taskName, String descriptor) - { - loadCatalog(); - catalog.put(taskName, descriptor); - Writer writer = null; - try - { - writer = new FileWriter(new File(scriptDir, CATALOG)); - catalog.store(writer, "do not edit"); - } - catch(IOException ioE) - { - log.error("Error saving scripted task catalog: " + CATALOG); - } - finally - { - if (writer != null) - { - try - { - writer.close(); - } - catch (IOException ioE) - { - log.error("Error closing scripted task catalog: " + CATALOG); - } - } - } - } - - /** - * Returns a task implementation for a given task name, - * or null if no implementation could be obtained. - * - * @param taskName - * logical task name - * @return task - * an object that implements the CurationTask interface - */ - public ResolvedTask resolveTask(String taskName) - { - CurationTask ctask = (CurationTask)CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(CurationTask.class, taskName); - if (ctask != null) - { - return new ResolvedTask(taskName, ctask); - } - // maybe it is implemented by a script? - loadCatalog(); - String scriptDesc = catalog.getProperty(taskName); - if (scriptDesc != null) - { - String[] tokens = scriptDesc.split("\\|"); - // first descriptor token is name ('alias') of scripting engine - ScriptEngineManager mgr = new ScriptEngineManager(); - ScriptEngine engine = mgr.getEngineByName(tokens[0]); - if (engine != null) - { - // see if we can locate the script file and load it - // the second token is the relative path to the file - File script = new File(scriptDir, tokens[1]); - if (script.exists()) - { - try - { - Reader reader = new FileReader(script); - engine.eval(reader); - reader.close(); - // third token is the constructor expression for the class - // implementing CurationTask interface - ScriptedTask stask = (ScriptedTask)engine.eval(tokens[2]); - return new ResolvedTask(taskName, stask); - } - catch (FileNotFoundException fnfE) - { - log.error("Script: '" + script.getName() + "' not found for task: " + taskName); - } - catch (IOException ioE) - { - log.error("Error loading script: '" + script.getName() + "'"); - } - catch (ScriptException scE) - { - log.error("Error evaluating script: '" + script.getName() + "' msg: " + scE.getMessage()); - } - } - else - { - log.error("No script: '" + script.getName() + "' found for task: " + taskName); - } - } - else - { - log.error("Script engine: '" + tokens[0] + "' is not installed"); - } - } - return null; - } - - /** - * Loads catalog of descriptors for tasks if not already loaded - */ - protected void loadCatalog() - { - if (catalog == null) - { - catalog = new Properties(); - File catalogFile = new File(scriptDir, CATALOG); - if (catalogFile.exists()) - { - try - { - Reader reader = new FileReader(catalogFile); - catalog.load(reader); - reader.close(); - } - catch(IOException ioE) - { - log.error("Error loading scripted task catalog: " + CATALOG); - } - } - } - } +public class TaskResolver { + // logging service + private static Logger log = Logger.getLogger(TaskResolver.class); + + // base directory of task scripts & catalog name + protected static final String CATALOG = "task.catalog"; + protected final String scriptDir; + + // catalog of script tasks + protected Properties catalog; + + public TaskResolver() { + scriptDir = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("curate.script.dir"); + } + + /** + * Installs a task script. Succeeds only if script: + * (1) exists in the configured script directory and + * (2) contains a recognizable descriptor in a comment line. + * If script lacks a descriptor, it may still be installed + * by manually invoking addDescriptor. + * + * @param taskName logical name of task to associate with script + * @param fileName name of file containing task script + * @return true if script installed, false if installation failed + */ + public boolean installScript(String taskName, String fileName) { + // Can we locate the file in the script directory? + File script = new File(scriptDir, fileName); + if (script.exists()) { + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(script)); + String line = null; + while ((line = reader.readLine()) != null) { + if (line.startsWith("#") && line.indexOf("$td=") > 0) { + String desc = line.substring(line.indexOf("$td=") + 4); + // insert relFilePath if missing + String[] tokens = desc.split("\\|"); + if (tokens[1].length() == 0) { + desc = tokens[0] + "|" + fileName + "|" + tokens[2]; + } + addDescriptor(taskName, desc); + return true; + } + } + } catch (IOException ioE) { + log.error("Error reading task script: " + fileName); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ioE) { + log.error("Error closing task script: " + fileName); + } + } + } + } else { + log.error("Task script: " + fileName + "not found in: " + scriptDir); + } + return false; + } + + /** + * Adds a task descriptor property and flushes catalog to disk. + * + * @param taskName logical task name + * @param descriptor descriptor for task + */ + public void addDescriptor(String taskName, String descriptor) { + loadCatalog(); + catalog.put(taskName, descriptor); + Writer writer = null; + try { + writer = new FileWriter(new File(scriptDir, CATALOG)); + catalog.store(writer, "do not edit"); + } catch (IOException ioE) { + log.error("Error saving scripted task catalog: " + CATALOG); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException ioE) { + log.error("Error closing scripted task catalog: " + CATALOG); + } + } + } + } + + /** + * Returns a task implementation for a given task name, + * or null if no implementation could be obtained. + * + * @param taskName logical task name + * @return task + * an object that implements the CurationTask interface + */ + public ResolvedTask resolveTask(String taskName) { + CurationTask ctask = (CurationTask) CoreServiceFactory.getInstance().getPluginService() + .getNamedPlugin(CurationTask.class, taskName); + if (ctask != null) { + return new ResolvedTask(taskName, ctask); + } + // maybe it is implemented by a script? + loadCatalog(); + String scriptDesc = catalog.getProperty(taskName); + if (scriptDesc != null) { + String[] tokens = scriptDesc.split("\\|"); + // first descriptor token is name ('alias') of scripting engine + ScriptEngineManager mgr = new ScriptEngineManager(); + ScriptEngine engine = mgr.getEngineByName(tokens[0]); + if (engine != null) { + // see if we can locate the script file and load it + // the second token is the relative path to the file + File script = new File(scriptDir, tokens[1]); + if (script.exists()) { + try { + Reader reader = new FileReader(script); + engine.eval(reader); + reader.close(); + // third token is the constructor expression for the class + // implementing CurationTask interface + ScriptedTask stask = (ScriptedTask) engine.eval(tokens[2]); + return new ResolvedTask(taskName, stask); + } catch (FileNotFoundException fnfE) { + log.error("Script: '" + script.getName() + "' not found for task: " + taskName); + } catch (IOException ioE) { + log.error("Error loading script: '" + script.getName() + "'"); + } catch (ScriptException scE) { + log.error("Error evaluating script: '" + script.getName() + "' msg: " + scE.getMessage()); + } + } else { + log.error("No script: '" + script.getName() + "' found for task: " + taskName); + } + } else { + log.error("Script engine: '" + tokens[0] + "' is not installed"); + } + } + return null; + } + + /** + * Loads catalog of descriptors for tasks if not already loaded + */ + protected void loadCatalog() { + if (catalog == null) { + catalog = new Properties(); + File catalogFile = new File(scriptDir, CATALOG); + if (catalogFile.exists()) { + try { + Reader reader = new FileReader(catalogFile); + catalog.load(reader); + reader.close(); + } catch (IOException ioE) { + log.error("Error loading scripted task catalog: " + CATALOG); + } + } + } + } } diff --git a/dspace-api/src/main/java/org/dspace/curate/Utils.java b/dspace-api/src/main/java/org/dspace/curate/Utils.java index 01ca98e60b..16e351ef60 100644 --- a/dspace-api/src/main/java/org/dspace/curate/Utils.java +++ b/dspace-api/src/main/java/org/dspace/curate/Utils.java @@ -22,39 +22,35 @@ import java.security.NoSuchAlgorithmException; * * @author richardrodgers */ -public class Utils -{ +public class Utils { private static final int BUFF_SIZE = 4096; // we can live with 4k preallocation private static final byte[] buffer = new byte[BUFF_SIZE]; - + + /** + * Default constructor + */ + private Utils() { } + /** * Calculates and returns a checksum for the passed file using the passed * algorithm. - * - * @param file - * file on which to calculate checksum - * @param algorithm - * string for algorithm: 'MD5', 'SHA1', etc + * + * @param file file on which to calculate checksum + * @param algorithm string for algorithm: 'MD5', 'SHA1', etc * @return checksum - * string of the calculated checksum - * + * string of the calculated checksum * @throws IOException if IO error */ - public static String checksum(File file, String algorithm) throws IOException - { + public static String checksum(File file, String algorithm) throws IOException { InputStream in = null; String chkSum = null; - try - { + try { in = new FileInputStream(file); chkSum = checksum(in, algorithm); - } - finally - { - if (in != null) - { - in.close(); + } finally { + if (in != null) { + in.close(); } } return chkSum; @@ -63,28 +59,20 @@ public class Utils /** * Calculates and returns a checksum for the passed IO stream using the passed * algorithm. - * - * @param in - * input stream on which to calculate checksum - * @param algorithm - * string for algorithm: 'MD5', 'SHA1', etc + * + * @param in input stream on which to calculate checksum + * @param algorithm string for algorithm: 'MD5', 'SHA1', etc * @return checksum - * string of the calculated checksum - * + * string of the calculated checksum * @throws IOException if IO error */ - public static String checksum(InputStream in, String algorithm) throws IOException - { - try - { + public static String checksum(InputStream in, String algorithm) throws IOException { + try { DigestInputStream din = new DigestInputStream(in, - MessageDigest.getInstance(algorithm)); - while (true) - { - synchronized (buffer) - { - if (din.read(buffer) == -1) - { + MessageDigest.getInstance(algorithm)); + while (true) { + synchronized (buffer) { + if (din.read(buffer) == -1) { break; } // otherwise, a no-op @@ -98,15 +86,16 @@ public class Utils /** * Reasonably efficient Hex checksum converter - * + * * @param data - * byte array + * byte array * @return hexString - * checksum + * checksum */ static final char[] HEX_CHARS = "0123456789abcdef".toCharArray(); + public static String toHex(byte[] data) { - if ((data == null) || (data.length == 0)) { + if ((data == null) || (data.length == 0)) { return null; } char[] chars = new char[2 * data.length]; @@ -116,33 +105,27 @@ public class Utils } return new String(chars); } - + /** * Performs a buffered copy from one file into another. - * - * @param inFile input file + * + * @param inFile input file * @param outFile output file * @throws IOException if IO error */ - public static void copy(File inFile, File outFile) throws IOException - { + public static void copy(File inFile, File outFile) throws IOException { FileInputStream in = null; FileOutputStream out = null; - try - { + try { in = new FileInputStream(inFile); out = new FileOutputStream(outFile); copy(in, out); - } - finally - { - if (in != null) - { + } finally { + if (in != null) { in.close(); } - - if (out != null) - { + + if (out != null) { out.close(); } } @@ -151,22 +134,16 @@ public class Utils /** * Performs a buffered copy from one IO stream into another. Note that stream * closure is responsibility of caller. - * - * @param in - * input stream - * @param out - * output stream + * + * @param in input stream + * @param out output stream * @throws IOException if IO error */ - public static void copy(InputStream in, OutputStream out) throws IOException - { - while (true) - { - synchronized (buffer) - { + public static void copy(InputStream in, OutputStream out) throws IOException { + while (true) { + synchronized (buffer) { int count = in.read(buffer); - if (-1 == count) - { + if (-1 == count) { break; } // write out those same bytes diff --git a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java index dd94a24563..580f8c42c3 100644 --- a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java @@ -7,7 +7,10 @@ */ package org.dspace.curate; -import org.dspace.content.Item; +import static javax.xml.stream.XMLStreamConstants.CHARACTERS; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -21,9 +24,9 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.apache.log4j.Logger; - import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; +import org.dspace.content.Item; import org.dspace.content.service.CollectionService; import org.dspace.core.Context; import org.dspace.core.LogManager; @@ -41,25 +44,25 @@ import org.dspace.workflowbasic.service.BasicWorkflowService; import org.springframework.beans.factory.annotation.Autowired; // Warning - static import ahead! -import static javax.xml.stream.XMLStreamConstants.*; /** * WorkflowCurator manages interactions between curation and workflow. * Specifically, it is invoked in WorkflowManager to allow the * performance of curation tasks during workflow. - * + * * @author richardrodgers */ -public class WorkflowCuratorServiceImpl implements WorkflowCuratorService -{ - - /** log4j logger */ +public class WorkflowCuratorServiceImpl implements WorkflowCuratorService { + + /** + * log4j logger + */ private Logger log = Logger.getLogger(WorkflowCuratorServiceImpl.class); - + protected Map tsMap = new HashMap(); - - protected final String[] flowSteps = { "step1", "step2", "step3", "archive" }; + + protected final String[] flowSteps = {"step1", "step2", "step3", "archive"}; @Autowired(required = true) protected CollectionService collectionService; @@ -79,17 +82,16 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService * Ensures the configurationService is injected, so that we can read the * settings from configuration * Called by "init-method" in Spring config. + * * @throws Exception ... */ public void init() throws Exception { File cfgFile = new File(configurationService.getProperty("dspace.dir") + File.separator + "config" + File.separator + "workflow-curation.xml"); - try - { + try { loadTaskConfig(cfgFile); - if (workflowServiceFactory.getWorkflowService() instanceof BasicWorkflowItemService) - { + if (workflowServiceFactory.getWorkflowService() instanceof BasicWorkflowItemService) { basicWorkflowService = (BasicWorkflowService) workflowServiceFactory.getWorkflowService(); basicWorkflowItemService = (BasicWorkflowItemService) workflowServiceFactory.getWorkflowItemService(); } @@ -99,19 +101,18 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService } } - protected WorkflowCuratorServiceImpl() - { + protected WorkflowCuratorServiceImpl() { } @Override public boolean needsCuration(BasicWorkflowItem wfi) { - return getFlowStep(wfi) != null; + return getFlowStep(wfi) != null; } - + @Override public boolean doCuration(Context c, BasicWorkflowItem wfi) - throws AuthorizeException, IOException, SQLException { + throws AuthorizeException, IOException, SQLException { FlowStep step = getFlowStep(wfi); if (step != null) { Curator curator = new Curator(); @@ -129,11 +130,11 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService } return true; } - + @Override public boolean curate(Curator curator, Context c, String wfId) - throws AuthorizeException, IOException, SQLException { + throws AuthorizeException, IOException, SQLException { BasicWorkflowItem wfi = basicWorkflowItemService.find(c, Integer.parseInt(wfId)); if (wfi != null) { if (curate(curator, c, wfi)) { @@ -145,10 +146,10 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService } return false; } - + @Override public boolean curate(Curator curator, Context c, BasicWorkflowItem wfi) - throws AuthorizeException, IOException, SQLException { + throws AuthorizeException, IOException, SQLException { FlowStep step = getFlowStep(wfi); if (step != null) { // assign collection to item in case task needs it @@ -169,7 +170,7 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService // if task so empowered, reject submission and terminate if ("reject".equals(action)) { basicWorkflowService.sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), - null, task.name + ": " + result); + null, task.name + ": " + result); return false; } } else if (status == Curator.CURATE_SUCCESS) { @@ -189,19 +190,19 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService } return true; } - + protected void notifyContacts(Context c, BasicWorkflowItem wfi, Task task, - String status, String action, String message) - throws AuthorizeException, IOException, SQLException { + String status, String action, String message) + throws AuthorizeException, IOException, SQLException { List epa = resolveContacts(c, task.getContacts(status), wfi); if (epa.size() > 0) { basicWorkflowService.notifyOfCuration(c, wfi, epa, task.name, action, message); } } - + protected List resolveContacts(Context c, List contacts, - BasicWorkflowItem wfi) - throws AuthorizeException, IOException, SQLException { + BasicWorkflowItem wfi) + throws AuthorizeException, IOException, SQLException { List epList = new ArrayList(); for (String contact : contacts) { // decode contacts @@ -222,7 +223,7 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService } } else if ("$siteadmin".equals(contact)) { EPerson siteEp = ePersonService.findByEmail(c, - configurationService.getProperty("mail.admin")); + configurationService.getProperty("mail.admin")); if (siteEp != null) { epList.add(siteEp); } @@ -237,12 +238,12 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService Group group = groupService.findByName(c, contact); if (group != null) { epList.addAll(groupService.allMembers(c, group)); - } + } } } return epList; } - + protected FlowStep getFlowStep(BasicWorkflowItem wfi) { Collection coll = wfi.getCollection(); String key = tsMap.containsKey(coll.getHandle()) ? coll.getHandle() : "default"; @@ -257,23 +258,20 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService } return null; } - + protected int state2step(int state) { - if (state <= BasicWorkflowServiceImpl.WFSTATE_STEP1POOL) - { + if (state <= BasicWorkflowServiceImpl.WFSTATE_STEP1POOL) { return 1; } - if (state <= BasicWorkflowServiceImpl.WFSTATE_STEP2POOL) - { + if (state <= BasicWorkflowServiceImpl.WFSTATE_STEP2POOL) { return 2; } - if (state <= BasicWorkflowServiceImpl.WFSTATE_STEP3POOL) - { + if (state <= BasicWorkflowServiceImpl.WFSTATE_STEP3POOL) { return 3; } return 4; } - + protected int stepName2step(String name) { for (int i = 0; i < flowSteps.length; i++) { if (flowSteps[i].equals(name)) { @@ -284,7 +282,7 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService log.warn("Invalid step: '" + name + "' provided"); return -1; } - + protected void loadTaskConfig(File cfgFile) throws IOException { Map collMap = new HashMap(); Map setMap = new HashMap(); @@ -295,7 +293,7 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService try { XMLInputFactory factory = XMLInputFactory.newInstance(); XMLStreamReader reader = factory.createXMLStreamReader( - new FileInputStream(cfgFile), "UTF-8"); + new FileInputStream(cfgFile), "UTF-8"); while (reader.hasNext()) { int event = reader.next(); if (event == START_ELEMENT) { @@ -308,8 +306,8 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService } else if ("flowstep".equals(eName)) { int count = reader.getAttributeCount(); String queue = (count == 2) ? - reader.getAttributeValue(1) : null; - flowStep = new FlowStep(reader.getAttributeValue(0), queue); + reader.getAttributeValue(1) : null; + flowStep = new FlowStep(reader.getAttributeValue(0), queue); } else if ("task".equals(eName)) { task = new Task(reader.getAttributeValue(0)); } else if ("workflow".equals(eName)) { @@ -320,7 +318,7 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService } else if (event == CHARACTERS) { if (task != null) { if ("power".equals(type)) { - task.addPower(reader.getText()); + task.addPower(reader.getText()); } else { task.addContact(type, reader.getText()); } @@ -340,7 +338,7 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService reader.close(); // stitch maps together for (Map.Entry collEntry : collMap.entrySet()) { - if (! "none".equals(collEntry.getValue()) && setMap.containsKey(collEntry.getValue())) { + if (!"none".equals(collEntry.getValue()) && setMap.containsKey(collEntry.getValue())) { tsMap.put(collEntry.getKey(), setMap.get(collEntry.getValue())); } } @@ -352,55 +350,55 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService protected class TaskSet { public String setName = null; public List steps = null; - + public TaskSet(String setName) { this.setName = setName; steps = new ArrayList(); } - + public void addStep(FlowStep step) { steps.add(step); } } - + protected class FlowStep { public int step = -1; public String queue = null; public List tasks = null; - + public FlowStep(String stepStr, String queueStr) { this.step = stepName2step(stepStr); this.queue = queueStr; tasks = new ArrayList(); } - + public void addTask(Task task) { tasks.add(task); } } - + protected class Task { public String name = null; public List powers = new ArrayList(); public Map> contacts = new HashMap>(); - + public Task(String name) { this.name = name; } - + public void addPower(String power) { powers.add(power); } - + public void addContact(String status, String contact) { List sContacts = contacts.get(status); if (sContacts == null) { sContacts = new ArrayList(); contacts.put(status, sContacts); - } + } sContacts.add(contact); } - + public List getContacts(String status) { List ret = contacts.get(status); return (ret != null) ? ret : new ArrayList(); diff --git a/dspace-api/src/main/java/org/dspace/curate/factory/CurateServiceFactory.java b/dspace-api/src/main/java/org/dspace/curate/factory/CurateServiceFactory.java index bd6058bc55..2063979fd5 100644 --- a/dspace-api/src/main/java/org/dspace/curate/factory/CurateServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/curate/factory/CurateServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.curate.service.WorkflowCuratorService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the curate package, use CurateServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the curate package, use CurateServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class CurateServiceFactory { public abstract WorkflowCuratorService getWorkflowCuratorService(); - public static CurateServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("curateServiceFactory", CurateServiceFactory.class); + public static CurateServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("curateServiceFactory", CurateServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/curate/factory/CurateServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/curate/factory/CurateServiceFactoryImpl.java index 617e7cfe7a..ad2bca1238 100644 --- a/dspace-api/src/main/java/org/dspace/curate/factory/CurateServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/curate/factory/CurateServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.curate.service.WorkflowCuratorService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the curate package, use CurateServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the curate package, use CurateServiceFactory.getInstance() to retrieve + * an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/curate/service/WorkflowCuratorService.java b/dspace-api/src/main/java/org/dspace/curate/service/WorkflowCuratorService.java index 2240008e22..9f62baf664 100644 --- a/dspace-api/src/main/java/org/dspace/curate/service/WorkflowCuratorService.java +++ b/dspace-api/src/main/java/org/dspace/curate/service/WorkflowCuratorService.java @@ -7,14 +7,14 @@ */ package org.dspace.curate.service; +import java.io.IOException; +import java.sql.SQLException; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.curate.Curator; import org.dspace.workflowbasic.BasicWorkflowItem; -import java.io.IOException; -import java.sql.SQLException; - /** * WorkflowCurator manages interactions between curation and workflow. * Specifically, it is invoked in WorkflowManager to allow the @@ -30,47 +30,47 @@ public interface WorkflowCuratorService { /** * Determines and executes curation on a Workflow item. * - * @param c the context + * @param c the context * @param wfi the workflow item * @return true if curation was completed or not required, - * false if tasks were queued for later completion, - * or item was rejected + * false if tasks were queued for later completion, + * or item was rejected * @throws AuthorizeException if authorization error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error */ public boolean doCuration(Context c, BasicWorkflowItem wfi) - throws AuthorizeException, IOException, SQLException; + throws AuthorizeException, IOException, SQLException; /** * Determines and executes curation of a Workflow item. * * @param curator the Curator object - * @param c the user context - * @param wfId the workflow id + * @param c the user context + * @param wfId the workflow id * @return true if curation was completed or not required, - * false if no workflow item found for id - * or item was rejected + * false if no workflow item found for id + * or item was rejected * @throws AuthorizeException if authorization error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error */ public boolean curate(Curator curator, Context c, String wfId) - throws AuthorizeException, IOException, SQLException; + throws AuthorizeException, IOException, SQLException; /** * Determines and executes curation of a Workflow item. * * @param curator the Curator object - * @param c the user context - * @param wfi the workflow item + * @param c the user context + * @param wfi the workflow item * @return true if curation was completed or not required, - * false if item was rejected + * false if item was rejected * @throws AuthorizeException if authorization error - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error */ public boolean curate(Curator curator, Context c, BasicWorkflowItem wfi) - throws AuthorizeException, IOException, SQLException; + throws AuthorizeException, IOException, SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/discovery/DiscoverFacetField.java b/dspace-api/src/main/java/org/dspace/discovery/DiscoverFacetField.java index 5bbd52e1b4..12a573b3c7 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/DiscoverFacetField.java +++ b/dspace-api/src/main/java/org/dspace/discovery/DiscoverFacetField.java @@ -17,7 +17,7 @@ import org.dspace.discovery.configuration.DiscoveryConfigurationParameters; public class DiscoverFacetField { private String field; private int limit; - private int offset=-1; + private int offset = -1; /* The facet prefix, all facet values will have to start with the given prefix */ private String prefix; private String type; @@ -30,7 +30,8 @@ public class DiscoverFacetField { this.sortOrder = sortOrder; } - public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, int offset) { + public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, + int offset) { this.field = field; this.type = type; this.limit = limit; @@ -38,7 +39,8 @@ public class DiscoverFacetField { this.offset = offset; } - public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, String prefix) { + public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, + String prefix) { this.prefix = prefix; this.limit = limit; this.type = type; @@ -46,7 +48,8 @@ public class DiscoverFacetField { this.field = field; } - public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, String prefix, int offset) { + public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, + String prefix, int offset) { this.prefix = prefix; this.limit = limit; this.type = type; @@ -54,6 +57,7 @@ public class DiscoverFacetField { this.field = field; this.offset = offset; } + public String getField() { return field; } @@ -73,14 +77,12 @@ public class DiscoverFacetField { public DiscoveryConfigurationParameters.SORT getSortOrder() { return sortOrder; } - - public int getOffset() - { + + public int getOffset() { return offset; } - - public void setOffset(int offset) - { + + public void setOffset(int offset) { this.offset = offset; } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/DiscoverFilterQuery.java b/dspace-api/src/main/java/org/dspace/discovery/DiscoverFilterQuery.java index 8408320430..b1cf741b23 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/DiscoverFilterQuery.java +++ b/dspace-api/src/main/java/org/dspace/discovery/DiscoverFilterQuery.java @@ -14,7 +14,6 @@ package org.dspace.discovery; * The displayed value * * @author Kevin Van de Velde (kevin at atmire dot com) - * */ public class DiscoverFilterQuery { diff --git a/dspace-api/src/main/java/org/dspace/discovery/DiscoverHitHighlightingField.java b/dspace-api/src/main/java/org/dspace/discovery/DiscoverHitHighlightingField.java index d51d659cf0..4e5ea53fcb 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/DiscoverHitHighlightingField.java +++ b/dspace-api/src/main/java/org/dspace/discovery/DiscoverHitHighlightingField.java @@ -23,15 +23,13 @@ public class DiscoverHitHighlightingField { private int maxChars; private int maxSnippets; - public DiscoverHitHighlightingField(String field, int maxChars, int maxSnippets) - { + public DiscoverHitHighlightingField(String field, int maxChars, int maxSnippets) { this.field = field; this.maxChars = maxChars; this.maxSnippets = maxSnippets; } - public String getField() - { + public String getField() { return field; } @@ -43,16 +41,14 @@ public class DiscoverHitHighlightingField { * * @return max number of characters shown for a hit */ - public int getMaxChars() - { + public int getMaxChars() { return maxChars; } /** * @return max number of result snippets */ - public int getMaxSnippets() - { + public int getMaxSnippets() { return maxSnippets; } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/DiscoverQuery.java b/dspace-api/src/main/java/org/dspace/discovery/DiscoverQuery.java index 49758fff73..94a41f6195 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/DiscoverQuery.java +++ b/dspace-api/src/main/java/org/dspace/discovery/DiscoverQuery.java @@ -7,17 +7,28 @@ */ package org.dspace.discovery; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.collections4.CollectionUtils; +import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; /** * This class represents a query which the discovery backend can use * * @author Kevin Van de Velde (kevin at atmire dot com) - * */ public class DiscoverQuery { - /** Main attributes for the discovery query **/ + /** + * Main attributes for the discovery query + **/ private String query; private List filterQueries; private int DSpaceObjectFilter = -1; @@ -27,15 +38,20 @@ public class DiscoverQuery { private int start = 0; private int maxResults = -1; - /** Attributes used for sorting of results **/ + /** + * Attributes used for sorting of results + **/ public enum SORT_ORDER { desc, asc } + private String sortField; private SORT_ORDER sortOrder; - /** Attributes required for the faceting of values **/ + /** + * Attributes required for the faceting of values + **/ private List facetFields; private List facetQueries; private int facetLimit = -1; @@ -43,10 +59,14 @@ public class DiscoverQuery { private int facetOffset = 0; private Map hitHighlighting; - /** Used when you want to search for a specific field value **/ + /** + * Used when you want to search for a specific field value + **/ private List searchFields; - /** Misc attributes can be implementation dependent **/ + /** + * Misc attributes can be implementation dependent + **/ private Map> properties; public DiscoverQuery() { @@ -79,7 +99,7 @@ public class DiscoverQuery { this.start = start; } - public void setSortField(String sortField, SORT_ORDER sortOrder){ + public void setSortField(String sortField, SORT_ORDER sortOrder) { this.sortField = sortField; this.sortOrder = sortOrder; } @@ -95,6 +115,7 @@ public class DiscoverQuery { /** * Sets the DSpace object filter, must be an DSpace Object type integer * can be used to only return objects from a certain DSpace Object type + * * @param DSpaceObjectFilter the DSpace object filer */ public void setDSpaceObjectFilter(int DSpaceObjectFilter) { @@ -104,6 +125,7 @@ public class DiscoverQuery { /** * Gets the DSpace object filter * can be used to only return objects from a certain DSpace Object type + * * @return the DSpace object filer */ public int getDSpaceObjectFilter() { @@ -112,6 +134,7 @@ public class DiscoverQuery { /** * The maximum number of results returned by this query + * * @return the number of results */ public int getMaxResults() { @@ -120,6 +143,7 @@ public class DiscoverQuery { /** * Sets the maximum number of results by this query + * * @param maxResults the number of results */ public void setMaxResults(int maxResults) { @@ -128,14 +152,16 @@ public class DiscoverQuery { /** * Adds new filter queries + * * @param filterQueries the filter queries to be added */ - public void addFilterQueries(String ...filterQueries){ + public void addFilterQueries(String... filterQueries) { this.filterQueries.addAll(Arrays.asList(filterQueries)); } /** * Returns the filter queries + * * @return the filter queries in a list */ public List getFilterQueries() { @@ -144,9 +170,10 @@ public class DiscoverQuery { /** * Adds a query that will ensure that a certain field is present in the index + * * @param fieldPresentQueries the queries to be added */ - public void addFieldPresentQueries(String ...fieldPresentQueries){ + public void addFieldPresentQueries(String... fieldPresentQueries) { this.fieldPresentQueries.addAll(Arrays.asList(fieldPresentQueries)); } @@ -156,14 +183,16 @@ public class DiscoverQuery { /** * Adds a new facet query + * * @param facetQuery the new facet query to be added */ - public void addFacetQuery(String facetQuery){ + public void addFacetQuery(String facetQuery) { this.facetQueries.add(facetQuery); } /** * Returns the facet queries + * * @return the facet queries for this query */ public List getFacetQueries() { @@ -172,14 +201,16 @@ public class DiscoverQuery { /** * Adds a new facet field + * * @param facetField the new facet field to be added */ - public void addFacetField(DiscoverFacetField facetField){ + public void addFacetField(DiscoverFacetField facetField) { facetFields.add(facetField); } /** * Gets the facets fields configured + * * @return the facet fields for this query */ public List getFacetFields() { @@ -188,6 +219,7 @@ public class DiscoverQuery { /** * Gets the minimum number of values that need to be present before a valid facet value has been found + * * @return facetMinCount the minimum number of values to be present for a valid facet */ public int getFacetMinCount() { @@ -196,6 +228,7 @@ public class DiscoverQuery { /** * Set the minimum number of values that need to be present before a valid facet value has been found + * * @param facetMinCount the minimum number of values to be present for a valid facet */ public void setFacetMinCount(int facetMinCount) { @@ -204,6 +237,7 @@ public class DiscoverQuery { /** * Gets the facet field offset + * * @return the facet field offset */ public int getFacetOffset() { @@ -212,6 +246,7 @@ public class DiscoverQuery { /** * Sets the facet field offset, one facet offset will be used for all the facet fields + * * @param facetOffset an integer representing the offset */ public void setFacetOffset(int facetOffset) { @@ -222,14 +257,16 @@ public class DiscoverQuery { * Sets the fields which you want Discovery to return in the search results. * It is HIGHLY recommended to limit the fields returned, as by default * some backends (like Solr) will return everything. + * * @param field field to add to the list of fields returned */ - public void addSearchField(String field){ + public void addSearchField(String field) { this.searchFields.add(field); } /** * Get list of fields which Discovery will return in the search results + * * @return List of field names */ public List getSearchFields() { @@ -238,6 +275,7 @@ public class DiscoverQuery { /** * Returns the misc search properties + * * @return a map containing the properties */ public Map> getProperties() { @@ -246,13 +284,13 @@ public class DiscoverQuery { /** * Adds a new search property to the misc search properties + * * @param property the name of the property - * @param value the value of the property + * @param value the value of the property */ - public void addProperty(String property, String value){ + public void addProperty(String property, String value) { List toAddList = properties.get(property); - if(toAddList == null) - { + if (toAddList == null) { toAddList = new ArrayList(); } @@ -261,18 +299,15 @@ public class DiscoverQuery { properties.put(property, toAddList); } - public DiscoverHitHighlightingField getHitHighlightingField(String field) - { + public DiscoverHitHighlightingField getHitHighlightingField(String field) { return hitHighlighting.get(field); } - public List getHitHighlightingFields() - { + public List getHitHighlightingFields() { return new ArrayList(hitHighlighting.values()); } - public void addHitHighlightingField(DiscoverHitHighlightingField hitHighlighting) - { + public void addHitHighlightingField(DiscoverHitHighlightingField hitHighlighting) { this.hitHighlighting.put(hitHighlighting.getField(), hitHighlighting); } @@ -283,4 +318,62 @@ public class DiscoverQuery { public void setSpellCheck(boolean spellCheck) { this.spellCheck = spellCheck; } + + public void addYearRangeFacet(DiscoverySearchFilterFacet facet, FacetYearRange facetYearRange) { + if (facetYearRange.isValid()) { + + int newestYear = facetYearRange.getNewestYear(); + int oldestYear = facetYearRange.getOldestYear(); + String dateFacet = facetYearRange.getDateFacet(); + int gap = facetYearRange.getYearGap(); + + // We need to determine our top year so we can start our count from a clean year + // Example: 2001 and a gap from 10 we need the following result: 2010 - 2000 ; 2000 - 1990 hence the top + // year + int topYear = getTopYear(newestYear, gap); + if (gap == 1) { + //We need a list of our years + //We have a date range add faceting for our field + //The faceting will automatically be limited to the 10 years in our span due to our filterquery + this.addFacetField(new DiscoverFacetField(facet.getIndexFieldName(), facet.getType(), 10, + facet.getSortOrderSidebar())); + } else { + List facetQueries = buildFacetQueriesWithGap(newestYear, oldestYear, dateFacet, gap, topYear, + facet.getFacetLimit()); + for (String facetQuery : CollectionUtils.emptyIfNull(facetQueries)) { + this.addFacetQuery(facetQuery); + } + } + } + } + + private List buildFacetQueriesWithGap(int newestYear, int oldestYear, String dateFacet, int gap, + int topYear, int facetLimit) { + List facetQueries = new LinkedList<>(); + for (int year = topYear; year > oldestYear && (facetQueries.size() < facetLimit); year -= gap) { + //Add a filter to remove the last year only if we aren't the last year + int bottomYear = year - gap; + //Make sure we don't go below our last year found + if (bottomYear < oldestYear) { + bottomYear = oldestYear; + } + + //Also make sure we don't go above our newest year + int currentTop = year; + if ((year == topYear)) { + currentTop = newestYear; + } else { + //We need to do -1 on this one to get a better result + currentTop--; + } + facetQueries.add(dateFacet + ":[" + bottomYear + " TO " + currentTop + "]"); + } + Collections.reverse(facetQueries); + return facetQueries; + } + + private int getTopYear(int newestYear, int gap) { + return (int) (Math.ceil((float) (newestYear) / gap) * gap); + } + } diff --git a/dspace-api/src/main/java/org/dspace/discovery/DiscoverResult.java b/dspace-api/src/main/java/org/dspace/discovery/DiscoverResult.java index 62389a17c8..9004b27f95 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/DiscoverResult.java +++ b/dspace-api/src/main/java/org/dspace/discovery/DiscoverResult.java @@ -7,9 +7,17 @@ */ package org.dspace.discovery; -import org.dspace.content.DSpaceObject; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; -import java.util.*; +import org.apache.commons.collections4.ListUtils; +import org.dspace.content.DSpaceObject; +import org.dspace.discovery.configuration.DiscoveryConfigurationParameters; +import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; /** * This class represents the result that the discovery search impl returns @@ -22,7 +30,9 @@ public class DiscoverResult { private int start; private List dspaceObjects; private Map> facetResults; - /** A map that contains all the documents sougth after, the key is a string representation of the DSpace object */ + /** + * A map that contains all the documents sougth after, the key is a string representation of the DSpace object + */ private Map> searchDocuments; private int maxResults = -1; private int searchTime; @@ -38,7 +48,7 @@ public class DiscoverResult { } - public void addDSpaceObject(DSpaceObject dso){ + public void addDSpaceObject(DSpaceObject dso) { this.dspaceObjects.add(dso); } @@ -70,20 +80,17 @@ public class DiscoverResult { this.maxResults = maxResults; } - public int getSearchTime() - { + public int getSearchTime() { return searchTime; } - public void setSearchTime(int searchTime) - { + public void setSearchTime(int searchTime) { this.searchTime = searchTime; } - public void addFacetResult(String facetField, FacetResult ...facetResults){ + public void addFacetResult(String facetField, FacetResult... facetResults) { List facetValues = this.facetResults.get(facetField); - if(facetValues == null) - { + if (facetValues == null) { facetValues = new ArrayList(); } facetValues.addAll(Arrays.asList(facetResults)); @@ -94,33 +101,43 @@ public class DiscoverResult { return facetResults; } - public List getFacetResult(String facet){ - return facetResults.get(facet) == null ? new ArrayList() : facetResults.get(facet); + public List getFacetResult(String facet) { + return ListUtils.emptyIfNull(facetResults.get(facet)); } - public DSpaceObjectHighlightResult getHighlightedResults(DSpaceObject dso) - { + public List getFacetResult(DiscoverySearchFilterFacet field) { + List facetValues = getFacetResult(field.getIndexFieldName()); + //Check if we are dealing with a date, sometimes the facet values arrive as dates ! + if (facetValues.size() == 0 && field.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) { + facetValues = getFacetResult(field.getIndexFieldName() + ".year"); + } + return ListUtils.emptyIfNull(facetValues); + } + + public DSpaceObjectHighlightResult getHighlightedResults(DSpaceObject dso) { return highlightedResults.get(dso.getHandle()); } - public void addHighlightedResult(DSpaceObject dso, DSpaceObjectHighlightResult highlightedResult) - { + public void addHighlightedResult(DSpaceObject dso, DSpaceObjectHighlightResult highlightedResult) { this.highlightedResults.put(dso.getHandle(), highlightedResult); } - public static final class FacetResult{ + public static final class FacetResult { private String asFilterQuery; private String displayedValue; private String authorityKey; private String sortValue; private long count; + private String fieldType; - public FacetResult(String asFilterQuery, String displayedValue, String authorityKey, String sortValue, long count) { + public FacetResult(String asFilterQuery, String displayedValue, String authorityKey, String sortValue, + long count, String fieldType) { this.asFilterQuery = asFilterQuery; this.displayedValue = displayedValue; this.authorityKey = authorityKey; this.sortValue = sortValue; this.count = count; + this.fieldType = fieldType; } public String getAsFilterQuery() { @@ -131,23 +148,24 @@ public class DiscoverResult { return displayedValue; } - public String getSortValue() - { + public String getSortValue() { return sortValue; } - + public long getCount() { return count; } - public String getAuthorityKey() - { + public String getAuthorityKey() { return authorityKey; } - public String getFilterType() - { - return authorityKey != null?"authority":"equals"; + public String getFilterType() { + return authorityKey != null ? "authority" : "equals"; + } + + public String getFieldType() { + return fieldType; } } @@ -159,32 +177,32 @@ public class DiscoverResult { this.spellCheckQuery = spellCheckQuery; } - public static final class DSpaceObjectHighlightResult - { + public static final class DSpaceObjectHighlightResult { private DSpaceObject dso; private Map> highlightResults; - public DSpaceObjectHighlightResult(DSpaceObject dso, Map> highlightResults) - { + public DSpaceObjectHighlightResult(DSpaceObject dso, Map> highlightResults) { this.dso = dso; this.highlightResults = highlightResults; } - public DSpaceObject getDso() - { + public DSpaceObject getDso() { return dso; } - public List getHighlightResults(String metadataKey) - { + public List getHighlightResults(String metadataKey) { return highlightResults.get(metadataKey); } + + public Map> getHighlightResults() { + return highlightResults; + } } - public void addSearchDocument(DSpaceObject dso, SearchDocument searchDocument){ + public void addSearchDocument(DSpaceObject dso, SearchDocument searchDocument) { String dsoString = SearchDocument.getDspaceObjectStringRepresentation(dso); List docs = searchDocuments.get(dsoString); - if(docs == null){ + if (docs == null) { docs = new ArrayList(); } docs.add(searchDocument); @@ -192,16 +210,17 @@ public class DiscoverResult { } /** - * Returns all the sought after search document values + * Returns all the sought after search document values + * * @param dso the dspace object we want our search documents for * @return the search documents list */ - public List getSearchDocument(DSpaceObject dso){ + public List getSearchDocument(DSpaceObject dso) { String dsoString = SearchDocument.getDspaceObjectStringRepresentation(dso); List result = searchDocuments.get(dsoString); - if(result == null){ + if (result == null) { return new ArrayList(); - }else{ + } else { return result; } } @@ -209,16 +228,16 @@ public class DiscoverResult { /** * This class contains values from the fields searched for in DiscoveryQuery.java */ - public static final class SearchDocument{ + public static final class SearchDocument { private Map> searchFields; public SearchDocument() { this.searchFields = new LinkedHashMap>(); } - public void addSearchField(String field, String ...values){ - ListsearchFieldValues = searchFields.get(field); - if(searchFieldValues == null){ + public void addSearchField(String field, String... values) { + List searchFieldValues = searchFields.get(field); + if (searchFieldValues == null) { searchFieldValues = new ArrayList(); } searchFieldValues.addAll(Arrays.asList(values)); @@ -229,14 +248,15 @@ public class DiscoverResult { return searchFields; } - public List getSearchFieldValues(String field){ - if(searchFields.get(field) == null) + public List getSearchFieldValues(String field) { + if (searchFields.get(field) == null) { return new ArrayList(); - else + } else { return searchFields.get(field); + } } - public static String getDspaceObjectStringRepresentation(DSpaceObject dso){ + public static String getDspaceObjectStringRepresentation(DSpaceObject dso) { return dso.getType() + ":" + dso.getID(); } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/FacetYearRange.java b/dspace-api/src/main/java/org/dspace/discovery/FacetYearRange.java new file mode 100644 index 0000000000..311d1814c5 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/discovery/FacetYearRange.java @@ -0,0 +1,153 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.discovery; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; +import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; + +/** + * Utilty class that represents the year range for a date facet + */ +public class FacetYearRange { + private static final Pattern PATTERN = Pattern.compile("\\[(.*? TO .*?)\\]"); + + private DiscoverySearchFilterFacet facet; + private String dateFacet; + private int oldestYear = -1; + private int newestYear = -1; + + public FacetYearRange(DiscoverySearchFilterFacet facet) { + this.facet = facet; + } + + public String getDateFacet() { + return dateFacet; + } + + public int getOldestYear() { + return oldestYear; + } + + public int getNewestYear() { + return newestYear; + } + + public boolean isValid() { + return oldestYear != -1 && newestYear != -1; + } + + public void calculateRange(Context context, List filterQueries, DSpaceObject scope, + SearchService searchService) throws SearchServiceException { + dateFacet = facet.getIndexFieldName() + ".year"; + //Get a range query so we can create facet queries ranging from our first to our last date + //Attempt to determine our oldest & newest year by checking for previously selected filters + lookupPreviousRangeInFilterQueries(filterQueries); + + //Check if we have found a range, if not then retrieve our first & last year using Solr + if (oldestYear == -1 && newestYear == -1) { + calculateNewRangeBasedOnSearchIndex(context, filterQueries, scope, searchService); + } + } + + private void lookupPreviousRangeInFilterQueries(List filterQueries) { + for (String filterQuery : filterQueries) { + if (filterQuery.startsWith(dateFacet + ":")) { + //Check for a range + Matcher matcher = PATTERN.matcher(filterQuery); + boolean hasPattern = matcher.find(); + if (hasPattern) { + filterQuery = matcher.group(0); + //We have a range + //Resolve our range to a first & last year + int tempOldYear = Integer.parseInt(filterQuery.split(" TO ")[0].replace("[", "").trim()); + int tempNewYear = Integer.parseInt(filterQuery.split(" TO ")[1].replace("]", "").trim()); + + //Check if we have a further filter (or a first one found) + if (tempNewYear < newestYear || oldestYear < tempOldYear || newestYear == -1) { + oldestYear = tempOldYear; + newestYear = tempNewYear; + } + + } else { + if (filterQuery.indexOf(" OR ") != -1) { + //Should always be the case + filterQuery = filterQuery.split(" OR ")[0]; + } + //We should have a single date + oldestYear = Integer.parseInt(filterQuery.split(":")[1].trim()); + newestYear = oldestYear; + //No need to look further + break; + } + } + } + } + + private void calculateNewRangeBasedOnSearchIndex(Context context, List filterQueries, DSpaceObject scope, + SearchService searchService) throws SearchServiceException { + DiscoverQuery yearRangeQuery = new DiscoverQuery(); + yearRangeQuery.setMaxResults(1); + //Set our query to anything that has this value + yearRangeQuery.addFieldPresentQueries(dateFacet); + //Set sorting so our last value will appear on top + yearRangeQuery.setSortField(dateFacet + "_sort", DiscoverQuery.SORT_ORDER.asc); + yearRangeQuery.addFilterQueries(filterQueries.toArray(new String[filterQueries.size()])); + yearRangeQuery.addSearchField(dateFacet); + DiscoverResult lastYearResult = searchService.search(context, scope, yearRangeQuery); + + if (0 < lastYearResult.getDspaceObjects().size()) { + List searchDocuments = lastYearResult + .getSearchDocument(lastYearResult.getDspaceObjects().get(0)); + if (0 < searchDocuments.size() && 0 < searchDocuments.get(0).getSearchFieldValues(dateFacet).size()) { + oldestYear = Integer.parseInt(searchDocuments.get(0).getSearchFieldValues(dateFacet).get(0)); + } + } + //Now get the first year + yearRangeQuery.setSortField(dateFacet + "_sort", DiscoverQuery.SORT_ORDER.desc); + DiscoverResult firstYearResult = searchService.search(context, scope, yearRangeQuery); + if (0 < firstYearResult.getDspaceObjects().size()) { + List searchDocuments = firstYearResult + .getSearchDocument(firstYearResult.getDspaceObjects().get(0)); + if (0 < searchDocuments.size() && 0 < searchDocuments.get(0).getSearchFieldValues(dateFacet).size()) { + newestYear = Integer.parseInt(searchDocuments.get(0).getSearchFieldValues(dateFacet).get(0)); + } + } + } + + public int getYearGap() { + int gap = 1; + //Attempt to retrieve our gap using the algorithm below + int yearDifference = newestYear - oldestYear; + if (yearDifference != 0) { + gap = round((double) yearDifference / facet.getFacetLimit(), 10); + } + return gap; + } + + private int round(double number, int multiple) { + + int result = new Double(Math.ceil(number)).intValue(); + + //If not already multiple of given number + + if (result % multiple != 0) { + + int division = (result / multiple) + 1; + + result = division * multiple; + + } + + return result; + } +} diff --git a/dspace-api/src/main/java/org/dspace/discovery/FullTextContentStreams.java b/dspace-api/src/main/java/org/dspace/discovery/FullTextContentStreams.java index 45559396cb..933ba459cb 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/FullTextContentStreams.java +++ b/dspace-api/src/main/java/org/dspace/discovery/FullTextContentStreams.java @@ -7,9 +7,24 @@ */ package org.dspace.discovery; +import static org.dspace.core.Utils.emptyIfNull; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.SequenceInputStream; +import java.nio.charset.StandardCharsets; +import java.sql.SQLException; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import javax.annotation.Nullable; + import com.google.common.base.Function; import com.google.common.collect.Iterables; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.Charsets; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -23,22 +38,10 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.core.Context; -import javax.annotation.Nullable; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.sql.SQLException; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import static org.dspace.core.Utils.emptyIfNull; - /** * Construct a ContentStream from a File */ -public class FullTextContentStreams extends ContentStreamBase -{ +public class FullTextContentStreams extends ContentStreamBase { private static final Logger log = Logger.getLogger(FullTextContentStreams.class); public static final String FULLTEXT_BUNDLE = "TEXT"; @@ -55,7 +58,7 @@ public class FullTextContentStreams extends ContentStreamBase protected void init(Item parentItem) { fullTextStreams = new LinkedList<>(); - if(parentItem != null) { + if (parentItem != null) { sourceInfo = parentItem.getHandle(); //extracted full text is always extracted as plain text @@ -79,9 +82,9 @@ public class FullTextContentStreams extends ContentStreamBase fullTextStreams.add(new FullTextBitstream(sourceInfo, fulltextBitstream)); log.debug("Added BitStream: " - + fulltextBitstream.getStoreNumber() + " " - + fulltextBitstream.getSequenceID() + " " - + fulltextBitstream.getName()); + + fulltextBitstream.getStoreNumber() + " " + + fulltextBitstream.getSequenceID() + " " + + fulltextBitstream.getName()); } } } @@ -102,14 +105,15 @@ public class FullTextContentStreams extends ContentStreamBase public Long getSize() { long result = 0; - if(CollectionUtils.isNotEmpty(fullTextStreams)) { - Iterable individualSizes = Iterables.transform(fullTextStreams, new Function() { - @Nullable - @Override - public Long apply(@Nullable FullTextBitstream input) { - return input == null ? 0L : input.getSize(); - } - }); + if (CollectionUtils.isNotEmpty(fullTextStreams)) { + Iterable individualSizes = Iterables + .transform(fullTextStreams, new Function() { + @Nullable + @Override + public Long apply(@Nullable FullTextBitstream input) { + return input == null ? 0L : input.getSize(); + } + }); for (Long size : individualSizes) { result += size; @@ -139,7 +143,7 @@ public class FullTextContentStreams extends ContentStreamBase } private BitstreamService getBitstreamService() { - if(bitstreamService == null) { + if (bitstreamService == null) { bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); } return bitstreamService; @@ -164,7 +168,7 @@ public class FullTextContentStreams extends ContentStreamBase } public long getSize() { - return bitstream.getSize(); + return bitstream.getSizeBytes(); } public InputStream getInputStream() throws SQLException, IOException, AuthorizeException { @@ -197,14 +201,15 @@ public class FullTextContentStreams extends ContentStreamBase inputStream = bitstream.getInputStream(); } catch (Exception e) { log.warn("Unable to add full text bitstream " + (bitstream == null ? "NULL" : - bitstream.getFileName() + " for item " + bitstream.getItemHandle()) - + " to SOLR:" + e.getMessage(), e); + bitstream.getFileName() + " for item " + bitstream.getItemHandle()) + + " to SOLR:" + e.getMessage(), e); - inputStream = new ByteArrayInputStream((e.getClass() + ": " + e.getMessage()).getBytes(StandardCharsets.UTF_8)); + inputStream = new ByteArrayInputStream( + (e.getClass() + ": " + e.getMessage()).getBytes(StandardCharsets.UTF_8)); } return inputStream == null ? null : new SequenceInputStream( - new ByteArrayInputStream("\n".getBytes(Charsets.UTF_8)), inputStream); + new ByteArrayInputStream("\n".getBytes(Charsets.UTF_8)), inputStream); } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/IndexClient.java b/dspace-api/src/main/java/org/dspace/discovery/IndexClient.java index ce815aa137..7aaf63fe2d 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/IndexClient.java +++ b/dspace-api/src/main/java/org/dspace/discovery/IndexClient.java @@ -7,8 +7,16 @@ */ package org.dspace.discovery; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; -import org.apache.commons.cli.*; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; @@ -20,10 +28,6 @@ import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.services.factory.DSpaceServicesFactory; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; - /** * Class used to reindex dspace communities/collections/items into discovery * @@ -33,18 +37,20 @@ import java.util.Iterator; */ public class IndexClient { - private static final Logger log = Logger.getLogger(IndexClient.class); + /** + * Default constructor + */ + private IndexClient() { } + /** * When invoked as a command-line tool, creates, updates, removes content * from the whole index * * @param args the command-line arguments, none used - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. * @throws SearchServiceException if something went wrong with querying the solr server */ public static void main(String[] args) throws SQLException, IOException, SearchServiceException { @@ -52,57 +58,58 @@ public class IndexClient { Context context = new Context(Context.Mode.READ_ONLY); context.turnOffAuthorisationSystem(); - String usage = "org.dspace.discovery.IndexClient [-cbhf] | [-r ] | [-i ] or nothing to update/clean an existing index."; + String usage = "org.dspace.discovery.IndexClient [-cbhf] | [-r ] | [-i ] or nothing to " + + "update/clean an existing index."; Options options = new Options(); HelpFormatter formatter = new HelpFormatter(); CommandLine line = null; options.addOption(OptionBuilder - .withArgName("handle to remove") - .hasArg(true) - .withDescription( - "remove an Item, Collection or Community from index based on its handle") - .create("r")); + .withArgName("handle to remove") + .hasArg(true) + .withDescription( + "remove an Item, Collection or Community from index based on its handle") + .create("r")); options.addOption(OptionBuilder - .withArgName("handle to add or update") - .hasArg(true) - .withDescription( - "add or update an Item, Collection or Community based on its handle") - .create("i")); + .withArgName("handle to add or update") + .hasArg(true) + .withDescription( + "add or update an Item, Collection or Community based on its handle") + .create("i")); options.addOption(OptionBuilder - .isRequired(false) - .withDescription( - "clean existing index removing any documents that no longer exist in the db") - .create("c")); + .isRequired(false) + .withDescription( + "clean existing index removing any documents that no longer exist in the db") + .create("c")); options.addOption(OptionBuilder - .isRequired(false) - .withDescription( - "(re)build index, wiping out current one if it exists") - .create("b")); + .isRequired(false) + .withDescription( + "(re)build index, wiping out current one if it exists") + .create("b")); options.addOption(OptionBuilder - .isRequired(false) - .withDescription( - "Rebuild the spellchecker, can be combined with -b and -f.") - .create("s")); + .isRequired(false) + .withDescription( + "Rebuild the spellchecker, can be combined with -b and -f.") + .create("s")); options.addOption(OptionBuilder - .isRequired(false) - .withDescription( - "if updating existing index, force each handle to be reindexed even if uptodate") - .create("f")); + .isRequired(false) + .withDescription( + "if updating existing index, force each handle to be reindexed even if uptodate") + .create("f")); options.addOption(OptionBuilder - .isRequired(false) - .withDescription( - "print this help message") - .create("h")); + .isRequired(false) + .withDescription( + "print this help message") + .create("h")); options.addOption(OptionBuilder.isRequired(false).withDescription( - "optimize search core").create("o")); + "optimize search core").create("o")); try { line = new PosixParser().parse(options, args); @@ -145,14 +152,15 @@ public class IndexClient { checkRebuildSpellCheck(line, indexer); } else if (line.hasOption('i')) { final String handle = line.getOptionValue('i'); - final DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, handle); + final DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService() + .resolveToObject(context, handle); if (dso == null) { throw new IllegalArgumentException("Cannot resolve " + handle + " to a DSpace object"); } log.info("Forcibly Indexing " + handle); final long startTimeMillis = System.currentTimeMillis(); - final long count = indexAll(indexer, ContentServiceFactory.getInstance().getItemService(), context, dso); - final long seconds = (System.currentTimeMillis() - startTimeMillis ) / 1000; + final long count = indexAll(indexer, ContentServiceFactory.getInstance().getItemService(), context, dso); + final long seconds = (System.currentTimeMillis() - startTimeMillis) / 1000; log.info("Indexed " + count + " DSpace object" + (count > 1 ? "s" : "") + " in " + seconds + " seconds"); } else { log.info("Updating and Cleaning Index"); @@ -168,25 +176,18 @@ public class IndexClient { * Indexes the given object and all children, if applicable. * * @param indexingService - * * @param itemService - * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to index recursively - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param context The relevant DSpace Context. + * @param dso DSpace object to index recursively + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. * @throws SearchServiceException in case of a solr exception - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ private static long indexAll(final IndexingService indexingService, final ItemService itemService, final Context context, final DSpaceObject dso) - throws IOException, SearchServiceException, SQLException - { + throws IOException, SearchServiceException, SQLException { long count = 0; indexingService.indexContent(context, dso, true, true); @@ -199,7 +200,9 @@ public class IndexClient { //To prevent memory issues, discard an object from the cache after processing context.uncacheEntity(subcommunity); } - final Community reloadedCommunity = (Community) HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, communityHandle); + final Community reloadedCommunity = (Community) HandleServiceFactory.getInstance().getHandleService() + .resolveToObject(context, + communityHandle); for (final Collection collection : reloadedCommunity.getCollections()) { count++; indexingService.indexContent(context, collection, true, true); @@ -218,25 +221,18 @@ public class IndexClient { * Indexes all items in the given collection. * * @param indexingService - * * @param itemService - * - * @param context - * The relevant DSpace Context. - * @param collection - * collection to index - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param context The relevant DSpace Context. + * @param collection collection to index + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. * @throws SearchServiceException in case of a solr exception - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ private static long indexItems(final IndexingService indexingService, final ItemService itemService, final Context context, final Collection collection) - throws IOException, SearchServiceException, SQLException - { + throws IOException, SearchServiceException, SQLException { long count = 0; final Iterator itemIterator = itemService.findByCollection(context, collection); @@ -254,13 +250,13 @@ public class IndexClient { /** * Check the command line options and rebuild the spell check if active. - * @param line the command line options + * + * @param line the command line options * @param indexer the solr indexer * @throws SearchServiceException in case of a solr exception */ protected static void checkRebuildSpellCheck(CommandLine line, IndexingService indexer) - throws SearchServiceException - { + throws SearchServiceException { if (line.hasOption("s")) { log.info("Rebuilding spell checker."); indexer.buildSpellCheck(); diff --git a/dspace-api/src/main/java/org/dspace/discovery/IndexEventConsumer.java b/dspace-api/src/main/java/org/dspace/discovery/IndexEventConsumer.java index 42885ffa3f..d8ec35806e 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/IndexEventConsumer.java +++ b/dspace-api/src/main/java/org/dspace/discovery/IndexEventConsumer.java @@ -7,6 +7,9 @@ */ package org.dspace.discovery; +import java.util.HashSet; +import java.util.Set; + import org.apache.log4j.Logger; import org.dspace.content.Bundle; import org.dspace.content.DSpaceObject; @@ -16,9 +19,6 @@ import org.dspace.event.Consumer; import org.dspace.event.Event; import org.dspace.services.factory.DSpaceServicesFactory; -import java.util.HashSet; -import java.util.Set; - /** * Class for updating search indices in discovery from content events. * @@ -38,7 +38,9 @@ public class IndexEventConsumer implements Consumer { // handles to delete since IDs are not useful by now. private Set handlesToDelete = null; - IndexingService indexer = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(IndexingService.class.getName(),IndexingService.class); + IndexingService indexer = DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(IndexingService.class.getName(), + IndexingService.class); @Override public void initialize() throws Exception { @@ -62,10 +64,10 @@ public class IndexEventConsumer implements Consumer { int st = event.getSubjectType(); if (!(st == Constants.ITEM || st == Constants.BUNDLE - || st == Constants.COLLECTION || st == Constants.COMMUNITY)) { + || st == Constants.COLLECTION || st == Constants.COMMUNITY)) { log - .warn("IndexConsumer should not have been given this kind of Subject in an event, skipping: " - + event.toString()); + .warn("IndexConsumer should not have been given this kind of Subject in an event, skipping: " + + event.toString()); return; } @@ -81,17 +83,15 @@ public class IndexEventConsumer implements Consumer { int et = event.getEventType(); if (st == Constants.BUNDLE) { if ((et == Event.ADD || et == Event.REMOVE) && subject != null - && ((Bundle) subject).getName().equals("TEXT")) { + && ((Bundle) subject).getName().equals("TEXT")) { st = Constants.ITEM; et = Event.MODIFY; subject = ((Bundle) subject).getItems().get(0); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Transforming Bundle event into MODIFY of Item " - + subject.getHandle()); + + subject.getHandle()); } - } else - { + } else { return; } } @@ -100,14 +100,12 @@ public class IndexEventConsumer implements Consumer { case Event.CREATE: case Event.MODIFY: case Event.MODIFY_METADATA: - if (subject == null) - { + if (subject == null) { log.warn(event.getEventTypeAsString() + " event, could not get object for " - + event.getSubjectTypeAsString() + " id=" - + String.valueOf(event.getSubjectID()) - + ", perhaps it has been deleted."); - } - else { + + event.getSubjectTypeAsString() + " id=" + + String.valueOf(event.getSubjectID()) + + ", perhaps it has been deleted."); + } else { log.debug("consume() adding event to update queue: " + event.toString()); objectsToUpdate.add(subject); } @@ -115,14 +113,12 @@ public class IndexEventConsumer implements Consumer { case Event.REMOVE: case Event.ADD: - if (object == null) - { + if (object == null) { log.warn(event.getEventTypeAsString() + " event, could not get object for " - + event.getObjectTypeAsString() + " id=" - + String.valueOf(event.getObjectID()) - + ", perhaps it has been deleted."); - } - else { + + event.getObjectTypeAsString() + " id=" + + String.valueOf(event.getObjectID()) + + ", perhaps it has been deleted."); + } else { log.debug("consume() adding event to update queue: " + event.toString()); objectsToUpdate.add(object); } @@ -130,21 +126,19 @@ public class IndexEventConsumer implements Consumer { case Event.DELETE: String detail = event.getDetail(); - if (detail == null) - { + if (detail == null) { log.warn("got null detail on DELETE event, skipping it."); - } - else { + } else { log.debug("consume() adding event to delete queue: " + event.toString()); handlesToDelete.add(detail); } break; default: log - .warn("IndexConsumer should not have been given a event of type=" - + event.getEventTypeAsString() - + " on subject=" - + event.getSubjectTypeAsString()); + .warn("IndexConsumer should not have been given a event of type=" + + event.getEventTypeAsString() + + " on subject=" + + event.getSubjectTypeAsString()); break; } } @@ -160,21 +154,21 @@ public class IndexEventConsumer implements Consumer { if (objectsToUpdate != null && handlesToDelete != null) { // update the changed Items not deleted because they were on create list - for (DSpaceObject iu : objectsToUpdate) { - /* we let all types through here and - * allow the search indexer to make + for (DSpaceObject o : objectsToUpdate) { + /* we let all types through here and + * allow the search indexer to make * decisions on indexing and/or removal */ + DSpaceObject iu = ctx.reloadEntity(o); String hdl = iu.getHandle(); if (hdl != null && !handlesToDelete.contains(hdl)) { try { indexer.indexContent(ctx, iu, true); log.debug("Indexed " - + Constants.typeText[iu.getType()] - + ", id=" + String.valueOf(iu.getID()) - + ", handle=" + hdl); - } - catch (Exception e) { + + Constants.typeText[iu.getType()] + + ", id=" + String.valueOf(iu.getID()) + + ", handle=" + hdl); + } catch (Exception e) { log.error("Failed while indexing object: ", e); } } @@ -183,12 +177,10 @@ public class IndexEventConsumer implements Consumer { for (String hdl : handlesToDelete) { try { indexer.unIndexContent(ctx, hdl, true); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("UN-Indexed Item, handle=" + hdl); } - } - catch (Exception e) { + } catch (Exception e) { log.error("Failed while UN-indexing object: " + hdl, e); } diff --git a/dspace-api/src/main/java/org/dspace/discovery/IndexingService.java b/dspace-api/src/main/java/org/dspace/discovery/IndexingService.java index f0fa93c891..eaa885edf4 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/IndexingService.java +++ b/dspace-api/src/main/java/org/dspace/discovery/IndexingService.java @@ -7,12 +7,12 @@ */ package org.dspace.discovery; -import org.dspace.content.DSpaceObject; -import org.dspace.core.Context; - import java.io.IOException; import java.sql.SQLException; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; + /** * Interface used for indexing dspaceobject into discovery * @@ -23,28 +23,28 @@ import java.sql.SQLException; public interface IndexingService { void indexContent(Context context, DSpaceObject dso) - throws SQLException; + throws SQLException; void indexContent(Context context, DSpaceObject dso, boolean force) throws SQLException; void indexContent(Context context, DSpaceObject dso, - boolean force, boolean commit) throws SQLException, SearchServiceException; - + boolean force, boolean commit) throws SQLException, SearchServiceException; + void unIndexContent(Context context, DSpaceObject dso) - throws SQLException, IOException; + throws SQLException, IOException; void unIndexContent(Context context, DSpaceObject dso, boolean commit) - throws SQLException, IOException; - + throws SQLException, IOException; + void unIndexContent(Context context, String handle) - throws SQLException, IOException; + throws SQLException, IOException; void unIndexContent(Context context, String handle, boolean commit) - throws SQLException, IOException; + throws SQLException, IOException; void reIndexContent(Context context, DSpaceObject dso) - throws SQLException, IOException; + throws SQLException, IOException; void createIndex(Context context) throws SQLException, IOException; @@ -53,7 +53,7 @@ public interface IndexingService { void updateIndex(Context context, boolean force); void cleanIndex(boolean force) throws IOException, - SQLException, SearchServiceException; + SQLException, SearchServiceException; void commit() throws SearchServiceException; diff --git a/dspace-api/src/main/java/org/dspace/discovery/SearchService.java b/dspace-api/src/main/java/org/dspace/discovery/SearchService.java index 641e740bb9..a955234e1e 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SearchService.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SearchService.java @@ -7,14 +7,15 @@ */ package org.dspace.discovery; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration; - -import java.io.InputStream; -import java.sql.SQLException; -import java.util.List; +import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; /** * Search interface that discovery uses @@ -29,92 +30,82 @@ public interface SearchService { * Convenient method to call @see #search(Context, DSpaceObject, * DiscoverQuery) with a null DSpace Object as scope (i.e. all the * repository) - * - * @param context - * DSpace Context object. - * @param query - * the discovery query object. + * + * @param context DSpace Context object. + * @param query the discovery query object. * @return discovery search result object * @throws SearchServiceException if search error */ DiscoverResult search(Context context, DiscoverQuery query) - throws SearchServiceException; + throws SearchServiceException; /** * Convenient method to call @see #search(Context, DSpaceObject, * DiscoverQuery, boolean) with includeWithdrawn=false - * - * @param context - * DSpace Context object - * @param dso - * a DSpace Object to use as scope of the search (only results - * within this object) - * @param query - * the discovery query object + * + * @param context DSpace Context object + * @param dso a DSpace Object to use as scope of the search (only results + * within this object) + * @param query the discovery query object * @return discovery search result object * @throws SearchServiceException if search error */ DiscoverResult search(Context context, DSpaceObject dso, DiscoverQuery query) - throws SearchServiceException; + throws SearchServiceException; /** - * - * @param context - * DSpace Context object. - * @param query - * the discovery query object. - * @param includeWithdrawn - * use true to include in the results also withdrawn - * items that match the query. + * @param context DSpace Context object. + * @param query the discovery query object. + * @param includeWithdrawn use true to include in the results also withdrawn + * items that match the query. * @return discovery search result object * @throws SearchServiceException if search error */ DiscoverResult search(Context context, DiscoverQuery query, - boolean includeWithdrawn) throws SearchServiceException; + boolean includeWithdrawn) throws SearchServiceException; /** - * - * @param context - * DSpace Context object - * @param dso - * a DSpace Object to use as scope of the search (only results - * within this object) - * @param query - * the discovery query object - * @param includeWithdrawn - * use true to include in the results also withdrawn - * items that match the query + * @param context DSpace Context object + * @param dso a DSpace Object to use as scope of the search (only results + * within this object) + * @param query the discovery query object + * @param includeWithdrawn use true to include in the results also withdrawn + * items that match the query * @return discovery search result object * @throws SearchServiceException if search error */ - DiscoverResult search(Context context, DSpaceObject dso, DiscoverQuery query, boolean includeWithdrawn) throws SearchServiceException; + DiscoverResult search(Context context, DSpaceObject dso, DiscoverQuery query, boolean includeWithdrawn) + throws SearchServiceException; + - InputStream searchJSON(Context context, DiscoverQuery query, String jsonIdentifier) throws SearchServiceException; - InputStream searchJSON(Context context, DiscoverQuery query, DSpaceObject dso, String jsonIdentifier) throws SearchServiceException; + InputStream searchJSON(Context context, DiscoverQuery query, DSpaceObject dso, String jsonIdentifier) + throws SearchServiceException; - List search(Context context, String query, String orderfield, boolean ascending, int offset, int max, String... filterquery); + List search(Context context, String query, String orderfield, boolean ascending, int offset, int max, + String... filterquery); /** * Transforms the given string field and value into a filter query - * @param context - * The relevant DSpace Context. - * @param field the field of the filter query + * + * @param context The relevant DSpace Context. + * @param field the field of the filter query * @param operator equals/notequals/notcontains/authority/notauthority - * @param value the filter query value + * @param value the filter query value * @return a filter query * @throws SQLException if database error - * An exception that provides information on a database access error or other errors. + * An exception that provides information on a database access error or other errors. */ DiscoverFilterQuery toFilterQuery(Context context, String field, String operator, String value) throws SQLException; - List getRelatedItems(Context context, Item item, DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration); - + List getRelatedItems(Context context, Item item, + DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration); + /** - * Method to create a Query that includes all + * Method to create a Query that includes all * communities and collections a user may administrate. * If a user has the appropriate rights to administrate communities and/or * collections we want to look up all contents of those communities and/or @@ -123,19 +114,18 @@ public interface SearchService { * method returns a query to filter for items that belong to those * communities/collections only. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return query string specific to the user's rights - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ String createLocationQueryForAdministrableItems(Context context) throws SQLException; /** - * Transforms the metadata field of the given sort configuration into the indexed field which we can then use in our Solr queries. + * Transforms the metadata field of the given sort configuration into the indexed field which we can then use in + * our Solr queries. * * @param metadataField the metadata field - * @param type see {@link org.dspace.discovery.configuration.DiscoveryConfigurationParameters} + * @param type see {@link org.dspace.discovery.configuration.DiscoveryConfigurationParameters} * @return the indexed field */ String toSortFieldIndex(String metadataField, String type); @@ -143,9 +133,28 @@ public interface SearchService { /** * Utility method to escape any special characters in a user's query * - * @param query - * User's query to escape. + * @param query User's query to escape. * @return query with any special characters escaped */ String escapeQueryChars(String query); + + FacetYearRange getFacetYearRange(Context context, DSpaceObject scope, DiscoverySearchFilterFacet facet, + List filterQueries) throws SearchServiceException; + + /** + * This method returns us either the highest or lowest value for the field that we give to it + * depending on what sortOrder we give this method. + * + * @param context The relevant DSpace context + * @param valueField The field in solr for which we'll calculate the extreme value + * @param sortField The field in solr for which we'll sort the calculated extreme value on + * This is typically the valueField appended with "_sort" + * @param sortOrder Entering ascending will return the minimum value + * Entering descending will return the maximum value + * @return Returns the min or max value based on the field in the parameters. + * @throws SearchServiceException + */ + String calculateExtremeValue(Context context, String valueField, + String sortField, DiscoverQuery.SORT_ORDER sortOrder) + throws SearchServiceException; } diff --git a/dspace-api/src/main/java/org/dspace/discovery/SearchServiceException.java b/dspace-api/src/main/java/org/dspace/discovery/SearchServiceException.java index 1403d2059a..434bb06500 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SearchServiceException.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SearchServiceException.java @@ -30,5 +30,5 @@ public class SearchServiceException extends Exception { public SearchServiceException(Throwable throwable) { super(throwable); } - + } diff --git a/dspace-api/src/main/java/org/dspace/discovery/SearchUtils.java b/dspace-api/src/main/java/org/dspace/discovery/SearchUtils.java index f5d8a33877..aa465dd1bc 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SearchUtils.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SearchUtils.java @@ -7,16 +7,20 @@ */ package org.dspace.discovery; -import org.dspace.content.*; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.discovery.configuration.DiscoveryConfiguration; import org.dspace.discovery.configuration.DiscoveryConfigurationService; import org.dspace.kernel.ServiceManager; import org.dspace.services.factory.DSpaceServicesFactory; -import java.sql.SQLException; -import java.util.*; - /** * Util methods used by discovery * @@ -25,15 +29,20 @@ import java.util.*; * @author Ben Bosman (ben at atmire dot com) */ public class SearchUtils { - /** Cached search service **/ + /** + * Cached search service + **/ private static SearchService searchService; + /** + * Default constructor + */ + private SearchUtils() { } - public static SearchService getSearchService() - { - if (searchService == null) { + public static SearchService getSearchService() { + if (searchService == null) { org.dspace.kernel.ServiceManager manager = DSpaceServicesFactory.getInstance().getServiceManager(); - searchService = manager.getServiceByName(SearchService.class.getName(),SearchService.class); + searchService = manager.getServiceByName(SearchService.class.getName(), SearchService.class); } return searchService; } @@ -45,28 +54,16 @@ public class SearchUtils { public static DiscoveryConfiguration getDiscoveryConfiguration(DSpaceObject dso) { DiscoveryConfigurationService configurationService = getConfigurationService(); - DiscoveryConfiguration result = null; - if (dso == null) { - result = configurationService.getMap().get("site"); - }else{ - result = configurationService.getMap().get(dso.getHandle()); - } - - if (result == null) { - //No specific configuration, get the default one - result = configurationService.getMap().get("default"); - } - - return result; + return configurationService.getDiscoveryConfiguration(dso); } public static DiscoveryConfigurationService getConfigurationService() { ServiceManager manager = DSpaceServicesFactory.getInstance().getServiceManager(); - return manager.getServiceByName(DiscoveryConfigurationService.class.getName(), DiscoveryConfigurationService.class); + return manager + .getServiceByName(DiscoveryConfigurationService.class.getName(), DiscoveryConfigurationService.class); } - public static List getIgnoredMetadataFields(int type) - { + public static List getIgnoredMetadataFields(int type) { return getConfigurationService().getToIgnoreMetadataFields().get(type); } @@ -76,8 +73,7 @@ public class SearchUtils { * * @param item the DSpace item * @return a list of configuration objects - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public static List getAllDiscoveryConfigurations(Item item) throws SQLException { Map result = new HashMap(); diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceContentInOriginalBundleFilterPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceContentInOriginalBundleFilterPlugin.java index 85f2d671bd..c43b0e6245 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceContentInOriginalBundleFilterPlugin.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceContentInOriginalBundleFilterPlugin.java @@ -20,36 +20,29 @@ import org.dspace.core.Context; * This plugin adds three fields to the solr index to make a facet with/without * content in the ORIGINAL Bundle possible (like full text, images...). It is * activated simply by adding this class as a bean to discovery.xml. - * + * * The facet is added to Discovery in the usual way (create a searchFilter bean * and add it to the expected place) just with an empty list of used metadata * fields because there are none. - * + * * @author Christian Scheible christian.scheible@uni-konstanz.de - * */ -public class SolrServiceContentInOriginalBundleFilterPlugin implements SolrServiceIndexPlugin -{ +public class SolrServiceContentInOriginalBundleFilterPlugin implements SolrServiceIndexPlugin { @Override - public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) - { - if (dso instanceof Item) - { + public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) { + if (dso instanceof Item) { Item item = (Item) dso; boolean hasOriginalBundleWithContent = hasOriginalBundleWithContent(item); // _keyword and _filter because // they are needed in order to work as a facet and filter. - if (!hasOriginalBundleWithContent) - { + if (!hasOriginalBundleWithContent) { // no content in the original bundle document.addField("has_content_in_original_bundle", false); document.addField("has_content_in_original_bundle_keyword", false); document.addField("has_content_in_original_bundle_filter", false); - } - else - { + } else { document.addField("has_content_in_original_bundle", true); document.addField("has_content_in_original_bundle_keyword", true); document.addField("has_content_in_original_bundle_filter", true); @@ -60,26 +53,20 @@ public class SolrServiceContentInOriginalBundleFilterPlugin implements SolrServi /** * Checks whether the given item has a bundle with the name ORIGINAL * containing at least one bitstream. - * - * @param item - * to check + * + * @param item to check * @return true if there is at least on bitstream in the bundle named - * ORIGINAL, otherwise false + * ORIGINAL, otherwise false */ - private boolean hasOriginalBundleWithContent(Item item) - { + private boolean hasOriginalBundleWithContent(Item item) { List bundles; bundles = item.getBundles(); - if (bundles != null) - { - for (Bundle curBundle : bundles) - { + if (bundles != null) { + for (Bundle curBundle : bundles) { String bName = curBundle.getName(); - if ((bName != null) && bName.equals("ORIGINAL")) - { + if ((bName != null) && bName.equals("ORIGINAL")) { List bitstreams = curBundle.getBitstreams(); - if (bitstreams != null && bitstreams.size() > 0) - { + if (bitstreams != null && bitstreams.size() > 0) { return true; } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceFileInfoPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceFileInfoPlugin.java new file mode 100644 index 0000000000..979c577b2b --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceFileInfoPlugin.java @@ -0,0 +1,68 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.discovery; + +import java.util.List; + +import org.apache.solr.common.SolrInputDocument; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.core.Context; + +/** + *

    + * Adds filenames and file descriptions of all files in the ORIGINAL bundle + * to the Solr search index. + * + *

    + * To activate the plugin, add the following line to discovery.xml + *

    + * {@code }
    + * 
    + * + *

    + * After activating the plugin, rebuild the discovery index by executing: + *

    + * [dspace]/bin/dspace index-discovery -b
    + * 
    + * + * @author Martin Walk + */ +public class SolrServiceFileInfoPlugin implements SolrServiceIndexPlugin { + private static final String BUNDLE_NAME = "ORIGINAL"; + private static final String SOLR_FIELD_NAME_FOR_FILENAMES = "original_bundle_filenames"; + private static final String SOLR_FIELD_NAME_FOR_DESCRIPTIONS = "original_bundle_descriptions"; + + @Override + public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) { + if (dso instanceof Item) { + Item item = (Item) dso; + List bundles = item.getBundles(); + if (bundles != null) { + for (Bundle bundle : bundles) { + String bundleName = bundle.getName(); + if ((bundleName != null) && bundleName.equals(BUNDLE_NAME)) { + List bitstreams = bundle.getBitstreams(); + if (bitstreams != null) { + for (Bitstream bitstream : bitstreams) { + document.addField(SOLR_FIELD_NAME_FOR_FILENAMES, bitstream.getName()); + + String description = bitstream.getDescription(); + if ((description != null) && (!description.isEmpty())) { + document.addField(SOLR_FIELD_NAME_FOR_DESCRIPTIONS, description); + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java index 1ff46a4024..263370ed62 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java @@ -7,21 +7,50 @@ */ package org.dspace.discovery; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.collections.MapUtils; -import org.apache.commons.collections.Transformer; +import static org.dspace.discovery.configuration.DiscoverySortConfiguration.SCORE; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.sql.SQLException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.UUID; +import java.util.Vector; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.collections4.Transformer; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateFormatUtils; import org.apache.commons.validator.routines.UrlValidator; -import org.apache.http.HttpHost; import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.params.ClientPNames; -import org.apache.http.client.utils.URIBuilder; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; import org.apache.log4j.Logger; import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.request.AbstractUpdateRequest; @@ -32,11 +61,23 @@ import org.apache.solr.client.solrj.util.ClientUtils; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.params.*; +import org.apache.solr.common.params.CommonParams; +import org.apache.solr.common.params.FacetParams; +import org.apache.solr.common.params.HighlightParams; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.params.MoreLikeThisParams; +import org.apache.solr.common.params.SpellingParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.handler.extraction.ExtractingParams; -import org.dspace.content.*; +import org.dspace.authorize.ResourcePolicy; +import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.content.authority.Choices; import org.dspace.content.authority.service.ChoiceAuthorityService; import org.dspace.content.authority.service.MetadataAuthorityService; @@ -44,8 +85,25 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; -import org.dspace.core.*; -import org.dspace.discovery.configuration.*; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; +import org.dspace.core.LogManager; +import org.dspace.discovery.configuration.DiscoveryConfiguration; +import org.dspace.discovery.configuration.DiscoveryConfigurationParameters; +import org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration; +import org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration; +import org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration; +import org.dspace.discovery.configuration.DiscoveryRecentSubmissionsConfiguration; +import org.dspace.discovery.configuration.DiscoverySearchFilter; +import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; +import org.dspace.discovery.configuration.DiscoverySortConfiguration; +import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration; +import org.dspace.discovery.configuration.HierarchicalSidebarFacetConfiguration; +import org.dspace.eperson.Group; +import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.handle.service.HandleService; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.storage.rdbms.DatabaseUtils; @@ -53,21 +111,6 @@ import org.dspace.util.MultiFormatDateParser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.net.URI; -import java.net.URISyntaxException; -import java.sql.SQLException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; -import org.dspace.authorize.ResourcePolicy; -import org.dspace.authorize.factory.AuthorizeServiceFactory; -import org.dspace.eperson.Group; -import org.dspace.eperson.factory.EPersonServiceFactory; - /** * SolrIndexer contains the methods that index Items and their metadata, * collections, communities, etc. It is meant to either be invoked from the @@ -122,47 +165,45 @@ public class SolrServiceImpl implements SearchService, IndexingService { protected MetadataAuthorityService metadataAuthorityService; /** - * Non-Static CommonsHttpSolrServer for processing indexing events. + * Non-Static SolrServer for processing indexing events. */ - private HttpSolrServer solr = null; + protected SolrServer solr = null; - protected SolrServiceImpl() - { + protected SolrServiceImpl() { } - protected HttpSolrServer getSolr() - { - if ( solr == null) - { - String solrService = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("discovery.search.server"); + protected SolrServer getSolr() { + if (solr == null) { + String solrService = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("discovery.search.server"); UrlValidator urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS); - if (urlValidator.isValid(solrService)||ConfigurationManager.getBooleanProperty("discovery","solr.url.validation.enabled",true)) - { + if (urlValidator.isValid(solrService) || ConfigurationManager + .getBooleanProperty("discovery", "solr.url.validation.enabled", true)) { try { log.debug("Solr URL: " + solrService); - solr = new HttpSolrServer(solrService); + HttpSolrServer solrServer = new HttpSolrServer(solrService); - solr.setBaseURL(solrService); - solr.setUseMultiPartPost(true); + solrServer.setBaseURL(solrService); + solrServer.setUseMultiPartPost(true); // Dummy/test query to search for Item (type=2) of ID=1 SolrQuery solrQuery = new SolrQuery() - .setQuery(RESOURCE_TYPE_FIELD + ":2 AND " + RESOURCE_ID_FIELD + ":1"); + .setQuery(RESOURCE_TYPE_FIELD + ":2 AND " + RESOURCE_ID_FIELD + ":1"); // Only return obj identifier fields in result doc solrQuery.setFields(RESOURCE_TYPE_FIELD, RESOURCE_ID_FIELD); - solr.query(solrQuery); + solrServer.query(solrQuery, SolrRequest.METHOD.POST); // As long as Solr initialized, check with DatabaseUtils to see // if a reindex is in order. If so, reindex everything DatabaseUtils.checkReindexDiscovery(this); + + solr = solrServer; } catch (SolrServerException e) { log.error("Error while initializing solr server", e); } - } - else - { + } else { log.error("Error while initializing solr, invalid url: " + solrService); } } @@ -181,7 +222,7 @@ public class SolrServiceImpl implements SearchService, IndexingService { */ @Override public void indexContent(Context context, DSpaceObject dso) - throws SQLException { + throws SQLException { indexContent(context, dso, false); } @@ -201,24 +242,20 @@ public class SolrServiceImpl implements SearchService, IndexingService { String handle = dso.getHandle(); - if (handle == null) - { + if (handle == null) { handle = handleService.findHandle(context, dso); } try { - switch (dso.getType()) - { + switch (dso.getType()) { case Constants.ITEM: Item item = (Item) dso; - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { /** * If the item is in the repository now, add it to the index */ if (requiresIndexing(handle, ((Item) dso).getLastModified()) - || force) - { + || force) { unIndexContent(context, handle); buildDocument(context, (Item) dso); } @@ -244,11 +281,10 @@ public class SolrServiceImpl implements SearchService, IndexingService { default: log - .error("Only Items, Collections and Communities can be Indexed"); + .error("Only Items, Collections and Communities can be Indexed"); } - } catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); } } @@ -256,40 +292,36 @@ public class SolrServiceImpl implements SearchService, IndexingService { /** * unIndex removes an Item, Collection, or Community * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @param dso DSpace Object, can be Community, Item, or Collection * @throws SQLException if database error - * @throws IOException if IO error + * @throws IOException if IO error */ @Override public void unIndexContent(Context context, DSpaceObject dso) - throws SQLException, IOException { + throws SQLException, IOException { unIndexContent(context, dso, false); } /** * unIndex removes an Item, Collection, or Community * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @param dso DSpace Object, can be Community, Item, or Collection - * @param commit if true force an immediate commit on SOLR + * @param commit if true force an immediate commit on SOLR * @throws SQLException if database error - * @throws IOException if IO error + * @throws IOException if IO error */ @Override public void unIndexContent(Context context, DSpaceObject dso, boolean commit) - throws SQLException, IOException { + throws SQLException, IOException { try { - if (dso == null) - { + if (dso == null) { return; } - String uniqueID = dso.getType()+"-"+dso.getID(); + String uniqueID = dso.getType() + "-" + dso.getID(); getSolr().deleteById(uniqueID); - if (commit) - { + if (commit) { getSolr().commit(); } } catch (Exception exception) { @@ -300,9 +332,10 @@ public class SolrServiceImpl implements SearchService, IndexingService { /** * Unindex a Document in the Lucene index. + * * @param context the dspace context - * @param handle the handle of the object to be deleted - * @throws IOException if IO error + * @param handle the handle of the object to be deleted + * @throws IOException if IO error * @throws SQLException if database error */ @Override @@ -312,25 +345,24 @@ public class SolrServiceImpl implements SearchService, IndexingService { /** * Unindex a Document in the Lucene Index. + * * @param context the dspace context - * @param handle the handle of the object to be deleted + * @param handle the handle of the object to be deleted * @throws SQLException if database error - * @throws IOException if IO error + * @throws IOException if IO error */ @Override public void unIndexContent(Context context, String handle, boolean commit) - throws SQLException, IOException { + throws SQLException, IOException { try { if (getSolr() != null) { getSolr().deleteByQuery(HANDLE_FIELD + ":\"" + handle + "\""); - if (commit) - { + if (commit) { getSolr().commit(); } } - } catch (SolrServerException e) - { + } catch (SolrServerException e) { log.error(e.getMessage(), e); } } @@ -343,11 +375,10 @@ public class SolrServiceImpl implements SearchService, IndexingService { */ @Override public void reIndexContent(Context context, DSpaceObject dso) - throws SQLException, IOException { + throws SQLException, IOException { try { indexContent(context, dso); - } catch (Exception exception) - { + } catch (Exception exception) { log.error(exception.getMessage(), exception); emailException(exception); } @@ -375,8 +406,7 @@ public class SolrServiceImpl implements SearchService, IndexingService { * @param context the dspace context */ @Override - public void updateIndex(Context context) - { + public void updateIndex(Context context) { updateIndex(context, false); } @@ -391,15 +421,13 @@ public class SolrServiceImpl implements SearchService, IndexingService { * are running a reindex. * * @param context the dspace context - * @param force whether or not to force the reindexing + * @param force whether or not to force the reindexing */ @Override - public void updateIndex(Context context, boolean force) - { + public void updateIndex(Context context, boolean force) { try { Iterator items = null; - for (items = itemService.findAllUnfiltered(context); items.hasNext();) - { + for (items = itemService.findAllUnfiltered(context); items.hasNext(); ) { Item item = items.next(); indexContent(context, item, force); //To prevent memory issues, discard an object from the cache after processing @@ -407,24 +435,20 @@ public class SolrServiceImpl implements SearchService, IndexingService { } List collections = collectionService.findAll(context); - for (Collection collection : collections) - { + for (Collection collection : collections) { indexContent(context, collection, force); } List communities = communityService.findAll(context); - for (Community community : communities) - { + for (Community community : communities) { indexContent(context, community, force); } - if (getSolr() != null) - { + if (getSolr() != null) { getSolr().commit(); } - } catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); } } @@ -434,25 +458,22 @@ public class SolrServiceImpl implements SearchService, IndexingService { * database, if not, they are removed. * * @param force whether or not to force a clean index - * @throws IOException IO exception - * @throws SQLException sql exception + * @throws IOException IO exception + * @throws SQLException sql exception * @throws SearchServiceException occurs when something went wrong with querying the solr server */ @Override public void cleanIndex(boolean force) throws IOException, - SQLException, SearchServiceException { + SQLException, SearchServiceException { Context context = new Context(); context.turnOffAuthorisationSystem(); - try - { - if (getSolr() == null) - { + try { + if (getSolr() == null) { return; } - if (force) - { + if (force) { getSolr().deleteByQuery(RESOURCE_TYPE_FIELD + ":[2 TO 4]"); } else { SolrQuery query = new SolrQuery(); @@ -460,44 +481,38 @@ public class SolrServiceImpl implements SearchService, IndexingService { // returning just their handle query.setFields(HANDLE_FIELD); query.setQuery(RESOURCE_TYPE_FIELD + ":[2 TO 4]"); - QueryResponse rsp = getSolr().query(query); + QueryResponse rsp = getSolr().query(query, SolrRequest.METHOD.POST); SolrDocumentList docs = rsp.getResults(); Iterator iter = docs.iterator(); - while (iter.hasNext()) - { + while (iter.hasNext()) { - SolrDocument doc = (SolrDocument) iter.next(); + SolrDocument doc = (SolrDocument) iter.next(); - String handle = (String) doc.getFieldValue(HANDLE_FIELD); + String handle = (String) doc.getFieldValue(HANDLE_FIELD); - DSpaceObject o = handleService.resolveToObject(context, handle); + DSpaceObject o = handleService.resolveToObject(context, handle); - if (o == null) - { - log.info("Deleting: " + handle); - /* - * Use IndexWriter to delete, its easier to manage - * write.lock - */ - unIndexContent(context, handle); - } else { - log.debug("Keeping: " + handle); + if (o == null) { + log.info("Deleting: " + handle); + /* + * Use IndexWriter to delete, its easier to manage + * write.lock + */ + unIndexContent(context, handle); + } else { + log.debug("Keeping: " + handle); + } } } - } - } catch (Exception e) - { + } catch (Exception e) { throw new SearchServiceException(e.getMessage(), e); - } finally - { + } finally { context.abort(); } - - } /** @@ -505,11 +520,9 @@ public class SolrServiceImpl implements SearchService, IndexingService { * Note: This might take a long time. */ @Override - public void optimize() - { + public void optimize() { try { - if (getSolr() == null) - { + if (getSolr() == null) { return; } long start = System.currentTimeMillis(); @@ -518,11 +531,9 @@ public class SolrServiceImpl implements SearchService, IndexingService { long finish = System.currentTimeMillis(); System.out.println("SOLR Search Optimize -- Process Finished:" + finish); System.out.println("SOLR Search Optimize -- Total time taken:" + (finish - start) + " (ms)."); - } catch (SolrServerException sse) - { + } catch (SolrServerException sse) { System.err.println(sse.getMessage()); - } catch (IOException ioe) - { + } catch (IOException ioe) { System.err.println(ioe.getMessage()); } } @@ -536,9 +547,8 @@ public class SolrServiceImpl implements SearchService, IndexingService { SolrQuery solrQuery = new SolrQuery(); solrQuery.set("spellcheck", true); solrQuery.set(SpellingParams.SPELLCHECK_BUILD, true); - getSolr().query(solrQuery); - }catch (SolrServerException e) - { + getSolr().query(solrQuery, SolrRequest.METHOD.POST); + } catch (SolrServerException e) { //Make sure to also log the exception since this command is usually run from a crontab. log.error(e, e); throw new SearchServiceException(e); @@ -549,27 +559,24 @@ public class SolrServiceImpl implements SearchService, IndexingService { // Private // ////////////////////////////////// - protected void emailException(Exception exception) - { + protected void emailException(Exception exception) { // Also email an alert, system admin may need to check for stale lock try { String recipient = ConfigurationManager - .getProperty("alert.recipient"); + .getProperty("alert.recipient"); - if (StringUtils.isNotBlank(recipient)) - { + if (StringUtils.isNotBlank(recipient)) { Email email = Email - .getEmail(I18nUtil.getEmailFilename( - Locale.getDefault(), "internal_error")); + .getEmail(I18nUtil.getEmailFilename( + Locale.getDefault(), "internal_error")); email.addRecipient(recipient); email.addArgument(ConfigurationManager - .getProperty("dspace.url")); + .getProperty("dspace.url")); email.addArgument(new Date()); String stackTrace; - if (exception != null) - { + if (exception != null) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); exception.printStackTrace(pw); @@ -582,8 +589,7 @@ public class SolrServiceImpl implements SearchService, IndexingService { email.addArgument(stackTrace); email.send(); } - } catch (Exception e) - { + } catch (Exception e) { // Not much we can do here! log.warn("Unable to send email alert", e); } @@ -595,15 +601,15 @@ public class SolrServiceImpl implements SearchService, IndexingService { * Is stale checks the lastModified time stamp in the database and the index * to determine if the index is stale. * - * @param handle the handle of the dso + * @param handle the handle of the dso * @param lastModified the last modified date of the DSpace object * @return a boolean indicating if the dso should be re indexed again - * @throws SQLException sql exception - * @throws IOException io exception + * @throws SQLException sql exception + * @throws IOException io exception * @throws SearchServiceException if something went wrong with querying the solr server */ protected boolean requiresIndexing(String handle, Date lastModified) - throws SQLException, IOException, SearchServiceException { + throws SQLException, IOException, SearchServiceException { boolean reindexItem = false; boolean inIndex = false; @@ -615,29 +621,24 @@ public class SolrServiceImpl implements SearchService, IndexingService { QueryResponse rsp; try { - if (getSolr() == null) - { + if (getSolr() == null) { return false; } - rsp = getSolr().query(query); - } catch (SolrServerException e) - { - throw new SearchServiceException(e.getMessage(),e); + rsp = getSolr().query(query, SolrRequest.METHOD.POST); + } catch (SolrServerException e) { + throw new SearchServiceException(e.getMessage(), e); } - for (SolrDocument doc : rsp.getResults()) - { + for (SolrDocument doc : rsp.getResults()) { inIndex = true; Object value = doc.getFieldValue(LAST_INDEXED_FIELD); - if (value instanceof Date) - { + if (value instanceof Date) { Date lastIndexed = (Date) value; - if (lastIndexed.before(lastModified)) - { + if (lastIndexed.before(lastModified)) { reindexItem = true; } @@ -650,12 +651,12 @@ public class SolrServiceImpl implements SearchService, IndexingService { /** * @param context DSpace context - * @param myitem the item for which our locations are to be retrieved + * @param myitem the item for which our locations are to be retrieved * @return a list containing the identifiers of the communities and collections * @throws SQLException sql exception */ protected List getItemLocations(Context context, Item myitem) - throws SQLException { + throws SQLException { List locations = new Vector(); // build list of community ids @@ -667,13 +668,11 @@ public class SolrServiceImpl implements SearchService, IndexingService { // now put those into strings int i = 0; - for (i = 0; i < communities.size(); i++) - { + for (i = 0; i < communities.size(); i++) { locations.add("m" + communities.get(i).getID()); } - for (i = 0; i < collections.size(); i++) - { + for (i = 0; i < collections.size(); i++) { locations.add("l" + collections.get(i).getID()); } @@ -686,56 +685,55 @@ public class SolrServiceImpl implements SearchService, IndexingService { List communities = communityService.getAllParents(context, target); // now put those into strings - for (Community community : communities) - { + for (Community community : communities) { locations.add("m" + community.getID()); } return locations; } - + @Override public String createLocationQueryForAdministrableItems(Context context) - throws SQLException - { + throws SQLException { StringBuilder locationQuery = new StringBuilder(); - - if (context.getCurrentUser() != null) - { + + if (context.getCurrentUser() != null) { List groupList = EPersonServiceFactory.getInstance().getGroupService() - .allMemberGroups(context, context.getCurrentUser()); - + .allMemberGroups(context, context.getCurrentUser()); + List communitiesPolicies = AuthorizeServiceFactory.getInstance().getResourcePolicyService() - .find(context, context.getCurrentUser(), groupList, Constants.ADMIN, Constants.COMMUNITY); + .find(context, context.getCurrentUser(), + groupList, Constants.ADMIN, + Constants.COMMUNITY); List collectionsPolicies = AuthorizeServiceFactory.getInstance().getResourcePolicyService() - .find(context, context.getCurrentUser(), groupList, Constants.ADMIN, Constants.COLLECTION); + .find(context, context.getCurrentUser(), + groupList, Constants.ADMIN, + Constants.COLLECTION); List allCollections = new ArrayList<>(); - - for( ResourcePolicy rp: collectionsPolicies) { + + for (ResourcePolicy rp : collectionsPolicies) { Collection collection = ContentServiceFactory.getInstance().getCollectionService() - .find(context, rp.getdSpaceObject().getID()); + .find(context, rp.getdSpaceObject().getID()); allCollections.add(collection); } - if (CollectionUtils.isNotEmpty(communitiesPolicies) || CollectionUtils.isNotEmpty(allCollections)) - { + if (CollectionUtils.isNotEmpty(communitiesPolicies) || CollectionUtils.isNotEmpty(allCollections)) { locationQuery.append("location:( "); - for (int i = 0; i< communitiesPolicies.size(); i++) - { + for (int i = 0; i < communitiesPolicies.size(); i++) { ResourcePolicy rp = communitiesPolicies.get(i); Community community = ContentServiceFactory.getInstance().getCommunityService() - .find(context, rp.getdSpaceObject().getID()); - + .find(context, rp.getdSpaceObject().getID()); + locationQuery.append("m").append(community.getID()); if (i != (communitiesPolicies.size() - 1)) { locationQuery.append(" OR "); } allCollections.addAll(ContentServiceFactory.getInstance().getCommunityService() - .getAllCollections(context, community)); + .getAllCollections(context, community)); } Iterator collIter = allCollections.iterator(); @@ -754,7 +752,7 @@ public class SolrServiceImpl implements SearchService, IndexingService { locationQuery.append(")"); } else { log.warn("We have a collection or community admin with ID: " + context.getCurrentUser().getID() - + " without any administrable collection or community!"); + + " without any administrable collection or community!"); } } return locationQuery.toString(); @@ -763,31 +761,24 @@ public class SolrServiceImpl implements SearchService, IndexingService { /** * Write the document to the index under the appropriate handle. * - * @param doc - * the solr document to be written to the server - * @param streams - * list of bitstream content streams - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param doc the solr document to be written to the server + * @param streams list of bitstream content streams + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ protected void writeDocument(SolrInputDocument doc, FullTextContentStreams streams) throws IOException { try { - if (getSolr() != null) - { - if (streams != null && !streams.isEmpty()) - { + if (getSolr() != null) { + if (streams != null && !streams.isEmpty()) { ContentStreamUpdateRequest req = new ContentStreamUpdateRequest("/update/extract"); req.addContentStream(streams); ModifiableSolrParams params = new ModifiableSolrParams(); //req.setParam(ExtractingParams.EXTRACT_ONLY, "true"); - for(String name : doc.getFieldNames()) - { - for(Object val : doc.getFieldValues(name)) - { - params.add(ExtractingParams.LITERALS_PREFIX + name,val.toString()); + for (String name : doc.getFieldNames()) { + for (Object val : doc.getFieldValues(name)) { + params.add(ExtractingParams.LITERALS_PREFIX + name, val.toString()); } } @@ -797,14 +788,11 @@ public class SolrServiceImpl implements SearchService, IndexingService { req.setParam(ExtractingParams.EXTRACT_FORMAT, "text"); req.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true); req.process(getSolr()); - } - else - { + } else { getSolr().add(doc); } } - } catch (SolrServerException e) - { + } catch (SolrServerException e) { log.error(e.getMessage(), e); } } @@ -812,25 +800,24 @@ public class SolrServiceImpl implements SearchService, IndexingService { /** * Build a solr document for a DSpace Community. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @param community Community to be indexed * @throws SQLException if database error - * @throws IOException if IO error + * @throws IOException if IO error */ protected void buildDocument(Context context, Community community) - throws SQLException, IOException { + throws SQLException, IOException { // Create Document SolrInputDocument doc = buildDocument(Constants.COMMUNITY, community.getID(), - community.getHandle(), null); + community.getHandle(), null); DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(community); - DiscoveryHitHighlightingConfiguration highlightingConfiguration = discoveryConfiguration.getHitHighlightingConfiguration(); + DiscoveryHitHighlightingConfiguration highlightingConfiguration = discoveryConfiguration + .getHitHighlightingConfiguration(); List highlightedMetadataFields = new ArrayList(); - if (highlightingConfiguration != null) - { - for (DiscoveryHitHighlightFieldConfiguration configuration : highlightingConfiguration.getMetadataFields()) - { + if (highlightingConfiguration != null) { + for (DiscoveryHitHighlightFieldConfiguration configuration : highlightingConfiguration + .getMetadataFields()) { highlightedMetadataFields.add(configuration.getField()); } } @@ -843,16 +830,20 @@ public class SolrServiceImpl implements SearchService, IndexingService { String title = communityService.getMetadata(community, "name"); List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(community.getType()); - addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description", description); - addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.abstract", description_abstract); - addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.tableofcontents", description_table); + addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description", + description); + addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.abstract", + description_abstract); + addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, + "dc.description.tableofcontents", description_table); addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights", rights); addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.title", title); //Do any additional indexing, depends on the plugins - List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager().getServicesByType(SolrServiceIndexPlugin.class); - for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) - { + List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager() + .getServicesByType( + SolrServiceIndexPlugin.class); + for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) { solrServiceIndexPlugin.additionalIndex(context, community, doc); } @@ -862,27 +853,26 @@ public class SolrServiceImpl implements SearchService, IndexingService { /** * Build a solr document for a DSpace Collection. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @param collection Collection to be indexed * @throws SQLException sql exception - * @throws IOException IO exception + * @throws IOException IO exception */ protected void buildDocument(Context context, Collection collection) - throws SQLException, IOException { + throws SQLException, IOException { List locations = getCollectionLocations(context, collection); // Create Lucene Document SolrInputDocument doc = buildDocument(Constants.COLLECTION, collection.getID(), - collection.getHandle(), locations); + collection.getHandle(), locations); DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(collection); - DiscoveryHitHighlightingConfiguration highlightingConfiguration = discoveryConfiguration.getHitHighlightingConfiguration(); + DiscoveryHitHighlightingConfiguration highlightingConfiguration = discoveryConfiguration + .getHitHighlightingConfiguration(); List highlightedMetadataFields = new ArrayList(); - if (highlightingConfiguration != null) - { - for (DiscoveryHitHighlightFieldConfiguration configuration : highlightingConfiguration.getMetadataFields()) - { + if (highlightingConfiguration != null) { + for (DiscoveryHitHighlightFieldConfiguration configuration : highlightingConfiguration + .getMetadataFields()) { highlightedMetadataFields.add(configuration.getField()); } } @@ -898,19 +888,24 @@ public class SolrServiceImpl implements SearchService, IndexingService { String title = collectionService.getMetadata(collection, "name"); List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(collection.getType()); - addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description", description); - addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.abstract", description_abstract); - addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.tableofcontents", description_table); + addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description", + description); + addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.description.abstract", + description_abstract); + addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, + "dc.description.tableofcontents", description_table); addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.provenance", provenance); addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights", rights); - addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights.license", rights_license); + addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.rights.license", + rights_license); addContainerMetadataField(doc, highlightedMetadataFields, toIgnoreMetadataFields, "dc.title", title); //Do any additional indexing, depends on the plugins - List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager().getServicesByType(SolrServiceIndexPlugin.class); - for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) - { + List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager() + .getServicesByType( + SolrServiceIndexPlugin.class); + for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) { solrServiceIndexPlugin.additionalIndex(context, collection, doc); } @@ -921,21 +916,18 @@ public class SolrServiceImpl implements SearchService, IndexingService { * Add the metadata value of the community/collection to the solr document * IF needed highlighting is added ! * - * @param doc the solr document + * @param doc the solr document * @param highlightedMetadataFields the list of metadata fields that CAN be highlighted - * @param toIgnoreMetadataFields the list of metadata fields to skip adding to Solr - * @param metadataField the metadata field added - * @param value the value (can be NULL !) + * @param toIgnoreMetadataFields the list of metadata fields to skip adding to Solr + * @param metadataField the metadata field added + * @param value the value (can be NULL !) */ - protected void addContainerMetadataField(SolrInputDocument doc, List highlightedMetadataFields, List toIgnoreMetadataFields, String metadataField, String value) - { - if (toIgnoreMetadataFields == null || !toIgnoreMetadataFields.contains(metadataField)) - { - if (StringUtils.isNotBlank(value)) - { + protected void addContainerMetadataField(SolrInputDocument doc, List highlightedMetadataFields, + List toIgnoreMetadataFields, String metadataField, String value) { + if (toIgnoreMetadataFields == null || !toIgnoreMetadataFields.contains(metadataField)) { + if (StringUtils.isNotBlank(value)) { doc.addField(metadataField, value); - if (highlightedMetadataFields.contains(metadataField)) - { + if (highlightedMetadataFields.contains(metadataField)) { doc.addField(metadataField + "_hl", value); } } @@ -948,14 +940,13 @@ public class SolrServiceImpl implements SearchService, IndexingService { * @param context Users Context * @param item The DSpace Item to be indexed * @throws SQLException if database error - * @throws IOException if IO error + * @throws IOException if IO error */ protected void buildDocument(Context context, Item item) - throws SQLException, IOException { + throws SQLException, IOException { String handle = item.getHandle(); - if (handle == null) - { + if (handle == null) { handle = handleService.findHandle(context, item); } @@ -963,7 +954,7 @@ public class SolrServiceImpl implements SearchService, IndexingService { List locations = getItemLocations(context, item); SolrInputDocument doc = buildDocument(Constants.ITEM, item.getID(), handle, - locations); + locations); log.debug("Building Item: " + handle); @@ -980,60 +971,96 @@ public class SolrServiceImpl implements SearchService, IndexingService { //A map used to save each sidebarFacet config by the metadata fields Map> searchFilters = new HashMap>(); - Map sortFields = new HashMap(); - Map recentSubmissionsConfigurationMap = new HashMap(); + Map sortFields = new HashMap(); + Map recentSubmissionsConfigurationMap = new + HashMap(); Set moreLikeThisFields = new HashSet(); - for (DiscoveryConfiguration discoveryConfiguration : discoveryConfigurations) - { - for (int i = 0; i < discoveryConfiguration.getSearchFilters().size(); i++) - { + for (DiscoveryConfiguration discoveryConfiguration : discoveryConfigurations) { + for (int i = 0; i < discoveryConfiguration.getSearchFilters().size(); i++) { + + List metadataValueList = new LinkedList<>(); + boolean shouldExposeMinMax = false; DiscoverySearchFilter discoverySearchFilter = discoveryConfiguration.getSearchFilters().get(i); - for (int j = 0; j < discoverySearchFilter.getMetadataFields().size(); j++) - { + if (StringUtils.equalsIgnoreCase(discoverySearchFilter.getFilterType(), "facet")) { + if (((DiscoverySearchFilterFacet) discoverySearchFilter).exposeMinAndMaxValue()) { + shouldExposeMinMax = true; + } + } + for (int j = 0; j < discoverySearchFilter.getMetadataFields().size(); j++) { String metadataField = discoverySearchFilter.getMetadataFields().get(j); List resultingList; - if (searchFilters.get(metadataField) != null) - { + if (searchFilters.get(metadataField) != null) { resultingList = searchFilters.get(metadataField); } else { //New metadata field, create a new list for it resultingList = new ArrayList(); } + + + if (shouldExposeMinMax) { + String[] splittedMetadataField = metadataField.split("\\."); + String schema = splittedMetadataField[0]; + String element = splittedMetadataField.length > 1 ? splittedMetadataField[1] : null; + String qualifier = splittedMetadataField.length > 2 ? splittedMetadataField[2] : null; + + metadataValueList.addAll(itemService.getMetadata(item, schema, + element, qualifier, Item.ANY)); + + } + resultingList.add(discoverySearchFilter); searchFilters.put(metadataField, resultingList); } + + if (!metadataValueList.isEmpty() && shouldExposeMinMax) { + metadataValueList.sort(new Comparator() { + public int compare(MetadataValue mdv1,MetadataValue mdv2) { + return mdv1.getValue().compareTo(mdv2.getValue()) ; + } + }); + MetadataValue firstMetadataValue = metadataValueList.get(0); + MetadataValue lastMetadataValue = metadataValueList.get(metadataValueList.size() - 1); + + doc.addField(discoverySearchFilter.getIndexFieldName() + "_min", firstMetadataValue.getValue()); + doc.addField(discoverySearchFilter.getIndexFieldName() + + "_min_sort", firstMetadataValue.getValue()); + doc.addField(discoverySearchFilter.getIndexFieldName() + "_max", lastMetadataValue.getValue()); + doc.addField(discoverySearchFilter.getIndexFieldName() + + "_max_sort", lastMetadataValue.getValue()); + + } } DiscoverySortConfiguration sortConfiguration = discoveryConfiguration.getSearchSortConfiguration(); - if (sortConfiguration != null) - { - for (DiscoverySortFieldConfiguration discoverySortConfiguration : sortConfiguration.getSortFields()) - { + if (sortConfiguration != null) { + for (DiscoverySortFieldConfiguration discoverySortConfiguration : sortConfiguration + .getSortFields()) { sortFields.put(discoverySortConfiguration.getMetadataField(), discoverySortConfiguration); } } - DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration = discoveryConfiguration.getRecentSubmissionConfiguration(); - if (recentSubmissionConfiguration != null) - { - recentSubmissionsConfigurationMap.put(recentSubmissionConfiguration.getMetadataSortField(), recentSubmissionConfiguration); + DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration = discoveryConfiguration + .getRecentSubmissionConfiguration(); + if (recentSubmissionConfiguration != null) { + recentSubmissionsConfigurationMap + .put(recentSubmissionConfiguration.getMetadataSortField(), recentSubmissionConfiguration); } - DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration = discoveryConfiguration.getHitHighlightingConfiguration(); - if (hitHighlightingConfiguration != null) - { - List fieldConfigurations = hitHighlightingConfiguration.getMetadataFields(); - for (DiscoveryHitHighlightFieldConfiguration fieldConfiguration : fieldConfigurations) - { + DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration = discoveryConfiguration + .getHitHighlightingConfiguration(); + if (hitHighlightingConfiguration != null) { + List fieldConfigurations = hitHighlightingConfiguration + .getMetadataFields(); + for (DiscoveryHitHighlightFieldConfiguration fieldConfiguration : fieldConfigurations) { hitHighlightingFields.add(fieldConfiguration.getField()); } } - DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration = discoveryConfiguration.getMoreLikeThisConfiguration(); - if (moreLikeThisConfiguration != null) - { - for(String metadataField : moreLikeThisConfiguration.getSimilarityMetadataFields()) - { + DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration = discoveryConfiguration + .getMoreLikeThisConfiguration(); + if (moreLikeThisConfiguration != null) { + for (String metadataField : moreLikeThisConfiguration.getSimilarityMetadataFields()) { moreLikeThisFields.add(metadataField); } } @@ -1041,7 +1068,8 @@ public class SolrServiceImpl implements SearchService, IndexingService { List toProjectionFields = new ArrayList(); - String[] projectionFields = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("discovery.index.projection"); + String[] projectionFields = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("discovery.index.projection"); if (projectionFields != null) { for (String field : projectionFields) { toProjectionFields.add(field.trim()); @@ -1050,8 +1078,7 @@ public class SolrServiceImpl implements SearchService, IndexingService { List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(item.getType()); List mydc = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue meta : mydc) - { + for (MetadataValue meta : mydc) { MetadataField metadataField = meta.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); String field = metadataSchema.getName() + "." + metadataField.getElement(); @@ -1059,19 +1086,17 @@ public class SolrServiceImpl implements SearchService, IndexingService { String value = meta.getValue(); - if (value == null) - { + if (value == null) { continue; } - if (metadataField.getQualifier() != null && !metadataField.getQualifier().trim().equals("")) - { + if (metadataField.getQualifier() != null && !metadataField.getQualifier().trim().equals("")) { field += "." + metadataField.getQualifier(); } //We are not indexing provenance, this is useless - if (toIgnoreMetadataFields != null && (toIgnoreMetadataFields.contains(field) || toIgnoreMetadataFields.contains(unqualifiedField + "." + Item.ANY))) - { + if (toIgnoreMetadataFields != null && (toIgnoreMetadataFields.contains(field) || toIgnoreMetadataFields + .contains(unqualifiedField + "." + Item.ANY))) { continue; } @@ -1079,81 +1104,81 @@ public class SolrServiceImpl implements SearchService, IndexingService { String preferedLabel = null; List variants = null; boolean isAuthorityControlled = metadataAuthorityService - .isAuthorityControlled(metadataField); + .isAuthorityControlled(metadataField); - int minConfidence = isAuthorityControlled? metadataAuthorityService - .getMinConfidence(metadataField) : Choices.CF_ACCEPTED; + int minConfidence = isAuthorityControlled ? metadataAuthorityService + .getMinConfidence(metadataField) : Choices.CF_ACCEPTED; if (isAuthorityControlled && meta.getAuthority() != null - && meta.getConfidence() >= minConfidence) - { - boolean ignoreAuthority = DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.index.authority.ignore." + field, - DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.index.authority.ignore", - new Boolean(false)), true); - if (!ignoreAuthority) - { + && meta.getConfidence() >= minConfidence) { + boolean ignoreAuthority = + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.index.authority.ignore." + field, + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.index.authority.ignore", + new Boolean(false)), + true); + if (!ignoreAuthority) { authority = meta.getAuthority(); - boolean ignorePrefered = DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.index.authority.ignore-prefered." - + field, - DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.index.authority.ignore-prefered", - new Boolean(false)), - true); - if (!ignorePrefered) - { + boolean ignorePrefered = + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.index.authority.ignore-prefered." + field, + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.index.authority.ignore-prefered", + new Boolean(false)), + true); + if (!ignorePrefered) { preferedLabel = choiceAuthorityService - .getLabel(meta, meta.getLanguage()); + .getLabel(meta, meta.getLanguage()); } - boolean ignoreVariants = DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.index.authority.ignore-variants." - + field, - DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.index.authority.ignore-variants", - new Boolean(false)), - true); - if (!ignoreVariants) - { + boolean ignoreVariants = + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.index.authority.ignore-variants." + field, + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.index.authority.ignore-variants", + new Boolean(false)), + true); + if (!ignoreVariants) { variants = choiceAuthorityService - .getVariants(meta); + .getVariants(meta); } } } - if ((searchFilters.get(field) != null || searchFilters.get(unqualifiedField + "." + Item.ANY) != null)) - { + if ((searchFilters.get(field) != null || searchFilters + .get(unqualifiedField + "." + Item.ANY) != null)) { List searchFilterConfigs = searchFilters.get(field); - if (searchFilterConfigs == null) - { + if (searchFilterConfigs == null) { searchFilterConfigs = searchFilters.get(unqualifiedField + "." + Item.ANY); } - for (DiscoverySearchFilter searchFilter : searchFilterConfigs) - { + for (DiscoverySearchFilter searchFilter : searchFilterConfigs) { Date date = null; - String separator = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("discovery.solr.facets.split.char"); - if (separator == null) - { + String separator = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("discovery.solr.facets.split.char"); + if (separator == null) { separator = FILTER_SEPARATOR; } - if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) - { + if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) { //For our search filters that are dates we format them properly date = MultiFormatDateParser.parse(value); - if (date != null) - { + if (date != null) { //TODO: make this date format configurable ! value = DateFormatUtils.formatUTC(date, "yyyy-MM-dd"); } @@ -1161,150 +1186,136 @@ public class SolrServiceImpl implements SearchService, IndexingService { doc.addField(searchFilter.getIndexFieldName(), value); doc.addField(searchFilter.getIndexFieldName() + "_keyword", value); - if (authority != null && preferedLabel == null) - { + if (authority != null && preferedLabel == null) { doc.addField(searchFilter.getIndexFieldName() - + "_keyword", value + AUTHORITY_SEPARATOR - + authority); + + "_keyword", value + AUTHORITY_SEPARATOR + + authority); doc.addField(searchFilter.getIndexFieldName() - + "_authority", authority); + + "_authority", authority); doc.addField(searchFilter.getIndexFieldName() - + "_acid", value.toLowerCase() - + separator + value - + AUTHORITY_SEPARATOR + authority); + + "_acid", value.toLowerCase() + + separator + value + + AUTHORITY_SEPARATOR + authority); } - if (preferedLabel != null) - { + if (preferedLabel != null) { doc.addField(searchFilter.getIndexFieldName(), - preferedLabel); + preferedLabel); doc.addField(searchFilter.getIndexFieldName() - + "_keyword", preferedLabel); + + "_keyword", preferedLabel); doc.addField(searchFilter.getIndexFieldName() - + "_keyword", preferedLabel - + AUTHORITY_SEPARATOR + authority); + + "_keyword", preferedLabel + + AUTHORITY_SEPARATOR + authority); doc.addField(searchFilter.getIndexFieldName() - + "_authority", authority); + + "_authority", authority); doc.addField(searchFilter.getIndexFieldName() - + "_acid", preferedLabel.toLowerCase() - + separator + preferedLabel - + AUTHORITY_SEPARATOR + authority); + + "_acid", preferedLabel.toLowerCase() + + separator + preferedLabel + + AUTHORITY_SEPARATOR + authority); } - if (variants != null) - { - for (String var : variants) - { + if (variants != null) { + for (String var : variants) { doc.addField(searchFilter.getIndexFieldName() + "_keyword", var); doc.addField(searchFilter.getIndexFieldName() - + "_acid", var.toLowerCase() - + separator + var - + AUTHORITY_SEPARATOR + authority); + + "_acid", var.toLowerCase() + + separator + var + + AUTHORITY_SEPARATOR + authority); } } //Add a dynamic fields for auto complete in search doc.addField(searchFilter.getIndexFieldName() + "_ac", - value.toLowerCase() + separator + value); - if (preferedLabel != null) - { + value.toLowerCase() + separator + value); + if (preferedLabel != null) { doc.addField(searchFilter.getIndexFieldName() - + "_ac", preferedLabel.toLowerCase() - + separator + preferedLabel); + + "_ac", preferedLabel.toLowerCase() + + separator + preferedLabel); } - if (variants != null) - { - for (String var : variants) - { + if (variants != null) { + for (String var : variants) { doc.addField(searchFilter.getIndexFieldName() - + "_ac", var.toLowerCase() + separator - + var); + + "_ac", var.toLowerCase() + separator + + var); } } - if (searchFilter.getFilterType().equals(DiscoverySearchFilterFacet.FILTER_TYPE_FACET)) - { - if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_TEXT)) - { + if (searchFilter.getFilterType().equals(DiscoverySearchFilterFacet.FILTER_TYPE_FACET)) { + if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_TEXT)) { //Add a special filter - //We use a separator to split up the lowercase and regular case, this is needed to get our filters in regular case + //We use a separator to split up the lowercase and regular case, this is needed to + // get our filters in regular case //Solr has issues with facet prefix and cases - if (authority != null) - { - String facetValue = preferedLabel != null?preferedLabel:value; - doc.addField(searchFilter.getIndexFieldName() + "_filter", facetValue.toLowerCase() + separator + facetValue + AUTHORITY_SEPARATOR + authority); + if (authority != null) { + String facetValue = preferedLabel != null ? preferedLabel : value; + doc.addField(searchFilter.getIndexFieldName() + "_filter", facetValue + .toLowerCase() + separator + facetValue + AUTHORITY_SEPARATOR + authority); + } else { + doc.addField(searchFilter.getIndexFieldName() + "_filter", + value.toLowerCase() + separator + value); } - else - { - doc.addField(searchFilter.getIndexFieldName() + "_filter", value.toLowerCase() + separator + value); - } - } else - if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) - { - if (date != null) - { - String indexField = searchFilter.getIndexFieldName() + ".year"; - String yearUTC = DateFormatUtils.formatUTC(date, "yyyy"); - doc.addField(searchFilter.getIndexFieldName() + "_keyword", yearUTC); - // add the year to the autocomplete index - doc.addField(searchFilter.getIndexFieldName() + "_ac", yearUTC); - doc.addField(indexField, yearUTC); + } else if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) { + if (date != null) { + String indexField = searchFilter.getIndexFieldName() + ".year"; + String yearUTC = DateFormatUtils.formatUTC(date, "yyyy"); + doc.addField(searchFilter.getIndexFieldName() + "_keyword", yearUTC); + // add the year to the autocomplete index + doc.addField(searchFilter.getIndexFieldName() + "_ac", yearUTC); + doc.addField(indexField, yearUTC); - if (yearUTC.startsWith("0")) - { - doc.addField( - searchFilter.getIndexFieldName() - + "_keyword", - yearUTC.replaceFirst("0*", "")); - // add date without starting zeros for autocomplete e filtering - doc.addField( - searchFilter.getIndexFieldName() - + "_ac", - yearUTC.replaceFirst("0*", "")); - doc.addField( - searchFilter.getIndexFieldName() - + "_ac", - value.replaceFirst("0*", "")); - doc.addField( - searchFilter.getIndexFieldName() - + "_keyword", - value.replaceFirst("0*", "")); - } + if (yearUTC.startsWith("0")) { + doc.addField( + searchFilter.getIndexFieldName() + + "_keyword", + yearUTC.replaceFirst("0*", "")); + // add date without starting zeros for autocomplete e filtering + doc.addField( + searchFilter.getIndexFieldName() + + "_ac", + yearUTC.replaceFirst("0*", "")); + doc.addField( + searchFilter.getIndexFieldName() + + "_ac", + value.replaceFirst("0*", "")); + doc.addField( + searchFilter.getIndexFieldName() + + "_keyword", + value.replaceFirst("0*", "")); + } - //Also save a sort value of this year, this is required for determining the upper & lower bound year of our facet - if (doc.getField(indexField + "_sort") == null) - { - //We can only add one year so take the first one - doc.addField(indexField + "_sort", yearUTC); - } + //Also save a sort value of this year, this is required for determining the upper + // & lower bound year of our facet + if (doc.getField(indexField + "_sort") == null) { + //We can only add one year so take the first one + doc.addField(indexField + "_sort", yearUTC); + } } - } else - if (searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) - { - HierarchicalSidebarFacetConfiguration hierarchicalSidebarFacetConfiguration = (HierarchicalSidebarFacetConfiguration) searchFilter; + + } else if (searchFilter.getType() + .equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) { + HierarchicalSidebarFacetConfiguration hierarchicalSidebarFacetConfiguration = + (HierarchicalSidebarFacetConfiguration) searchFilter; String[] subValues = value.split(hierarchicalSidebarFacetConfiguration.getSplitter()); - if (hierarchicalSidebarFacetConfiguration.isSkipFirstNodeLevel() && 1 < subValues.length) - { + if (hierarchicalSidebarFacetConfiguration + .isSkipFirstNodeLevel() && 1 < subValues.length) { //Remove the first element of our array subValues = (String[]) ArrayUtils.subarray(subValues, 1, subValues.length); } - for (int i = 0; i < subValues.length; i++) - { + for (int i = 0; i < subValues.length; i++) { StringBuilder valueBuilder = new StringBuilder(); - for(int j = 0; j <= i; j++) - { + for (int j = 0; j <= i; j++) { valueBuilder.append(subValues[j]); - if (j < i) - { + if (j < i) { valueBuilder.append(hierarchicalSidebarFacetConfiguration.getSplitter()); } } String indexValue = valueBuilder.toString().trim(); - doc.addField(searchFilter.getIndexFieldName() + "_tax_" + i + "_filter", indexValue.toLowerCase() + separator + indexValue); + doc.addField(searchFilter.getIndexFieldName() + "_tax_" + i + "_filter", + indexValue.toLowerCase() + separator + indexValue); //We add the field x times that it has occurred - for(int j = i; j < subValues.length; j++) - { - doc.addField(searchFilter.getIndexFieldName() + "_filter", indexValue.toLowerCase() + separator + indexValue); + for (int j = i; j < subValues.length; j++) { + doc.addField(searchFilter.getIndexFieldName() + "_filter", + indexValue.toLowerCase() + separator + indexValue); doc.addField(searchFilter.getIndexFieldName() + "_keyword", indexValue); } } @@ -1313,25 +1324,23 @@ public class SolrServiceImpl implements SearchService, IndexingService { } } - if ((sortFields.get(field) != null || recentSubmissionsConfigurationMap.get(field) != null) && !sortFieldsAdded.contains(field)) - { + if ((sortFields.get(field) != null || recentSubmissionsConfigurationMap + .get(field) != null) && !sortFieldsAdded.contains(field)) { //Only add sort value once String type; - if (sortFields.get(field) != null) - { + if (sortFields.get(field) != null) { type = sortFields.get(field).getType(); } else { type = recentSubmissionsConfigurationMap.get(field).getType(); } - if (type.equals(DiscoveryConfigurationParameters.TYPE_DATE)) - { + if (type.equals(DiscoveryConfigurationParameters.TYPE_DATE)) { Date date = MultiFormatDateParser.parse(value); - if (date != null) - { + if (date != null) { doc.addField(field + "_dt", date); } else { - log.warn("Error while indexing sort date field, item: " + item.getHandle() + " metadata field: " + field + " date value: " + date); + log.warn("Error while indexing sort date field, item: " + item + .getHandle() + " metadata field: " + field + " date value: " + date); } } else { doc.addField(field + "_sort", value); @@ -1339,48 +1348,45 @@ public class SolrServiceImpl implements SearchService, IndexingService { sortFieldsAdded.add(field); } - if (hitHighlightingFields.contains(field) || hitHighlightingFields.contains("*") || hitHighlightingFields.contains(unqualifiedField + "." + Item.ANY)) - { + if (hitHighlightingFields.contains(field) || hitHighlightingFields + .contains("*") || hitHighlightingFields.contains(unqualifiedField + "." + Item.ANY)) { doc.addField(field + "_hl", value); } - if (moreLikeThisFields.contains(field) || moreLikeThisFields.contains(unqualifiedField + "." + Item.ANY)) - { + if (moreLikeThisFields.contains(field) || moreLikeThisFields + .contains(unqualifiedField + "." + Item.ANY)) { doc.addField(field + "_mlt", value); } doc.addField(field, value); - if (toProjectionFields.contains(field) || toProjectionFields.contains(unqualifiedField + "." + Item.ANY)) - { + if (toProjectionFields.contains(field) || toProjectionFields + .contains(unqualifiedField + "." + Item.ANY)) { StringBuffer variantsToStore = new StringBuffer(); - if (variants != null) - { - for (String var : variants) - { + if (variants != null) { + for (String var : variants) { variantsToStore.append(VARIANTS_STORE_SEPARATOR); variantsToStore.append(var); } } doc.addField( - field + "_stored", - value + STORE_SEPARATOR + preferedLabel - + STORE_SEPARATOR - + (variantsToStore.length() > VARIANTS_STORE_SEPARATOR - .length() ? variantsToStore - .substring(VARIANTS_STORE_SEPARATOR - .length()) : "null") - + STORE_SEPARATOR + authority - + STORE_SEPARATOR + meta.getLanguage()); + field + "_stored", + value + STORE_SEPARATOR + preferedLabel + + STORE_SEPARATOR + + (variantsToStore.length() > VARIANTS_STORE_SEPARATOR + .length() ? variantsToStore + .substring(VARIANTS_STORE_SEPARATOR + .length()) : "null") + + STORE_SEPARATOR + authority + + STORE_SEPARATOR + meta.getLanguage()); } - if (meta.getLanguage() != null && !meta.getLanguage().trim().equals("")) - { + if (meta.getLanguage() != null && !meta.getLanguage().trim().equals("")) { String langField = field + "." + meta.getLanguage(); doc.addField(langField, value); } } - } catch (Exception e) { + } catch (Exception e) { log.error(e.getMessage(), e); } @@ -1391,36 +1397,29 @@ public class SolrServiceImpl implements SearchService, IndexingService { List values = itemService.getMetadataByMetadataString(item, "dc.relation.ispartof"); - if (values != null && values.size() > 0 && values.get(0) != null && values.get(0).getValue() != null) - { + if (values != null && values.size() > 0 && values.get(0) != null && values.get(0).getValue() != null) { // group on parent - String handlePrefix = ConfigurationManager.getProperty("handle.canonical.prefix"); - if (handlePrefix == null || handlePrefix.length() == 0) - { - handlePrefix = "http://hdl.handle.net/"; - } + String handlePrefix = handleService.getCanonicalPrefix(); - doc.addField("publication_grp",values.get(0).getValue().replaceFirst(handlePrefix, "") ); + doc.addField("publication_grp", values.get(0).getValue().replaceFirst(handlePrefix, "")); - } - else - { + } else { // group on self doc.addField("publication_grp", item.getHandle()); } - } catch (Exception e) - { - log.error(e.getMessage(),e); + } catch (Exception e) { + log.error(e.getMessage(), e); } log.debug(" Added Grouping"); //Do any additional indexing, depends on the plugins - List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager().getServicesByType(SolrServiceIndexPlugin.class); - for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) - { + List solrServiceIndexPlugins = DSpaceServicesFactory.getInstance().getServiceManager() + .getServicesByType( + SolrServiceIndexPlugin.class); + for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) { solrServiceIndexPlugin.additionalIndex(context, item, doc); } @@ -1428,28 +1427,22 @@ public class SolrServiceImpl implements SearchService, IndexingService { try { writeDocument(doc, new FullTextContentStreams(context, item)); log.info("Wrote Item: " + handle + " to Index"); - } catch (RuntimeException e) - { - log.error("Error while writing item to discovery index: " + handle + " message:"+ e.getMessage(), e); + } catch (RuntimeException e) { + log.error("Error while writing item to discovery index: " + handle + " message:" + e.getMessage(), e); } } /** * Create Lucene document with all the shared fields initialized. * - * @param type - * Type of DSpace Object - * @param id - * internal identifier - * @param handle - * handle string - * @param locations - * list of collection/community internal identifiers + * @param type Type of DSpace Object + * @param id internal identifier + * @param handle handle string + * @param locations list of collection/community internal identifiers * @return initialized Lucene document */ protected SolrInputDocument buildDocument(int type, UUID id, String handle, - List locations) - { + List locations) { SolrInputDocument doc = new SolrInputDocument(); // want to be able to check when last updated @@ -1458,30 +1451,24 @@ public class SolrServiceImpl implements SearchService, IndexingService { // New fields to weaken the dependence on handles, and allow for faster // list display - doc.addField("search.uniqueid", type+"-"+id); + doc.addField("search.uniqueid", type + "-" + id); doc.addField(RESOURCE_TYPE_FIELD, Integer.toString(type)); doc.addField(RESOURCE_ID_FIELD, id.toString()); // want to be able to search for handle, so use keyword // (not tokenized, but it is indexed) - if (handle != null) - { + if (handle != null) { // want to be able to search for handle, so use keyword // (not tokenized, but it is indexed) doc.addField(HANDLE_FIELD, handle); } - if (locations != null) - { - for (String location : locations) - { + if (locations != null) { + for (String location : locations) { doc.addField("location", location); - if (location.startsWith("m")) - { + if (location.startsWith("m")) { doc.addField("location.comm", location.substring(1)); - } - else - { + } else { doc.addField("location.coll", location.substring(1)); } } @@ -1497,60 +1484,59 @@ public class SolrServiceImpl implements SearchService, IndexingService { * @param t the string to be transformed to a date * @return a date if the formatting was successful, null if not able to transform to a date */ - public Date toDate(String t) - { + public Date toDate(String t) { SimpleDateFormat[] dfArr; // Choose the likely date formats based on string length - switch (t.length()) - { + switch (t.length()) { // case from 1 to 3 go through adding anyone a single 0. Case 4 define // for all the SimpleDateFormat case 1: t = "0" + t; + // fall through case 2: t = "0" + t; + // fall through case 3: t = "0" + t; + // fall through case 4: - dfArr = new SimpleDateFormat[]{new SimpleDateFormat("yyyy")}; + dfArr = new SimpleDateFormat[] {new SimpleDateFormat("yyyy")}; break; case 6: - dfArr = new SimpleDateFormat[]{new SimpleDateFormat("yyyyMM")}; + dfArr = new SimpleDateFormat[] {new SimpleDateFormat("yyyyMM")}; break; case 7: - dfArr = new SimpleDateFormat[]{new SimpleDateFormat("yyyy-MM")}; + dfArr = new SimpleDateFormat[] {new SimpleDateFormat("yyyy-MM")}; break; case 8: - dfArr = new SimpleDateFormat[]{new SimpleDateFormat("yyyyMMdd"), - new SimpleDateFormat("yyyy MMM")}; + dfArr = new SimpleDateFormat[] {new SimpleDateFormat("yyyyMMdd"), + new SimpleDateFormat("yyyy MMM")}; break; case 10: - dfArr = new SimpleDateFormat[]{new SimpleDateFormat("yyyy-MM-dd")}; + dfArr = new SimpleDateFormat[] {new SimpleDateFormat("yyyy-MM-dd")}; break; case 11: - dfArr = new SimpleDateFormat[]{new SimpleDateFormat("yyyy MMM dd")}; + dfArr = new SimpleDateFormat[] {new SimpleDateFormat("yyyy MMM dd")}; break; case 20: - dfArr = new SimpleDateFormat[]{new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss'Z'")}; + dfArr = new SimpleDateFormat[] {new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss'Z'")}; break; default: - dfArr = new SimpleDateFormat[]{new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")}; + dfArr = new SimpleDateFormat[] {new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")}; break; } - for (SimpleDateFormat df : dfArr) - { + for (SimpleDateFormat df : dfArr) { try { // Parse the date df.setCalendar(Calendar - .getInstance(TimeZone.getTimeZone("UTC"))); + .getInstance(TimeZone.getTimeZone("UTC"))); df.setLenient(false); return df.parse(t); - } catch (ParseException pe) - { + } catch (ParseException pe) { log.error("Unable to parse date format", pe); } } @@ -1559,16 +1545,13 @@ public class SolrServiceImpl implements SearchService, IndexingService { } public String locationToName(Context context, String field, String value) throws SQLException { - if ("location.comm".equals(field) || "location.coll".equals(field)) - { + if ("location.comm".equals(field) || "location.coll".equals(field)) { int type = ("location.comm").equals(field) ? Constants.COMMUNITY : Constants.COLLECTION; DSpaceObject commColl = null; - if (StringUtils.isNotBlank(value)) - { + if (StringUtils.isNotBlank(value)) { commColl = contentServiceFactory.getDSpaceObjectService(type).find(context, UUID.fromString(value)); } - if (commColl != null) - { + if (commColl != null) { return commColl.getName(); } @@ -1578,31 +1561,26 @@ public class SolrServiceImpl implements SearchService, IndexingService { //========== SearchService implementation @Override - public DiscoverResult search(Context context, DiscoverQuery query) throws SearchServiceException - { + public DiscoverResult search(Context context, DiscoverQuery query) throws SearchServiceException { return search(context, query, false); } @Override public DiscoverResult search(Context context, DSpaceObject dso, - DiscoverQuery query) - throws SearchServiceException - { + DiscoverQuery query) + throws SearchServiceException { return search(context, dso, query, false); } @Override - public DiscoverResult search(Context context, DSpaceObject dso, DiscoverQuery discoveryQuery, boolean includeUnDiscoverable) throws SearchServiceException { - if (dso != null) - { - if (dso instanceof Community) - { + public DiscoverResult search(Context context, DSpaceObject dso, DiscoverQuery discoveryQuery, + boolean includeUnDiscoverable) throws SearchServiceException { + if (dso != null) { + if (dso instanceof Community) { discoveryQuery.addFilterQueries("location:m" + dso.getID()); - } else if (dso instanceof Collection) - { + } else if (dso instanceof Collection) { discoveryQuery.addFilterQueries("location:l" + dso.getID()); - } else if (dso instanceof Item) - { + } else if (dso instanceof Item) { discoveryQuery.addFilterQueries(HANDLE_FIELD + ":" + dso.getHandle()); } } @@ -1612,7 +1590,8 @@ public class SolrServiceImpl implements SearchService, IndexingService { @Override - public DiscoverResult search(Context context, DiscoverQuery discoveryQuery, boolean includeUnDiscoverable) throws SearchServiceException { + public DiscoverResult search(Context context, DiscoverQuery discoveryQuery, boolean includeUnDiscoverable) + throws SearchServiceException { try { if (getSolr() == null) { return new DiscoverResult(); @@ -1620,22 +1599,20 @@ public class SolrServiceImpl implements SearchService, IndexingService { SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery, includeUnDiscoverable); - QueryResponse queryResponse = getSolr().query(solrQuery); + QueryResponse queryResponse = getSolr().query(solrQuery, SolrRequest.METHOD.POST); return retrieveResult(context, discoveryQuery, queryResponse); - } catch (Exception e) - { - throw new org.dspace.discovery.SearchServiceException(e.getMessage(),e); + } catch (Exception e) { + throw new org.dspace.discovery.SearchServiceException(e.getMessage(), e); } } - protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery, boolean includeUnDiscoverable) - { + protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery, + boolean includeUnDiscoverable) { SolrQuery solrQuery = new SolrQuery(); String query = "*:*"; - if (discoveryQuery.getQuery() != null) - { + if (discoveryQuery.getQuery() != null) { query = discoveryQuery.getQuery(); } @@ -1643,8 +1620,7 @@ public class SolrServiceImpl implements SearchService, IndexingService { // Add any search fields to our query. This is the limited list // of fields that will be returned in the solr result - for(String fieldName : discoveryQuery.getSearchFields()) - { + for (String fieldName : discoveryQuery.getSearchFields()) { solrQuery.addField(fieldName); } // Also ensure a few key obj identifier fields are returned with every query @@ -1652,139 +1628,126 @@ public class SolrServiceImpl implements SearchService, IndexingService { solrQuery.addField(RESOURCE_TYPE_FIELD); solrQuery.addField(RESOURCE_ID_FIELD); - if (discoveryQuery.isSpellCheck()) - { + if (discoveryQuery.isSpellCheck()) { solrQuery.setParam(SpellingParams.SPELLCHECK_Q, query); solrQuery.setParam(SpellingParams.SPELLCHECK_COLLATE, Boolean.TRUE); solrQuery.setParam("spellcheck", Boolean.TRUE); } - if (!includeUnDiscoverable) - { + if (!includeUnDiscoverable) { solrQuery.addFilterQuery("NOT(withdrawn:true)"); solrQuery.addFilterQuery("NOT(discoverable:false)"); } - for (int i = 0; i < discoveryQuery.getFilterQueries().size(); i++) - { + for (int i = 0; i < discoveryQuery.getFilterQueries().size(); i++) { String filterQuery = discoveryQuery.getFilterQueries().get(i); solrQuery.addFilterQuery(filterQuery); } - if (discoveryQuery.getDSpaceObjectFilter() != -1) - { + if (discoveryQuery.getDSpaceObjectFilter() != -1) { solrQuery.addFilterQuery(RESOURCE_TYPE_FIELD + ":" + discoveryQuery.getDSpaceObjectFilter()); } - for (int i = 0; i < discoveryQuery.getFieldPresentQueries().size(); i++) - { + for (int i = 0; i < discoveryQuery.getFieldPresentQueries().size(); i++) { String filterQuery = discoveryQuery.getFieldPresentQueries().get(i); solrQuery.addFilterQuery(filterQuery + ":[* TO *]"); } - if (discoveryQuery.getStart() != -1) - { + if (discoveryQuery.getStart() != -1) { solrQuery.setStart(discoveryQuery.getStart()); } - if (discoveryQuery.getMaxResults() != -1) - { + if (discoveryQuery.getMaxResults() != -1) { solrQuery.setRows(discoveryQuery.getMaxResults()); } - if (discoveryQuery.getSortField() != null) - { + if (discoveryQuery.getSortField() != null) { SolrQuery.ORDER order = SolrQuery.ORDER.asc; - if (discoveryQuery.getSortOrder().equals(DiscoverQuery.SORT_ORDER.desc)) + if (discoveryQuery.getSortOrder().equals(DiscoverQuery.SORT_ORDER.desc)) { order = SolrQuery.ORDER.desc; + } solrQuery.addSortField(discoveryQuery.getSortField(), order); } - for(String property : discoveryQuery.getProperties().keySet()) - { + for (String property : discoveryQuery.getProperties().keySet()) { List values = discoveryQuery.getProperties().get(property); solrQuery.add(property, values.toArray(new String[values.size()])); } List facetFields = discoveryQuery.getFacetFields(); - if (0 < facetFields.size()) - { + if (0 < facetFields.size()) { //Only add facet information if there are any facets - for (DiscoverFacetField facetFieldConfig : facetFields) - { + for (DiscoverFacetField facetFieldConfig : facetFields) { String field = transformFacetField(facetFieldConfig, facetFieldConfig.getField(), false); solrQuery.addFacetField(field); // Setting the facet limit in this fashion ensures that each facet can have its own max - solrQuery.add("f." + field + "." + FacetParams.FACET_LIMIT, String.valueOf(facetFieldConfig.getLimit())); + solrQuery + .add("f." + field + "." + FacetParams.FACET_LIMIT, String.valueOf(facetFieldConfig.getLimit())); String facetSort; - if (DiscoveryConfigurationParameters.SORT.COUNT.equals(facetFieldConfig.getSortOrder())) - { + if (DiscoveryConfigurationParameters.SORT.COUNT.equals(facetFieldConfig.getSortOrder())) { facetSort = FacetParams.FACET_SORT_COUNT; } else { facetSort = FacetParams.FACET_SORT_INDEX; } solrQuery.add("f." + field + "." + FacetParams.FACET_SORT, facetSort); - if (facetFieldConfig.getOffset() != -1) - { + if (facetFieldConfig.getOffset() != -1) { solrQuery.setParam("f." + field + "." - + FacetParams.FACET_OFFSET, - String.valueOf(facetFieldConfig.getOffset())); + + FacetParams.FACET_OFFSET, + String.valueOf(facetFieldConfig.getOffset())); } - if (facetFieldConfig.getPrefix() != null) - { + if (facetFieldConfig.getPrefix() != null) { solrQuery.setFacetPrefix(field, facetFieldConfig.getPrefix()); } } + } - List facetQueries = discoveryQuery.getFacetQueries(); - for (String facetQuery : facetQueries) - { - solrQuery.addFacetQuery(facetQuery); - } + List facetQueries = discoveryQuery.getFacetQueries(); + for (String facetQuery : facetQueries) { + solrQuery.addFacetQuery(facetQuery); + } - if (discoveryQuery.getFacetMinCount() != -1) - { - solrQuery.setFacetMinCount(discoveryQuery.getFacetMinCount()); - } + if (discoveryQuery.getFacetMinCount() != -1) { + solrQuery.setFacetMinCount(discoveryQuery.getFacetMinCount()); + } + if (CollectionUtils.isNotEmpty(facetFields) || CollectionUtils.isNotEmpty(facetQueries)) { solrQuery.setParam(FacetParams.FACET_OFFSET, String.valueOf(discoveryQuery.getFacetOffset())); } - if (0 < discoveryQuery.getHitHighlightingFields().size()) - { + if (0 < discoveryQuery.getHitHighlightingFields().size()) { solrQuery.setHighlight(true); solrQuery.add(HighlightParams.USE_PHRASE_HIGHLIGHTER, Boolean.TRUE.toString()); - for (DiscoverHitHighlightingField highlightingField : discoveryQuery.getHitHighlightingFields()) - { + for (DiscoverHitHighlightingField highlightingField : discoveryQuery.getHitHighlightingFields()) { solrQuery.addHighlightField(highlightingField.getField() + "_hl"); - solrQuery.add("f." + highlightingField.getField() + "_hl." + HighlightParams.FRAGSIZE, String.valueOf(highlightingField.getMaxChars())); - solrQuery.add("f." + highlightingField.getField() + "_hl." + HighlightParams.SNIPPETS, String.valueOf(highlightingField.getMaxSnippets())); + solrQuery.add("f." + highlightingField.getField() + "_hl." + HighlightParams.FRAGSIZE, + String.valueOf(highlightingField.getMaxChars())); + solrQuery.add("f." + highlightingField.getField() + "_hl." + HighlightParams.SNIPPETS, + String.valueOf(highlightingField.getMaxSnippets())); } } //Add any configured search plugins ! - List solrServiceSearchPlugins = DSpaceServicesFactory.getInstance().getServiceManager().getServicesByType(SolrServiceSearchPlugin.class); - for (SolrServiceSearchPlugin searchPlugin : solrServiceSearchPlugins) - { + List solrServiceSearchPlugins = DSpaceServicesFactory.getInstance().getServiceManager() + .getServicesByType( + SolrServiceSearchPlugin + .class); + for (SolrServiceSearchPlugin searchPlugin : solrServiceSearchPlugins) { searchPlugin.additionalSearchParameters(context, discoveryQuery, solrQuery); } return solrQuery; } @Override - public InputStream searchJSON(Context context, DiscoverQuery query, DSpaceObject dso, String jsonIdentifier) throws SearchServiceException { - if (dso != null) - { - if (dso instanceof Community) - { + public InputStream searchJSON(Context context, DiscoverQuery query, DSpaceObject dso, String jsonIdentifier) + throws SearchServiceException { + if (dso != null) { + if (dso instanceof Community) { query.addFilterQueries("location:m" + dso.getID()); - } else if (dso instanceof Collection) - { + } else if (dso instanceof Collection) { query.addFilterQueries("location:l" + dso.getID()); - } else if (dso instanceof Item) - { + } else if (dso instanceof Item) { query.addFilterQueries(HANDLE_FIELD + ":" + dso.getHandle()); } } @@ -1793,9 +1756,9 @@ public class SolrServiceImpl implements SearchService, IndexingService { @Override - public InputStream searchJSON(Context context, DiscoverQuery discoveryQuery, String jsonIdentifier) throws SearchServiceException { - if (getSolr() == null) - { + public InputStream searchJSON(Context context, DiscoverQuery discoveryQuery, String jsonIdentifier) + throws SearchServiceException { + if (getSolr() == null || !(getSolr() instanceof HttpSolrServer)) { return null; } @@ -1806,128 +1769,139 @@ public class SolrServiceImpl implements SearchService, IndexingService { solrQuery.setParam(CommonParams.WT, "json"); StringBuilder urlBuilder = new StringBuilder(); - urlBuilder.append(getSolr().getBaseURL()).append("/select?"); - urlBuilder.append(solrQuery.toString()); + //urlBuilder.append(getSolr().getBaseURL()).append("/select?"); + //urlBuilder.append(solrQuery.toString()); + // New url without any query params appended + urlBuilder.append(((HttpSolrServer)getSolr()).getBaseURL()).append("/select"); + // Post setup + NamedList solrParameters = solrQuery.toNamedList(); + List postParameters = new ArrayList<>(); + for (Map.Entry solrParameter : solrParameters) { + if (solrParameter.getValue() instanceof String[]) { + // Multi-valued solr parameter + for (String val : (String[])solrParameter.getValue()) { + postParameters.add(new BasicNameValuePair(solrParameter.getKey(), val)); + } + } else if (solrParameter.getValue() instanceof String) { + postParameters.add(new BasicNameValuePair(solrParameter.getKey(), solrParameter.getValue().toString())); + } else { + log.warn("Search parameters contain non-string value: " + solrParameter.getValue().toString()); + } + } try { - HttpGet get = new HttpGet(urlBuilder.toString()); - HttpResponse response = new DefaultHttpClient().execute(get); + HttpPost post = new HttpPost(urlBuilder.toString()); + post.setEntity(new UrlEncodedFormEntity(postParameters)); + HttpResponse response = new DefaultHttpClient().execute(post); return response.getEntity().getContent(); - } catch (Exception e) - { + } catch (Exception e) { log.error("Error while getting json solr result for discovery search recommendation", e); } return null; } - protected DiscoverResult retrieveResult(Context context, DiscoverQuery query, QueryResponse solrQueryResponse) throws SQLException { + protected DiscoverResult retrieveResult(Context context, DiscoverQuery query, QueryResponse solrQueryResponse) + throws SQLException { DiscoverResult result = new DiscoverResult(); - if (solrQueryResponse != null) - { + if (solrQueryResponse != null) { result.setSearchTime(solrQueryResponse.getQTime()); result.setStart(query.getStart()); result.setMaxResults(query.getMaxResults()); result.setTotalSearchResults(solrQueryResponse.getResults().getNumFound()); List searchFields = query.getSearchFields(); - for (SolrDocument doc : solrQueryResponse.getResults()) - { + for (SolrDocument doc : solrQueryResponse.getResults()) { DSpaceObject dso = findDSpaceObject(context, doc); - if (dso != null) - { + if (dso != null) { result.addDSpaceObject(dso); } else { - log.error(LogManager.getHeader(context, "Error while retrieving DSpace object from discovery index", "Handle: " + doc.getFirstValue(HANDLE_FIELD))); + log.error(LogManager.getHeader(context, "Error while retrieving DSpace object from discovery index", + "Handle: " + doc.getFirstValue(HANDLE_FIELD))); continue; } DiscoverResult.SearchDocument resultDoc = new DiscoverResult.SearchDocument(); //Add information about our search fields - for (String field : searchFields) - { + for (String field : searchFields) { List valuesAsString = new ArrayList(); - for (Object o : doc.getFieldValues(field)) - { + for (Object o : doc.getFieldValues(field)) { valuesAsString.add(String.valueOf(o)); } resultDoc.addSearchField(field, valuesAsString.toArray(new String[valuesAsString.size()])); } result.addSearchDocument(dso, resultDoc); - if (solrQueryResponse.getHighlighting() != null) - { - Map> highlightedFields = solrQueryResponse.getHighlighting().get(dso.getType() + "-" + dso.getID()); - if (MapUtils.isNotEmpty(highlightedFields)) - { + if (solrQueryResponse.getHighlighting() != null) { + Map> highlightedFields = solrQueryResponse.getHighlighting().get( + dso.getType() + "-" + dso.getID()); + if (MapUtils.isNotEmpty(highlightedFields)) { //We need to remove all the "_hl" appendix strings from our keys Map> resultMap = new HashMap>(); - for(String key : highlightedFields.keySet()) - { + for (String key : highlightedFields.keySet()) { resultMap.put(key.substring(0, key.lastIndexOf("_hl")), highlightedFields.get(key)); } - result.addHighlightedResult(dso, new DiscoverResult.DSpaceObjectHighlightResult(dso, resultMap)); + result + .addHighlightedResult(dso, new DiscoverResult.DSpaceObjectHighlightResult(dso, resultMap)); } } } //Resolve our facet field values List facetFields = solrQueryResponse.getFacetFields(); - if (facetFields != null) - { - for (int i = 0; i < facetFields.size(); i++) - { + if (facetFields != null) { + for (int i = 0; i < facetFields.size(); i++) { FacetField facetField = facetFields.get(i); DiscoverFacetField facetFieldConfig = query.getFacetFields().get(i); List facetValues = facetField.getValues(); - if (facetValues != null) - { - if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE) && facetFieldConfig.getSortOrder().equals(DiscoveryConfigurationParameters.SORT.VALUE)) - { - //If we have a date & are sorting by value, ensure that the results are flipped for a proper result - Collections.reverse(facetValues); + if (facetValues != null) { + if (facetFieldConfig.getType() + .equals(DiscoveryConfigurationParameters.TYPE_DATE) && facetFieldConfig + .getSortOrder().equals(DiscoveryConfigurationParameters.SORT.VALUE)) { + //If we have a date & are sorting by value, ensure that the results are flipped for a + // proper result + Collections.reverse(facetValues); } - for (FacetField.Count facetValue : facetValues) - { - String displayedValue = transformDisplayedValue(context, facetField.getName(), facetValue.getName()); + for (FacetField.Count facetValue : facetValues) { + String displayedValue = transformDisplayedValue(context, facetField.getName(), + facetValue.getName()); String field = transformFacetField(facetFieldConfig, facetField.getName(), true); - String authorityValue = transformAuthorityValue(context, facetField.getName(), facetValue.getName()); + String authorityValue = transformAuthorityValue(context, facetField.getName(), + facetValue.getName()); String sortValue = transformSortValue(context, facetField.getName(), facetValue.getName()); String filterValue = displayedValue; - if (StringUtils.isNotBlank(authorityValue)) - { + if (StringUtils.isNotBlank(authorityValue)) { filterValue = authorityValue; } result.addFacetResult( - field, - new DiscoverResult.FacetResult(filterValue, - displayedValue, authorityValue, - sortValue, facetValue.getCount())); + field, + new DiscoverResult.FacetResult(filterValue, + displayedValue, authorityValue, + sortValue, facetValue.getCount(), + facetFieldConfig.getType())); } } } } - if (solrQueryResponse.getFacetQuery() != null) - { + if (solrQueryResponse.getFacetQuery() != null) { // just retrieve the facets in the order they where requested! // also for the date we ask it in proper (reverse) order // At the moment facet queries are only used for dates - LinkedHashMap sortedFacetQueries = new LinkedHashMap(solrQueryResponse.getFacetQuery()); - for(String facetQuery : sortedFacetQueries.keySet()) - { + LinkedHashMap sortedFacetQueries = new LinkedHashMap( + solrQueryResponse.getFacetQuery()); + for (String facetQuery : sortedFacetQueries.keySet()) { //TODO: do not assume this, people may want to use it for other ends, use a regex to make sure //We have a facet query, the values looks something like: dateissued.year:[1990 TO 2000] AND -2000 //Prepare the string from {facet.field.name}:[startyear TO endyear] to startyear - endyear String facetField = facetQuery.substring(0, facetQuery.indexOf(":")); String name = ""; String filter = ""; - if (facetQuery.indexOf('[') > -1 && facetQuery.lastIndexOf(']') > -1) - { + if (facetQuery.indexOf('[') > -1 && facetQuery.lastIndexOf(']') > -1) { name = facetQuery.substring(facetQuery.indexOf('[') + 1); name = name.substring(0, name.lastIndexOf(']')).replaceAll("TO", "-"); filter = facetQuery.substring(facetQuery.indexOf('[')); @@ -1937,18 +1911,18 @@ public class SolrServiceImpl implements SearchService, IndexingService { Integer count = sortedFacetQueries.get(facetQuery); //No need to show empty years - if (0 < count) - { - result.addFacetResult(facetField, new DiscoverResult.FacetResult(filter, name, null, name, count)); + if (0 < count) { + result.addFacetResult(facetField, + new DiscoverResult.FacetResult(filter, name, null, name, count, + DiscoveryConfigurationParameters + .TYPE_DATE)); } } } - if (solrQueryResponse.getSpellCheckResponse() != null) - { + if (solrQueryResponse.getSpellCheckResponse() != null) { String recommendedQuery = solrQueryResponse.getSpellCheckResponse().getCollatedResult(); - if (StringUtils.isNotBlank(recommendedQuery)) - { + if (StringUtils.isNotBlank(recommendedQuery)) { result.setSpellCheckQuery(recommendedQuery); } } @@ -1960,13 +1934,10 @@ public class SolrServiceImpl implements SearchService, IndexingService { /** * Find DSpace object by type and UUID or by handle from given Solr document * - * @param context - * The relevant DSpace Context. - * @param doc - * the solr document + * @param context The relevant DSpace Context. + * @param doc the solr document * @return DSpace object - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ protected DSpaceObject findDSpaceObject(Context context, SolrDocument doc) throws SQLException { @@ -1974,61 +1945,25 @@ public class SolrServiceImpl implements SearchService, IndexingService { UUID id = UUID.fromString((String) doc.getFirstValue(RESOURCE_ID_FIELD)); String handle = (String) doc.getFirstValue(HANDLE_FIELD); - if (type != null && id != null) - { + if (type != null && id != null) { return contentServiceFactory.getDSpaceObjectService(type).find(context, id); - } else if (handle != null) - { + } else if (handle != null) { return handleService.resolveToObject(context, handle); } return null; } - - /** - * Simple means to return the search result as an InputStream - * - * @param query discovery query - * @return input stream - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SearchServiceException if something went wrong with querying the solr server - */ - public java.io.InputStream searchAsInputStream(DiscoverQuery query) throws SearchServiceException, java.io.IOException { - if (getSolr() == null) - { - return null; - } - HttpHost hostURL = (HttpHost)(getSolr().getHttpClient().getParams().getParameter(ClientPNames.DEFAULT_HOST)); - - HttpGet method = new HttpGet(hostURL.toHostString() + ""); - try - { - URI uri = new URIBuilder(method.getURI()).addParameter("q",query.toString()).build(); - } - catch (URISyntaxException e) - { - throw new SearchServiceException(e); - } - - HttpResponse response = getSolr().getHttpClient().execute(method); - - return response.getEntity().getContent(); - } - - public List search(Context context, String query, int offset, int max, String... filterquery) - { + public List search(Context context, String query, int offset, int max, String... filterquery) { return search(context, query, null, true, offset, max, filterquery); } @Override - public List search(Context context, String query, String orderfield, boolean ascending, int offset, int max, String... filterquery) - { + public List search(Context context, String query, String orderfield, boolean ascending, int offset, + int max, String... filterquery) { try { - if (getSolr() == null) - { + if (getSolr() == null) { return Collections.emptyList(); } @@ -2038,33 +1973,30 @@ public class SolrServiceImpl implements SearchService, IndexingService { solrQuery.setFields(RESOURCE_ID_FIELD, RESOURCE_TYPE_FIELD); solrQuery.setStart(offset); solrQuery.setRows(max); - if (orderfield != null) - { + if (orderfield != null) { solrQuery.setSortField(orderfield, ascending ? SolrQuery.ORDER.asc : SolrQuery.ORDER.desc); } - if (filterquery != null) - { + if (filterquery != null) { solrQuery.addFilterQuery(filterquery); } - QueryResponse rsp = getSolr().query(solrQuery); + QueryResponse rsp = getSolr().query(solrQuery, SolrRequest.METHOD.POST); SolrDocumentList docs = rsp.getResults(); Iterator iter = docs.iterator(); List result = new ArrayList(); - while (iter.hasNext()) - { + while (iter.hasNext()) { SolrDocument doc = (SolrDocument) iter.next(); - DSpaceObject o = contentServiceFactory.getDSpaceObjectService((Integer) doc.getFirstValue(RESOURCE_TYPE_FIELD)).find(context, UUID.fromString((String) doc.getFirstValue(RESOURCE_ID_FIELD))); + DSpaceObject o = contentServiceFactory + .getDSpaceObjectService((Integer) doc.getFirstValue(RESOURCE_TYPE_FIELD)) + .find(context, UUID.fromString((String) doc.getFirstValue(RESOURCE_ID_FIELD))); - if (o != null) - { + if (o != null) { result.add(o); } } return result; - } catch (Exception e) - { + } catch (Exception e) { // Any acception that we get ignore it. // We do NOT want any crashed to shown by the user log.error(LogManager.getHeader(context, "Error while quering solr", "Queyr: " + query), e); @@ -2073,58 +2005,47 @@ public class SolrServiceImpl implements SearchService, IndexingService { } @Override - public DiscoverFilterQuery toFilterQuery(Context context, String field, String operator, String value) throws SQLException{ + public DiscoverFilterQuery toFilterQuery(Context context, String field, String operator, String value) + throws SQLException { DiscoverFilterQuery result = new DiscoverFilterQuery(); StringBuilder filterQuery = new StringBuilder(); - if (StringUtils.isNotBlank(field) && StringUtils.isNotBlank(value)) - { + if (StringUtils.isNotBlank(field) && StringUtils.isNotBlank(value)) { filterQuery.append(field); - if ("equals".equals(operator)) - { - //Query the keyword indexed field ! + + + if (operator.endsWith("equals")) { filterQuery.append("_keyword"); - } - else if ("authority".equals(operator)) - { - //Query the authority indexed field ! + } else if (operator.endsWith("authority")) { filterQuery.append("_authority"); } - else if ("notequals".equals(operator) - || "notcontains".equals(operator) - || "notauthority".equals(operator)) - { + + if (operator.startsWith("not")) { filterQuery.insert(0, "-"); } + + + filterQuery.append(":"); - if ("equals".equals(operator) || "notequals".equals(operator)) - { + if ("equals".equals(operator) || "notequals".equals(operator)) { //DO NOT ESCAPE RANGE QUERIES ! - if (!value.matches("\\[.*TO.*\\]")) - { + if (!value.matches("\\[.*TO.*\\]")) { value = ClientUtils.escapeQueryChars(value); filterQuery.append(value); - } - else - { - if (value.matches("\\[\\d{1,4} TO \\d{1,4}\\]")) - { - int minRange = Integer.parseInt(value.substring(1, value.length()-1).split(" TO ")[0]); - int maxRange = Integer.parseInt(value.substring(1, value.length()-1).split(" TO ")[1]); - value = "["+String.format("%04d", minRange) + " TO "+ String.format("%04d", maxRange) + "]"; + } else { + if (value.matches("\\[\\d{1,4} TO \\d{1,4}\\]")) { + int minRange = Integer.parseInt(value.substring(1, value.length() - 1).split(" TO ")[0]); + int maxRange = Integer.parseInt(value.substring(1, value.length() - 1).split(" TO ")[1]); + value = "[" + String.format("%04d", minRange) + " TO " + String.format("%04d", maxRange) + "]"; } filterQuery.append(value); } - } - else { + } else { //DO NOT ESCAPE RANGE QUERIES ! - if (!value.matches("\\[.*TO.*\\]")) - { + if (!value.matches("\\[.*TO.*\\]")) { value = ClientUtils.escapeQueryChars(value); filterQuery.append("(").append(value).append(")"); - } - else - { + } else { filterQuery.append(value); } } @@ -2137,10 +2058,9 @@ public class SolrServiceImpl implements SearchService, IndexingService { } @Override - public List getRelatedItems(Context context, Item item, DiscoveryMoreLikeThisConfiguration mltConfig) - { + public List getRelatedItems(Context context, Item item, DiscoveryMoreLikeThisConfiguration mltConfig) { List results = new ArrayList(); - try{ + try { SolrQuery solrQuery = new SolrQuery(); //Set the query to handle since this is unique solrQuery.setQuery(HANDLE_FIELD + ": " + item.getHandle()); @@ -2150,105 +2070,89 @@ public class SolrServiceImpl implements SearchService, IndexingService { solrQuery.setParam(MoreLikeThisParams.MLT, true); //Add a comma separated list of the similar fields @SuppressWarnings("unchecked") - java.util.Collection similarityMetadataFields = CollectionUtils.collect(mltConfig.getSimilarityMetadataFields(), new Transformer() - { - @Override - public Object transform(Object input) - { - //Add the mlt appendix ! - return input + "_mlt"; - } - }); + java.util.Collection similarityMetadataFields = CollectionUtils + .collect(mltConfig.getSimilarityMetadataFields(), new Transformer() { + @Override + public Object transform(Object input) { + //Add the mlt appendix ! + return input + "_mlt"; + } + }); solrQuery.setParam(MoreLikeThisParams.SIMILARITY_FIELDS, StringUtils.join(similarityMetadataFields, ',')); solrQuery.setParam(MoreLikeThisParams.MIN_TERM_FREQ, String.valueOf(mltConfig.getMinTermFrequency())); solrQuery.setParam(MoreLikeThisParams.DOC_COUNT, String.valueOf(mltConfig.getMax())); solrQuery.setParam(MoreLikeThisParams.MIN_WORD_LEN, String.valueOf(mltConfig.getMinWordLength())); - if (getSolr() == null) - { + if (getSolr() == null) { return Collections.emptyList(); } - QueryResponse rsp = getSolr().query(solrQuery); + QueryResponse rsp = getSolr().query(solrQuery, SolrRequest.METHOD.POST); NamedList mltResults = (NamedList) rsp.getResponse().get("moreLikeThis"); - if (mltResults != null && mltResults.get(item.getType() + "-" + item.getID()) != null) - { + if (mltResults != null && mltResults.get(item.getType() + "-" + item.getID()) != null) { SolrDocumentList relatedDocs = (SolrDocumentList) mltResults.get(item.getType() + "-" + item.getID()); - for (Object relatedDoc : relatedDocs) - { + for (Object relatedDoc : relatedDocs) { SolrDocument relatedDocument = (SolrDocument) relatedDoc; DSpaceObject relatedItem = findDSpaceObject(context, relatedDocument); - if (relatedItem.getType() == Constants.ITEM) - { + if (relatedItem.getType() == Constants.ITEM) { results.add((Item) relatedItem); } } } - } catch (Exception e) - { - log.error(LogManager.getHeader(context, "Error while retrieving related items", "Handle: " + item.getHandle()), e); + } catch (Exception e) { + log.error( + LogManager.getHeader(context, "Error while retrieving related items", "Handle: " + item.getHandle()), + e); } return results; } @Override - public String toSortFieldIndex(String metadataField, String type) - { - if (type.equals(DiscoveryConfigurationParameters.TYPE_DATE)) - { + public String toSortFieldIndex(String metadataField, String type) { + if (StringUtils.equalsIgnoreCase(SCORE, metadataField)) { + return SCORE; + } else if (StringUtils.equals(type, DiscoveryConfigurationParameters.TYPE_DATE)) { return metadataField + "_dt"; } else { return metadataField + "_sort"; } } - protected String transformFacetField(DiscoverFacetField facetFieldConfig, String field, boolean removePostfix) - { - if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_TEXT)) - { - if (removePostfix) - { + protected String transformFacetField(DiscoverFacetField facetFieldConfig, String field, boolean removePostfix) { + if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_TEXT)) { + if (removePostfix) { return field.substring(0, field.lastIndexOf("_filter")); } else { return field + "_filter"; } - } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) - { - if (removePostfix) - { + } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)) { + if (removePostfix) { return field.substring(0, field.lastIndexOf(".year")); } else { return field + ".year"; } - } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_AC)) - { - if (removePostfix) - { + } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_AC)) { + if (removePostfix) { return field.substring(0, field.lastIndexOf("_ac")); } else { return field + "_ac"; } - } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) - { - if (removePostfix) - { + } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) { + if (removePostfix) { return StringUtils.substringBeforeLast(field, "_tax_"); } else { //Only display top level filters ! return field + "_tax_0_filter"; } - } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_AUTHORITY)) - { - if (removePostfix) - { + } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_AUTHORITY)) { + if (removePostfix) { return field.substring(0, field.lastIndexOf("_acid")); } else { return field + "_acid"; } - } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_STANDARD)) - { + } else if (facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_STANDARD)) { return field; } else { return field; @@ -2256,17 +2160,14 @@ public class SolrServiceImpl implements SearchService, IndexingService { } protected String transformDisplayedValue(Context context, String field, String value) throws SQLException { - if (field.equals("location.comm") || field.equals("location.coll")) - { + if (field.equals("location.comm") || field.equals("location.coll")) { value = locationToName(context, field, value); - } - else if (field.endsWith("_filter") || field.endsWith("_ac") - || field.endsWith("_acid")) - { + } else if (field.endsWith("_filter") || field.endsWith("_ac") + || field.endsWith("_acid")) { //We have a filter make sure we split ! - String separator = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("discovery.solr.facets.split.char"); - if (separator == null) - { + String separator = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("discovery.solr.facets.split.char"); + if (separator == null) { separator = FILTER_SEPARATOR; } //Escape any regex chars @@ -2274,32 +2175,28 @@ public class SolrServiceImpl implements SearchService, IndexingService { String[] fqParts = value.split(separator); StringBuffer valueBuffer = new StringBuffer(); int start = fqParts.length / 2; - for(int i = start; i < fqParts.length; i++) - { + for (int i = start; i < fqParts.length; i++) { String[] split = fqParts[i].split(AUTHORITY_SEPARATOR, 2); valueBuffer.append(split[0]); } value = valueBuffer.toString(); - } else if (value.matches("\\((.*?)\\)")) - { + } else if (value.matches("\\((.*?)\\)")) { //The brackets where added for better solr results, remove the first & last one - value = value.substring(1, value.length() -1); + value = value.substring(1, value.length() - 1); } return value; } protected String transformAuthorityValue(Context context, String field, String value) throws SQLException { - if (field.equals("location.comm") || field.equals("location.coll")) - { + if (field.equals("location.comm") || field.equals("location.coll")) { return value; } if (field.endsWith("_filter") || field.endsWith("_ac") - || field.endsWith("_acid")) - { + || field.endsWith("_acid")) { //We have a filter make sure we split ! - String separator = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("discovery.solr.facets.split.char"); - if (separator == null) - { + String separator = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("discovery.solr.facets.split.char"); + if (separator == null) { separator = FILTER_SEPARATOR; } //Escape any regex chars @@ -2307,16 +2204,13 @@ public class SolrServiceImpl implements SearchService, IndexingService { String[] fqParts = value.split(separator); StringBuffer authorityBuffer = new StringBuffer(); int start = fqParts.length / 2; - for(int i = start; i < fqParts.length; i++) - { + for (int i = start; i < fqParts.length; i++) { String[] split = fqParts[i].split(AUTHORITY_SEPARATOR, 2); - if (split.length == 2) - { + if (split.length == 2) { authorityBuffer.append(split[1]); } } - if (authorityBuffer.length() > 0) - { + if (authorityBuffer.length() > 0) { return authorityBuffer.toString(); } } @@ -2324,17 +2218,14 @@ public class SolrServiceImpl implements SearchService, IndexingService { } protected String transformSortValue(Context context, String field, String value) throws SQLException { - if (field.equals("location.comm") || field.equals("location.coll")) - { + if (field.equals("location.comm") || field.equals("location.coll")) { value = locationToName(context, field, value); - } - else if (field.endsWith("_filter") || field.endsWith("_ac") - || field.endsWith("_acid")) - { + } else if (field.endsWith("_filter") || field.endsWith("_ac") + || field.endsWith("_acid")) { //We have a filter make sure we split ! - String separator = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("discovery.solr.facets.split.char"); - if (separator == null) - { + String separator = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("discovery.solr.facets.split.char"); + if (separator == null) { separator = FILTER_SEPARATOR; } //Escape any regex chars @@ -2342,25 +2233,22 @@ public class SolrServiceImpl implements SearchService, IndexingService { String[] fqParts = value.split(separator); StringBuffer valueBuffer = new StringBuffer(); int end = fqParts.length / 2; - for(int i = 0; i < end; i++) - { + for (int i = 0; i < end; i++) { valueBuffer.append(fqParts[i]); } value = valueBuffer.toString(); - } else if (value.matches("\\((.*?)\\)")) - { + } else if (value.matches("\\((.*?)\\)")) { //The brackets where added for better solr results, remove the first & last one - value = value.substring(1, value.length() -1); + value = value.substring(1, value.length() - 1); } return value; } @Override public void indexContent(Context context, DSpaceObject dso, boolean force, - boolean commit) throws SearchServiceException, SQLException { + boolean commit) throws SearchServiceException, SQLException { indexContent(context, dso, force); - if (commit) - { + if (commit) { commit(); } } @@ -2368,8 +2256,7 @@ public class SolrServiceImpl implements SearchService, IndexingService { @Override public void commit() throws SearchServiceException { try { - if (getSolr() != null) - { + if (getSolr() != null) { getSolr().commit(); } } catch (Exception e) { @@ -2385,4 +2272,37 @@ public class SolrServiceImpl implements SearchService, IndexingService { // rely on special characters to separate the field from the query value) return ClientUtils.escapeQueryChars(query); } + + @Override + public FacetYearRange getFacetYearRange(Context context, DSpaceObject scope, DiscoverySearchFilterFacet facet, + List filterQueries) throws SearchServiceException { + FacetYearRange result = new FacetYearRange(facet); + result.calculateRange(context, filterQueries, scope, this); + return result; + } + + @Override + public String calculateExtremeValue(Context context, String valueField, + String sortField, + DiscoverQuery.SORT_ORDER sortOrder) + throws SearchServiceException { + + DiscoverQuery maxQuery = new DiscoverQuery(); + maxQuery.setMaxResults(1); + //Set our query to anything that has this value + maxQuery.addFieldPresentQueries(valueField); + //Set sorting so our last value will appear on top + maxQuery.setSortField(sortField, sortOrder); + maxQuery.addSearchField(valueField); + DiscoverResult maxResult = this.search(context,maxQuery); + if (0 < maxResult.getDspaceObjects().size()) { + List searchDocuments = maxResult + .getSearchDocument(maxResult.getDspaceObjects().get(0)); + if (0 < searchDocuments.size() && 0 < searchDocuments.get(0).getSearchFieldValues + (valueField).size()) { + return searchDocuments.get(0).getSearchFieldValues(valueField).get(0); + } + } + return null; + } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceIndexOutputPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceIndexOutputPlugin.java index e162be4f7d..58c0f92c8f 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceIndexOutputPlugin.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceIndexOutputPlugin.java @@ -17,7 +17,7 @@ import org.dspace.core.Context; * * @author Kevin Van de Velde (kevin at atmire dot com) */ -public class SolrServiceIndexOutputPlugin implements SolrServiceIndexPlugin{ +public class SolrServiceIndexOutputPlugin implements SolrServiceIndexPlugin { @Override public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) { diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceMetadataBrowseIndexingPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceMetadataBrowseIndexingPlugin.java index 9874f40eee..b47f81b6a2 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceMetadataBrowseIndexingPlugin.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceMetadataBrowseIndexingPlugin.java @@ -8,88 +8,81 @@ package org.dspace.discovery; import java.util.HashSet; -import org.apache.solr.common.SolrInputDocument; -import org.dspace.content.MetadataValue; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; -import org.dspace.content.service.ItemService; -import org.dspace.core.Context; -import org.springframework.beans.factory.annotation.Autowired; - import java.util.List; import java.util.Set; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.apache.solr.common.SolrInputDocument; import org.dspace.browse.BrowseException; import org.dspace.browse.BrowseIndex; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.authority.service.ChoiceAuthorityService; import org.dspace.content.authority.service.MetadataAuthorityService; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.sort.OrderFormat; import org.dspace.sort.SortException; import org.dspace.sort.SortOption; +import org.springframework.beans.factory.annotation.Autowired; /** * A Solr Indexing plugin for the "metadata" browse index type. *

    * For Example: - * webui.browse.index.2 = author:metadata:dc.contributor.*\,dc.creator:text - * OR - * webui.browse.index.4 = subject:metadata:dc.subject.*:text + * webui.browse.index.2 = author:metadata:dc.contributor.*\,dc.creator:text + * OR + * webui.browse.index.4 = subject:metadata:dc.subject.*:text *

    * This plugin was based heavily on the old (DSpace 5.x or below), SolrBrowseCreateDAO * class, specifically its "additionalIndex()" method, which used to perform this function. - * + * * @author Tim Donohue */ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndexPlugin { private static final Logger log = Logger - .getLogger(SolrServiceMetadataBrowseIndexingPlugin.class); - + .getLogger(SolrServiceMetadataBrowseIndexingPlugin.class); + @Autowired(required = true) protected ItemService itemService; - + @Autowired(required = true) protected MetadataAuthorityService metadataAuthorityService; - + @Autowired(required = true) protected ChoiceAuthorityService choiceAuthorityService; @Override - public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) - { + public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) { // Only works for Items - if (!(dso instanceof Item)) - { + if (!(dso instanceof Item)) { return; } Item item = (Item) dso; // Get the currently configured browse indexes BrowseIndex[] bis; - try - { + try { bis = BrowseIndex.getBrowseIndices(); - } - catch (BrowseException e) - { + } catch (BrowseException e) { log.error(e.getMessage(), e); throw new IllegalStateException(e); } - + // Faceting for metadata browsing. It is different than search facet // because if there are authority with variants support we want all the // variants to go in the facet... they are sorted by count so just the // prefered label is relevant - for (BrowseIndex bi : bis) - { + for (BrowseIndex bi : bis) { log.debug("Indexing for item " + item.getID() + ", for index: " - + bi.getTableName()); + + bi.getTableName()); // ONLY perform indexing for "metadata" type indices - if (bi.isMetadataIndex()) - { + if (bi.isMetadataIndex()) { // Generate our bits of metadata (so getMdBits() can be used below) bi.generateMdBits(); @@ -104,154 +97,153 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex // now index the new details - but only if it's archived or // withdrawn - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { // get the metadata from the item - for (int mdIdx = 0; mdIdx < bi.getMetadataCount(); mdIdx++) - { + for (int mdIdx = 0; mdIdx < bi.getMetadataCount(); mdIdx++) { String[] md = bi.getMdBits(mdIdx); List values = itemService.getMetadata(item, md[0], md[1], - md[2], Item.ANY); + md[2], Item.ANY); // if we have values to index on, then do so - if (values != null && values.size() > 0) - { - int minConfidence = metadataAuthorityService.getMinConfidence(values.get(0).getMetadataField()); + if (values != null && values.size() > 0) { + int minConfidence = metadataAuthorityService + .getMinConfidence(values.get(0).getMetadataField()); - boolean ignoreAuthority = DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.browse.authority.ignore." - + bi.getName(), - DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.browse.authority.ignore", - new Boolean(false)), - true); - for (int x = 0; x < values.size(); x++) - { + boolean ignoreAuthority = + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.browse.authority.ignore." + bi.getName(), + DSpaceServicesFactory.getInstance() + .getConfigurationService() + .getPropertyAsType( + "discovery.browse.authority.ignore", + new Boolean(false) + ), + true); + + for (int x = 0; x < values.size(); x++) { // Ensure that there is a value to index before // inserting it - if (StringUtils.isEmpty(values.get(x).getValue())) - { + if (StringUtils.isEmpty(values.get(x).getValue())) { log.error("Null metadata value for item " - + item.getID() - + ", field: " - + values.get(x).getMetadataField().toString() + + item.getID() + + ", field: " + + values.get(x).getMetadataField().toString() ); - } - else - { + } else { if (bi.isAuthorityIndex() - && (values.get(x).getAuthority() == null || values.get(x).getConfidence() < minConfidence)) - { + && (values.get(x).getAuthority() == null || values.get(x) + .getConfidence() < + minConfidence)) { // if we have an authority index only // authored metadata will go here! log.debug("Skipping item=" - + item.getID() + ", field=" - + values.get(x).getMetadataField().toString() - + ", value=" + values.get(x).getValue() - + ", authority=" - + values.get(x).getAuthority() - + ", confidence=" - + values.get(x).getConfidence() - + " (BAD AUTHORITY)"); + + item.getID() + ", field=" + + values.get(x).getMetadataField().toString() + + ", value=" + values.get(x).getValue() + + ", authority=" + + values.get(x).getAuthority() + + ", confidence=" + + values.get(x).getConfidence() + + " (BAD AUTHORITY)"); continue; } // is there any valid (with appropriate // confidence) authority key? if ((ignoreAuthority && !bi.isAuthorityIndex()) - || (values.get(x).getAuthority() != null && values.get(x).getConfidence() >= minConfidence)) - { + || (values.get(x).getAuthority() != null && values.get(x) + .getConfidence() >= + minConfidence)) { distFAuths.add(values.get(x).getAuthority()); distValuesForAC.add(values.get(x).getValue()); String preferedLabel = null; - boolean ignorePrefered = DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.browse.authority.ignore-prefered." - + bi.getName(), - DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.browse.authority.ignore-prefered", - new Boolean( - false)), - true); - if (!ignorePrefered) - { + boolean ignorePrefered = + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.browse.authority.ignore-prefered." + + bi.getName(), + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType( + "discovery.browse.authority.ignore-prefered", + new Boolean(false)), + true); + if (!ignorePrefered) { preferedLabel = choiceAuthorityService - .getLabel(values.get(x), values.get(x).getLanguage()); + .getLabel(values.get(x), values.get(x).getLanguage()); } List variants = null; - boolean ignoreVariants = DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.browse.authority.ignore-variants." - + bi.getName(), - DSpaceServicesFactory.getInstance().getConfigurationService() - .getPropertyAsType( - "discovery.browse.authority.ignore-variants", - new Boolean( - false)), - true); - if (!ignoreVariants) - { + boolean ignoreVariants = + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType("discovery.browse.authority.ignore-variants." + + bi.getName(), + DSpaceServicesFactory + .getInstance() + .getConfigurationService() + .getPropertyAsType( + "discovery.browse.authority.ignore-variants", + new Boolean(false)), + true); + if (!ignoreVariants) { variants = choiceAuthorityService - .getVariants( - values.get(x)); + .getVariants( + values.get(x)); } if (StringUtils - .isNotBlank(preferedLabel)) - { + .isNotBlank(preferedLabel)) { String nLabel = OrderFormat - .makeSortString( - preferedLabel, - values.get(x).getLanguage(), - bi.getDataType()); + .makeSortString( + preferedLabel, + values.get(x).getLanguage(), + bi.getDataType()); distFValues - .add(nLabel - + SolrServiceImpl.FILTER_SEPARATOR - + preferedLabel - + SolrServiceImpl.AUTHORITY_SEPARATOR - + values.get(x).getAuthority()); + .add(nLabel + + SolrServiceImpl.FILTER_SEPARATOR + + preferedLabel + + SolrServiceImpl.AUTHORITY_SEPARATOR + + values.get(x).getAuthority()); distValuesForAC.add(preferedLabel); } - if (variants != null) - { - for (String var : variants) - { + if (variants != null) { + for (String var : variants) { String nVal = OrderFormat - .makeSortString( - var, - values.get(x).getLanguage(), - bi.getDataType()); + .makeSortString( + var, + values.get(x).getLanguage(), + bi.getDataType()); distFValues - .add(nVal - + SolrServiceImpl.FILTER_SEPARATOR - + var - + SolrServiceImpl.AUTHORITY_SEPARATOR - + values.get(x).getAuthority()); + .add(nVal + + SolrServiceImpl.FILTER_SEPARATOR + + var + + SolrServiceImpl.AUTHORITY_SEPARATOR + + values.get(x).getAuthority()); distValuesForAC.add(var); } } - } - else - // put it in the browse index as if it - // hasn't have an authority key - { - // get the normalised version of the - // value + } else { + // put it in the browse index as if it + // hasn't have an authority key + + // get the normalised version of the value String nVal = OrderFormat - .makeSortString( - values.get(x).getValue(), - values.get(x).getLanguage(), - bi.getDataType()); + .makeSortString( + values.get(x).getValue(), + values.get(x).getLanguage(), + bi.getDataType()); distFValues - .add(nVal - + SolrServiceImpl.FILTER_SEPARATOR - + values.get(x).getValue()); + .add(nVal + + SolrServiceImpl.FILTER_SEPARATOR + + values.get(x).getValue()); distFVal.add(values.get(x).getValue()); distValuesForAC.add(values.get(x).getValue()); } @@ -261,43 +253,34 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex } } - for (String facet : distFValues) - { + for (String facet : distFValues) { document.addField(bi.getDistinctTableName() + "_filter", facet); } - for (String facet : distFAuths) - { + for (String facet : distFAuths) { document.addField(bi.getDistinctTableName() - + "_authority_filter", facet); + + "_authority_filter", facet); } - for (String facet : distValuesForAC) - { + for (String facet : distValuesForAC) { document.addField(bi.getDistinctTableName() + "_partial", facet); } - for (String facet : distFVal) - { - document.addField(bi.getDistinctTableName()+"_value_filter", facet); + for (String facet : distFVal) { + document.addField(bi.getDistinctTableName() + "_value_filter", facet); } } } // Add sorting options as configurated for the browse system - try - { - for (SortOption so : SortOption.getSortOptions()) - { + try { + for (SortOption so : SortOption.getSortOptions()) { List dcvalue = itemService.getMetadataByMetadataString(item, so.getMetadata()); - if (dcvalue != null && dcvalue.size() > 0) - { + if (dcvalue != null && dcvalue.size() > 0) { String nValue = OrderFormat - .makeSortString(dcvalue.get(0).getValue(), - dcvalue.get(0).getLanguage(), so.getType()); + .makeSortString(dcvalue.get(0).getValue(), + dcvalue.get(0).getLanguage(), so.getType()); document.addField("bi_sort_" + so.getNumber() + "_sort", nValue); } } - } - catch (SortException e) - { + } catch (SortException e) { // we can't solve it so rethrow as runtime exception throw new RuntimeException(e.getMessage(), e); } diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceResourceRestrictionPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceResourceRestrictionPlugin.java index ee8c265984..4bea98390d 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceResourceRestrictionPlugin.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceResourceRestrictionPlugin.java @@ -7,6 +7,9 @@ */ package org.dspace.discovery; +import java.sql.SQLException; +import java.util.List; +import java.util.Set; import org.apache.log4j.Logger; import org.apache.solr.client.solrj.SolrQuery; @@ -26,10 +29,6 @@ import org.dspace.eperson.service.GroupService; import org.dspace.services.factory.DSpaceServicesFactory; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.List; -import java.util.Set; - /** * Restriction plugin that ensures that indexes all the resource policies. * When a search is performed extra filter queries are added to retrieve only results to which the user has READ access @@ -38,7 +37,7 @@ import java.util.Set; * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) */ -public class SolrServiceResourceRestrictionPlugin implements SolrServiceIndexPlugin, SolrServiceSearchPlugin{ +public class SolrServiceResourceRestrictionPlugin implements SolrServiceIndexPlugin, SolrServiceSearchPlugin { private static final Logger log = Logger.getLogger(SolrServiceResourceRestrictionPlugin.class); @@ -59,10 +58,10 @@ public class SolrServiceResourceRestrictionPlugin implements SolrServiceIndexPlu List policies = authorizeService.getPoliciesActionFilter(context, dso, Constants.READ); for (ResourcePolicy resourcePolicy : policies) { String fieldValue; - if(resourcePolicy.getGroup() != null){ + if (resourcePolicy.getGroup() != null) { //We have a group add it to the value fieldValue = "g" + resourcePolicy.getGroup().getID(); - }else{ + } else { //We have an eperson add it to the value fieldValue = "e" + resourcePolicy.getEPerson().getID(); @@ -74,24 +73,25 @@ public class SolrServiceResourceRestrictionPlugin implements SolrServiceIndexPlu context.uncacheEntity(resourcePolicy); } } catch (SQLException e) { - log.error(LogManager.getHeader(context, "Error while indexing resource policies", "DSpace object: (id " + dso.getID() + " type " + dso.getType() + ")")); + log.error(LogManager.getHeader(context, "Error while indexing resource policies", + "DSpace object: (id " + dso.getID() + " type " + dso.getType() + ")")); } } @Override public void additionalSearchParameters(Context context, DiscoverQuery discoveryQuery, SolrQuery solrQuery) { - try { - if(!authorizeService.isAdmin(context)){ - StringBuilder resourceQuery = new StringBuilder(); + try { + if (!authorizeService.isAdmin(context)) { + StringBuilder resourceQuery = new StringBuilder(); //Always add the anonymous group id to the query - Group anonymousGroup = groupService.findByName(context,Group.ANONYMOUS); + Group anonymousGroup = groupService.findByName(context, Group.ANONYMOUS); String anonGroupId = ""; - if(anonymousGroup!=null){ + if (anonymousGroup != null) { anonGroupId = anonymousGroup.getID().toString(); } - resourceQuery.append("read:(g"+anonGroupId); + resourceQuery.append("read:(g" + anonGroupId); EPerson currentUser = context.getCurrentUser(); - if(currentUser != null){ + if (currentUser != null) { resourceQuery.append(" OR e").append(currentUser.getID()); } @@ -101,17 +101,18 @@ public class SolrServiceResourceRestrictionPlugin implements SolrServiceIndexPlu resourceQuery.append(" OR g").append(group.getID()); } - resourceQuery.append(")"); - - if(authorizeService.isCommunityAdmin(context) - || authorizeService.isCollectionAdmin(context)) - { + resourceQuery.append(")"); + + if (authorizeService.isCommunityAdmin(context) + || authorizeService.isCollectionAdmin(context)) { resourceQuery.append(" OR "); resourceQuery.append(DSpaceServicesFactory.getInstance() - .getServiceManager().getServiceByName(SearchService.class.getName(), SearchService.class) - .createLocationQueryForAdministrableItems(context)); + .getServiceManager() + .getServiceByName(SearchService.class.getName(), + SearchService.class) + .createLocationQueryForAdministrableItems(context)); } - + solrQuery.addFilterQuery(resourceQuery.toString()); } } catch (SQLException e) { diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceSpellIndexingPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceSpellIndexingPlugin.java index c7bade91f6..c6a4b602ca 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceSpellIndexingPlugin.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceSpellIndexingPlugin.java @@ -7,16 +7,16 @@ */ package org.dspace.discovery; +import java.util.List; + import org.apache.solr.common.SolrInputDocument; -import org.dspace.content.MetadataValue; import org.dspace.content.DSpaceObject; 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; -import java.util.List; - /** * Created with IntelliJ IDEA. * User: kevin @@ -31,12 +31,12 @@ public class SolrServiceSpellIndexingPlugin implements SolrServiceIndexPlugin { @Override public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) { - if(dso instanceof Item){ + if (dso instanceof Item) { Item item = (Item) dso; List dcValues = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); List toIgnoreMetadataFields = SearchUtils.getIgnoredMetadataFields(item.getType()); for (MetadataValue dcValue : dcValues) { - if(!toIgnoreMetadataFields.contains(dcValue.getMetadataField().toString('.'))){ + if (!toIgnoreMetadataFields.contains(dcValue.getMetadataField().toString('.'))) { document.addField("a_spell", dcValue.getValue()); } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfiguration.java index 5cc8032ecc..b9fe50a7ae 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfiguration.java @@ -7,37 +7,46 @@ */ package org.dspace.discovery.configuration; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Required; - import java.util.ArrayList; import java.util.Collection; import java.util.List; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Required; + /** * @author Kevin Van de Velde (kevin at atmire dot com) */ -public class DiscoveryConfiguration implements InitializingBean{ +public class DiscoveryConfiguration implements InitializingBean { - /** The configuration for the sidebar facets **/ - private List sidebarFacets = new ArrayList(); + /** + * The configuration for the sidebar facets + **/ + private List sidebarFacets = new ArrayList<>(); private TagCloudFacetConfiguration tagCloudFacetConfiguration = new TagCloudFacetConfiguration(); - - /** The default filter queries which will be applied to any search & the recent submissions **/ + + /** + * The default filter queries which will be applied to any search & the recent submissions + **/ private List defaultFilterQueries; - /** Configuration object for the recent submissions **/ + /** + * Configuration object for the recent submissions + **/ private DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration; - /** The search filters which can be selected on the search page**/ - private List searchFilters = new ArrayList(); + /** + * The search filters which can be selected on the search page + **/ + private List searchFilters = new ArrayList<>(); private DiscoverySortConfiguration searchSortConfiguration; private int defaultRpp = 10; - + private String id; private DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration; private DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration; @@ -61,18 +70,18 @@ public class DiscoveryConfiguration implements InitializingBean{ } public TagCloudFacetConfiguration getTagCloudFacetConfiguration() { - return tagCloudFacetConfiguration; - } + return tagCloudFacetConfiguration; + } - public void setTagCloudFacetConfiguration(TagCloudFacetConfiguration tagCloudFacetConfiguration) { - this.tagCloudFacetConfiguration = tagCloudFacetConfiguration; - } + public void setTagCloudFacetConfiguration(TagCloudFacetConfiguration tagCloudFacetConfiguration) { + this.tagCloudFacetConfiguration = tagCloudFacetConfiguration; + } - public List getDefaultFilterQueries() { + public List getDefaultFilterQueries() { //Since default filter queries are not mandatory we will return an empty list - if(defaultFilterQueries == null){ + if (defaultFilterQueries == null) { return new ArrayList(); - }else{ + } else { return defaultFilterQueries; } } @@ -85,7 +94,8 @@ public class DiscoveryConfiguration implements InitializingBean{ return recentSubmissionConfiguration; } - public void setRecentSubmissionConfiguration(DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration) { + public void setRecentSubmissionConfiguration( + DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration) { this.recentSubmissionConfiguration = recentSubmissionConfiguration; } @@ -93,6 +103,15 @@ public class DiscoveryConfiguration implements InitializingBean{ return searchFilters; } + public DiscoverySearchFilter getSearchFilter(String name) { + for (DiscoverySearchFilter filter : CollectionUtils.emptyIfNull(searchFilters)) { + if (StringUtils.equals(name, filter.getIndexFieldName())) { + return filter; + } + } + return null; + } + @Required public void setSearchFilters(List searchFilters) { this.searchFilters = searchFilters; @@ -106,14 +125,12 @@ public class DiscoveryConfiguration implements InitializingBean{ public void setSearchSortConfiguration(DiscoverySortConfiguration searchSortConfiguration) { this.searchSortConfiguration = searchSortConfiguration; } - - public void setDefaultRpp(int defaultRpp) - { + + public void setDefaultRpp(int defaultRpp) { this.defaultRpp = defaultRpp; } - - public int getDefaultRpp() - { + + public int getDefaultRpp() { return defaultRpp; } @@ -147,15 +164,12 @@ public class DiscoveryConfiguration implements InitializingBean{ * @throws Exception throws an exception if this isn't the case */ @Override - public void afterPropertiesSet() throws Exception - { + public void afterPropertiesSet() throws Exception { Collection missingSearchFilters = CollectionUtils.subtract(getSidebarFacets(), getSearchFilters()); - if(CollectionUtils.isNotEmpty(missingSearchFilters)) - { + if (CollectionUtils.isNotEmpty(missingSearchFilters)) { StringBuilder error = new StringBuilder(); error.append("The following sidebar facet configurations are not present in the search filters list: "); - for (Object missingSearchFilter : missingSearchFilters) - { + for (Object missingSearchFilter : missingSearchFilters) { DiscoverySearchFilter searchFilter = (DiscoverySearchFilter) missingSearchFilter; error.append(searchFilter.getIndexFieldName()).append(" "); @@ -164,14 +178,13 @@ public class DiscoveryConfiguration implements InitializingBean{ throw new DiscoveryConfigurationException(error.toString()); } - - Collection missingTagCloudSearchFilters = CollectionUtils.subtract(getTagCloudFacetConfiguration().getTagCloudFacets(), getSearchFilters()); - if(CollectionUtils.isNotEmpty(missingTagCloudSearchFilters)) - { + + Collection missingTagCloudSearchFilters = CollectionUtils + .subtract(getTagCloudFacetConfiguration().getTagCloudFacets(), getSearchFilters()); + if (CollectionUtils.isNotEmpty(missingTagCloudSearchFilters)) { StringBuilder error = new StringBuilder(); error.append("The following tagCloud facet configurations are not present in the search filters list: "); - for (Object missingSearchFilter : missingTagCloudSearchFilters) - { + for (Object missingSearchFilter : missingTagCloudSearchFilters) { DiscoverySearchFilter searchFilter = (DiscoverySearchFilter) missingSearchFilter; error.append(searchFilter.getIndexFieldName()).append(" "); @@ -180,5 +193,14 @@ public class DiscoveryConfiguration implements InitializingBean{ throw new DiscoveryConfigurationException(error.toString()); } - } + } + + public DiscoverySearchFilterFacet getSidebarFacet(final String facetName) { + for (DiscoverySearchFilterFacet sidebarFacet : sidebarFacets) { + if (StringUtils.equals(sidebarFacet.getIndexFieldName(), facetName)) { + return sidebarFacet; + } + } + return null; + } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationException.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationException.java index 1675109b0c..d0c5af85bd 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationException.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationException.java @@ -14,7 +14,7 @@ package org.dspace.discovery.configuration; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class DiscoveryConfigurationException extends Exception{ +public class DiscoveryConfigurationException extends Exception { public DiscoveryConfigurationException() { } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationParameters.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationParameters.java index a555c9bcbc..ed51fa8ef8 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationParameters.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationParameters.java @@ -21,7 +21,10 @@ public class DiscoveryConfigurationParameters { public static final String TYPE_AUTHORITY = "authority"; public static final String TYPE_STANDARD = "standard"; - public static enum SORT {VALUE, COUNT} - + public static enum SORT { VALUE, COUNT } + /** + * Default constructor + */ + private DiscoveryConfigurationParameters() { } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationService.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationService.java index 351371a70e..d2d32d5ad9 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationService.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryConfigurationService.java @@ -7,12 +7,14 @@ */ package org.dspace.discovery.configuration; -import org.dspace.services.factory.DSpaceServicesFactory; - import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.lang.StringUtils; +import org.dspace.content.DSpaceObject; +import org.dspace.services.factory.DSpaceServicesFactory; + /** * @author Kevin Van de Velde (kevin at atmire dot com) */ @@ -37,11 +39,48 @@ public class DiscoveryConfigurationService { this.toIgnoreMetadataFields = toIgnoreMetadataFields; } + public DiscoveryConfiguration getDiscoveryConfiguration(DSpaceObject dso) { + String name; + if (dso == null) { + name = "site"; + } else { + name = dso.getHandle(); + } + + return getDiscoveryConfiguration(name); + } + + public DiscoveryConfiguration getDiscoveryConfiguration(final String name) { + DiscoveryConfiguration result; + + result = StringUtils.isBlank(name) ? null : getMap().get(name); + + if (result == null) { + //No specific configuration, get the default one + result = getMap().get("default"); + } + + return result; + } + + public DiscoveryConfiguration getDiscoveryConfigurationByNameOrDso(final String configurationName, + final DSpaceObject dso) { + if (StringUtils.isNotBlank(configurationName) && getMap().containsKey(configurationName)) { + return getMap().get(configurationName); + } else { + return getDiscoveryConfiguration(dso); + } + } + public static void main(String[] args) { System.out.println(DSpaceServicesFactory.getInstance().getServiceManager().getServicesNames().size()); - DiscoveryConfigurationService mainService = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(DiscoveryConfigurationService.class.getName(), DiscoveryConfigurationService.class); + DiscoveryConfigurationService mainService = DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName( + DiscoveryConfigurationService.class + .getName(), + DiscoveryConfigurationService.class); - for(String key : mainService.getMap().keySet()){ + for (String key : mainService.getMap().keySet()) { System.out.println(key); System.out.println("Facets:"); @@ -66,12 +105,13 @@ public class DiscoveryConfigurationService { } System.out.println("Recent submissions configuration:"); - DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration = discoveryConfiguration.getRecentSubmissionConfiguration(); + DiscoveryRecentSubmissionsConfiguration recentSubmissionConfiguration = discoveryConfiguration + .getRecentSubmissionConfiguration(); System.out.println("\tMetadata sort field: " + recentSubmissionConfiguration.getMetadataSortField()); System.out.println("\tMax recent submissions: " + recentSubmissionConfiguration.getMax()); List defaultFilterQueries = discoveryConfiguration.getDefaultFilterQueries(); - if(0 < defaultFilterQueries.size()){ + if (0 < defaultFilterQueries.size()) { System.out.println("Default filter queries"); for (String fq : defaultFilterQueries) { System.out.println("\t" + fq); diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryHitHighlightFieldConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryHitHighlightFieldConfiguration.java index 81b79b4bfe..568810e81a 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryHitHighlightFieldConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryHitHighlightFieldConfiguration.java @@ -16,40 +16,35 @@ import org.springframework.beans.factory.annotation.Required; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class DiscoveryHitHighlightFieldConfiguration -{ +public class DiscoveryHitHighlightFieldConfiguration { private String field; private int maxSize = 0; private int snippets = 3; - public String getField() - { + public String getField() { return field; } @Required - public void setField(String field) - { + public void setField(String field) { this.field = field; } - public int getMaxSize() - { + public int getMaxSize() { return maxSize; } - public void setMaxSize(int maxSize) - { + public void setMaxSize(int maxSize) { this.maxSize = maxSize; } /** * Set the maximum number of highlighted snippets to generate per field + * * @param snippets the number of maximum snippets */ - public void setSnippets(int snippets) - { + public void setSnippets(int snippets) { this.snippets = snippets; } @@ -58,8 +53,7 @@ public class DiscoveryHitHighlightFieldConfiguration * * @return maximum number of highlighted snippets to generate per field */ - public int getSnippets() - { + public int getSnippets() { return snippets; } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryHitHighlightingConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryHitHighlightingConfiguration.java index fafc2e0302..6485cdf71f 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryHitHighlightingConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryHitHighlightingConfiguration.java @@ -7,33 +7,31 @@ */ package org.dspace.discovery.configuration; -import org.springframework.beans.factory.annotation.Required; - import java.util.List; +import org.springframework.beans.factory.annotation.Required; + /** * Class that contains all the configuration concerning the hit highlighting in search resutls - * This class can be configured in the [dspace.dir]/config/spring/discovery/spring-dspace-addon-discovery-configuration-services.xml + * This class can be configured in the [dspace + * .dir]/config/spring/discovery/spring-dspace-addon-discovery-configuration-services.xml * * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class DiscoveryHitHighlightingConfiguration -{ +public class DiscoveryHitHighlightingConfiguration { /* A list of metadata fields for which the hit highlighting is possible */ private List metadataFields; @Required - public void setMetadataFields(List metadataFields) - { + public void setMetadataFields(List metadataFields) { this.metadataFields = metadataFields; } - public List getMetadataFields() - { + public List getMetadataFields() { return metadataFields; } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryMoreLikeThisConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryMoreLikeThisConfiguration.java index 7dc98139b7..d0959900dc 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryMoreLikeThisConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoveryMoreLikeThisConfiguration.java @@ -7,10 +7,10 @@ */ package org.dspace.discovery.configuration; -import org.springframework.beans.factory.annotation.Required; - import java.util.List; +import org.springframework.beans.factory.annotation.Required; + /** * Class that contains the more like this configuration on item pages * @@ -25,45 +25,37 @@ public class DiscoveryMoreLikeThisConfiguration { private int minWordLength; @Required - public void setSimilarityMetadataFields(List similarityMetadataFields) - { + public void setSimilarityMetadataFields(List similarityMetadataFields) { this.similarityMetadataFields = similarityMetadataFields; } - public List getSimilarityMetadataFields() - { + public List getSimilarityMetadataFields() { return similarityMetadataFields; } @Required - public void setMinTermFrequency(int minTermFrequency) - { + public void setMinTermFrequency(int minTermFrequency) { this.minTermFrequency = minTermFrequency; } - public int getMinTermFrequency() - { + public int getMinTermFrequency() { return minTermFrequency; } @Required - public void setMax(int max) - { + public void setMax(int max) { this.max = max; } - public int getMax() - { + public int getMax() { return max; } - public int getMinWordLength() - { + public int getMinWordLength() { return minWordLength; } - public void setMinWordLength(int minWordLength) - { + public void setMinWordLength(int minWordLength) { this.minWordLength = minWordLength; } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySearchFilter.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySearchFilter.java index f83567f3cc..a9031eea77 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySearchFilter.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySearchFilter.java @@ -7,10 +7,10 @@ */ package org.dspace.discovery.configuration; -import org.springframework.beans.factory.annotation.Required; - import java.util.List; +import org.springframework.beans.factory.annotation.Required; + /** * @author Kevin Van de Velde (kevin at atmire dot com) */ @@ -20,6 +20,9 @@ public class DiscoverySearchFilter { protected List metadataFields; protected String type = DiscoveryConfigurationParameters.TYPE_TEXT; public static final String FILTER_TYPE_DEFAULT = "default"; + protected boolean isOpenByDefault = false; + + protected int pageSize; public String getIndexFieldName() { return indexFieldName; @@ -39,29 +42,65 @@ public class DiscoverySearchFilter { this.metadataFields = metadataFields; } + /** + * Returns the type of the DiscoverySearchFilter + * @return The type of the DiscoverySearchFilter + */ public String getType() { return type; } + /** + * Sets the type of the DiscoverySearchFilter to the one given in the parameter if it matches + * a set of possible types + * The possible types are described in: {@link org.dspace.discovery.configuration.DiscoveryConfigurationParameters} + * For the DiscoverySearchFilter only the TYPE_TEXT, TYPE_DATE and TYPE_HIERARCHICAL are allowed + * + * @param type The type for this DiscoverySearchFilter + * @throws DiscoveryConfigurationException If none of the types match, this error will be thrown indiciating this + */ public void setType(String type) throws DiscoveryConfigurationException { - if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_TEXT)) - { + if (type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_TEXT)) { this.type = DiscoveryConfigurationParameters.TYPE_TEXT; - } else - if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_DATE)) - { + } else if (type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_DATE)) { this.type = DiscoveryConfigurationParameters.TYPE_DATE; - } else - if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) - { - throw new DiscoveryConfigurationException("The " + type + " can't be used with a default side bar facet use the \"HierarchicalSidebarFacetConfiguration\" class instead."); - }else{ + } else if (type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) { + throw new DiscoveryConfigurationException( + "The " + type + " can't be used with a default side bar facet use the " + + "\"HierarchicalSidebarFacetConfiguration\" class instead."); + } else { this.type = type; } } - public String getFilterType(){ + public String getFilterType() { return FILTER_TYPE_DEFAULT; } + /** + * This method returns a boolean value indicating whether the search filter + * should be open or closed by default in the UI + * @return A boolean value indicating whether the search filter in the ui should be open + * or closed by default + */ + public boolean isOpenByDefault() { + return isOpenByDefault; + } + + /** + * Sets the DiscoverySearchFilter to be open by default or not depending on the parameter given + * @param isOpenByDefault A boolean value that will indicate whether this DiscoverySearchFilter + * should be open by default or not in the UI. + */ + public void setIsOpenByDefault(boolean isOpenByDefault) { + this.isOpenByDefault = isOpenByDefault; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySearchFilterFacet.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySearchFilterFacet.java index 0f930c1672..fbed40977b 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySearchFilterFacet.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySearchFilterFacet.java @@ -21,45 +21,57 @@ public class DiscoverySearchFilterFacet extends DiscoverySearchFilter { private DiscoveryConfigurationParameters.SORT sortOrderSidebar = DiscoveryConfigurationParameters.SORT.COUNT; private DiscoveryConfigurationParameters.SORT sortOrderFilterPage = DiscoveryConfigurationParameters.SORT.COUNT; public static final String FILTER_TYPE_FACET = "facet"; + private boolean exposeMinMax = false; - - public int getFacetLimit() - { - if(facetLimit == -1){ + public int getFacetLimit() { + if (facetLimit == -1) { return DEFAULT_FACET_LIMIT; - }else{ + } else { return facetLimit; } } - public void setFacetLimit(int facetLimit) - { + public void setFacetLimit(int facetLimit) { this.facetLimit = facetLimit; } - public DiscoveryConfigurationParameters.SORT getSortOrderFilterPage() - { + public DiscoveryConfigurationParameters.SORT getSortOrderFilterPage() { return sortOrderFilterPage; } - public void setSortOrderFilterPage(DiscoveryConfigurationParameters.SORT sortOrderFilterPage) - { + public void setSortOrderFilterPage(DiscoveryConfigurationParameters.SORT sortOrderFilterPage) { this.sortOrderFilterPage = sortOrderFilterPage; } - public DiscoveryConfigurationParameters.SORT getSortOrderSidebar() - { + public DiscoveryConfigurationParameters.SORT getSortOrderSidebar() { return sortOrderSidebar; } - public void setSortOrderSidebar(DiscoveryConfigurationParameters.SORT sortOrderSidebar) - { + public void setSortOrderSidebar(DiscoveryConfigurationParameters.SORT sortOrderSidebar) { this.sortOrderSidebar = sortOrderSidebar; } @Override - public String getFilterType() - { + public String getFilterType() { return FILTER_TYPE_FACET; } + + /** + * This method returns whether or not the DiscoverySearchFilterFacet should return a + * min and max value. + * + * @return A boolean indicating whether or not this DiscoverySearchFilterFacet should expose + * a min and max value + */ + public boolean exposeMinAndMaxValue() { + return exposeMinMax; + } + + /** + * This method sets the boolean for {@link org.dspace.discovery.configuration.DiscoverySearchFilterFacet#exposeMinAndMaxValue} + * @param exposeMinMax A boolean value that will be set to return in the above mentioned link + */ + public void setExposeMinAndMaxValue(boolean exposeMinMax) { + this.exposeMinMax = exposeMinMax; + } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySortConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySortConfiguration.java index fd68c2dc83..8538b54db2 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySortConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySortConfiguration.java @@ -1,10 +1,3 @@ -/** - * 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/ - */ /** * 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 @@ -14,15 +7,19 @@ */ package org.dspace.discovery.configuration; - import java.util.ArrayList; import java.util.List; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang.StringUtils; + /** * @author Kevin Van de Velde (kevin at atmire dot com) */ public class DiscoverySortConfiguration { + public static final String SCORE = "score"; + /** Attributes used for sorting of results **/ public enum SORT_ORDER { desc, @@ -58,4 +55,27 @@ public class DiscoverySortConfiguration { public void setDefaultSortOrder(SORT_ORDER defaultSortOrder) { this.defaultSortOrder = defaultSortOrder; } + + public DiscoverySortFieldConfiguration getSortFieldConfiguration(String sortField) { + if (StringUtils.isBlank(sortField)) { + return null; + } + + if (StringUtils.equalsIgnoreCase(SCORE, sortField)) { + DiscoverySortFieldConfiguration configuration = new DiscoverySortFieldConfiguration(); + configuration.setMetadataField(SCORE); + return configuration; + } + + if (defaultSort != null && StringUtils.equals(defaultSort.getMetadataField(), sortField)) { + return defaultSort; + } + + for (DiscoverySortFieldConfiguration sortFieldConfiguration : CollectionUtils.emptyIfNull(sortFields)) { + if (StringUtils.equals(sortFieldConfiguration.getMetadataField(), sortField)) { + return sortFieldConfiguration; + } + } + return null; + } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySortFieldConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySortFieldConfiguration.java index fd55a52582..37e024515a 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySortFieldConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/DiscoverySortFieldConfiguration.java @@ -36,9 +36,10 @@ public class DiscoverySortFieldConfiguration { @Override public boolean equals(Object obj) { - if(obj != null && obj instanceof DiscoverySortFieldConfiguration){ + if (obj != null && obj instanceof DiscoverySortFieldConfiguration) { DiscoverySortFieldConfiguration compareConfig = (DiscoverySortFieldConfiguration) obj; - if(compareConfig.getMetadataField().equals(getMetadataField()) && compareConfig.getType().equals(getType())){ + if (compareConfig.getMetadataField().equals(getMetadataField()) && compareConfig.getType() + .equals(getType())) { return true; } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/HierarchicalSidebarFacetConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/HierarchicalSidebarFacetConfiguration.java index 45fc8de608..86d5a8ede5 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/HierarchicalSidebarFacetConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/HierarchicalSidebarFacetConfiguration.java @@ -16,7 +16,7 @@ import org.springframework.beans.factory.annotation.Required; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class HierarchicalSidebarFacetConfiguration extends DiscoverySearchFilterFacet{ +public class HierarchicalSidebarFacetConfiguration extends DiscoverySearchFilterFacet { private String splitter; private boolean skipFirstNodeLevel = true; @@ -46,10 +46,12 @@ public class HierarchicalSidebarFacetConfiguration extends DiscoverySearchFilter @Override public void setType(String type) throws DiscoveryConfigurationException { - if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)){ + if (type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)) { this.type = type; - }else{ - throw new DiscoveryConfigurationException("The " + type + " can't be used with a hierarchical facet side bar facet use the \"DiscoverySearchFilterFacet\" class instead."); + } else { + throw new DiscoveryConfigurationException( + "The " + type + " can't be used with a hierarchical facet side bar facet use the " + + "\"DiscoverySearchFilterFacet\" class instead."); } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/SidebarFacetConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/SidebarFacetConfiguration.java index 29b82c16ca..19fdc079f0 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/SidebarFacetConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/SidebarFacetConfiguration.java @@ -7,10 +7,10 @@ */ package org.dspace.discovery.configuration; -import org.springframework.beans.factory.annotation.Required; - import java.util.List; +import org.springframework.beans.factory.annotation.Required; + /** * @author Kevin Van de Velde (kevin at atmire dot com) */ @@ -43,9 +43,9 @@ public class SidebarFacetConfiguration { } public int getFacetLimit() { - if(facetLimit == -1){ + if (facetLimit == -1) { return DEFAULT_FACET_LIMIT; - }else{ + } else { return facetLimit; } } @@ -59,12 +59,11 @@ public class SidebarFacetConfiguration { } public void setType(String type) { - if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_TEXT)){ + if (type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_TEXT)) { this.type = DiscoveryConfigurationParameters.TYPE_TEXT; - } else - if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_DATE)){ + } else if (type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_DATE)) { this.type = DiscoveryConfigurationParameters.TYPE_DATE; - }else{ + } else { this.type = type; } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/TagCloudConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/TagCloudConfiguration.java index 61d8b244a6..c6fd4170a1 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/TagCloudConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/TagCloudConfiguration.java @@ -9,203 +9,202 @@ package org.dspace.discovery.configuration; /** * @author kstamatis - * */ public class TagCloudConfiguration { - String cloudCase; - String width; - - String fontFrom; - String fontTo; - - String cuttingLevel; - int totalTags; - boolean randomColors; - - String ordering; - - boolean displayScore; - boolean shouldCenter; - - String locale; - - /** - * - */ - public TagCloudConfiguration() { - //Default values; - - width = "100%"; - - cloudCase = "Case.PRESERVE_CASE"; - - fontFrom = "1.1";//"15"; - fontTo = "3.2";//"40"; - - cuttingLevel = "0"; - totalTags = -1; - randomColors = true; - - ordering = "Tag.NameComparatorAsc"; - - displayScore = false; - shouldCenter = true; - - locale = "el"; - } + String cloudCase; + String width; - /** - * @return the cloudCase - */ - public String getCloudCase() { - return cloudCase; - } + String fontFrom; + String fontTo; - /** - * @param cloudCase the cloudCase to set - */ - public void setCloudCase(String cloudCase) { - this.cloudCase = cloudCase; - } + String cuttingLevel; + int totalTags; + boolean randomColors; - /** - * @return the width - */ - public String getWidth() { - return width; - } + String ordering; - /** - * @param width the width to set - */ - public void setWidth(String width) { - this.width = width; - } + boolean displayScore; + boolean shouldCenter; - /** - * @return the fontFrom - */ - public String getFontFrom() { - return fontFrom; - } + String locale; - /** - * @param fontFrom the fontFrom to set - */ - public void setFontFrom(String fontFrom) { - this.fontFrom = fontFrom; - } + /** + * + */ + public TagCloudConfiguration() { + //Default values; - /** - * @return the fontTo - */ - public String getFontTo() { - return fontTo; - } + width = "100%"; - /** - * @param fontTo the fontTo to set - */ - public void setFontTo(String fontTo) { - this.fontTo = fontTo; - } + cloudCase = "Case.PRESERVE_CASE"; - /** - * @return the cuttingLevel - */ - public String getCuttingLevel() { - return cuttingLevel; - } + fontFrom = "1.1";//"15"; + fontTo = "3.2";//"40"; - /** - * @param cuttingLevel the cuttingLevel to set - */ - public void setCuttingLevel(String cuttingLevel) { - this.cuttingLevel = cuttingLevel; - } + cuttingLevel = "0"; + totalTags = -1; + randomColors = true; - /** - * @return the totalTags - */ - public int getTotalTags() { - return totalTags; - } + ordering = "Tag.NameComparatorAsc"; - /** - * @param totalTags the totalTags to set - */ - public void setTotalTags(int totalTags) { - this.totalTags = totalTags; - } + displayScore = false; + shouldCenter = true; - /** - * @return the randomColors - */ - public boolean isRandomColors() { - return randomColors; - } + locale = "el"; + } - /** - * @param randomColors the randomColors to set - */ - public void setRandomColors(boolean randomColors) { - this.randomColors = randomColors; - } + /** + * @return the cloudCase + */ + public String getCloudCase() { + return cloudCase; + } - /** - * @return the ordering - */ - public String getOrdering() { - return ordering; - } + /** + * @param cloudCase the cloudCase to set + */ + public void setCloudCase(String cloudCase) { + this.cloudCase = cloudCase; + } - /** - * @param ordering the ordering to set - */ - public void setOrdering(String ordering) { - this.ordering = ordering; - } + /** + * @return the width + */ + public String getWidth() { + return width; + } - /** - * @return the displayScore - */ - public boolean isDisplayScore() { - return displayScore; - } + /** + * @param width the width to set + */ + public void setWidth(String width) { + this.width = width; + } - /** - * @param displayScore the displayScore to set - */ - public void setDisplayScore(boolean displayScore) { - this.displayScore = displayScore; - } + /** + * @return the fontFrom + */ + public String getFontFrom() { + return fontFrom; + } - /** - * @return the shouldCenter - */ - public boolean isShouldCenter() { - return shouldCenter; - } + /** + * @param fontFrom the fontFrom to set + */ + public void setFontFrom(String fontFrom) { + this.fontFrom = fontFrom; + } - /** - * @param shouldCenter the shouldCenter to set - */ - public void setShouldCenter(boolean shouldCenter) { - this.shouldCenter = shouldCenter; - } + /** + * @return the fontTo + */ + public String getFontTo() { + return fontTo; + } - /** - * @return the locale - */ - public String getLocale() { - return locale; - } + /** + * @param fontTo the fontTo to set + */ + public void setFontTo(String fontTo) { + this.fontTo = fontTo; + } - /** - * @param locale the locale to set - */ - public void setLocale(String locale) { - this.locale = locale; - } + /** + * @return the cuttingLevel + */ + public String getCuttingLevel() { + return cuttingLevel; + } + + /** + * @param cuttingLevel the cuttingLevel to set + */ + public void setCuttingLevel(String cuttingLevel) { + this.cuttingLevel = cuttingLevel; + } + + /** + * @return the totalTags + */ + public int getTotalTags() { + return totalTags; + } + + /** + * @param totalTags the totalTags to set + */ + public void setTotalTags(int totalTags) { + this.totalTags = totalTags; + } + + /** + * @return the randomColors + */ + public boolean isRandomColors() { + return randomColors; + } + + /** + * @param randomColors the randomColors to set + */ + public void setRandomColors(boolean randomColors) { + this.randomColors = randomColors; + } + + /** + * @return the ordering + */ + public String getOrdering() { + return ordering; + } + + /** + * @param ordering the ordering to set + */ + public void setOrdering(String ordering) { + this.ordering = ordering; + } + + /** + * @return the displayScore + */ + public boolean isDisplayScore() { + return displayScore; + } + + /** + * @param displayScore the displayScore to set + */ + public void setDisplayScore(boolean displayScore) { + this.displayScore = displayScore; + } + + /** + * @return the shouldCenter + */ + public boolean isShouldCenter() { + return shouldCenter; + } + + /** + * @param shouldCenter the shouldCenter to set + */ + public void setShouldCenter(boolean shouldCenter) { + this.shouldCenter = shouldCenter; + } + + /** + * @return the locale + */ + public String getLocale() { + return locale; + } + + /** + * @param locale the locale to set + */ + public void setLocale(String locale) { + this.locale = locale; + } } diff --git a/dspace-api/src/main/java/org/dspace/discovery/configuration/TagCloudFacetConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/configuration/TagCloudFacetConfiguration.java index 60b5aeaa22..490d30c891 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/configuration/TagCloudFacetConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/discovery/configuration/TagCloudFacetConfiguration.java @@ -10,40 +10,39 @@ package org.dspace.discovery.configuration; import java.util.ArrayList; import java.util.List; -import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; - /** * @author kstamatis - * */ public class TagCloudFacetConfiguration { - TagCloudConfiguration tagCloudConfiguration; - - /** The configuration for the tagcloud facets **/ + TagCloudConfiguration tagCloudConfiguration; + + /** + * The configuration for the tagcloud facets + **/ private List tagCloudFacets = new ArrayList(); - - /** - * - */ - public TagCloudFacetConfiguration() { - // TODO Auto-generated constructor stub - } - public TagCloudConfiguration getTagCloudConfiguration() { - return tagCloudConfiguration; - } + /** + * + */ + public TagCloudFacetConfiguration() { + // TODO Auto-generated constructor stub + } - public void setTagCloudConfiguration( - TagCloudConfiguration tagCloudConfiguration) { - this.tagCloudConfiguration = tagCloudConfiguration; - } + public TagCloudConfiguration getTagCloudConfiguration() { + return tagCloudConfiguration; + } - public List getTagCloudFacets() { - return tagCloudFacets; - } + public void setTagCloudConfiguration( + TagCloudConfiguration tagCloudConfiguration) { + this.tagCloudConfiguration = tagCloudConfiguration; + } - public void setTagCloudFacets(List tagCloudFacets) { - this.tagCloudFacets = tagCloudFacets; - } + public List getTagCloudFacets() { + return tagCloudFacets; + } + + public void setTagCloudFacets(List tagCloudFacets) { + this.tagCloudFacets = tagCloudFacets; + } } diff --git a/dspace-api/src/main/java/org/dspace/disseminate/CitationDocumentServiceImpl.java b/dspace-api/src/main/java/org/dspace/disseminate/CitationDocumentServiceImpl.java index 732f87fa23..a96ed6c3d3 100644 --- a/dspace-api/src/main/java/org/dspace/disseminate/CitationDocumentServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/disseminate/CitationDocumentServiceImpl.java @@ -7,19 +7,37 @@ */ package org.dspace.disseminate; +import java.awt.Color; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.log4j.Logger; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageTree; import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; @@ -30,12 +48,6 @@ import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import java.awt.*; -import java.io.*; -import java.sql.SQLException; -import java.util.*; -import java.util.List; - /** * The Citation Document produces a dissemination package (DIP) that is different that the archival package (AIP). * In this case we append the descriptive metadata to the end (configurable) of the document. i.e. last page of PDF. @@ -82,6 +94,11 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini protected String[] fields; protected String footer; + /** + * Citation page format + */ + protected PDRectangle citationPageFormat = PDRectangle.LETTER; + @Autowired(required = true) protected AuthorizeService authorizeService; @Autowired(required = true) @@ -96,7 +113,6 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini @Autowired(required = true) protected HandleService handleService; - @Override public void afterPropertiesSet() throws Exception { // Add valid format MIME types to set. This could be put in the Schema @@ -118,77 +134,88 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini //Populate VALID_TYPES VALID_TYPES.addAll(PDF_MIMES); + // Global enabled? + citationEnabledGlobally = configurationService.getBooleanProperty("citation-page.enable_globally", false); //Load enabled collections - String[] citationEnabledCollections = configurationService.getArrayProperty("citation-page.enabled_collections"); + String[] citationEnabledCollections = configurationService + .getArrayProperty("citation-page.enabled_collections"); citationEnabledCollectionsList = Arrays.asList(citationEnabledCollections); //Load enabled communities, and add to collection-list - String[] citationEnabledCommunities = configurationService.getArrayProperty("citation-page.enabled_communities"); - if(citationEnabledCollectionsList == null) { + String[] citationEnabledCommunities = configurationService + .getArrayProperty("citation-page.enabled_communities"); + if (citationEnabledCollectionsList == null) { citationEnabledCollectionsList = new ArrayList(); } - if(citationEnabledCommunities != null && citationEnabledCommunities.length > 0) - { + if (citationEnabledCommunities != null && citationEnabledCommunities.length > 0) { Context context = null; - try - { + try { context = new Context(); - for(String communityString : citationEnabledCommunities) { + for (String communityString : citationEnabledCommunities) { DSpaceObject dsoCommunity = handleService.resolveToObject(context, communityString.trim()); - if(dsoCommunity instanceof Community) { - Community community = (Community)dsoCommunity; + if (dsoCommunity instanceof Community) { + Community community = (Community) dsoCommunity; List collections = communityService.getAllCollections(context, community); - for(Collection collection : collections) { + for (Collection collection : collections) { citationEnabledCollectionsList.add(collection.getHandle()); } } else { - log.error("Invalid community for citation.enabled_communities, value:" + communityString.trim()); + log.error( + "Invalid community for citation.enabled_communities, value:" + communityString.trim()); } } } catch (SQLException e) { log.error(e.getMessage()); - } - finally { - if (context!=null) + } finally { + if (context != null) { context.abort(); + } } } // Configurable text/fields, we'll set sane defaults header1 = configurationService.getArrayProperty("citation-page.header1"); - if (header1==null || header1.length==0) - { - header1 = new String[]{"DSpace Institution", ""}; + if (header1 == null || header1.length == 0) { + header1 = new String[] {"DSpace Institution", ""}; } header2 = configurationService.getArrayProperty("citation-page.header2"); - if (header2==null || header2.length==0) - { - header2 = new String[]{"DSpace Repository", "http://dspace.org"}; + if (header2 == null || header2.length == 0) { + header2 = new String[] {"DSpace Repository", "http://dspace.org"}; } fields = configurationService.getArrayProperty("citation-page.fields"); - if (fields==null || fields.length==0) - { - fields = new String[]{"dc.date.issued", "dc.title", "dc.creator", "dc.contributor.author", "dc.publisher", "_line_", "dc.identifier.citation", "dc.identifier.uri"}; + if (fields == null || fields.length == 0) { + fields = new String[] {"dc.date.issued", "dc.title", "dc.creator", "dc.contributor.author", + "dc.publisher", "_line_", "dc.identifier.citation", "dc.identifier.uri"}; } String footerConfig = configurationService.getProperty("citation-page.footer"); - if(StringUtils.isNotBlank(footerConfig)) { + if (StringUtils.isNotBlank(footerConfig)) { footer = footerConfig; } else { footer = "Downloaded from DSpace Repository, DSpace Institution's institutional repository"; } + String pageformatCfg = configurationService.getProperty("citation-page.page_format"); + + if (pageformatCfg != null) { + if (pageformatCfg.equalsIgnoreCase("A4")) { + citationPageFormat = PDRectangle.A4; + } else if (!pageformatCfg.equalsIgnoreCase("LETTER")) { + log.info("Citation-page: Unknown page format ' " + pageformatCfg + "', using LETTER."); + } + } + //Ensure a temp directory is available String tempDirString = configurationService.getProperty("dspace.dir") + File.separator + "temp"; tempDir = new File(tempDirString); - if(!tempDir.exists()) { + if (!tempDir.exists()) { boolean success = tempDir.mkdir(); - if(success) { + if (success) { log.info("Created temp directory at: " + tempDirString); } else { log.info("Unable to create temp directory at: " + tempDirString); @@ -197,7 +224,8 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini } - protected CitationDocumentServiceImpl() {} + protected CitationDocumentServiceImpl() { + } /** * Boolean to determine is citation-functionality is enabled globally for entire site. @@ -206,27 +234,23 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini protected Boolean citationEnabledGlobally = null; protected boolean isCitationEnabledGlobally() { - if(citationEnabledGlobally == null) { - citationEnabledGlobally = configurationService.getBooleanProperty("citation-page.enable_globally", false); - } - return citationEnabledGlobally; } protected boolean isCitationEnabledThroughCollection(Context context, Bitstream bitstream) throws SQLException { //Reject quickly if no-enabled collections - if(citationEnabledCollectionsList.size() == 0) { + if (citationEnabledCollectionsList.size() == 0) { return false; } DSpaceObject owningDSO = bitstreamService.getParentObject(context, bitstream); - if(owningDSO instanceof Item) { - Item item = (Item)owningDSO; + if (owningDSO instanceof Item) { + Item item = (Item) owningDSO; List collections = item.getCollections(); - for(Collection collection : collections) { - if(citationEnabledCollectionsList.contains(collection.getHandle())) { + for (Collection collection : collections) { + if (citationEnabledCollectionsList.contains(collection.getHandle())) { return true; } } @@ -238,11 +262,11 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini @Override public Boolean isCitationEnabledForBitstream(Bitstream bitstream, Context context) throws SQLException { - if(isCitationEnabledGlobally() || isCitationEnabledThroughCollection(context, bitstream)) { + if (isCitationEnabledGlobally() || isCitationEnabledThroughCollection(context, bitstream)) { boolean adminUser = authorizeService.isAdmin(context); - if(!adminUser && canGenerateCitationVersion(context, bitstream)) { + if (!adminUser && canGenerateCitationVersion(context, bitstream)) { return true; } } @@ -259,7 +283,7 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini protected Boolean citationAsFirstPage = null; protected Boolean isCitationFirstPage() { - if(citationAsFirstPage == null) { + if (citationAsFirstPage == null) { citationAsFirstPage = configurationService.getBooleanProperty("citation-page.citation_as_first_page", true); } @@ -267,32 +291,38 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini } @Override - public boolean canGenerateCitationVersion(Context context, Bitstream bitstream) throws SQLException - { + public boolean canGenerateCitationVersion(Context context, Bitstream bitstream) throws SQLException { return VALID_TYPES.contains(bitstream.getFormat(context).getMIMEType()); } @Override - public File makeCitedDocument(Context context, Bitstream bitstream) + public Pair makeCitedDocument(Context context, Bitstream bitstream) throws IOException, SQLException, AuthorizeException { PDDocument document = new PDDocument(); PDDocument sourceDocument = new PDDocument(); try { Item item = (Item) bitstreamService.getParentObject(context, bitstream); sourceDocument = sourceDocument.load(bitstreamService.retrieve(context, bitstream)); - PDPage coverPage = new PDPage(PDRectangle.LETTER); // TODO: needs to be configurable + PDPage coverPage = new PDPage(citationPageFormat); generateCoverPage(context, document, coverPage, item); addCoverPageToDocument(document, sourceDocument, coverPage); - document.save(tempDir.getAbsolutePath() + "/bitstream.cover.pdf"); - return new File(tempDir.getAbsolutePath() + "/bitstream.cover.pdf"); + //We already have the full PDF in memory, so keep it there + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + document.save(out); + + byte[] data = out.toByteArray(); + return Pair.of((InputStream) new ByteArrayInputStream(data), new Long(data.length)); + } + } finally { sourceDocument.close(); document.close(); } } - protected void generateCoverPage(Context context, PDDocument document, PDPage coverPage, Item item) throws IOException { + protected void generateCoverPage(Context context, PDDocument document, PDPage coverPage, Item item) + throws IOException { PDPageContentStream contentStream = new PDPageContentStream(document, coverPage); try { int ypos = 760; @@ -307,45 +337,46 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini String[][] content = {header1}; drawTable(coverPage, contentStream, ypos, xpos, content, fontHelveticaBold, 11, false); - ypos -=(ygap); + ypos -= (ygap); String[][] content2 = {header2}; drawTable(coverPage, contentStream, ypos, xpos, content2, fontHelveticaBold, 11, false); - ypos -=ygap; + ypos -= ygap; contentStream.fillRect(xpos, ypos, xwidth, 1); contentStream.closeAndStroke(); String[][] content3 = {{getOwningCommunity(context, item), getOwningCollection(item)}}; drawTable(coverPage, contentStream, ypos, xpos, content3, fontHelvetica, 9, false); - ypos -=ygap; + ypos -= ygap; contentStream.fillRect(xpos, ypos, xwidth, 1); contentStream.closeAndStroke(); - ypos -=(ygap*2); + ypos -= (ygap * 2); - for(String field : fields) { + for (String field : fields) { field = field.trim(); PDFont font = fontHelvetica; int fontSize = 11; - if(field.contains("title")) { + if (field.contains("title")) { fontSize = 26; ypos -= ygap; - } else if(field.contains("creator") || field.contains("contributor")) { + } else if (field.contains("creator") || field.contains("contributor")) { fontSize = 16; } - if(field.equals("_line_")) { + if (field.equals("_line_")) { contentStream.fillRect(xpos, ypos, xwidth, 1); contentStream.closeAndStroke(); - ypos -=(ygap); + ypos -= (ygap); - } else if(StringUtils.isNotEmpty(itemService.getMetadata(item, field))) { - ypos = drawStringWordWrap(coverPage, contentStream, itemService.getMetadata(item, field), xpos, ypos, font, fontSize); + } else if (StringUtils.isNotEmpty(itemService.getMetadata(item, field))) { + ypos = drawStringWordWrap(coverPage, contentStream, itemService.getMetadata(item, field), xpos, + ypos, font, fontSize); } - if(field.contains("title")) { - ypos -=ygap; + if (field.contains("title")) { + ypos -= ygap; } } @@ -379,38 +410,33 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini @Override public int drawStringWordWrap(PDPage page, PDPageContentStream contentStream, String text, - int startX, int startY, PDFont pdfFont, float fontSize) throws IOException { + int startX, int startY, PDFont pdfFont, float fontSize) throws IOException { float leading = 1.5f * fontSize; PDRectangle mediabox = page.getMediaBox(); float margin = 72; - float width = mediabox.getWidth() - 2*margin; + float width = mediabox.getWidth() - 2 * margin; List lines = new ArrayList<>(); int lastSpace = -1; - while (text.length() > 0) - { + while (text.length() > 0) { int spaceIndex = text.indexOf(' ', lastSpace + 1); - if (spaceIndex < 0) - { + if (spaceIndex < 0) { lines.add(text); text = ""; - } - else - { + } else { String subString = text.substring(0, spaceIndex); float size = fontSize * pdfFont.getStringWidth(subString) / 1000; - if (size > width) - { - if (lastSpace < 0) // So we have a word longer than the line... draw it anyways + if (size > width) { + // So we have a word longer than the line... draw it anyways + if (lastSpace < 0) { lastSpace = spaceIndex; + } subString = text.substring(0, lastSpace); lines.add(subString); text = text.substring(lastSpace).trim(); lastSpace = -1; - } - else - { + } else { lastSpace = spaceIndex; } } @@ -420,8 +446,7 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini contentStream.setFont(pdfFont, fontSize); contentStream.moveTextPositionByAmount(startX, startY); int currentY = startY; - for (String line: lines) - { + for (String line : lines) { contentStream.drawString(line); currentY -= leading; contentStream.moveTextPositionByAmount(0, -leading); @@ -434,7 +459,7 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini public String getOwningCommunity(Context context, Item item) { try { List comms = itemService.getCommunities(context, item); - if(comms.size() > 0) { + if (comms.size() > 0) { return comms.get(0).getName(); } else { return " "; @@ -457,8 +482,8 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini ArrayList valueArray = new ArrayList(); - for(MetadataValue dcValue : dcValues) { - if(StringUtils.isNotBlank(dcValue.getValue())) { + for (MetadataValue dcValue : dcValues) { + if (StringUtils.isNotBlank(dcValue.getValue())) { valueArray.add(dcValue.getValue()); } } @@ -468,28 +493,28 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini @Override public void drawTable(PDPage page, PDPageContentStream contentStream, - float y, float margin, - String[][] content, PDFont font, int fontSize, boolean cellBorders) throws IOException { + float y, float margin, + String[][] content, PDFont font, int fontSize, boolean cellBorders) throws IOException { final int rows = content.length; final int cols = content[0].length; final float rowHeight = 20f; - final float tableWidth = page.getMediaBox().getWidth()-(2*margin); + final float tableWidth = page.getMediaBox().getWidth() - (2 * margin); final float tableHeight = rowHeight * rows; - final float colWidth = tableWidth/(float)cols; - final float cellMargin=5f; + final float colWidth = tableWidth / (float) cols; + final float cellMargin = 5f; - if(cellBorders) { + if (cellBorders) { //draw the rows - float nexty = y ; + float nexty = y; for (int i = 0; i <= rows; i++) { - contentStream.drawLine(margin,nexty,margin+tableWidth,nexty); - nexty-= rowHeight; + contentStream.drawLine(margin, nexty, margin + tableWidth, nexty); + nexty -= rowHeight; } //draw the columns float nextx = margin; for (int i = 0; i <= cols; i++) { - contentStream.drawLine(nextx,y,nextx,y-tableHeight); + contentStream.drawLine(nextx, y, nextx, y - tableHeight); nextx += colWidth; } } @@ -497,19 +522,19 @@ public class CitationDocumentServiceImpl implements CitationDocumentService, Ini //now add the text contentStream.setFont(font, fontSize); - float textx = margin+cellMargin; - float texty = y-15; - for(int i = 0; i < content.length; i++){ - for(int j = 0 ; j < content[i].length; j++){ + float textx = margin + cellMargin; + float texty = y - 15; + for (int i = 0; i < content.length; i++) { + for (int j = 0; j < content[i].length; j++) { String text = content[i][j]; contentStream.beginText(); - contentStream.moveTextPositionByAmount(textx,texty); + contentStream.moveTextPositionByAmount(textx, texty); contentStream.drawString(text); contentStream.endText(); textx += colWidth; } - texty-=rowHeight; - textx = margin+cellMargin; + texty -= rowHeight; + textx = margin + cellMargin; } } } diff --git a/dspace-api/src/main/java/org/dspace/disseminate/factory/DisseminateServiceFactory.java b/dspace-api/src/main/java/org/dspace/disseminate/factory/DisseminateServiceFactory.java index ce8c86339a..50838bbd5f 100644 --- a/dspace-api/src/main/java/org/dspace/disseminate/factory/DisseminateServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/disseminate/factory/DisseminateServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.disseminate.service.CitationDocumentService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the disseminate package, use DisseminateServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the disseminate package, use DisseminateServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class DisseminateServiceFactory { public abstract CitationDocumentService getCitationDocumentService(); - public static DisseminateServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("disseminateServiceFactory", DisseminateServiceFactory.class); + public static DisseminateServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("disseminateServiceFactory", DisseminateServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/disseminate/factory/DisseminateServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/disseminate/factory/DisseminateServiceFactoryImpl.java index c98d9bd758..015cf9e16a 100644 --- a/dspace-api/src/main/java/org/dspace/disseminate/factory/DisseminateServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/disseminate/factory/DisseminateServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.disseminate.service.CitationDocumentService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the disseminate package, use DisseminateServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the disseminate package, use DisseminateServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/disseminate/service/CitationDocumentService.java b/dspace-api/src/main/java/org/dspace/disseminate/service/CitationDocumentService.java index 9743579c0b..d6c7935a86 100644 --- a/dspace-api/src/main/java/org/dspace/disseminate/service/CitationDocumentService.java +++ b/dspace-api/src/main/java/org/dspace/disseminate/service/CitationDocumentService.java @@ -7,6 +7,11 @@ */ package org.dspace.disseminate.service; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; + +import org.apache.commons.lang3.tuple.Pair; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; @@ -15,10 +20,6 @@ import org.dspace.content.Bitstream; import org.dspace.content.Item; import org.dspace.core.Context; -import java.io.File; -import java.io.IOException; -import java.sql.SQLException; - /** * The Citation Document produces a dissemination package (DIP) that is different that the archival package (AIP). * In this case we append the descriptive metadata to the end (configurable) of the document. i.e. last page of PDF. @@ -30,30 +31,32 @@ public interface CitationDocumentService { /** * Repository policy can specify to have a custom citation cover/tail page to the document, which embeds metadata. - * We need to determine if we will intercept this bitstream download, and give out a citation dissemination rendition. + * We need to determine if we will intercept this bitstream download, and give out a citation dissemination + * rendition. * * What will trigger a redirect/intercept? - * Citation enabled globally (all citable bitstreams will get "watermarked") modules/disseminate-citation: enable_globally - * OR - * The container is this object is whitelist enabled. - * - community: modules/disseminate-citation: enabled_communities - * - collection: modules/disseminate-citation: enabled_collections + * Citation enabled globally (all citable bitstreams will get "watermarked") modules/disseminate-citation: + * enable_globally + * OR + * The container is this object is whitelist enabled. + * - community: modules/disseminate-citation: enabled_communities + * - collection: modules/disseminate-citation: enabled_collections * AND - * This User is not an admin. (Admins need to be able to view the "raw" original instead.) + * This User is not an admin. (Admins need to be able to view the "raw" original instead.) * AND - * This object is citation-able (presently, just PDF) + * This object is citation-able (presently, just PDF) + * + * The module must be enabled, before the permission level checks happen. * - * The module must be enabled, before the permission level checks happen. * @param bitstream DSpace bitstream - * @param context DSpace context - * @throws SQLException if error + * @param context DSpace context * @return true or false + * @throws SQLException if error */ public Boolean isCitationEnabledForBitstream(Bitstream bitstream, Context context) throws SQLException; /** - * - * @param context DSpace Context + * @param context DSpace Context * @param bitstream DSpace Bitstream * @return true or false * @throws SQLException if error @@ -67,48 +70,49 @@ public interface CitationDocumentService { *

    * The Process for adding a cover page is as follows: *

      - *
    1. Load source file into PdfReader and create a - * Document to put our cover page into.
    2. - *
    3. Create cover page and add content to it.
    4. - *
    5. Concatenate the coverpage and the source - * document.
    6. + *
    7. Load source file into PdfReader and create a + * Document to put our cover page into.
    8. + *
    9. Create cover page and add content to it.
    10. + *
    11. Concatenate the coverpage and the source + * document.
    12. *
    * - * @param context DSpace context + * @param context DSpace context * @param bitstream The source bitstream being cited. This must be a PDF. * @return The temporary File that is the finished, cited document. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ - public File makeCitedDocument(Context context, Bitstream bitstream) + public Pair makeCitedDocument(Context context, Bitstream bitstream) throws IOException, SQLException, AuthorizeException; /** - * - * @param page page + * @param page page * @param contentStream content stream - * @param text text to draw - * @param startX x-coordinate of word - * @param startY y-coordinate of word - * @param pdfFont font - * @param fontSize size of font + * @param text text to draw + * @param startX x-coordinate of word + * @param startY y-coordinate of word + * @param pdfFont font + * @param fontSize size of font * @return integer * @throws IOException if IO error */ public int drawStringWordWrap(PDPage page, PDPageContentStream contentStream, String text, - int startX, int startY, PDFont pdfFont, float fontSize) throws IOException; + int startX, int startY, PDFont pdfFont, float fontSize) throws IOException; /** * Get name of owning community + * * @param context DSpace context - * @param item DSpace Item + * @param item DSpace Item * @return name */ public String getOwningCommunity(Context context, Item item); /** * Get name of owning collection + * * @param item DSpace Item * @return owning collection name */ @@ -116,26 +120,28 @@ public interface CitationDocumentService { /** * Get metadata separated by value separator (semicolon) - * @param item DSpace Item + * + * @param item DSpace Item * @param metadataKey metadata string - * @see org.dspace.content.service.DSpaceObjectService#getMetadataByMetadataString(org.dspace.content.DSpaceObject, java.lang.String) * @return string + * @see org.dspace.content.service.DSpaceObjectService#getMetadataByMetadataString(org.dspace.content + * .DSpaceObject, java.lang.String) */ public String getAllMetadataSeparated(Item item, String metadataKey); /** - * @param page page + * @param page page * @param contentStream content stream - * @param y the y-coordinate of the first row - * @param margin the padding on left and right of table - * @param content a 2d array containing the table data - * @param font PDFont - * @param fontSize size of font (int) - * @param cellBorders whether to include cellBorders + * @param y the y-coordinate of the first row + * @param margin the padding on left and right of table + * @param content a 2d array containing the table data + * @param font PDFont + * @param fontSize size of font (int) + * @param cellBorders whether to include cellBorders * @throws IOException if error */ public void drawTable(PDPage page, PDPageContentStream contentStream, - float y, float margin, - String[][] content, PDFont font, int fontSize, boolean cellBorders) throws IOException; + float y, float margin, + String[][] content, PDFont font, int fontSize, boolean cellBorders) throws IOException; } diff --git a/dspace-api/src/main/java/org/dspace/embargo/DayTableEmbargoSetter.java b/dspace-api/src/main/java/org/dspace/embargo/DayTableEmbargoSetter.java index b1a2a054ac..ec2c7d69fd 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/DayTableEmbargoSetter.java +++ b/dspace-api/src/main/java/org/dspace/embargo/DayTableEmbargoSetter.java @@ -30,39 +30,39 @@ import org.dspace.services.factory.DSpaceServicesFactory; * All the {@code } fields should be defined in a 'value-pairs' element, * and the field configured as the embargo terms should employ a drop-down using * that element in input_forms.xml, if user submission is desired. - * + * * @author Richard Rodgers */ -public class DayTableEmbargoSetter extends DefaultEmbargoSetter -{ +public class DayTableEmbargoSetter extends DefaultEmbargoSetter { public DayTableEmbargoSetter() { super(); } - + /** * Parse the terms into a definite date. Only terms expressions processed * are those defined in 'embargo.terms.days' configuration property. - * + * * @param context the DSpace context - * @param item the item to embargo - * @param terms the embargo terms + * @param item the item to embargo + * @param terms the embargo terms * @return parsed date in DCDate format */ @Override public DCDate parseTerms(Context context, Item item, String terms) throws SQLException, AuthorizeException { - String termsOpen = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("embargo.terms.open"); + String termsOpen = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("embargo.terms.open"); Properties termProps = getTermProperties(); - if (terms != null) { + if (terms != null) { if (termsOpen.equals(terms)) { return EmbargoServiceImpl.FOREVER; } String days = termProps.getProperty(terms); if (days != null && days.length() > 0) { - long lift = System.currentTimeMillis() + - (Long.parseLong(days) * 24 * 60 * 60 * 1000); + long lift = System.currentTimeMillis() + + (Long.parseLong(days) * 24 * 60 * 60 * 1000); return new DCDate(new Date(lift)); } } @@ -71,13 +71,14 @@ public class DayTableEmbargoSetter extends DefaultEmbargoSetter /** * Get term properties from configuration + * * @return Properties */ - private Properties getTermProperties() - { + private Properties getTermProperties() { Properties termProps = new Properties(); - String terms[] = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("embargo.terms.days"); + String terms[] = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("embargo.terms.days"); if (terms != null) { for (String term : terms) { diff --git a/dspace-api/src/main/java/org/dspace/embargo/DefaultEmbargoLifter.java b/dspace-api/src/main/java/org/dspace/embargo/DefaultEmbargoLifter.java index 875d70d60b..332f8628f0 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/DefaultEmbargoLifter.java +++ b/dspace-api/src/main/java/org/dspace/embargo/DefaultEmbargoLifter.java @@ -7,8 +7,8 @@ */ package org.dspace.embargo; -import java.sql.SQLException; import java.io.IOException; +import java.sql.SQLException; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; @@ -21,11 +21,9 @@ import org.dspace.core.Context; * @author Larry Stone * @author Richard Rodgers */ -public class DefaultEmbargoLifter implements EmbargoLifter -{ +public class DefaultEmbargoLifter implements EmbargoLifter { - public DefaultEmbargoLifter() - { + public DefaultEmbargoLifter() { super(); } @@ -38,10 +36,10 @@ public class DefaultEmbargoLifter implements EmbargoLifter */ @Override public void liftEmbargo(Context context, Item item) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { // remove the item's policies and replace them with // the defaults from the collection - ContentServiceFactory.getInstance().getItemService().inheritCollectionDefaultPolicies(context, item, item.getOwningCollection()); + ContentServiceFactory.getInstance().getItemService() + .inheritCollectionDefaultPolicies(context, item, item.getOwningCollection()); } } diff --git a/dspace-api/src/main/java/org/dspace/embargo/DefaultEmbargoSetter.java b/dspace-api/src/main/java/org/dspace/embargo/DefaultEmbargoSetter.java index 208c0629d3..45b2d407ac 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/DefaultEmbargoSetter.java +++ b/dspace-api/src/main/java/org/dspace/embargo/DefaultEmbargoSetter.java @@ -7,8 +7,8 @@ */ package org.dspace.embargo; -import java.sql.SQLException; import java.io.IOException; +import java.sql.SQLException; import java.util.Date; import java.util.List; @@ -18,9 +18,14 @@ import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.ResourcePolicyService; -import org.dspace.content.*; -import org.dspace.core.Context; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.core.Constants; +import org.dspace.core.Context; import org.dspace.embargo.factory.EmbargoServiceFactory; import org.dspace.embargo.service.EmbargoService; import org.dspace.eperson.Group; @@ -32,19 +37,17 @@ import org.dspace.services.factory.DSpaceServicesFactory; * Default plugin implementation of the embargo setting function. * The parseTerms() provides only very rudimentary terms logic - entry * of a configurable string (in terms field) for 'unlimited' embargo, otherwise - * a standard ISO 8601 (yyyy-mm-dd) date is assumed. Users are encouraged + * a standard ISO 8601 (yyyy-mm-dd) date is assumed. Users are encouraged * to override this method for enhanced functionality. * * @author Larry Stone * @author Richard Rodgers */ -public class DefaultEmbargoSetter implements EmbargoSetter -{ +public class DefaultEmbargoSetter implements EmbargoSetter { protected AuthorizeService authorizeService; protected ResourcePolicyService resourcePolicyService; - public DefaultEmbargoSetter() - { + public DefaultEmbargoSetter() { super(); } @@ -52,29 +55,25 @@ public class DefaultEmbargoSetter implements EmbargoSetter * Parse the terms into a definite date. Terms are expected to consist of * either: a token (value configured in 'embargo.terms.open' property) to indicate * indefinite embargo, or a literal lift date formatted in ISO 8601 format (yyyy-mm-dd) - * + * * @param context the DSpace context - * @param item the item to embargo - * @param terms the embargo terms + * @param item the item to embargo + * @param terms the embargo terms * @return parsed date in DCDate format */ @Override public DCDate parseTerms(Context context, Item item, String terms) - throws SQLException, AuthorizeException - { - String termsOpen = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("embargo.terms.open"); + throws SQLException, AuthorizeException { + String termsOpen = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("embargo.terms.open"); - if (terms != null && terms.length() > 0) - { - if (termsOpen.equals(terms)) - { + if (terms != null && terms.length() > 0) { + if (termsOpen.equals(terms)) { return EmbargoService.FOREVER; - } - else - { + } else { return new DCDate(terms); } - } + } return null; } @@ -83,23 +82,20 @@ public class DefaultEmbargoSetter implements EmbargoSetter * this Item. * * @param context the DSpace context - * @param item the item to embargo + * @param item the item to embargo */ @Override public void setEmbargo(Context context, Item item) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { DCDate liftDate = EmbargoServiceFactory.getInstance().getEmbargoService().getEmbargoTermsAsDate(context, item); - for (Bundle bn : item.getBundles()) - { + for (Bundle bn : item.getBundles()) { // Skip the LICENSE and METADATA bundles, they stay world-readable String bnn = bn.getName(); - if (!(bnn.equals(Constants.LICENSE_BUNDLE_NAME) || bnn.equals(Constants.METADATA_BUNDLE_NAME) || bnn.equals(CreativeCommonsServiceImpl.CC_BUNDLE_NAME))) - { + if (!(bnn.equals(Constants.LICENSE_BUNDLE_NAME) || bnn.equals(Constants.METADATA_BUNDLE_NAME) || bnn + .equals(CreativeCommonsServiceImpl.CC_BUNDLE_NAME))) { //AuthorizeManager.removePoliciesActionFilter(context, bn, Constants.READ); generatePolicies(context, liftDate.toDate(), null, bn, item.getOwningCollection()); - for (Bitstream bs : bn.getBitstreams()) - { + for (Bitstream bs : bn.getBitstreams()) { //AuthorizeManager.removePoliciesActionFilter(context, bs, Constants.READ); generatePolicies(context, liftDate.toDate(), null, bs, item.getOwningCollection()); } @@ -108,79 +104,88 @@ public class DefaultEmbargoSetter implements EmbargoSetter } protected void generatePolicies(Context context, Date embargoDate, - String reason, DSpaceObject dso, Collection owningCollection) throws SQLException, AuthorizeException { + String reason, DSpaceObject dso, Collection owningCollection) + throws SQLException, AuthorizeException { // add only embargo policy - if(embargoDate!=null){ + if (embargoDate != null) { - List authorizedGroups = getAuthorizeService().getAuthorizedGroups(context, owningCollection, Constants.DEFAULT_ITEM_READ); + List authorizedGroups = getAuthorizeService() + .getAuthorizedGroups(context, owningCollection, Constants.DEFAULT_ITEM_READ); // look for anonymous - boolean isAnonymousInPlace=false; - for(Group g : authorizedGroups){ - if(StringUtils.equals(g.getName(), Group.ANONYMOUS)){ - isAnonymousInPlace=true; + boolean isAnonymousInPlace = false; + for (Group g : authorizedGroups) { + if (StringUtils.equals(g.getName(), Group.ANONYMOUS)) { + isAnonymousInPlace = true; } } - if(!isAnonymousInPlace){ + if (!isAnonymousInPlace) { // add policies for all the groups - for(Group g : authorizedGroups){ - ResourcePolicy rp = getAuthorizeService().createOrModifyPolicy(null, context, null, g, null, embargoDate, Constants.READ, reason, dso); - if(rp!=null) + for (Group g : authorizedGroups) { + ResourcePolicy rp = getAuthorizeService() + .createOrModifyPolicy(null, context, null, g, null, embargoDate, + Constants.READ, reason, dso); + if (rp != null) { getResourcePolicyService().update(context, rp); + } } - } - else{ + } else { // add policy just for anonymous - ResourcePolicy rp = getAuthorizeService().createOrModifyPolicy(null, context, null, EPersonServiceFactory.getInstance().getGroupService().findByName(context, Group.ANONYMOUS), null, embargoDate, Constants.READ, reason, dso); - if(rp!=null) + ResourcePolicy rp = getAuthorizeService() + .createOrModifyPolicy(null, context, null, + EPersonServiceFactory.getInstance() + .getGroupService() + .findByName(context, Group.ANONYMOUS), + null, embargoDate, Constants.READ, reason, dso); + if (rp != null) { getResourcePolicyService().update(context, rp); + } } } } - - - /** * Check that embargo is properly set on Item: no read access to bitstreams. * * @param context the DSpace context - * @param item the item to embargo + * @param item the item to embargo */ @Override public void checkEmbargo(Context context, Item item) - throws SQLException, AuthorizeException, IOException - { - for (Bundle bn : item.getBundles()) - { + throws SQLException, AuthorizeException, IOException { + for (Bundle bn : item.getBundles()) { // Skip the LICENSE and METADATA bundles, they stay world-readable String bnn = bn.getName(); - if (!(bnn.equals(Constants.LICENSE_BUNDLE_NAME) || bnn.equals(Constants.METADATA_BUNDLE_NAME) || bnn.equals(CreativeCommonsServiceImpl.CC_BUNDLE_NAME))) - { + if (!(bnn.equals(Constants.LICENSE_BUNDLE_NAME) || bnn.equals(Constants.METADATA_BUNDLE_NAME) || bnn + .equals(CreativeCommonsServiceImpl.CC_BUNDLE_NAME))) { // don't report on "TEXT" or "THUMBNAIL" bundles; those // can have READ long as the bitstreams in them do not. - if (!(bnn.equals("TEXT") || bnn.equals("THUMBNAIL"))) - { + if (!(bnn.equals("TEXT") || bnn.equals("THUMBNAIL"))) { // check for ANY read policies and report them: - for (ResourcePolicy rp : getAuthorizeService().getPoliciesActionFilter(context, bn, Constants.READ)) - { - System.out.println("CHECK WARNING: Item "+item.getHandle()+", Bundle "+bn.getName()+" allows READ by "+ - ((rp.getEPerson() != null) ? "Group "+rp.getGroup().getName() : - "EPerson "+rp.getEPerson().getFullName())); + for (ResourcePolicy rp : getAuthorizeService() + .getPoliciesActionFilter(context, bn, Constants.READ)) { + if (rp.getStartDate() == null) { + System.out.println("CHECK WARNING: Item " + item.getHandle() + ", Bundle " + bn + .getName() + " allows READ by " + + ((rp.getEPerson() != null) ? "Group " + rp.getGroup().getName() : + "EPerson " + rp.getEPerson().getFullName())); + } } } - for (Bitstream bs : bn.getBitstreams()) - { - for (ResourcePolicy rp : getAuthorizeService().getPoliciesActionFilter(context, bs, Constants.READ)) - { - System.out.println("CHECK WARNING: Item "+item.getHandle()+", Bitstream "+bs.getName()+" (in Bundle "+bn.getName()+") allows READ by "+ - ((rp.getEPerson() != null) ? "Group "+rp.getGroup().getName() : - "EPerson "+rp.getEPerson().getFullName())); + for (Bitstream bs : bn.getBitstreams()) { + for (ResourcePolicy rp : getAuthorizeService() + .getPoliciesActionFilter(context, bs, Constants.READ)) { + if (rp.getStartDate() == null) { + System.out.println("CHECK WARNING: Item " + item.getHandle() + ", Bitstream " + bs + .getName() + " (in Bundle " + bn.getName() + ") allows READ by " + + ((rp.getEPerson() != null) ? "Group " + rp.getGroup().getName() : + "EPerson " + rp.getEPerson().getFullName())); + } } } } @@ -188,16 +193,14 @@ public class DefaultEmbargoSetter implements EmbargoSetter } private AuthorizeService getAuthorizeService() { - if(authorizeService == null) - { + if (authorizeService == null) { authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); } return authorizeService; } private ResourcePolicyService getResourcePolicyService() { - if(resourcePolicyService == null) - { + if (resourcePolicyService == null) { resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); } return resourcePolicyService; diff --git a/dspace-api/src/main/java/org/dspace/embargo/EmbargoCLITool.java b/dspace-api/src/main/java/org/dspace/embargo/EmbargoCLITool.java index d8cf169307..c0ee6ad720 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/EmbargoCLITool.java +++ b/dspace-api/src/main/java/org/dspace/embargo/EmbargoCLITool.java @@ -7,7 +7,15 @@ */ package org.dspace.embargo; -import org.apache.commons.cli.*; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.dspace.content.DCDate; import org.dspace.content.DSpaceObject; @@ -19,10 +27,6 @@ import org.dspace.embargo.factory.EmbargoServiceFactory; import org.dspace.embargo.service.EmbargoService; import org.dspace.handle.factory.HandleServiceFactory; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - /** * CLI class for the embargo service * @@ -30,11 +34,17 @@ import java.util.List; */ public class EmbargoCLITool { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(EmbargoServiceImpl.class); private static final EmbargoService embargoService = EmbargoServiceFactory.getInstance().getEmbargoService(); - ; + + /** + * Default constructor + */ + private EmbargoCLITool() { } /** * Command-line service to scan for every Item with an expired embargo, @@ -42,116 +52,98 @@ public class EmbargoCLITool { *

    * Options: *

    - *
    -c,--check
    - *
    Function: ONLY check the state of embargoed Items, do - * NOT lift any embargoes.
    - *
    -h,--help
    - *
    Help.
    - *
    -i,--identifier
    - *
    Process ONLY this Handle identifier(s), which must be - * an Item. Can be repeated.
    - *
    -l,--lift
    - *
    Function: ONLY lift embargoes, do NOT check the state - * of any embargoed Items.
    - *
    -n,--dryrun
    - *
    Do not change anything in the data model; print - * message instead.
    - *
    -v,--verbose
    - *
    Print a line describing action taken for each - * embargoed Item found.
    - *
    -q,--quiet
    - *
    No output except upon error.
    + *
    -c,--check
    + *
    Function: ONLY check the state of embargoed Items, do + * NOT lift any embargoes.
    + *
    -h,--help
    + *
    Help.
    + *
    -i,--identifier
    + *
    Process ONLY this Handle identifier(s), which must be + * an Item. Can be repeated.
    + *
    -l,--lift
    + *
    Function: ONLY lift embargoes, do NOT check the state + * of any embargoed Items.
    + *
    -n,--dryrun
    + *
    Do not change anything in the data model; print + * message instead.
    + *
    -v,--verbose
    + *
    Print a line describing action taken for each + * embargoed Item found.
    + *
    -q,--quiet
    + *
    No output except upon error.
    *
    * * @param argv the command line arguments given */ - public static void main(String argv[]) - { + public static void main(String argv[]) { int status = 0; Options options = new Options(); options.addOption("v", "verbose", false, - "Print a line describing action taken for each embargoed Item found."); + "Print a line describing action taken for each embargoed Item found."); options.addOption("q", "quiet", false, - "Do not print anything except for errors."); + "Do not print anything except for errors."); options.addOption("n", "dryrun", false, - "Do not change anything in the data model, print message instead."); + "Do not change anything in the data model, print message instead."); options.addOption("i", "identifier", true, - "Process ONLY this Handle identifier(s), which must be an Item. Can be repeated."); + "Process ONLY this Handle identifier(s), which must be an Item. Can be repeated."); options.addOption("c", "check", false, - "Function: ONLY check the state of embargoed Items, do NOT lift any embargoes."); + "Function: ONLY check the state of embargoed Items, do NOT lift any embargoes."); options.addOption("l", "lift", false, - "Function: ONLY lift embargoes, do NOT check the state of any embargoed Items."); + "Function: ONLY lift embargoes, do NOT check the state of any embargoed Items."); options.addOption("a", "adjust", false, - "Function: Adjust bitstreams policies"); + "Function: Adjust bitstreams policies"); options.addOption("h", "help", false, "help"); CommandLine line = null; - try - { + try { line = new PosixParser().parse(options, argv); - } - catch(ParseException e) - { + } catch (ParseException e) { System.err.println("Command error: " + e.getMessage()); new HelpFormatter().printHelp(EmbargoServiceImpl.class.getName(), options); System.exit(1); } - if (line.hasOption('h')) - { + if (line.hasOption('h')) { new HelpFormatter().printHelp(EmbargoServiceImpl.class.getName(), options); System.exit(0); } // sanity check, --lift and --check are mutually exclusive: - if (line.hasOption('l') && line.hasOption('c')) - { + if (line.hasOption('l') && line.hasOption('c')) { System.err.println("Command error: --lift and --check are mutually exclusive, try --help for assistance."); System.exit(1); } Context context = null; - try - { + try { context = new Context(Context.Mode.BATCH_EDIT); context.turnOffAuthorisationSystem(); Date now = new Date(); // scan items under embargo - if (line.hasOption('i')) - { - for (String handle : line.getOptionValues('i')) - { - DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, handle); - if (dso == null) - { - System.err.println("Error, cannot resolve handle="+handle+" to a DSpace Item."); + if (line.hasOption('i')) { + for (String handle : line.getOptionValues('i')) { + DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService() + .resolveToObject(context, handle); + if (dso == null) { + System.err.println("Error, cannot resolve handle=" + handle + " to a DSpace Item."); status = 1; - } - else if (dso.getType() != Constants.ITEM) - { - System.err.println("Error, the handle="+handle+" is not a DSpace Item."); + } else if (dso.getType() != Constants.ITEM) { + System.err.println("Error, the handle=" + handle + " is not a DSpace Item."); status = 1; - } - else - { - if (processOneItem(context, (Item)dso, line, now)) - { + } else { + if (processOneItem(context, (Item) dso, line, now)) { status = 1; } } } - } - else - { + } else { Iterator ii = embargoService.findItemsByLiftMetadata(context); - while (ii.hasNext()) - { + while (ii.hasNext()) { Item item = ii.next(); - if (processOneItem(context, item, line, now)) - { + if (processOneItem(context, item, line, now)) { status = 1; } context.uncacheEntity(item); @@ -159,23 +151,16 @@ public class EmbargoCLITool { } context.complete(); context = null; - } - catch (Exception e) - { - System.err.println("ERROR, got exception: "+e); + } catch (Exception e) { + System.err.println("ERROR, got exception: " + e); e.printStackTrace(); status = 1; - } - finally - { - if (context != null) - { - try - { + } finally { + if (context != null) { + try { context.abort(); - } - catch (Exception e) - { + } catch (Exception e) { + // ignore } } } @@ -186,52 +171,42 @@ public class EmbargoCLITool { // lift or check embargo on one Item, handle exceptions // return false on success, true if there was fatal exception. protected static boolean processOneItem(Context context, Item item, CommandLine line, Date now) - throws Exception - { + throws Exception { boolean status = false; List lift = embargoService.getLiftMetadata(context, item); - if (lift.size() > 0) - { + if (lift.size() > 0) { DCDate liftDate = new DCDate(lift.get(0).getValue()); // need to survive any failure on a single item, go on to process the rest. - try - { - if (line.hasOption('a')){ + try { + if (line.hasOption('a')) { embargoService.setEmbargo(context, item); - } - else { - log.debug("Testing embargo on item="+item.getHandle()+", date="+liftDate.toString()); - if (liftDate.toDate().before(now)) - { - if (line.hasOption('v')) - { - System.err.println("Lifting embargo from Item handle=" + item.getHandle() + ", lift date=" + lift.get(0).getValue()); + } else { + log.debug("Testing embargo on item=" + item.getHandle() + ", date=" + liftDate.toString()); + if (liftDate.toDate().before(now)) { + if (line.hasOption('v')) { + System.err.println( + "Lifting embargo from Item handle=" + item.getHandle() + ", lift date=" + + lift.get(0).getValue()); } - if (line.hasOption('n')) - { - if (!line.hasOption('q')) - { - System.err.println("DRY RUN: would have lifted embargo from Item handle=" + item.getHandle() + ", lift date=" + lift.get(0).getValue()); + if (line.hasOption('n')) { + if (!line.hasOption('q')) { + System.err.println("DRY RUN: would have lifted embargo from Item handle=" + item + .getHandle() + ", lift date=" + lift.get(0).getValue()); } - } - else if (!line.hasOption('c')) - { + } else if (!line.hasOption('c')) { embargoService.liftEmbargo(context, item); } - } - else if (!line.hasOption('l')) - { - if (line.hasOption('v')) - { - System.err.println("Checking current embargo on Item handle=" + item.getHandle() + ", lift date=" + lift.get(0).getValue()); + } else if (!line.hasOption('l')) { + if (line.hasOption('v')) { + System.err.println( + "Checking current embargo on Item handle=" + item.getHandle() + ", lift date=" + lift + .get(0).getValue()); } embargoService.checkEmbargo(context, item); } } - } - catch (Exception e) - { + } catch (Exception e) { log.error("Failed attempting to lift embargo, item=" + item.getHandle() + ": ", e); System.err.println("Failed attempting to lift embargo, item=" + item.getHandle() + ": " + e); status = true; diff --git a/dspace-api/src/main/java/org/dspace/embargo/EmbargoLifter.java b/dspace-api/src/main/java/org/dspace/embargo/EmbargoLifter.java index 71ec1763bb..479193ae69 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/EmbargoLifter.java +++ b/dspace-api/src/main/java/org/dspace/embargo/EmbargoLifter.java @@ -7,8 +7,8 @@ */ package org.dspace.embargo; -import java.sql.SQLException; import java.io.IOException; +import java.sql.SQLException; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; @@ -21,24 +21,18 @@ import org.dspace.core.Context; * @author Larry Stone * @author Richard Rodgers */ -public interface EmbargoLifter -{ +public interface EmbargoLifter { /** * Implement the lifting of embargo in the "resource policies" * (access control) by (for example) turning on default read access to all * Bitstreams. * - * @param context - * The relevant DSpace Context. - * @param item - * the Item on which to lift the embargo - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param item the Item on which to lift the embargo + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void liftEmbargo(Context context, Item item) throws SQLException, AuthorizeException, IOException; diff --git a/dspace-api/src/main/java/org/dspace/embargo/EmbargoServiceImpl.java b/dspace-api/src/main/java/org/dspace/embargo/EmbargoServiceImpl.java index 2f298f6355..68efce46e1 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/EmbargoServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/embargo/EmbargoServiceImpl.java @@ -15,7 +15,10 @@ import java.util.List; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DCDate; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.core.service.PluginService; @@ -28,24 +31,26 @@ import org.springframework.beans.factory.annotation.Autowired; *

    * Configuration properties: (with examples) * {@code - * # DC metadata field to hold the user-supplied embargo terms - * embargo.field.terms = dc.embargo.terms - * # DC metadata field to hold computed "lift date" of embargo - * embargo.field.lift = dc.date.available - * # String to indicate indefinite (forever) embargo in terms - * embargo.terms.open = Indefinite - * # implementation of embargo setter plugin - * plugin.single.org.dspace.embargo.EmbargoSetter = edu.my.Setter - * # implementation of embargo lifter plugin - * plugin.single.org.dspace.embargo.EmbargoLifter = edu.my.Lifter + * # DC metadata field to hold the user-supplied embargo terms + * embargo.field.terms = dc.embargo.terms + * # DC metadata field to hold computed "lift date" of embargo + * embargo.field.lift = dc.date.available + * # String to indicate indefinite (forever) embargo in terms + * embargo.terms.open = Indefinite + * # implementation of embargo setter plugin + * plugin.single.org.dspace.embargo.EmbargoSetter = edu.my.Setter + * # implementation of embargo lifter plugin + * plugin.single.org.dspace.embargo.EmbargoLifter = edu.my.Lifter * } + * * @author Larry Stone * @author Richard Rodgers */ -public class EmbargoServiceImpl implements EmbargoService -{ +public class EmbargoServiceImpl implements EmbargoService { - /** log4j category */ + /** + * log4j category + */ private final Logger log = Logger.getLogger(EmbargoServiceImpl.class); // Metadata field components for user-supplied embargo terms @@ -74,72 +79,65 @@ public class EmbargoServiceImpl implements EmbargoService @Autowired(required = true) protected PluginService pluginService; - protected EmbargoServiceImpl() - { + protected EmbargoServiceImpl() { } @Override public void setEmbargo(Context context, Item item) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { // if lift is null, we might be restoring an item from an AIP DCDate myLift = getEmbargoTermsAsDate(context, item); - if (myLift == null) - { - if ((myLift = recoverEmbargoDate(item)) == null) - { - return; - } + if (myLift == null) { + if ((myLift = recoverEmbargoDate(item)) == null) { + return; + } } String slift = myLift.toString(); - try - { + try { context.turnOffAuthorisationSystem(); itemService.clearMetadata(context, item, lift_schema, lift_element, lift_qualifier, Item.ANY); itemService.addMetadata(context, item, lift_schema, lift_element, lift_qualifier, null, slift); - log.info("Set embargo on Item "+item.getHandle()+", expires on: "+slift); + log.info("Set embargo on Item " + item.getHandle() + ", expires on: " + slift); setter.setEmbargo(context, item); itemService.update(context, item); - } - finally - { + } finally { context.restoreAuthSystemState(); } } @Override public DCDate getEmbargoTermsAsDate(Context context, Item item) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { List terms = itemService.getMetadata(item, terms_schema, terms_element, - terms_qualifier, Item.ANY); + terms_qualifier, Item.ANY); DCDate result = null; // Its poor form to blindly use an object that could be null... - if (terms == null) + if (terms == null) { return null; + } result = setter.parseTerms(context, item, - terms.size() > 0 ? terms.get(0).getValue() : null); + terms.size() > 0 ? terms.get(0).getValue() : null); - if (result == null) + if (result == null) { return null; + } // new DCDate(non-date String) means toDate() will return null Date liftDate = result.toDate(); - if (liftDate == null) - { + if (liftDate == null) { throw new IllegalArgumentException( - "Embargo lift date is uninterpretable: " - + result.toString()); + "Embargo lift date is uninterpretable: " + + result.toString()); } /* - * NOTE: We do not check here for past dates as it can result in errors during AIP restoration. + * NOTE: We do not check here for past dates as it can result in errors during AIP restoration. * Therefore, UIs should perform any such date validation on input. See DS-3348 */ return result; @@ -148,17 +146,18 @@ public class EmbargoServiceImpl implements EmbargoService @Override public void liftEmbargo(Context context, Item item) - throws SQLException, AuthorizeException, IOException - { - // new version of Embargo policies remain in place. - //lifter.liftEmbargo(context, item); + throws SQLException, AuthorizeException, IOException { + // Since 3.0 the lift process for all embargoes is performed through the dates + // on the authorization process (see DS-2588) + // lifter.liftEmbargo(context, item); itemService.clearMetadata(context, item, lift_schema, lift_element, lift_qualifier, Item.ANY); // set the dc.date.available value to right now itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "available", Item.ANY); - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "available", null, DCDate.getCurrent().toString()); + itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "available", null, + DCDate.getCurrent().toString()); - log.info("Lifting embargo on Item "+item.getHandle()); + log.info("Lifting embargo on Item " + item.getHandle()); itemService.update(context, item); } @@ -171,15 +170,14 @@ public class EmbargoServiceImpl implements EmbargoService * * @throws Exception on generic exception */ - public void init() throws Exception - { - if (terms_schema == null) - { + public void init() throws Exception { + if (terms_schema == null) { String terms = configurationService.getProperty("embargo.field.terms"); String lift = configurationService.getProperty("embargo.field.lift"); - if (terms == null || lift == null) - { - throw new IllegalStateException("Missing one or more of the required DSpace configuration properties for EmbargoManager, check your configuration file."); + if (terms == null || lift == null) { + throw new IllegalStateException( + "Missing one or more of the required DSpace configuration properties for EmbargoManager, check " + + "your configuration file."); } terms_schema = getSchemaOf(terms); terms_element = getElementOf(terms); @@ -188,36 +186,31 @@ public class EmbargoServiceImpl implements EmbargoService lift_element = getElementOf(lift); lift_qualifier = getQualifierOf(lift); - setter = (EmbargoSetter)pluginService.getSinglePlugin(EmbargoSetter.class); - if (setter == null) - { + setter = (EmbargoSetter) pluginService.getSinglePlugin(EmbargoSetter.class); + if (setter == null) { throw new IllegalStateException("The EmbargoSetter plugin was not defined in DSpace configuration."); } - lifter = (EmbargoLifter)pluginService.getSinglePlugin(EmbargoLifter.class); - if (lifter == null) - { + lifter = (EmbargoLifter) pluginService.getSinglePlugin(EmbargoLifter.class); + if (lifter == null) { throw new IllegalStateException("The EmbargoLifter plugin was not defined in DSpace configuration."); } } } // return the schema part of "schema.element.qualifier" metadata field spec - protected String getSchemaOf(String field) - { + protected String getSchemaOf(String field) { String sa[] = field.split("\\.", 3); return sa[0]; } // return the element part of "schema.element.qualifier" metadata field spec, if any - protected String getElementOf(String field) - { + protected String getElementOf(String field) { String sa[] = field.split("\\.", 3); return sa.length > 1 ? sa[1] : null; } // return the qualifier part of "schema.element.qualifier" metadata field spec, if any - protected String getQualifierOf(String field) - { + protected String getQualifierOf(String field) { String sa[] = field.split("\\.", 3); return sa.length > 2 ? sa[2] : null; } @@ -227,12 +220,10 @@ public class EmbargoServiceImpl implements EmbargoService protected DCDate recoverEmbargoDate(Item item) { DCDate liftDate = null; List lift = itemService.getMetadata(item, lift_schema, lift_element, lift_qualifier, Item.ANY); - if (lift.size() > 0) - { + if (lift.size() > 0) { liftDate = new DCDate(lift.get(0).getValue()); // sanity check: do not allow an embargo lift date in the past. - if (liftDate.toDate().before(new Date())) - { + if (liftDate.toDate().before(new Date())) { liftDate = null; } } @@ -245,13 +236,13 @@ public class EmbargoServiceImpl implements EmbargoService } @Override - public List getLiftMetadata(Context context, Item item) - { + public List getLiftMetadata(Context context, Item item) { return itemService.getMetadata(item, lift_schema, lift_element, lift_qualifier, Item.ANY); } @Override - public Iterator findItemsByLiftMetadata(Context context) throws SQLException, IOException, AuthorizeException { + public Iterator findItemsByLiftMetadata(Context context) + throws SQLException, IOException, AuthorizeException { return itemService.findByMetadataField(context, lift_schema, lift_element, lift_qualifier, Item.ANY); } } diff --git a/dspace-api/src/main/java/org/dspace/embargo/EmbargoSetter.java b/dspace-api/src/main/java/org/dspace/embargo/EmbargoSetter.java index 08de5349c2..5b905b10d0 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/EmbargoSetter.java +++ b/dspace-api/src/main/java/org/dspace/embargo/EmbargoSetter.java @@ -7,8 +7,8 @@ */ package org.dspace.embargo; -import java.sql.SQLException; import java.io.IOException; +import java.sql.SQLException; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; @@ -21,8 +21,7 @@ import org.dspace.core.Context; * @author Larry Stone * @author Richard Rodgers */ -public interface EmbargoSetter -{ +public interface EmbargoSetter { /** * Get lift date of embargo from the "terms" supplied in the * metadata (or other available state) of this Item. Return null @@ -39,14 +38,12 @@ public interface EmbargoSetter * significant if the embargo lift date is computed relative to the present. * * @param context the DSpace context - * @param item the item to embargo - * @param terms value of the metadata field configured as embargo terms, if any. + * @param item the item to embargo + * @param terms value of the metadata field configured as embargo terms, if any. * @return absolute date on which the embargo is to be lifted, or null if none - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public DCDate parseTerms(Context context, Item item, String terms) throws SQLException, AuthorizeException; @@ -56,12 +53,10 @@ public interface EmbargoSetter * bitstreams in this Item. * * @param context the DSpace context - * @param item the item to embargo - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param item the item to embargo + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void setEmbargo(Context context, Item item) throws SQLException, AuthorizeException; @@ -77,14 +72,11 @@ public interface EmbargoSetter * long as its member Bitstreams are not readable. * * @param context the DSpace context - * @param item the item to embargo - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param item the item to embargo + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void checkEmbargo(Context context, Item item) throws SQLException, AuthorizeException, IOException; diff --git a/dspace-api/src/main/java/org/dspace/embargo/factory/EmbargoServiceFactory.java b/dspace-api/src/main/java/org/dspace/embargo/factory/EmbargoServiceFactory.java index c377aff80e..1af8cb810d 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/factory/EmbargoServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/embargo/factory/EmbargoServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.embargo.service.EmbargoService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the embargo package, use EmbargoServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the embargo package, use EmbargoServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class EmbargoServiceFactory { public abstract EmbargoService getEmbargoService(); - public static EmbargoServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("embargoServiceFactory", EmbargoServiceFactory.class); + public static EmbargoServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("embargoServiceFactory", EmbargoServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/embargo/factory/EmbargoServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/embargo/factory/EmbargoServiceFactoryImpl.java index 53be326208..e1e46008c3 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/factory/EmbargoServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/embargo/factory/EmbargoServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.embargo.service.EmbargoService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the embargo package, use EmbargoServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the embargo package, use EmbargoServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/embargo/service/EmbargoService.java b/dspace-api/src/main/java/org/dspace/embargo/service/EmbargoService.java index c5e5f37d32..70f37d0de6 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/service/EmbargoService.java +++ b/dspace-api/src/main/java/org/dspace/embargo/service/EmbargoService.java @@ -7,40 +7,42 @@ */ package org.dspace.embargo.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.core.Context; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Public interface to the embargo subsystem. *

    * Configuration properties: (with examples) * {@code - * # DC metadata field to hold the user-supplied embargo terms - * embargo.field.terms = dc.embargo.terms - * # DC metadata field to hold computed "lift date" of embargo - * embargo.field.lift = dc.date.available - * # String to indicate indefinite (forever) embargo in terms - * embargo.terms.open = Indefinite - * # implementation of embargo setter plugin - * plugin.single.org.dspace.embargo.EmbargoSetter = edu.my.Setter - * # implementation of embargo lifter plugin - * plugin.single.org.dspace.embargo.EmbargoLifter = edu.my.Lifter + * # DC metadata field to hold the user-supplied embargo terms + * embargo.field.terms = dc.embargo.terms + * # DC metadata field to hold computed "lift date" of embargo + * embargo.field.lift = dc.date.available + * # String to indicate indefinite (forever) embargo in terms + * embargo.terms.open = Indefinite + * # implementation of embargo setter plugin + * plugin.single.org.dspace.embargo.EmbargoSetter = edu.my.Setter + * # implementation of embargo lifter plugin + * plugin.single.org.dspace.embargo.EmbargoLifter = edu.my.Lifter * } + * * @author Larry Stone * @author Richard Rodgers */ public interface EmbargoService { - /** Special date signalling an Item is to be embargoed forever. - ** The actual date is the first day of the year 10,000 UTC. + /** + * Special date signalling an Item is to be embargoed forever. + * * The actual date is the first day of the year 10,000 UTC. **/ public static final DCDate FOREVER = new DCDate("10000-01-01"); @@ -50,12 +52,10 @@ public interface EmbargoService { * Calls EmbargoSetter plugin to adjust Item access control policies. * * @param context the DSpace context - * @param item the item to embargo - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param item the item to embargo + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void setEmbargo(Context context, Item item) throws SQLException, AuthorizeException; @@ -72,13 +72,11 @@ public interface EmbargoService { * specified field. * * @param context the DSpace context - * @param item the item to embargo + * @param item the item to embargo * @return lift date on which the embargo is to be lifted, or null if none - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public DCDate getEmbargoTermsAsDate(Context context, Item item) throws SQLException, AuthorizeException; @@ -89,14 +87,11 @@ public interface EmbargoService { * the administrative metadata fields that dictated embargo date. * * @param context the DSpace context - * @param item the item on which to lift the embargo - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param item the item on which to lift the embargo + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void liftEmbargo(Context context, Item item) throws SQLException, AuthorizeException, IOException; diff --git a/dspace-api/src/main/java/org/dspace/eperson/AccountServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/AccountServiceImpl.java index 4a11f1e7ca..6b9531788a 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/AccountServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/AccountServiceImpl.java @@ -7,21 +7,24 @@ */ package org.dspace.eperson; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Locale; +import javax.mail.MessagingException; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.core.*; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; +import org.dspace.core.Utils; import org.dspace.eperson.service.AccountService; import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.RegistrationDataService; import org.springframework.beans.factory.annotation.Autowired; -import javax.mail.MessagingException; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Locale; - /** - * * Methods for handling registration by email and forgotten passwords. When * someone registers as a user, or forgets their password, the * sendRegistrationInfo or sendForgotPasswordInfo methods can be used to send an @@ -35,17 +38,17 @@ import java.util.Locale; * @author Peter Breton * @version $Revision$ */ -public class AccountServiceImpl implements AccountService -{ - /** log4j log */ +public class AccountServiceImpl implements AccountService { + /** + * log4j log + */ private static Logger log = Logger.getLogger(AccountServiceImpl.class); @Autowired(required = true) protected EPersonService ePersonService; @Autowired(required = true) protected RegistrationDataService registrationDataService; - protected AccountServiceImpl() - { + protected AccountServiceImpl() { } @@ -57,16 +60,13 @@ public class AccountServiceImpl implements AccountService * Error reading email template (throws IOException) Authorization error * (throws AuthorizeException) * - * @param context - * DSpace context - * @param email - * Email address to send the registration email to + * @param context DSpace context + * @param email Email address to send the registration email to */ @Override public void sendRegistrationInfo(Context context, String email) - throws SQLException, IOException, MessagingException, - AuthorizeException - { + throws SQLException, IOException, MessagingException, + AuthorizeException { sendInfo(context, email, true, true); } @@ -78,16 +78,13 @@ public class AccountServiceImpl implements AccountService * sending email (throws MessagingException) Error reading email template * (throws IOException) Authorization error (throws AuthorizeException) * - * @param context - * DSpace context - * @param email - * Email address to send the forgot-password email to + * @param context DSpace context + * @param email Email address to send the forgot-password email to */ @Override public void sendForgotPasswordInfo(Context context, String email) - throws SQLException, IOException, MessagingException, - AuthorizeException - { + throws SQLException, IOException, MessagingException, + AuthorizeException { sendInfo(context, email, false, true); } @@ -102,23 +99,18 @@ public class AccountServiceImpl implements AccountService * If the token is not found return null. *

    * - * @param context - * DSpace context - * @param token - * Account token + * @param context DSpace context + * @param token Account token * @return The EPerson corresponding to token, or null. - * @throws SQLException - * If the token or eperson cannot be retrieved from the - * database. + * @throws SQLException If the token or eperson cannot be retrieved from the + * database. */ @Override public EPerson getEPerson(Context context, String token) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { String email = getEmail(context, token); - if (email == null) - { + if (email == null) { return null; } @@ -129,20 +121,16 @@ public class AccountServiceImpl implements AccountService * Return the e-mail address referred to by a token, or null if email * address can't be found ignores expiration of token * - * @param context - * DSpace context - * @param token - * Account token + * @param context DSpace context + * @param token Account token * @return The email address corresponding to token, or null. */ @Override public String getEmail(Context context, String token) - throws SQLException - { + throws SQLException { RegistrationData registrationData = registrationDataService.findByToken(context, token); - if (registrationData == null) - { + if (registrationData == null) { return null; } @@ -157,17 +145,13 @@ public class AccountServiceImpl implements AccountService /** * Delete token. * - * @param context - * DSpace context - * @param token - * The token to delete - * @throws SQLException - * If a database error occurs + * @param context DSpace context + * @param token The token to delete + * @throws SQLException If a database error occurs */ @Override public void deleteToken(Context context, String token) - throws SQLException - { + throws SQLException { registrationDataService.deleteByToken(context, token); } @@ -180,29 +164,27 @@ public class AccountServiceImpl implements AccountService * email. If send is TRUE, the email is sent; otherwise it is skipped. * * Potential error conditions: - * @return null if no EPerson with that email found - * @throws SQLException Cannot create registration data in database - * @throws MessagingException Error sending email - * @throws IOException Error reading email template - * @throws AuthorizeException Authorization error * - * @param context DSpace context - * @param email Email address to send the forgot-password email to + * @param context DSpace context + * @param email Email address to send the forgot-password email to * @param isRegister If true, this is for registration; otherwise, it is - * for forgot-password - * @param send If true, send email; otherwise do not send any email + * for forgot-password + * @param send If true, send email; otherwise do not send any email + * @return null if no EPerson with that email found + * @throws SQLException Cannot create registration data in database + * @throws MessagingException Error sending email + * @throws IOException Error reading email template + * @throws AuthorizeException Authorization error */ protected RegistrationData sendInfo(Context context, String email, - boolean isRegister, boolean send) throws SQLException, IOException, - MessagingException, AuthorizeException - { + boolean isRegister, boolean send) throws SQLException, IOException, + MessagingException, AuthorizeException { // See if a registration token already exists for this user RegistrationData rd = registrationDataService.findByEmail(context, email); // If it already exists, just re-issue it - if (rd == null) - { + if (rd == null) { rd = registrationDataService.create(context); rd.setToken(Utils.generateHexKey()); @@ -214,17 +196,15 @@ public class AccountServiceImpl implements AccountService // This is a potential problem -- if we create the callback // and then crash, registration will get SNAFU-ed. // So FIRST leave some breadcrumbs - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Created callback " - + rd.getID() - + " with token " + rd.getToken() - + " with email \"" + email + "\""); + + rd.getID() + + " with token " + rd.getToken() + + " with email \"" + email + "\""); } } - if (send) - { + if (send) { sendEmail(context, email, isRegister, rd); } @@ -237,45 +217,36 @@ public class AccountServiceImpl implements AccountService * If isRegister is true, this is registration email; * otherwise, it is a forgot-password email. * - * @param context - * The relevant DSpace Context. - * @param email - * The email address to mail to - * @param isRegister - * If true, this is registration email; otherwise it is - * forgot-password email. - * @param rd - * The RDBMS row representing the registration data. - * @throws MessagingException - * If an error occurs while sending email - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param context The relevant DSpace Context. + * @param email The email address to mail to + * @param isRegister If true, this is registration email; otherwise it is + * forgot-password email. + * @param rd The RDBMS row representing the registration data. + * @throws MessagingException If an error occurs while sending email + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. */ protected void sendEmail(Context context, String email, boolean isRegister, RegistrationData rd) - throws MessagingException, IOException, SQLException - { + throws MessagingException, IOException, SQLException { String base = ConfigurationManager.getProperty("dspace.url"); // Note change from "key=" to "token=" String specialLink = new StringBuffer().append(base).append( - base.endsWith("/") ? "" : "/").append( - isRegister ? "register" : "forgot").append("?") - .append("token=").append(rd.getToken()) - .toString(); + base.endsWith("/") ? "" : "/").append( + isRegister ? "register" : "forgot").append("?") + .append("token=").append(rd.getToken()) + .toString(); Locale locale = context.getCurrentLocale(); Email bean = Email.getEmail(I18nUtil.getEmailFilename(locale, isRegister ? "register" - : "change_password")); + : "change_password")); bean.addRecipient(email); bean.addArgument(specialLink); bean.send(); // Breadcrumbs - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Sent " + (isRegister ? "registration" : "account") - + " information to " + email); + + " information to " + email); } } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/EPerson.java b/dspace-api/src/main/java/org/dspace/eperson/EPerson.java index 2f97545ffa..5835ebeac8 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/EPerson.java +++ b/dspace-api/src/main/java/org/dspace/eperson/EPerson.java @@ -7,6 +7,20 @@ */ package org.dspace.eperson; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.dspace.content.DSpaceObject; @@ -19,15 +33,9 @@ import org.dspace.eperson.service.EPersonService; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - /** * Class representing an e-person. - * + * * @author David Stuve * @version $Revision$ */ @@ -35,67 +43,80 @@ import java.util.List; @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, include = "non-lazy") @Table(name = "eperson") -public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport -{ - @Column(name="eperson_id", insertable = false, updatable = false) +public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport { + @Column(name = "eperson_id", insertable = false, updatable = false) private Integer legacyId; - @Column(name="netid", length = 64) + @Column(name = "netid", length = 64) private String netid; - @Column(name="last_active") + @Column(name = "last_active") @Temporal(TemporalType.TIMESTAMP) private Date lastActive; - @Column(name="can_log_in", nullable = true) + @Column(name = "can_log_in", nullable = true) private Boolean canLogIn; - @Column(name="email", unique=true, length = 64) + @Column(name = "email", unique = true, length = 64) private String email; - @Column(name="require_certificate") + @Column(name = "require_certificate") private boolean requireCertificate = false; - @Column(name="self_registered") + @Column(name = "self_registered") private boolean selfRegistered = false; - @Column(name="password", length = 128) + @Column(name = "password", length = 128) private String password; - @Column(name="salt", length = 32) + @Column(name = "salt", length = 32) private String salt; - @Column(name="digest_algorithm", length = 16) + @Column(name = "session_salt", length = 32) + private String sessionSalt; + + @Column(name = "digest_algorithm", length = 16) private String digestAlgorithm; @ManyToMany(fetch = FetchType.LAZY, mappedBy = "epeople") private final List groups = new ArrayList<>(); - /** The e-mail field (for sorting) */ + /** + * The e-mail field (for sorting) + */ public static final int EMAIL = 1; - /** The last name (for sorting) */ + /** + * The last name (for sorting) + */ public static final int LASTNAME = 2; - /** The e-mail field (for sorting) */ + /** + * The e-mail field (for sorting) + */ public static final int ID = 3; - /** The netid field (for sorting) */ + /** + * The netid field (for sorting) + */ public static final int NETID = 4; - /** The e-mail field (for sorting) */ + /** + * The e-mail field (for sorting) + */ public static final int LANGUAGE = 5; @Transient protected transient EPersonService ePersonService; + @Transient + private Date previousActive; + /** * Protected constructor, create object using: * {@link org.dspace.eperson.service.EPersonService#create(Context)} - * */ - protected EPerson() - { + protected EPerson() { } @@ -106,33 +127,27 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport /** * Return true if this object equals obj, false otherwise. - * + * * @param obj another EPerson. * @return true if EPerson objects are equal in ID, email, and full name */ @Override - public boolean equals(Object obj) - { - if (obj == null) - { + public boolean equals(Object obj) { + if (obj == null) { return false; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } final EPerson other = (EPerson) obj; - if (this.getID() != other.getID()) - { + if (this.getID() != other.getID()) { return false; } - if (!StringUtils.equals(this.getEmail(), other.getEmail())) - { + if (!StringUtils.equals(this.getEmail(), other.getEmail())) { return false; } - if (!StringUtils.equals(this.getFullName(), other.getFullName())) - { + if (!StringUtils.equals(this.getFullName(), other.getFullName())) { return false; } return true; @@ -144,78 +159,68 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport * @return int hash of object */ @Override - public int hashCode() - { + public int hashCode() { int hash = 5; hash = 89 * hash + this.getID().hashCode(); - hash = 89 * hash + (this.getEmail() != null? this.getEmail().hashCode():0); - hash = 89 * hash + (this.getFullName() != null? this.getFullName().hashCode():0); + hash = 89 * hash + (this.getEmail() != null ? this.getEmail().hashCode() : 0); + hash = 89 * hash + (this.getFullName() != null ? this.getFullName().hashCode() : 0); return hash; } /** * Get the e-person's language - * + * * @return language code (or null if the column is an SQL NULL) */ - public String getLanguage() - { - return getePersonService().getMetadataFirstValue(this, "eperson", "language", null, Item.ANY); - } - - /** + public String getLanguage() { + return getePersonService().getMetadataFirstValue(this, "eperson", "language", null, Item.ANY); + } + + /** * Set the EPerson's language. Value is expected to be a Unix/POSIX * Locale specification of the form {language} or {language}_{territory}, * e.g. "en", "en_US", "pt_BR" (the latter is Brazilian Portugese). - * - * @param context - * The relevant DSpace Context. - * @param language - * language code - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * + * @param context The relevant DSpace Context. + * @param language language code + * @throws SQLException An exception that provides information on a database access error or other errors. */ - public void setLanguage(Context context, String language) throws SQLException { - getePersonService().setMetadataSingleValue(context, this, "eperson", "language", null, null, language); - } + public void setLanguage(Context context, String language) throws SQLException { + getePersonService().setMetadataSingleValue(context, this, "eperson", "language", null, null, language); + } /** * Get the e-person's email address - * + * * @return their email address (or null if the column is an SQL NULL) */ - public String getEmail() - { + public String getEmail() { return email; } /** * Set the EPerson's email - * - * @param s - * the new email + * + * @param s the new email */ - public void setEmail(String s) - { + public void setEmail(String s) { this.email = StringUtils.lowerCase(s); setModified(); } /** * Get the e-person's netid - * + * * @return their netid (DB constraints ensure it's never NULL) */ - public String getNetid() - { + public String getNetid() { return netid; } /** * Set the EPerson's netid - * - * @param netid - * the new netid + * + * @param netid the new netid */ public void setNetid(String netid) { this.netid = netid; @@ -225,47 +230,37 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the e-person's full name, combining first and last name in a * displayable string. - * + * * @return their full name (first + last name; if both are NULL, returns email) */ - public String getFullName() - { + public String getFullName() { String f = getFirstName(); - String l= getLastName(); + String l = getLastName(); - if ((l == null) && (f == null)) - { + if ((l == null) && (f == null)) { return getEmail(); - } - else if (f == null) - { + } else if (f == null) { return l; - } - else - { + } else { return (f + " " + l); } } /** * Get the eperson's first name. - * + * * @return their first name (or null if the column is an SQL NULL) */ - public String getFirstName() - { + public String getFirstName() { return getePersonService().getMetadataFirstValue(this, "eperson", "firstname", null, Item.ANY); } /** * Set the eperson's first name - * - * @param context - * The relevant DSpace Context. - * @param firstname - * the person's first name - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * + * @param context The relevant DSpace Context. + * @param firstname the person's first name + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void setFirstName(Context context, String firstname) throws SQLException { getePersonService().setMetadataSingleValue(context, this, "eperson", "firstname", null, null, firstname); @@ -274,23 +269,19 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport /** * Get the eperson's last name. - * + * * @return their last name (or null if the column is an SQL NULL) */ - public String getLastName() - { + public String getLastName() { return getePersonService().getMetadataFirstValue(this, "eperson", "lastname", null, Item.ANY); } /** * Set the eperson's last name - * - * @param context - * The relevant DSpace Context. - * @param lastname - * the person's last name - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * + * @param context The relevant DSpace Context. + * @param lastname the person's last name + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void setLastName(Context context, String lastname) throws SQLException { getePersonService().setMetadataSingleValue(context, this, "eperson", "lastname", null, null, lastname); @@ -299,87 +290,77 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport /** * Indicate whether the user can log in - * - * @param login - * boolean yes/no + * + * @param login boolean yes/no */ - public void setCanLogIn(boolean login) - { + public void setCanLogIn(boolean login) { this.canLogIn = login; setModified(); } /** * Can the user log in? - * + * * @return boolean, yes/no */ - public boolean canLogIn() - { + public boolean canLogIn() { return BooleanUtils.isTrue(canLogIn); } /** * Set require cert yes/no - * - * @param isrequired - * boolean yes/no + * + * @param isrequired boolean yes/no */ - public void setRequireCertificate(boolean isrequired) - { + public void setRequireCertificate(boolean isrequired) { this.requireCertificate = isrequired; setModified(); } /** * Get require certificate or not - * + * * @return boolean, yes/no (or false if the column is an SQL NULL) */ - public boolean getRequireCertificate() - { + public boolean getRequireCertificate() { return requireCertificate; } /** * Indicate whether the user self-registered - * - * @param sr - * boolean yes/no + * + * @param sr boolean yes/no */ - public void setSelfRegistered(boolean sr) - { + public void setSelfRegistered(boolean sr) { this.selfRegistered = sr; setModified(); } /** * Is the user self-registered? - * + * * @return boolean, yes/no (or false if the column is an SQL NULL) */ - public boolean getSelfRegistered() - { + public boolean getSelfRegistered() { return selfRegistered; } /** * Stamp the EPerson's last-active date. - * + * * @param when latest activity timestamp, or null to clear. */ - public void setLastActive(Date when) - { + public void setLastActive(Date when) { + this.previousActive = lastActive; this.lastActive = when; } /** * Get the EPerson's last-active stamp. - * + * * @return date when last logged on, or null. */ - public Date getLastActive() - { + public Date getLastActive() { return lastActive; } @@ -387,14 +368,12 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport * @return type found in Constants, see {@link org.dspace.core.Constants#Constants Constants} */ @Override - public int getType() - { + public int getType() { return Constants.EPERSON; } @Override - public String getName() - { + public String getName() { return getEmail(); } @@ -427,10 +406,25 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport } private EPersonService getePersonService() { - if(ePersonService == null) - { + if (ePersonService == null) { ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); } return ePersonService; } + + public String getSessionSalt() { + return sessionSalt; + } + + public void setSessionSalt(String sessionSalt) { + this.sessionSalt = sessionSalt; + } + + public Date getPreviousActive() { + if (previousActive == null) { + return new Date(0); + } + return previousActive; + } + } diff --git a/dspace-api/src/main/java/org/dspace/eperson/EPersonCLITool.java b/dspace-api/src/main/java/org/dspace/eperson/EPersonCLITool.java index 1c86e0aa33..850cb992bc 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/EPersonCLITool.java +++ b/dspace-api/src/main/java/org/dspace/eperson/EPersonCLITool.java @@ -7,16 +7,22 @@ */ package org.dspace.eperson; -import org.apache.commons.cli.*; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Locale; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.GnuParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Locale; - public class EPersonCLITool { /* @@ -28,35 +34,42 @@ public class EPersonCLITool { private static final Option VERB_LIST = new Option("L", "list", false, "list EPersons"); private static final Option VERB_MODIFY = new Option("M", "modify", false, "modify an EPerson"); - private static final Option OPT_GIVENNAME = new Option("g", "givenname", true, "the person's actual first or personal name"); - private static final Option OPT_SURNAME = new Option("s", "surname", true, "the person's actual last or family name"); + private static final Option OPT_GIVENNAME = new Option("g", "givenname", true, + "the person's actual first or personal name"); + private static final Option OPT_SURNAME = new Option("s", "surname", true, + "the person's actual last or family name"); private static final Option OPT_PHONE = new Option("t", "telephone", true, "telephone number, empty for none"); private static final Option OPT_LANGUAGE = new Option("l", "language", true, "the person's preferred language"); - private static final Option OPT_REQUIRE_CERTIFICATE = new Option("c", "requireCertificate", true, "if 'true', an X.509 certificate will be required for login"); + private static final Option OPT_REQUIRE_CERTIFICATE = new Option("c", "requireCertificate", true, + "if 'true', an X.509 certificate will be " + + "required for login"); private static final Option OPT_CAN_LOGIN = new Option("C", "canLogIn", true, "'true' if the user can log in"); private static final Option OPT_EMAIL = new Option("m", "email", true, "the user's email address, empty for none"); - private static final Option OPT_NETID = new Option("n", "netid", true, "network ID associated with the person, empty for none"); + private static final Option OPT_NETID = new Option("n", "netid", true, + "network ID associated with the person, empty for none"); private static final Option OPT_NEW_EMAIL = new Option("i", "newEmail", true, "new email address"); private static final Option OPT_NEW_NETID = new Option("I", "newNetid", true, "new network ID"); private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); + /** + * Default constructor + */ + private EPersonCLITool() { } + /** * Tool for manipulating user accounts. * * @param argv the command line arguments given - * @throws ParseException - * Base for Exceptions thrown during parsing of a command-line. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws ParseException Base for Exceptions thrown during parsing of a command-line. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public static void main(String argv[]) - throws ParseException, SQLException, AuthorizeException { + throws ParseException, SQLException, AuthorizeException { final OptionGroup VERBS = new OptionGroup(); VERBS.addOption(VERB_ADD); VERBS.addOption(VERB_DELETE); @@ -76,28 +89,17 @@ public class EPersonCLITool { context.turnOffAuthorisationSystem(); int status = 0; - if (command.hasOption(VERB_ADD.getOpt())) - { + if (command.hasOption(VERB_ADD.getOpt())) { status = cmdAdd(context, argv); - } - else if (command.hasOption(VERB_DELETE.getOpt())) - { + } else if (command.hasOption(VERB_DELETE.getOpt())) { status = cmdDelete(context, argv); - } - else if (command.hasOption(VERB_MODIFY.getOpt())) - { + } else if (command.hasOption(VERB_MODIFY.getOpt())) { status = cmdModify(context, argv); - } - else if (command.hasOption(VERB_LIST.getOpt())) - { + } else if (command.hasOption(VERB_LIST.getOpt())) { status = cmdList(context, argv); - } - else if (command.hasOption('h')) - { + } else if (command.hasOption('h')) { new HelpFormatter().printHelp("user [options]", globalOptions); - } - else - { + } else { System.err.println("Unknown operation."); new HelpFormatter().printHelp("user [options]", globalOptions); context.abort(); @@ -105,8 +107,7 @@ public class EPersonCLITool { throw new IllegalArgumentException(); } - if (context.isValid()) - { + if (context.isValid()) { try { context.complete(); } catch (SQLException ex) { @@ -115,7 +116,9 @@ public class EPersonCLITool { } } - /** Command to create an EPerson. */ + /** + * Command to create an EPerson. + */ private static int cmdAdd(Context context, String[] argv) throws AuthorizeException, SQLException { Options options = new Options(); @@ -148,21 +151,18 @@ public class EPersonCLITool { return 1; } - if (command.hasOption('h')) - { + if (command.hasOption('h')) { new HelpFormatter().printHelp("user --add [options]", options); return 0; } // Check that we got sufficient credentials to define a user. - if ((!command.hasOption(OPT_EMAIL.getOpt())) && (!command.hasOption(OPT_NETID.getOpt()))) - { + if ((!command.hasOption(OPT_EMAIL.getOpt())) && (!command.hasOption(OPT_NETID.getOpt()))) { System.err.println("You must provide an email address or a netid to identify the new user."); return 1; } - if (!command.hasOption('p')) - { + if (!command.hasOption('p')) { System.err.println("You must provide a password for the new user."); return 1; } @@ -183,17 +183,14 @@ public class EPersonCLITool { eperson.setFirstName(context, command.getOptionValue(OPT_GIVENNAME.getOpt())); eperson.setLastName(context, command.getOptionValue(OPT_SURNAME.getOpt())); eperson.setLanguage(context, command.getOptionValue(OPT_LANGUAGE.getOpt(), - Locale.getDefault().getLanguage())); + Locale.getDefault().getLanguage())); ePersonService.setMetadata(context, eperson, "phone", command.getOptionValue(OPT_PHONE.getOpt())); eperson.setNetid(command.getOptionValue(OPT_NETID.getOpt())); ePersonService.setPassword(eperson, command.getOptionValue('p')); - if (command.hasOption(OPT_REQUIRE_CERTIFICATE.getOpt())) - { + if (command.hasOption(OPT_REQUIRE_CERTIFICATE.getOpt())) { eperson.setRequireCertificate(Boolean.valueOf(command.getOptionValue( - OPT_REQUIRE_CERTIFICATE.getOpt()))); - } - else - { + OPT_REQUIRE_CERTIFICATE.getOpt()))); + } else { eperson.setRequireCertificate(false); } @@ -210,9 +207,10 @@ public class EPersonCLITool { return 0; } - /** Command to delete an EPerson. */ - private static int cmdDelete(Context context, String[] argv) - { + /** + * Command to delete an EPerson. + */ + private static int cmdDelete(Context context, String[] argv) { Options options = new Options(); options.addOption(VERB_DELETE); @@ -234,8 +232,7 @@ public class EPersonCLITool { return 1; } - if (command.hasOption('h')) - { + if (command.hasOption('h')) { new HelpFormatter().printHelp("user --delete [options]", options); return 0; } @@ -243,16 +240,11 @@ public class EPersonCLITool { // Delete! EPerson eperson = null; try { - if (command.hasOption(OPT_NETID.getOpt())) - { + if (command.hasOption(OPT_NETID.getOpt())) { eperson = ePersonService.findByNetid(context, command.getOptionValue(OPT_NETID.getOpt())); - } - else if (command.hasOption(OPT_EMAIL.getOpt())) - { + } else if (command.hasOption(OPT_EMAIL.getOpt())) { eperson = ePersonService.findByEmail(context, command.getOptionValue(OPT_EMAIL.getOpt())); - } - else - { + } else { System.err.println("You must specify the user's email address or netid."); return 1; } @@ -261,8 +253,7 @@ public class EPersonCLITool { return 1; } - if (null == eperson) - { + if (null == eperson) { System.err.println("No such EPerson"); return 1; } @@ -285,7 +276,9 @@ public class EPersonCLITool { return 0; } - /** Command to modify an EPerson. */ + /** + * Command to modify an EPerson. + */ private static int cmdModify(Context context, String[] argv) throws AuthorizeException, SQLException { Options options = new Options(); @@ -318,8 +311,7 @@ public class EPersonCLITool { return 1; } - if (command.hasOption('h')) - { + if (command.hasOption('h')) { new HelpFormatter().printHelp("user --modify [options]", options); return 0; } @@ -327,16 +319,11 @@ public class EPersonCLITool { // Modify! EPerson eperson = null; try { - if (command.hasOption(OPT_NETID.getOpt())) - { + if (command.hasOption(OPT_NETID.getOpt())) { eperson = ePersonService.findByNetid(context, command.getOptionValue(OPT_NETID.getOpt())); - } - else if (command.hasOption(OPT_EMAIL.getOpt())) - { + } else if (command.hasOption(OPT_EMAIL.getOpt())) { eperson = ePersonService.findByEmail(context, command.getOptionValue(OPT_EMAIL.getOpt())); - } - else - { + } else { System.err.println("No EPerson selected"); return 1; } @@ -346,56 +333,44 @@ public class EPersonCLITool { } boolean modified = false; - if (null == eperson) - { + if (null == eperson) { System.err.println("No such EPerson"); return 1; - } - else - { - if (command.hasOption(OPT_NEW_EMAIL.getOpt())) - { + } else { + if (command.hasOption(OPT_NEW_EMAIL.getOpt())) { eperson.setEmail(command.getOptionValue(OPT_NEW_EMAIL.getOpt())); modified = true; } - if (command.hasOption(OPT_NEW_NETID.getOpt())) - { + if (command.hasOption(OPT_NEW_NETID.getOpt())) { eperson.setNetid(command.getOptionValue(OPT_NEW_NETID.getOpt())); modified = true; } - if (command.hasOption(OPT_GIVENNAME.getOpt())) - { + if (command.hasOption(OPT_GIVENNAME.getOpt())) { eperson.setFirstName(context, command.getOptionValue(OPT_GIVENNAME.getOpt())); modified = true; } - if (command.hasOption(OPT_SURNAME.getOpt())) - { + if (command.hasOption(OPT_SURNAME.getOpt())) { eperson.setLastName(context, command.getOptionValue(OPT_SURNAME.getOpt())); modified = true; } - if (command.hasOption(OPT_PHONE.getOpt())) - { + if (command.hasOption(OPT_PHONE.getOpt())) { ePersonService.setMetadata(context, eperson, "phone", command.getOptionValue(OPT_PHONE.getOpt())); modified = true; } - if (command.hasOption(OPT_LANGUAGE.getOpt())) - { + if (command.hasOption(OPT_LANGUAGE.getOpt())) { eperson.setLanguage(context, command.getOptionValue(OPT_LANGUAGE.getOpt())); modified = true; } - if (command.hasOption(OPT_REQUIRE_CERTIFICATE.getOpt())) - { + if (command.hasOption(OPT_REQUIRE_CERTIFICATE.getOpt())) { eperson.setRequireCertificate(Boolean.valueOf(command.getOptionValue( - OPT_REQUIRE_CERTIFICATE.getOpt()))); + OPT_REQUIRE_CERTIFICATE.getOpt()))); modified = true; } - if (command.hasOption(OPT_CAN_LOGIN.getOpt())) - { + if (command.hasOption(OPT_CAN_LOGIN.getOpt())) { eperson.setCanLogIn(Boolean.valueOf(command.getOptionValue(OPT_CAN_LOGIN.getOpt()))); modified = true; } - if (modified) - { + if (modified) { try { ePersonService.update(context, eperson); context.complete(); @@ -405,9 +380,7 @@ public class EPersonCLITool { System.err.println(ex.getMessage()); return 1; } catch (AuthorizeException ex) { /* XXX SNH */ } - } - else - { + } else { System.out.println("No changes."); } } @@ -415,21 +388,21 @@ public class EPersonCLITool { return 0; } - /** Command to list known EPersons. */ - private static int cmdList(Context context, String[] argv) - { + /** + * Command to list known EPersons. + */ + private static int cmdList(Context context, String[] argv) { // XXX ideas: // specific user/netid // wild or regex match user/netid // select details (pseudo-format string) try { - for (EPerson person : ePersonService.findAll(context, EPerson.EMAIL)) - { + for (EPerson person : ePersonService.findAll(context, EPerson.EMAIL)) { System.out.printf("%s\t%s/%s\t%s, %s\n", - person.getID().toString(), - person.getEmail(), - person.getNetid(), - person.getLastName(), person.getFirstName()); // TODO more user details + person.getID().toString(), + person.getEmail(), + person.getNetid(), + person.getLastName(), person.getFirstName()); // TODO more user details } } catch (SQLException ex) { System.err.println(ex.getMessage()); diff --git a/dspace-api/src/main/java/org/dspace/eperson/EPersonConsumer.java b/dspace-api/src/main/java/org/dspace/eperson/EPersonConsumer.java index 9e9b7fbd47..62761444a5 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/EPersonConsumer.java +++ b/dspace-api/src/main/java/org/dspace/eperson/EPersonConsumer.java @@ -7,29 +7,34 @@ */ package org.dspace.eperson; +import java.util.Date; +import java.util.UUID; +import javax.mail.MessagingException; + import org.apache.log4j.Logger; -import org.dspace.core.*; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; +import org.dspace.core.LogManager; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.event.Consumer; import org.dspace.event.Event; -import javax.mail.MessagingException; -import java.util.Date; -import java.util.UUID; - /** * Class for handling updates to EPersons * * Recommended filter: EPerson+Create * - * @version $Revision$ - * * @author Stuart Lewis + * @version $Revision$ */ -public class EPersonConsumer implements Consumer -{ - /** log4j logger */ +public class EPersonConsumer implements Consumer { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(EPersonConsumer.class); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); @@ -41,34 +46,28 @@ public class EPersonConsumer implements Consumer */ @Override public void initialize() - throws Exception - { + throws Exception { } /** * Consume the event * - * @param context - * The relevant DSpace Context. - * @param event - * Which Event to consume + * @param context The relevant DSpace Context. + * @param event Which Event to consume * @throws Exception if error */ @Override public void consume(Context context, Event event) - throws Exception - { + throws Exception { int st = event.getSubjectType(); int et = event.getEventType(); UUID id = event.getSubjectID(); - switch (st) - { + switch (st) { // If an EPerson is changed case Constants.EPERSON: - if (et == Event.CREATE) - { + if (et == Event.CREATE) { // Notify of new user registration String notifyRecipient = ConfigurationManager.getProperty("registration.notify"); if (notifyRecipient == null) { @@ -76,12 +75,11 @@ public class EPersonConsumer implements Consumer } notifyRecipient = notifyRecipient.trim(); - if(!notifyRecipient.equals("")) - { - try - { + if (!notifyRecipient.equals("")) { + try { EPerson eperson = ePersonService.find(context, id); - Email adminEmail = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(), "registration_notify")); + Email adminEmail = Email + .getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(), "registration_notify")); adminEmail.addRecipient(notifyRecipient); adminEmail.addArgument(ConfigurationManager.getProperty("dspace.name")); @@ -95,16 +93,13 @@ public class EPersonConsumer implements Consumer adminEmail.send(); log.info(LogManager.getHeader(context, "registerion_alert", "user=" - + eperson.getEmail())); - } - catch (MessagingException me) - { + + eperson.getEmail())); + } catch (MessagingException me) { log.warn(LogManager.getHeader(context, - "error_emailing_administrator", ""), me); + "error_emailing_administrator", ""), me); } } - } else if (et == Event.DELETE) - { + } else if (et == Event.DELETE) { // TODO: Implement this if required } break; @@ -117,26 +112,22 @@ public class EPersonConsumer implements Consumer /** * Handle the end of the event * - * @param ctx - * The relevant DSpace Context. + * @param ctx The relevant DSpace Context. * @throws Exception if error */ @Override public void end(Context ctx) - throws Exception - { + throws Exception { } /** * Finish the event * - * @param ctx - * The relevant DSpace Context. + * @param ctx The relevant DSpace Context. */ @Override - public void finish(Context ctx) - { + public void finish(Context ctx) { } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/EPersonDeletionException.java b/dspace-api/src/main/java/org/dspace/eperson/EPersonDeletionException.java index 6d3c585a3b..5429f3d102 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/EPersonDeletionException.java +++ b/dspace-api/src/main/java/org/dspace/eperson/EPersonDeletionException.java @@ -12,43 +12,37 @@ import java.util.List; /** * Exception indicating that an EPerson may not be deleted due to the presence * of the EPerson's ID in certain tables - * + * * @author Grace Carpenter */ -public class EPersonDeletionException extends Exception -{ +public class EPersonDeletionException extends Exception { private List myTableList; //set of tables in which EPerson exists /** * Create an empty EPersonDeletionException */ - public EPersonDeletionException() - { + public EPersonDeletionException() { super(); myTableList = null; } /** * Create an EPersonDeletionException - * - * @param tableList - * tables in which the eperson ID exists. An person cannot be - * deleted if it exists in these tables. - * + * + * @param tableList tables in which the eperson ID exists. An person cannot be + * deleted if it exists in these tables. */ - public EPersonDeletionException(List tableList) - { + public EPersonDeletionException(List tableList) { super(); myTableList = tableList; } /** * Return the list of offending tables. - * + * * @return The tables in which the eperson ID exists. */ - public List getTables() - { + public List getTables() { return myTableList; } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java index e7c42f67a5..4c04482f1f 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java @@ -7,8 +7,17 @@ */ package org.dspace.eperson; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.UUID; + import org.apache.commons.codec.DecoderException; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; @@ -29,9 +38,6 @@ import org.dspace.workflow.WorkflowService; import org.dspace.workflow.factory.WorkflowServiceFactory; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.*; - /** * Service implementation for the EPerson object. * This class is responsible for all business logic calls for the EPerson object and is autowired by spring. @@ -41,7 +47,9 @@ import java.util.*; */ public class EPersonServiceImpl extends DSpaceObjectServiceImpl implements EPersonService { - /** log4j logger */ + /** + * log4j logger + */ private final Logger log = Logger.getLogger(EPersonServiceImpl.class); @Autowired(required = true) @@ -54,8 +62,7 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Autowired(required = true) protected SubscribeService subscribeService; - protected EPersonServiceImpl() - { + protected EPersonServiceImpl() { super(); } @@ -66,12 +73,9 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public EPerson findByIdOrLegacyId(Context context, String id) throws SQLException { - if(StringUtils.isNumeric(id)) - { + if (StringUtils.isNumeric(id)) { return findByLegacyId(context, Integer.parseInt(id)); - } - else - { + } else { return find(context, UUID.fromString(id)); } } @@ -83,8 +87,7 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public EPerson findByEmail(Context context, String email) throws SQLException { - if (email == null) - { + if (email == null) { return null; } @@ -94,8 +97,7 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public EPerson findByNetid(Context context, String netId) throws SQLException { - if (netId == null) - { + if (netId == null) { return null; } @@ -104,8 +106,7 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public List search(Context context, String query) throws SQLException { - if(StringUtils.isBlank(query)) - { + if (StringUtils.isBlank(query)) { //If we don't have a query, just return everything. return findAll(context, EPerson.EMAIL); } @@ -117,19 +118,18 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme try { List ePerson = new ArrayList<>(); EPerson person = find(context, UUID.fromString(query)); - if(person != null) - { + if (person != null) { ePerson.add(person); } return ePerson; - } catch(IllegalArgumentException e) { + } catch (IllegalArgumentException e) { MetadataField firstNameField = metadataFieldService.findByElement(context, "eperson", "firstname", null); MetadataField lastNameField = metadataFieldService.findByElement(context, "eperson", "lastname", null); - if (StringUtils.isBlank(query)) - { + if (StringUtils.isBlank(query)) { query = null; } - return ePersonDAO.search(context, query, Arrays.asList(firstNameField, lastNameField), Arrays.asList(firstNameField, lastNameField), offset, limit); + return ePersonDAO.search(context, query, Arrays.asList(firstNameField, lastNameField), + Arrays.asList(firstNameField, lastNameField), offset, limit); } } @@ -137,21 +137,22 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme public int searchResultCount(Context context, String query) throws SQLException { MetadataField firstNameField = metadataFieldService.findByElement(context, "eperson", "firstname", null); MetadataField lastNameField = metadataFieldService.findByElement(context, "eperson", "lastname", null); - if(StringUtils.isBlank(query)) query = null; + if (StringUtils.isBlank(query)) { + query = null; + } return ePersonDAO.searchResultCount(context, query, Arrays.asList(firstNameField, lastNameField)); } @Override public List findAll(Context context, int sortField) throws SQLException { - return findAll(context, sortField, -1, -1); + return findAll(context, sortField, -1, -1); } - + @Override public List findAll(Context context, int sortField, int pageSize, int offset) throws SQLException { String sortColumn = null; MetadataField metadataFieldSort = null; - switch (sortField) - { + switch (sortField) { case EPerson.ID: sortColumn = "eperson_id"; break; @@ -176,20 +177,19 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public EPerson create(Context context) throws SQLException, AuthorizeException { // authorized? - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "You must be an admin to create an EPerson"); + "You must be an admin to create an EPerson"); } // Create a table row EPerson e = ePersonDAO.create(context, new EPerson()); log.info(LogManager.getHeader(context, "create_eperson", "eperson_id=" - + e.getID())); + + e.getID())); context.addEvent(new Event(Event.CREATE, Constants.EPERSON, e.getID(), - null, getIdentifiers(context, e))); + null, getIdentifiers(context, e))); return e; } @@ -197,10 +197,9 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public void delete(Context context, EPerson ePerson) throws SQLException, AuthorizeException { // authorized? - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "You must be an admin to delete an EPerson"); + "You must be an admin to delete an EPerson"); } // check for presence of eperson in tables that @@ -209,12 +208,12 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme // if eperson exists in tables that have constraints // on eperson, throw an exception - if (constraintList.size() > 0) - { + if (constraintList.size() > 0) { throw new AuthorizeException(new EPersonDeletionException(constraintList)); } - context.addEvent(new Event(Event.DELETE, Constants.EPERSON, ePerson.getID(), ePerson.getEmail(), getIdentifiers(context, ePerson))); + context.addEvent(new Event(Event.DELETE, Constants.EPERSON, ePerson.getID(), ePerson.getEmail(), + getIdentifiers(context, ePerson))); // XXX FIXME: This sidesteps the object model code so it won't // generate REMOVE events on the affected Groups. @@ -235,7 +234,7 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme ePersonDAO.delete(context, ePerson); log.info(LogManager.getHeader(context, "delete_eperson", - "eperson_id=" + ePerson.getID())); + "eperson_id=" + ePerson.getID())); } @Override @@ -253,14 +252,11 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public void setPasswordHash(EPerson ePerson, PasswordHash password) { - if (null == password) - { + if (null == password) { ePerson.setDigestAlgorithm(null); ePerson.setSalt(null); ePerson.setPassword(null); - } - else - { + } else { ePerson.setDigestAlgorithm(password.getAlgorithm()); ePerson.setSalt(password.getSaltString()); ePerson.setPassword(password.getHashString()); @@ -272,8 +268,8 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme PasswordHash hash = null; try { hash = new PasswordHash(ePerson.getDigestAlgorithm(), - ePerson.getSalt(), - ePerson.getPassword()); + ePerson.getSalt(), + ePerson.getPassword()); } catch (DecoderException ex) { log.error("Problem decoding stored salt or hash: " + ex.getMessage()); } @@ -283,22 +279,19 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public boolean checkPassword(Context context, EPerson ePerson, String attempt) { PasswordHash myHash; - try - { + try { myHash = new PasswordHash( - ePerson.getDigestAlgorithm(), - ePerson.getSalt(), - ePerson.getPassword()); - } catch (DecoderException ex) - { + ePerson.getDigestAlgorithm(), + ePerson.getSalt(), + ePerson.getPassword()); + } catch (DecoderException ex) { log.error(ex.getMessage()); return false; } boolean answer = myHash.matches(attempt); // If using the old unsalted hash, and this password is correct, update to a new hash - if (answer && (null == ePerson.getDigestAlgorithm())) - { + if (answer && (null == ePerson.getDigestAlgorithm())) { log.info("Upgrading password hash for EPerson " + ePerson.getID()); setPassword(ePerson, attempt); try { @@ -319,9 +312,8 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme // Check authorisation - if you're not the eperson // see if the authorization system says you can if (!context.ignoreAuthorization() - && ((context.getCurrentUser() == null) || (ePerson.getID() != context - .getCurrentUser().getID()))) - { + && ((context.getCurrentUser() == null) || (ePerson.getID() != context + .getCurrentUser().getID()))) { authorizeService.authorizeAction(context, ePerson, Constants.WRITE); } @@ -330,29 +322,25 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme ePersonDAO.save(context, ePerson); log.info(LogManager.getHeader(context, "update_eperson", - "eperson_id=" + ePerson.getID())); + "eperson_id=" + ePerson.getID())); - if (ePerson.isModified()) - { + if (ePerson.isModified()) { context.addEvent(new Event(Event.MODIFY, Constants.EPERSON, - ePerson.getID(), null, getIdentifiers(context, ePerson))); + ePerson.getID(), null, getIdentifiers(context, ePerson))); ePerson.clearModified(); } - if (ePerson.isMetadataModified()) - { + if (ePerson.isMetadataModified()) { ePerson.clearDetails(); } } @Override - public List getDeleteConstraints(Context context, EPerson ePerson) throws SQLException - { + public List getDeleteConstraints(Context context, EPerson ePerson) throws SQLException { List tableList = new ArrayList(); // check for eperson in item table Iterator itemsBySubmitter = itemService.findBySubmitter(context, ePerson); - if (itemsBySubmitter.hasNext()) - { + if (itemsBySubmitter.hasNext()) { tableList.add("item"); } @@ -368,10 +356,9 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl impleme @Override public List findByGroups(Context c, Set groups) throws SQLException { //Make sure we at least have one group, if not don't even bother searching. - if(CollectionUtils.isNotEmpty(groups)) - { + if (CollectionUtils.isNotEmpty(groups)) { return ePersonDAO.findByGroups(c, groups); - }else{ + } else { return new ArrayList<>(); } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/Groomer.java b/dspace-api/src/main/java/org/dspace/eperson/Groomer.java index 9a4ae42130..6a2450cbe9 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/Groomer.java +++ b/dspace-api/src/main/java/org/dspace/eperson/Groomer.java @@ -11,12 +11,18 @@ package org.dspace.eperson; import java.io.IOException; import java.sql.SQLException; import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.List; -import org.apache.commons.cli.*; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.MissingOptionException; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.factory.EPersonServiceFactory; @@ -27,8 +33,7 @@ import org.dspace.eperson.service.EPersonService; * * @author mwood */ -public class Groomer -{ +public class Groomer { private static final ThreadLocal dateFormat = new ThreadLocal() { @Override protected DateFormat initialValue() { @@ -37,16 +42,20 @@ public class Groomer }; private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); + + /** + * Default constructor + */ + private Groomer() { } + /** * Command line tool for "grooming" the EPerson collection. * * @param argv the command line arguments given - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ static public void main(String[] argv) - throws SQLException - { + throws SQLException { final String USAGE = "Groomer -verb [option...]"; OptionGroup verbs = new OptionGroup(); @@ -59,9 +68,9 @@ public class Groomer options.addOptionGroup(verbs); options.addOption("b", "last-used-before", true, - "date of last login was before this (for example: " - + dateFormat.get().format(Calendar.getInstance().getTime()) - + ')'); + "date of last login was before this (for example: " + + dateFormat.get().format(Calendar.getInstance().getTime()) + + ')'); options.addOption("d", "delete", false, "delete matching epersons"); PosixParser parser = new PosixParser(); @@ -70,30 +79,26 @@ public class Groomer command = parser.parse(options, argv); } catch (ParseException ex) { System.err.println(ex.getMessage()); - if (! (ex instanceof MissingOptionException)) + if (!(ex instanceof MissingOptionException)) { new HelpFormatter().printHelp(USAGE, options); + } System.exit(1); } - // Help the user - if (null == command || command.hasOption('h') || command.hasOption('?')) - { + // Help the user + if (null == command || command.hasOption('h') || command.hasOption('?')) { new HelpFormatter().printHelp(USAGE, options); System.exit(0); - } - // Scan for disused accounts - else if (command.hasOption('a')) - { + } else if (command.hasOption('a')) { + // Scan for disused accounts aging(command); - } - // List accounts with unsalted passwords - else if (command.hasOption('u')) - { + } else if (command.hasOption('u')) { + // List accounts with unsalted passwords findUnsalted(); - } - // Should not happen: verb option defined but no code! - else + } else { + // Should not happen: verb option defined but no code! System.err.println("Unimplemented verb: " + verbs.getSelected()); + } } /** @@ -102,65 +107,59 @@ public class Groomer * @param command a parsed command line. * @throws SQLException from callees. */ - private static void aging(CommandLine command) throws SQLException - { - if (!command.hasOption('b')) - { - System.err.println("A last login date is required."); - System.exit(1); - } + private static void aging(CommandLine command) throws SQLException { + if (!command.hasOption('b')) { + System.err.println("A last login date is required."); + System.exit(1); + } - Date before = null; - try { - before = dateFormat.get().parse(command.getOptionValue('b')); - } catch (java.text.ParseException ex) { - System.err.println(ex.getMessage()); - System.exit(1); - } + Date before = null; + try { + before = dateFormat.get().parse(command.getOptionValue('b')); + } catch (java.text.ParseException ex) { + System.err.println(ex.getMessage()); + System.exit(1); + } - boolean delete = command.hasOption('d'); + boolean delete = command.hasOption('d'); - Context myContext = new Context(); - List epeople = ePersonService.findNotActiveSince(myContext, before); + Context myContext = new Context(); + List epeople = ePersonService.findNotActiveSince(myContext, before); - myContext.turnOffAuthorisationSystem(); - for (EPerson account : epeople) - { - System.out.print(account.getID()); - System.out.print('\t'); - System.out.print(account.getLastActive()); - System.out.print('\t'); - System.out.print(account.getEmail()); - System.out.print('\t'); - System.out.print(account.getNetid()); - System.out.print('\t'); - System.out.print(account.getFullName()); - System.out.println(); + myContext.turnOffAuthorisationSystem(); + for (EPerson account : epeople) { + System.out.print(account.getID()); + System.out.print('\t'); + System.out.print(account.getLastActive()); + System.out.print('\t'); + System.out.print(account.getEmail()); + System.out.print('\t'); + System.out.print(account.getNetid()); + System.out.print('\t'); + System.out.print(account.getFullName()); + System.out.println(); - if (delete) - { - List whyNot = ePersonService.getDeleteConstraints(myContext, account); - if (!whyNot.isEmpty()) - { - System.out.print("\tCannot be deleted; referenced in"); - for (String table : whyNot) - { - System.out.print(' '); - System.out.print(table); - } - System.out.println(); + if (delete) { + List whyNot = ePersonService.getDeleteConstraints(myContext, account); + if (!whyNot.isEmpty()) { + System.out.print("\tCannot be deleted; referenced in"); + for (String table : whyNot) { + System.out.print(' '); + System.out.print(table); } - else - try { - ePersonService.delete(myContext, account); - } catch (AuthorizeException | IOException ex) { - System.err.println(ex.getMessage()); - } + System.out.println(); + } else { + try { + ePersonService.delete(myContext, account); + } catch (AuthorizeException | IOException ex) { + System.err.println(ex.getMessage()); } + } } + } - myContext.restoreAuthSystemState(); - myContext.complete(); + myContext.restoreAuthSystemState(); + myContext.complete(); } /** @@ -169,12 +168,12 @@ public class Groomer * @throws SQLException if database error */ private static void findUnsalted() - throws SQLException - { + throws SQLException { Context myContext = new Context(); List ePersons = ePersonService.findUnsalted(myContext); - for (EPerson ePerson : ePersons) + for (EPerson ePerson : ePersons) { System.out.println(ePerson.getEmail()); + } myContext.abort(); // No changes to commit } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/Group.java b/dspace-api/src/main/java/org/dspace/eperson/Group.java index 04ff87f576..09b5ce189b 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/Group.java +++ b/dspace-api/src/main/java/org/dspace/eperson/Group.java @@ -7,22 +7,27 @@ */ package org.dspace.eperson; -import org.apache.commons.lang3.StringUtils; -import org.dspace.content.DSpaceObject; -import org.dspace.content.DSpaceObjectLegacySupport; -import org.dspace.content.MetadataSchema; -import org.dspace.content.WorkspaceItem; -import org.dspace.core.Constants; -import org.dspace.core.Context; -import org.dspace.eperson.factory.EPersonServiceFactory; -import org.dspace.eperson.service.GroupService; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.proxy.HibernateProxyHelper; - -import javax.persistence.*; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import javax.persistence.Cacheable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.apache.commons.lang3.StringUtils; +import org.dspace.content.DSpaceObject; +import org.dspace.content.DSpaceObjectLegacySupport; +import org.dspace.content.WorkspaceItem; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.proxy.HibernateProxyHelper; /** * Class representing a group of e-people. @@ -32,9 +37,8 @@ import java.util.List; @Entity @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, include = "non-lazy") -@Table(name = "epersongroup" ) -public class Group extends DSpaceObject implements DSpaceObjectLegacySupport -{ +@Table(name = "epersongroup") +public class Group extends DSpaceObject implements DSpaceObjectLegacySupport { @Transient public static final String ANONYMOUS = "Anonymous"; @@ -45,30 +49,34 @@ public class Group extends DSpaceObject implements DSpaceObjectLegacySupport /** * Initial value is set to 2 since 0 and 1 are reserved for anonymous and administrative uses, respectively */ - @Column(name="eperson_group_id", insertable = false, updatable = false) + @Column(name = "eperson_group_id", insertable = false, updatable = false) private Integer legacyId; - /** This Group may not be deleted or renamed. */ + /** + * This Group may not be deleted or renamed. + */ @Column private Boolean permanent = false; @Column(length = 250, unique = true) private String name; - /** lists of epeople and groups in the group */ + /** + * lists of epeople and groups in the group + */ @ManyToMany(fetch = FetchType.LAZY) @JoinTable( - name = "epersongroup2eperson", - joinColumns = {@JoinColumn(name = "eperson_group_id") }, - inverseJoinColumns = {@JoinColumn(name = "eperson_id") } + name = "epersongroup2eperson", + joinColumns = {@JoinColumn(name = "eperson_group_id")}, + inverseJoinColumns = {@JoinColumn(name = "eperson_id")} ) private final List epeople = new ArrayList<>(); @ManyToMany(fetch = FetchType.LAZY) @JoinTable( - name = "group2group", - joinColumns = {@JoinColumn(name = "parent_id") }, - inverseJoinColumns = {@JoinColumn(name = "child_id") } + name = "group2group", + joinColumns = {@JoinColumn(name = "parent_id")}, + inverseJoinColumns = {@JoinColumn(name = "child_id")} ) private final List groups = new ArrayList<>(); @@ -84,15 +92,12 @@ public class Group extends DSpaceObject implements DSpaceObjectLegacySupport /** * Protected constructor, create object using: * {@link org.dspace.eperson.service.GroupService#create(Context)} - * */ - protected Group() - { + protected Group() { } - void addMember(EPerson e) - { + void addMember(EPerson e) { getMembers().add(e); } @@ -101,47 +106,39 @@ public class Group extends DSpaceObject implements DSpaceObjectLegacySupport * * @return list of EPersons */ - public List getMembers() - { + public List getMembers() { return epeople; } - void addMember(Group g) - { + void addMember(Group g) { getMemberGroups().add(g); groupsChanged = true; } - void addParentGroup(Group group) - { + void addParentGroup(Group group) { getParentGroups().add(group); groupsChanged = true; } - void removeParentGroup(Group group) - { + void removeParentGroup(Group group) { getParentGroups().remove(group); groupsChanged = true; } - boolean remove(EPerson e) - { + boolean remove(EPerson e) { return getMembers().remove(e); } - boolean remove(Group g) - { + boolean remove(Group g) { groupsChanged = true; return getMemberGroups().remove(g); } - boolean contains(Group g) - { + boolean contains(Group g) { return getMemberGroups().contains(g); } - boolean contains(EPerson e) - { + boolean contains(EPerson e) { return getMembers().contains(e); } @@ -154,8 +151,7 @@ public class Group extends DSpaceObject implements DSpaceObjectLegacySupport * * @return list of groups */ - public List getMemberGroups() - { + public List getMemberGroups() { return groups; } @@ -163,55 +159,47 @@ public class Group extends DSpaceObject implements DSpaceObjectLegacySupport * Return true if other is the same Group as * this object, false otherwise * - * @param obj - * object to compare to - * + * @param obj object to compare to * @return true if object passed in represents the same group - * as this object + * as this object */ - @Override - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (getClass() != objClass) - { - return false; - } - final Group other = (Group) obj; - return this.getID().equals(other.getID()); - } - - @Override - public int hashCode() - { - int hash = 7; - hash = 59 * hash + this.getID().hashCode(); - hash = 59 * hash + (this.getName() != null? this.getName().hashCode():0); - return hash; - } + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); + if (getClass() != objClass) { + return false; + } + final Group other = (Group) obj; + return this.getID().equals(other.getID()); + } + @Override + public int hashCode() { + int hash = 7; + hash = 59 * hash + this.getID().hashCode(); + hash = 59 * hash + (this.getName() != null ? this.getName().hashCode() : 0); + return hash; + } @Override - public int getType() - { + public int getType() { return Constants.GROUP; } @Override - public String getName() - { + public String getName() { return name; } - /** Change the name of this Group. */ - void setName(String name) throws SQLException - { - if(!StringUtils.equals(this.name, name) && !isPermanent()) { + /** + * Change the name of this Group. + */ + void setName(String name) throws SQLException { + if (!StringUtils.equals(this.name, name) && !isPermanent()) { this.name = name; groupsChanged = true; } @@ -240,8 +228,7 @@ public class Group extends DSpaceObject implements DSpaceObjectLegacySupport * * @return true if this Group may not be renamed or deleted. */ - public Boolean isPermanent() - { + public Boolean isPermanent() { return permanent; } @@ -251,8 +238,7 @@ public class Group extends DSpaceObject implements DSpaceObjectLegacySupport * * @param permanence true if this group may not be renamed or deleted. */ - void setPermanent(boolean permanence) - { + void setPermanent(boolean permanence) { permanent = permanence; setModified(); } diff --git a/dspace-api/src/main/java/org/dspace/eperson/Group2GroupCache.java b/dspace-api/src/main/java/org/dspace/eperson/Group2GroupCache.java index 4fb14344f0..df57f173b3 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/Group2GroupCache.java +++ b/dspace-api/src/main/java/org/dspace/eperson/Group2GroupCache.java @@ -7,11 +7,15 @@ */ package org.dspace.eperson; -import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.hibernate.proxy.HibernateProxyHelper; - -import javax.persistence.*; import java.io.Serializable; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.hibernate.proxy.HibernateProxyHelper; /** * Database entity representation of the group2groupcache table @@ -19,7 +23,7 @@ import java.io.Serializable; * @author kevinvandevelde at atmire.com */ @Entity -@Table(name = "group2groupcache" ) +@Table(name = "group2groupcache") public class Group2GroupCache implements Serializable { @Id @@ -51,31 +55,25 @@ public class Group2GroupCache implements Serializable { /** * Protected constructor, create object using: * {@link org.dspace.eperson.service.GroupService} - * */ - protected Group2GroupCache() - { + protected Group2GroupCache() { } @Override public boolean equals(Object obj) { - if (obj == null) - { + if (obj == null) { return false; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } final Group2GroupCache other = (Group2GroupCache) obj; - if(!parent.equals(other.getParent())) - { + if (!parent.equals(other.getParent())) { return false; } - if(!child.equals(other.getChild())) - { + if (!child.equals(other.getChild())) { return false; } return true; @@ -84,8 +82,8 @@ public class Group2GroupCache implements Serializable { @Override public int hashCode() { return new org.apache.commons.lang.builder.HashCodeBuilder() - .append(parent == null ? "" : parent.getID()) - .append(child == null ? "" : child.getID()) - .toHashCode(); + .append(parent == null ? "" : parent.getID()) + .append(child == null ? "" : child.getID()) + .toHashCode(); } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java index dd11f6c3e8..fccaf3f1c8 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java @@ -7,7 +7,17 @@ */ package org.dspace.eperson; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; @@ -33,9 +43,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.*; - /** * Service implementation for the Group object. * This class is responsible for all business logic calls for the Group object and is autowired by spring. @@ -43,8 +50,7 @@ import java.util.*; * * @author kevinvandevelde at atmire.com */ -public class GroupServiceImpl extends DSpaceObjectServiceImpl implements GroupService -{ +public class GroupServiceImpl extends DSpaceObjectServiceImpl implements GroupService { private static final Logger log = LoggerFactory.getLogger(GroupServiceImpl.class); @Autowired(required = true) @@ -65,25 +71,23 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements @Autowired(required = true) protected AuthorizeService authorizeService; - protected GroupServiceImpl() - { + protected GroupServiceImpl() { super(); } @Override public Group create(Context context) throws SQLException, AuthorizeException { // FIXME - authorization? - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "You must be an admin to create an EPerson Group"); + "You must be an admin to create an EPerson Group"); } // Create a table row Group g = groupDAO.create(context, new Group()); log.info(LogManager.getHeader(context, "create_group", "group_id=" - + g.getID())); + + g.getID())); context.addEvent(new Event(Event.CREATE, Constants.GROUP, g.getID(), null, getIdentifiers(context, g))); update(context, g); @@ -93,56 +97,57 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements @Override public void setName(Group group, String name) throws SQLException { - if (group.isPermanent()) - { + if (group.isPermanent()) { log.error("Attempt to rename permanent Group {} to {}.", - group.getName(), name); + group.getName(), name); throw new SQLException("Attempt to rename a permanent Group"); - } - else + } else { group.setName(name); + } } @Override public void addMember(Context context, Group group, EPerson e) { - if (isDirectMember(group, e)) - { + if (isDirectMember(group, e)) { return; } group.addMember(e); e.getGroups().add(group); - context.addEvent(new Event(Event.ADD, Constants.GROUP, group.getID(), Constants.EPERSON, e.getID(), e.getEmail(), getIdentifiers(context, group))); + context.addEvent( + new Event(Event.ADD, Constants.GROUP, group.getID(), Constants.EPERSON, e.getID(), e.getEmail(), + getIdentifiers(context, group))); } @Override public void addMember(Context context, Group groupParent, Group groupChild) throws SQLException { - // don't add if it's already a member + // don't add if it's already a member // and don't add itself - if (groupParent.contains(groupChild) || groupParent.getID()==groupChild.getID()) - { + if (groupParent.contains(groupChild) || groupParent.getID() == groupChild.getID()) { return; } groupParent.addMember(groupChild); groupChild.addParentGroup(groupParent); - context.addEvent(new Event(Event.ADD, Constants.GROUP, groupParent.getID(), Constants.GROUP, groupChild.getID(), groupChild.getName(), getIdentifiers(context, groupParent))); + context.addEvent(new Event(Event.ADD, Constants.GROUP, groupParent.getID(), Constants.GROUP, groupChild.getID(), + groupChild.getName(), getIdentifiers(context, groupParent))); } @Override public void removeMember(Context context, Group group, EPerson ePerson) { - if (group.remove(ePerson)) - { - context.addEvent(new Event(Event.REMOVE, Constants.GROUP, group.getID(), Constants.EPERSON, ePerson.getID(), ePerson.getEmail(), getIdentifiers(context, group))); + if (group.remove(ePerson)) { + context.addEvent(new Event(Event.REMOVE, Constants.GROUP, group.getID(), Constants.EPERSON, ePerson.getID(), + ePerson.getEmail(), getIdentifiers(context, group))); } } @Override public void removeMember(Context context, Group groupParent, Group childGroup) throws SQLException { - if (groupParent.remove(childGroup)) - { + if (groupParent.remove(childGroup)) { childGroup.removeParentGroup(groupParent); - context.addEvent(new Event(Event.REMOVE, Constants.GROUP, groupParent.getID(), Constants.GROUP, childGroup.getID(), childGroup.getName(), getIdentifiers(context, groupParent))); + context.addEvent( + new Event(Event.REMOVE, Constants.GROUP, groupParent.getID(), Constants.GROUP, childGroup.getID(), + childGroup.getName(), getIdentifiers(context, groupParent))); } } @@ -169,9 +174,8 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements @Override public boolean isMember(Context context, EPerson ePerson, Group group) - throws SQLException - { - if(group == null) { + throws SQLException { + if (group == null) { return false; // special, everyone is member of group 0 (anonymous) @@ -181,14 +185,14 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements } else { Boolean cachedGroupMembership = context.getCachedGroupMembership(group, ePerson); - if(cachedGroupMembership != null) { + if (cachedGroupMembership != null) { return cachedGroupMembership.booleanValue(); } else { boolean isMember = false; //If we have an ePerson, check we can find membership in the database - if(ePerson != null) { + if (ePerson != null) { //lookup eperson in normal groups and subgroups with 1 query isMember = isEPersonInGroup(context, group, ePerson); } @@ -198,7 +202,9 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements //special group is a subgroup of the provided group. //Note that special groups should only be checked if the current user == the ePerson. //This also works for anonymous users (ePerson == null) if IP authentication used - if(!isMember && CollectionUtils.isNotEmpty(context.getSpecialGroups()) && isAuthenticatedUser(context, ePerson)) { + if (!isMember && CollectionUtils.isNotEmpty(context.getSpecialGroups()) && + isAuthenticatedUser(context, ePerson)) { + Iterator it = context.getSpecialGroups().iterator(); while (it.hasNext() && !isMember) { @@ -239,14 +245,13 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements @Override public Set allMemberGroupsSet(Context context, EPerson ePerson) throws SQLException { Set cachedGroupMembership = context.getCachedAllMemberGroupsSet(ePerson); - if(cachedGroupMembership != null) { + if (cachedGroupMembership != null) { return cachedGroupMembership; } Set groups = new HashSet<>(); - if (ePerson != null) - { + if (ePerson != null) { // two queries - first to get groups eperson is a member of // second query gets parent groups for groups eperson is a member of groups.addAll(groupDAO.findByEPerson(context, ePerson)); @@ -256,11 +261,9 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements // However, we only do this is we are looking up the special groups // of the current user, as we cannot look up the special groups // of a user who is not logged in. - if ((context.getCurrentUser() == null) || (context.getCurrentUser().equals(ePerson))) - { + if ((context.getCurrentUser() == null) || (context.getCurrentUser().equals(ePerson))) { List specialGroups = context.getSpecialGroups(); - for(Group special : specialGroups) - { + for (Group special : specialGroups) { groups.add(special); } } @@ -281,8 +284,7 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements } @Override - public List allMembers(Context c, Group g) throws SQLException - { + public List allMembers(Context c, Group g) throws SQLException { // two queries - first to get all groups which are a member of this group // second query gets all members of each group in the first query @@ -312,15 +314,16 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements @Override public Group findByName(Context context, String name) throws SQLException { - if (name == null) - { + if (name == null) { return null; } return groupDAO.findByName(context, name); } - /** DEPRECATED: Please use {@code findAll(Context context, List metadataSortFields)} instead */ + /** + * DEPRECATED: Please use {@code findAll(Context context, List metadataSortFields)} instead + */ @Override @Deprecated public List findAll(Context context, int sortField) throws SQLException { @@ -330,16 +333,15 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements throw new UnsupportedOperationException("You can only find all groups sorted by name with this method"); } } - + @Override - public List findAll(Context context, List metadataSortFields) throws SQLException - { - return findAll(context, metadataSortFields, -1, -1); + public List findAll(Context context, List metadataSortFields) throws SQLException { + return findAll(context, metadataSortFields, -1, -1); } - + @Override - public List findAll(Context context, List metadataSortFields, int pageSize, int offset) throws SQLException - { + public List findAll(Context context, List metadataSortFields, int pageSize, int offset) + throws SQLException { if (CollectionUtils.isEmpty(metadataSortFields)) { return groupDAO.findAll(context, pageSize, offset); } else { @@ -353,8 +355,7 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements } @Override - public List search(Context context, String groupIdentifier, int offset, int limit) throws SQLException - { + public List search(Context context, String groupIdentifier, int offset, int limit) throws SQLException { List groups = new ArrayList<>(); UUID uuid = UUIDUtils.fromString(groupIdentifier); if (uuid == null) { @@ -363,8 +364,7 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements } else { //Search by group id Group group = find(context, uuid); - if (group != null) - { + if (group != null) { groups.add(group); } } @@ -376,14 +376,13 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements public int searchResultCount(Context context, String groupIdentifier) throws SQLException { int result = 0; UUID uuid = UUIDUtils.fromString(groupIdentifier); - if (uuid == null && StringUtils.isNotBlank(groupIdentifier)) { + if (uuid == null) { //Search by group name result = groupDAO.countByNameLike(context, groupIdentifier); } else { //Search by group id Group group = find(context, uuid); - if (group != null) - { + if (group != null) { result = 1; } } @@ -393,14 +392,13 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements @Override public void delete(Context context, Group group) throws SQLException { - if (group.isPermanent()) - { + if (group.isPermanent()) { log.error("Attempt to delete permanent Group $", group.getName()); throw new SQLException("Attempt to delete a permanent Group"); } context.addEvent(new Event(Event.DELETE, Constants.GROUP, group.getID(), - group.getName(), getIdentifiers(context, group))); + group.getName(), getIdentifiers(context, group))); //Remove the supervised group from any workspace items linked to us. group.getSupervisedItems().clear(); @@ -426,7 +424,7 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements rethinkGroupCache(context, false); log.info(LogManager.getHeader(context, "delete_group", "group_id=" - + group.getID())); + + group.getID())); } @Override @@ -438,21 +436,17 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements * Return true if group has no direct or indirect members */ @Override - public boolean isEmpty(Group group) - { + public boolean isEmpty(Group group) { // the only fast check available is on epeople... boolean hasMembers = (!group.getMembers().isEmpty()); - if (hasMembers) - { + if (hasMembers) { return false; - } - else - { + } else { // well, groups is never null... - for (Group subGroup : group.getMemberGroups()){ + for (Group subGroup : group.getMemberGroups()) { hasMembers = !isEmpty(subGroup); - if (hasMembers){ + if (hasMembers) { return false; } } @@ -465,8 +459,7 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); // Check for Anonymous group. If not found, create it Group anonymousGroup = groupService.findByName(context, Group.ANONYMOUS); - if (anonymousGroup==null) - { + if (anonymousGroup == null) { anonymousGroup = groupService.create(context); anonymousGroup.setName(Group.ANONYMOUS); anonymousGroup.setPermanent(true); @@ -476,8 +469,7 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements // Check for Administrator group. If not found, create it Group adminGroup = groupService.findByName(context, Group.ADMIN); - if (adminGroup == null) - { + if (adminGroup == null) { adminGroup = groupService.create(context); adminGroup.setName(Group.ADMIN); adminGroup.setPermanent(true); @@ -488,11 +480,9 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements /** * Get a list of groups with no members. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return list of groups with no members - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ @Override public List getEmptyGroups(Context context) throws SQLException { @@ -502,46 +492,37 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements /** * Update the group - writing out group object and EPerson list if necessary * - * @param context - * The relevant DSpace Context. - * @param group - * Group to update - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param group Group to update + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ @Override - public void update(Context context, Group group) throws SQLException, AuthorizeException - { + public void update(Context context, Group group) throws SQLException, AuthorizeException { super.update(context, group); // FIXME: Check authorisation groupDAO.save(context, group); - if (group.isMetadataModified()) - { - context.addEvent(new Event(Event.MODIFY_METADATA, Constants.GROUP, group.getID(), group.getDetails(), getIdentifiers(context, group))); + if (group.isMetadataModified()) { + context.addEvent(new Event(Event.MODIFY_METADATA, Constants.GROUP, group.getID(), group.getDetails(), + getIdentifiers(context, group))); group.clearDetails(); } - if (group.isGroupsChanged()) - { + if (group.isGroupsChanged()) { rethinkGroupCache(context, true); group.clearGroupsChanged(); } log.info(LogManager.getHeader(context, "update_group", "group_id=" - + group.getID())); + + group.getID())); } - - protected boolean isEPersonInGroup(Context context, Group group, EPerson ePerson) - throws SQLException - { + throws SQLException { return groupDAO.findByIdAndMembership(context, group.getID(), ePerson) != null; } @@ -550,12 +531,9 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements * Regenerate the group cache AKA the group2groupcache table in the database - * meant to be called when a group is added or removed from another group * - * @param context - * The relevant DSpace Context. - * @param flushQueries - * flushQueries Flush all pending queries - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param context The relevant DSpace Context. + * @param flushQueries flushQueries Flush all pending queries + * @throws SQLException An exception that provides information on a database access error or other errors. */ protected void rethinkGroupCache(Context context, boolean flushQueries) throws SQLException { @@ -604,8 +582,8 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements Group childGroup = find(context, child); - if (parentGroup != null && childGroup != null && group2GroupCacheDAO.find(context, parentGroup, childGroup) == null) - { + if (parentGroup != null && childGroup != null && group2GroupCacheDAO + .find(context, parentGroup, childGroup) == null) { Group2GroupCache group2GroupCache = group2GroupCacheDAO.create(context, new Group2GroupCache()); group2GroupCache.setParent(parentGroup); group2GroupCache.setChild(childGroup); @@ -616,71 +594,53 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements } @Override - public DSpaceObject getParentObject(Context context, Group group) throws SQLException - { - if (group == null) - { + public DSpaceObject getParentObject(Context context, Group group) throws SQLException { + if (group == null) { return null; } // could a collection/community administrator manage related groups? // check before the configuration options could give a performance gain // if all group management are disallowed if (AuthorizeConfiguration.canCollectionAdminManageAdminGroup() - || AuthorizeConfiguration.canCollectionAdminManageSubmitters() - || AuthorizeConfiguration.canCollectionAdminManageWorkflows() - || AuthorizeConfiguration.canCommunityAdminManageAdminGroup() - || AuthorizeConfiguration - .canCommunityAdminManageCollectionAdminGroup() - || AuthorizeConfiguration - .canCommunityAdminManageCollectionSubmitters() - || AuthorizeConfiguration - .canCommunityAdminManageCollectionWorkflows()) - { + || AuthorizeConfiguration.canCollectionAdminManageSubmitters() + || AuthorizeConfiguration.canCollectionAdminManageWorkflows() + || AuthorizeConfiguration.canCommunityAdminManageAdminGroup() + || AuthorizeConfiguration + .canCommunityAdminManageCollectionAdminGroup() + || AuthorizeConfiguration + .canCommunityAdminManageCollectionSubmitters() + || AuthorizeConfiguration + .canCommunityAdminManageCollectionWorkflows()) { // is this a collection related group? org.dspace.content.Collection collection = collectionService.findByGroup(context, group); - if (collection != null) - { + if (collection != null) { if ((group.equals(collection.getWorkflowStep1()) || - group.equals(collection.getWorkflowStep2()) || - group.equals(collection.getWorkflowStep3()))) - { - if (AuthorizeConfiguration.canCollectionAdminManageWorkflows()) - { + group.equals(collection.getWorkflowStep2()) || + group.equals(collection.getWorkflowStep3()))) { + if (AuthorizeConfiguration.canCollectionAdminManageWorkflows()) { return collection; - } - else if (AuthorizeConfiguration.canCommunityAdminManageCollectionWorkflows()) - { + } else if (AuthorizeConfiguration.canCommunityAdminManageCollectionWorkflows()) { return collectionService.getParentObject(context, collection); } } - if (group.equals(collection.getSubmitters())) - { - if (AuthorizeConfiguration.canCollectionAdminManageSubmitters()) - { + if (group.equals(collection.getSubmitters())) { + if (AuthorizeConfiguration.canCollectionAdminManageSubmitters()) { return collection; - } - else if (AuthorizeConfiguration.canCommunityAdminManageCollectionSubmitters()) - { + } else if (AuthorizeConfiguration.canCommunityAdminManageCollectionSubmitters()) { return collectionService.getParentObject(context, collection); } } - if (group.equals(collection.getAdministrators())) - { - if (AuthorizeConfiguration.canCollectionAdminManageAdminGroup()) - { + if (group.equals(collection.getAdministrators())) { + if (AuthorizeConfiguration.canCollectionAdminManageAdminGroup()) { return collection; - } - else if (AuthorizeConfiguration.canCommunityAdminManageCollectionAdminGroup()) - { + } else if (AuthorizeConfiguration.canCommunityAdminManageCollectionAdminGroup()) { return collectionService.getParentObject(context, collection); } } - } - // is the group related to a community and community administrator allowed - // to manage it? - else if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup()) - { + } else if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup()) { + // is the group related to a community and community administrator allowed + // to manage it? return communityService.findByAdminGroup(context, group); } } @@ -696,24 +656,20 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements * Used recursively to generate a map of ALL of the children of the given * parent * - * @param parents - * Map of parent,child relationships - * @param parent - * the parent you're interested in + * @param parents Map of parent,child relationships + * @param parent the parent you're interested in * @return Map whose keys are all of the children of a parent */ - protected Set getChildren(Map> parents, UUID parent) - { + protected Set getChildren(Map> parents, UUID parent) { Set myChildren = new HashSet<>(); // degenerate case, this parent has no children - if (!parents.containsKey(parent)) - { + if (!parents.containsKey(parent)) { return myChildren; } // got this far, so we must have children - Set children = parents.get(parent); + Set children = parents.get(parent); // now iterate over all of the children @@ -730,12 +686,9 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements @Override public Group findByIdOrLegacyId(Context context, String id) throws SQLException { - if (org.apache.commons.lang.StringUtils.isNumeric(id)) - { + if (org.apache.commons.lang.StringUtils.isNumeric(id)) { return findByLegacyId(context, Integer.parseInt(id)); - } - else - { + } else { return find(context, UUIDUtils.fromString(id)); } } @@ -751,7 +704,8 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements } @Override - public List findByMetadataField(final Context context, final String searchValue, final MetadataField metadataField) throws SQLException { + public List findByMetadataField(final Context context, final String searchValue, + final MetadataField metadataField) throws SQLException { return groupDAO.findByMetadataField(context, searchValue, metadataField); } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/LoadLastLogin.java b/dspace-api/src/main/java/org/dspace/eperson/LoadLastLogin.java index a0f6537200..94be5c300e 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/LoadLastLogin.java +++ b/dspace-api/src/main/java/org/dspace/eperson/LoadLastLogin.java @@ -18,6 +18,7 @@ import java.util.Date; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; + import jdbm.RecordManager; import jdbm.RecordManagerFactory; import jdbm.RecordManagerOptions; @@ -42,20 +43,24 @@ import org.dspace.eperson.service.EPersonService; * * @author mwood */ -public class LoadLastLogin -{ +public class LoadLastLogin { + + /** + * Default constructor + */ + private LoadLastLogin() { } + public static void main(String[] argv) - throws IOException, SQLException, AuthorizeException - { + throws IOException, SQLException, AuthorizeException { final String USAGE = "LoadLastLogin [options] path...path\n\n" - + "'path's are paths to DSpace log files"; + + "'path's are paths to DSpace log files"; final String loginRE = "([0-9-]+) ([0-9:]+)[^@]+@ " // Date(1), time(2), goop - + "([^:]+):" // user(3) - + "session_id=[^:]+:" - + "ip_addr=[0-9a-f.:]+:" - + "login:type=(implicit|explicit)"; + + "([^:]+):" // user(3) + + "session_id=[^:]+:" + + "ip_addr=[0-9a-f.:]+:" + + "login:type=(implicit|explicit)"; // Handle options, if any Options options = new Options(); @@ -69,13 +74,13 @@ public class LoadLastLogin command = parser.parse(options, argv); } catch (org.apache.commons.cli.ParseException ex) { System.err.println(ex.getMessage()); - if (! (ex instanceof MissingOptionException)) + if (!(ex instanceof MissingOptionException)) { new HelpFormatter().printHelp(USAGE, options); + } System.exit(1); } - if (command.hasOption('h')) - { + if (command.hasOption('h')) { System.out.println("Load users' last_active dates into the database from DSpace logs."); System.out.println(); new HelpFormatter().printHelp(USAGE, options); @@ -92,8 +97,9 @@ public class LoadLastLogin rmProps.put(RecordManagerOptions.DISABLE_TRANSACTIONS, "true"); String dbname = new File(System.getProperty("java.io.tmpdir"), "lastlogindb").getCanonicalPath(); - if (VERBOSE) + if (VERBOSE) { System.out.println("dbname: " + dbname); + } RecordManager stamps = RecordManagerFactory.createRecordManager(dbname, rmProps); BTree stampDb = BTree.createInstance(stamps, new StringComparator()); @@ -101,23 +107,24 @@ public class LoadLastLogin final Pattern loginCracker = Pattern.compile(loginRE); final SimpleDateFormat dateEncoder = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - for (String logName : args) - { + for (String logName : args) { BufferedReader logReader = new BufferedReader(new FileReader(logName)); - while(true) - { + while (true) { String line = logReader.readLine(); // End of file? - if (null == line) + if (null == line) { break; + } // Skip if definitely not a login record - if (!line.contains(":login:")) + if (!line.contains(":login:")) { continue; + } // Try to recognize the interesting fields Matcher loginMatcher = loginCracker.matcher(line); - if (!loginMatcher.matches()) + if (!loginMatcher.matches()) { continue; + } // Pretty sure we have a login String date = loginMatcher.group(1); @@ -133,8 +140,7 @@ public class LoadLastLogin continue; } Date previous = (Date) stampDb.find(user); - if (null == previous || stamp.after(previous)) - { + if (null == previous || stamp.after(previous)) { stampDb.insert(user, stamp, true); // Record this user's newest login so far } } @@ -149,34 +155,29 @@ public class LoadLastLogin EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); - while(walker.getNext(stamp)) - { + while (walker.getNext(stamp)) { // Update an EPerson's last login String name = (String) stamp.getKey(); Date date = (Date) stamp.getValue(); EPerson ePerson; ePerson = ePersonService.findByEmail(ctx, name); - if (null == ePerson) + if (null == ePerson) { ePerson = ePersonService.findByNetid(ctx, name); - if (null == ePerson) - { + } + if (null == ePerson) { System.err.println("Skipping unknown user: " + name); continue; } Date previous = ePerson.getLastActive(); - if ((null == previous) || date.after(previous)) - { - if (PRETEND) - { + if ((null == previous) || date.after(previous)) { + if (PRETEND) { System.out.printf("%s\t%s\t%s\t%s\t%s\n", - ePerson.getID().toString(), - date, - ePerson.getEmail(), - ePerson.getNetid(), - ePerson.getFullName()); - } - else - { + ePerson.getID().toString(), + date, + ePerson.getEmail(), + ePerson.getNetid(), + ePerson.getFullName()); + } else { ePerson.setLastActive(date); ePersonService.update(ctx, ePerson); } @@ -191,11 +192,13 @@ public class LoadLastLogin File target; target = new File(dbname + ".db"); - if (target.exists()) + if (target.exists()) { target.delete(); + } target = new File(dbname + ".lg"); - if (target.exists()) + if (target.exists()) { target.delete(); + } } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/PasswordHash.java b/dspace-api/src/main/java/org/dspace/eperson/PasswordHash.java index 8c5f5d3d91..17340c5a58 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/PasswordHash.java +++ b/dspace-api/src/main/java/org/dspace/eperson/PasswordHash.java @@ -13,6 +13,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; + import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import org.dspace.services.ConfigurationService; @@ -29,48 +30,54 @@ import org.slf4j.LoggerFactory; * * @author mwood */ -public class PasswordHash -{ +public class PasswordHash { private static final Logger log = LoggerFactory.getLogger(PasswordHash.class); private static final ConfigurationService config - = DSpaceServicesFactory.getInstance().getConfigurationService(); + = DSpaceServicesFactory.getInstance().getConfigurationService(); private static final Charset UTF_8 = Charset.forName("UTF-8"); // Should always succeed: UTF-8 is required private static final String DEFAULT_DIGEST_ALGORITHM = "SHA-512"; // XXX magic private static final String ALGORITHM_PROPERTY = "authentication-password.digestAlgorithm"; - private static final int SALT_BYTES = 128/8; // XXX magic we want 128 bits + private static final int SALT_BYTES = 128 / 8; // XXX magic we want 128 bits private static final int HASH_ROUNDS = 1024; // XXX magic 1024 rounds private static final int SEED_BYTES = 64; // XXX magic private static final int RESEED_INTERVAL = 100; // XXX magic - /** A secure random number generator instance. */ + /** + * A secure random number generator instance. + */ private static SecureRandom rng = null; - /** How many times has the RNG been called without re-seeding? */ + /** + * How many times has the RNG been called without re-seeding? + */ private static int rngUses; private String algorithm; private byte[] salt; private byte[] hash; - /** Don't allow empty instances. */ - private PasswordHash() {} + /** + * Don't allow empty instances. + */ + private PasswordHash() { + } /** * Construct a hash structure from existing data, just for passing around. * * @param algorithm the digest algorithm used in producing {@code hash}. - * If empty, set to null. Other methods will treat this as unsalted MD5. - * If you want salted multi-round MD5, specify "MD5". - * @param salt the salt hashed with the secret, or null. - * @param hash the hashed secret. + * If empty, set to null. Other methods will treat this as unsalted MD5. + * If you want salted multi-round MD5, specify "MD5". + * @param salt the salt hashed with the secret, or null. + * @param hash the hashed secret. */ - public PasswordHash(String algorithm, byte[] salt, byte[] hash) - { - if ((null != algorithm) && algorithm.isEmpty()) + public PasswordHash(String algorithm, byte[] salt, byte[] hash) { + if ((null != algorithm) && algorithm.isEmpty()) { this.algorithm = null; - else + } else { this.algorithm = algorithm; + } this.salt = salt; @@ -79,31 +86,34 @@ public class PasswordHash /** * Convenience: like {@link #PasswordHash(String, byte[], byte[])} but with - * hexadecimal-encoded {@code String}s. + * hexadecimal-encoded {@code String}s. + * * @param algorithm the digest algorithm used in producing {@code hash}. - * If empty, set to null. Other methods will treat this as unsalted MD5. - * If you want salted multi-round MD5, specify "MD5". - * @param salt hexadecimal digits encoding the bytes of the salt, or null. - * @param hash hexadecimal digits encoding the bytes of the hash. + * If empty, set to null. Other methods will treat this as unsalted MD5. + * If you want salted multi-round MD5, specify "MD5". + * @param salt hexadecimal digits encoding the bytes of the salt, or null. + * @param hash hexadecimal digits encoding the bytes of the hash. * @throws DecoderException if salt or hash is not proper hexadecimal. */ public PasswordHash(String algorithm, String salt, String hash) - throws DecoderException - { - if ((null != algorithm) && algorithm.isEmpty()) + throws DecoderException { + if ((null != algorithm) && algorithm.isEmpty()) { this.algorithm = null; - else + } else { this.algorithm = algorithm; + } - if (null == salt) + if (null == salt) { this.salt = null; - else + } else { this.salt = Hex.decodeHex(salt.toCharArray()); + } - if (null == hash) + if (null == hash) { this.hash = null; - else + } else { this.hash = Hex.decodeHex(hash.toCharArray()); + } } /** @@ -112,8 +122,7 @@ public class PasswordHash * * @param password the secret to be hashed. */ - public PasswordHash(String password) - { + public PasswordHash(String password) { // Generate some salt salt = generateSalt(); @@ -125,7 +134,7 @@ public class PasswordHash hash = digest(salt, algorithm, password); } catch (NoSuchAlgorithmException e) { log.error(e.getMessage()); - hash = new byte[] { 0 }; + hash = new byte[] {0}; } } @@ -135,8 +144,7 @@ public class PasswordHash * @param secret string to be hashed and compared to this hash. * @return true if secret hashes to the value held by this instance. */ - public boolean matches(String secret) - { + public boolean matches(String secret) { byte[] candidate; try { candidate = digest(salt, algorithm, secret); @@ -152,8 +160,7 @@ public class PasswordHash * * @return the value of hash */ - public byte[] getHash() - { + public byte[] getHash() { return hash; } @@ -162,12 +169,12 @@ public class PasswordHash * * @return hash encoded as hexadecimal digits, or null if none. */ - public String getHashString() - { - if (null != hash) + public String getHashString() { + if (null != hash) { return new String(Hex.encodeHex(hash)); - else + } else { return null; + } } /** @@ -175,8 +182,7 @@ public class PasswordHash * * @return the value of salt */ - public byte[] getSalt() - { + public byte[] getSalt() { return salt; } @@ -185,12 +191,12 @@ public class PasswordHash * * @return salt encoded as hexadecimal digits, or null if none. */ - public String getSaltString() - { - if (null != salt) + public String getSaltString() { + if (null != salt) { return new String(Hex.encodeHex(salt)); - else + } else { return null; + } } /** @@ -198,35 +204,32 @@ public class PasswordHash * * @return the value of algorithm */ - public String getAlgorithm() - { + public String getAlgorithm() { return algorithm; } /** * The digest algorithm used if none is configured. - * + * * @return name of the default digest. */ - static public String getDefaultAlgorithm() - { + static public String getDefaultAlgorithm() { return DEFAULT_DIGEST_ALGORITHM; } - /** Generate an array of random bytes. */ - private synchronized byte[] generateSalt() - { + /** + * Generate an array of random bytes. + */ + private synchronized byte[] generateSalt() { // Initialize a random-number generator - if (null == rng) - { + if (null == rng) { rng = new SecureRandom(); log.info("Initialized a random number stream using {} provided by {}", - rng.getAlgorithm(), rng.getProvider()); + rng.getAlgorithm(), rng.getProvider()); rngUses = 0; } - if (rngUses++ > RESEED_INTERVAL) - { // re-seed the generator periodically to break up possible patterns + if (rngUses++ > RESEED_INTERVAL) { // re-seed the generator periodically to break up possible patterns log.debug("Re-seeding the RNG"); rng.setSeed(rng.generateSeed(SEED_BYTES)); rngUses = 0; @@ -240,39 +243,38 @@ public class PasswordHash /** * Generate a salted hash of a string using a given algorithm. * - * @param salt random bytes to salt the hash. + * @param salt random bytes to salt the hash. * @param algorithm name of the digest algorithm to use. Assume unsalted MD5 if null. - * @param secret the string to be hashed. Null is treated as an empty string (""). + * @param secret the string to be hashed. Null is treated as an empty string (""). * @return hash bytes. * @throws NoSuchAlgorithmException if algorithm is unknown. */ private byte[] digest(byte[] salt, String algorithm, String secret) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { MessageDigest digester; - if (null == secret) + if (null == secret) { secret = ""; + } // Special case: old unsalted one-trip MD5 hash. - if (null == algorithm) - { + if (null == algorithm) { digester = MessageDigest.getInstance("MD5"); digester.update(secret.getBytes(UTF_8)); return digester.digest(); } // Set up a digest - digester = MessageDigest.getInstance(algorithm); + digester = MessageDigest.getInstance(algorithm); // Grind up the salt with the password, yielding a hash - if (null != salt) + if (null != salt) { digester.update(salt); + } digester.update(secret.getBytes(UTF_8)); // Round 0 - for (int round = 1; round < HASH_ROUNDS; round++) - { + for (int round = 1; round < HASH_ROUNDS; round++) { byte[] lastRound = digester.digest(); digester.reset(); digester.update(lastRound); diff --git a/dspace-api/src/main/java/org/dspace/eperson/RegistrationData.java b/dspace-api/src/main/java/org/dspace/eperson/RegistrationData.java index b0c575eb1a..f4f41bdff2 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/RegistrationData.java +++ b/dspace-api/src/main/java/org/dspace/eperson/RegistrationData.java @@ -7,25 +7,33 @@ */ package org.dspace.eperson; +import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; -import javax.persistence.*; -import java.util.Date; - /** * Database entity representation of the registrationdata table * * @author kevinvandevelde at atmire.com */ @Entity -@Table(name="registrationdata") +@Table(name = "registrationdata") public class RegistrationData implements ReloadableEntity { @Id - @Column(name="registrationdata_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="registrationdata_seq") - @SequenceGenerator(name="registrationdata_seq", sequenceName="registrationdata_seq", allocationSize = 1) + @Column(name = "registrationdata_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "registrationdata_seq") + @SequenceGenerator(name = "registrationdata_seq", sequenceName = "registrationdata_seq", allocationSize = 1) private Integer id; @Column(name = "email", unique = true, length = 64) @@ -41,10 +49,8 @@ public class RegistrationData implements ReloadableEntity { /** * Protected constructor, create object using: * {@link org.dspace.eperson.service.RegistrationDataService#create(Context)} - * */ - protected RegistrationData() - { + protected RegistrationData() { } diff --git a/dspace-api/src/main/java/org/dspace/eperson/RegistrationDataServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/RegistrationDataServiceImpl.java index 3a5d3ab097..b272751685 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/RegistrationDataServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/RegistrationDataServiceImpl.java @@ -7,17 +7,17 @@ */ package org.dspace.eperson; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.dao.RegistrationDataDAO; import org.dspace.eperson.service.RegistrationDataService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Collections; -import java.util.List; - /** * Service implementation for the RegistrationData object. * This class is responsible for all business logic calls for the RegistrationData object and is autowired by spring. @@ -25,13 +25,11 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class RegistrationDataServiceImpl implements RegistrationDataService -{ +public class RegistrationDataServiceImpl implements RegistrationDataService { @Autowired(required = true) protected RegistrationDataDAO registrationDataDAO; - protected RegistrationDataServiceImpl() - { + protected RegistrationDataServiceImpl() { } @@ -68,8 +66,9 @@ public class RegistrationDataServiceImpl implements RegistrationDataService } @Override - public void update(Context context, List registrationDataRecords) throws SQLException, AuthorizeException { - if(CollectionUtils.isNotEmpty(registrationDataRecords)) { + public void update(Context context, List registrationDataRecords) + throws SQLException, AuthorizeException { + if (CollectionUtils.isNotEmpty(registrationDataRecords)) { for (RegistrationData registrationData : registrationDataRecords) { registrationDataDAO.save(context, registrationData); } diff --git a/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java b/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java index 64cf7d1e70..1cdefcbbdd 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java +++ b/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java @@ -7,15 +7,39 @@ */ package org.dspace.eperson; -import org.apache.commons.cli.*; +import java.io.IOException; +import java.sql.SQLException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.TimeZone; +import javax.mail.MessagingException; + +import org.apache.commons.cli.CommandLine; +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.apache.commons.lang.StringUtils; import org.apache.log4j.Level; import org.apache.log4j.Logger; -import org.dspace.content.*; import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.Item; +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.*; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; +import org.dspace.core.LogManager; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.SubscribeService; import org.dspace.handle.factory.HandleServiceFactory; @@ -23,13 +47,6 @@ import org.dspace.handle.service.HandleService; import org.dspace.search.Harvest; import org.dspace.search.HarvestedItemInfo; -import javax.mail.MessagingException; -import java.io.IOException; -import java.sql.SQLException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; - /** * CLI tool used for sending new item e-mail alerts to users * @@ -44,6 +61,11 @@ public class SubscribeCLITool { private static ItemService itemService = ContentServiceFactory.getInstance().getItemService(); private static SubscribeService subscribeService = EPersonServiceFactory.getInstance().getSubscribeService(); + /** + * Default constructor + */ + private SubscribeCLITool() { } + /** * Process subscriptions. This must be invoked only once a day. Messages are * only sent out when a collection has actually received new items, so that @@ -57,17 +79,13 @@ public class SubscribeCLITool { * For example, if today's date is 2002-10-10 (in UTC) items made available * during 2002-10-09 (UTC) will be included. * - * @param context - * The relevant DSpace Context. - * @param test - * If true, do a "dry run", i.e. don't actually send email, just log the attempt - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param context The relevant DSpace Context. + * @param test If true, do a "dry run", i.e. don't actually send email, just log the attempt + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ public static void processDaily(Context context, boolean test) throws SQLException, - IOException { + IOException { // Grab the subscriptions List subscriptions = subscribeService.findAll(context); @@ -79,8 +97,8 @@ public class SubscribeCLITool { for (Subscription subscription : subscriptions) { // Does this row relate to the same e-person as the last? if ((currentEPerson == null) - || (!subscription.getePerson().getID().equals(currentEPerson - .getID()))) { + || (!subscription.getePerson().getID().equals(currentEPerson + .getID()))) { // New e-person. Send mail for previous e-person if (currentEPerson != null) { @@ -88,7 +106,7 @@ public class SubscribeCLITool { sendEmail(context, currentEPerson, collections, test); } catch (MessagingException me) { log.error("Failed to send subscription to eperson_id=" - + currentEPerson.getID()); + + currentEPerson.getID()); log.error(me); } } @@ -106,7 +124,7 @@ public class SubscribeCLITool { sendEmail(context, currentEPerson, collections, test); } catch (MessagingException me) { log.error("Failed to send subscription to eperson_id=" - + currentEPerson.getID()); + + currentEPerson.getID()); log.error(me); } } @@ -120,18 +138,14 @@ public class SubscribeCLITool { * @param context DSpace context object * @param eperson eperson to send to * @param collections List of collection IDs (Integers) - * @param test - * If true, do a "dry run", i.e. don't actually send email, just log the attempt - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws MessagingException - * A general class of exceptions for sending email. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param test If true, do a "dry run", i.e. don't actually send email, just log the attempt + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws MessagingException A general class of exceptions for sending email. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public static void sendEmail(Context context, EPerson eperson, List collections, boolean test) throws IOException, MessagingException, - SQLException { + SQLException { // Get a resource bundle according to the eperson language preferences Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); ResourceBundle labels = ResourceBundle.getBundle("Messages", supportedLocale); @@ -162,19 +176,21 @@ public class SubscribeCLITool { Collection c = collections.get(i); try { - boolean includeAll = ConfigurationManager.getBooleanProperty("harvest.includerestricted.subscription", true); + boolean includeAll = ConfigurationManager + .getBooleanProperty("harvest.includerestricted.subscription", true); // we harvest all the changed item from yesterday until now - List itemInfos = Harvest.harvest(context, c, new DCDate(midnightYesterday).toString(), null, 0, // Limit - // and - // offset - // zero, - // get - // everything - 0, true, // Need item objects - false, // But not containers - false, // Or withdrawals - includeAll); + List itemInfos = Harvest + .harvest(context, c, new DCDate(midnightYesterday).toString(), null, 0, // Limit + // and + // offset + // zero, + // get + // everything + 0, true, // Need item objects + false, // But not containers + false, // Or withdrawals + includeAll); if (ConfigurationManager.getBooleanProperty("eperson.subscription.onlynew", false)) { // get only the items archived yesterday @@ -189,21 +205,22 @@ public class SubscribeCLITool { if (itemInfos.size() > 0) { if (!isFirst) { emailText - .append("\n---------------------------------------\n"); + .append("\n---------------------------------------\n"); } else { isFirst = false; } emailText.append(labels.getString("org.dspace.eperson.Subscribe.new-items")).append(" ").append( - c.getName()).append(": ").append( - itemInfos.size()).append("\n\n"); + c.getName()).append(": ").append( + itemInfos.size()).append("\n\n"); for (int j = 0; j < itemInfos.size(); j++) { HarvestedItemInfo hii = (HarvestedItemInfo) itemInfos - .get(j); + .get(j); String title = hii.item.getName(); - emailText.append(" ").append(labels.getString("org.dspace.eperson.Subscribe.title")).append(" "); + emailText.append(" ").append(labels.getString("org.dspace.eperson.Subscribe.title")) + .append(" "); if (StringUtils.isNotBlank(title)) { emailText.append(title); @@ -211,21 +228,24 @@ public class SubscribeCLITool { emailText.append(labels.getString("org.dspace.eperson.Subscribe.untitled")); } - List authors = itemService.getMetadata(hii.item, MetadataSchema.DC_SCHEMA, "contributor", Item.ANY, Item.ANY); + List authors = itemService + .getMetadata(hii.item, MetadataSchema.DC_SCHEMA, "contributor", Item.ANY, Item.ANY); if (authors.size() > 0) { - emailText.append("\n ").append(labels.getString("org.dspace.eperson.Subscribe.authors")).append(" ").append( - authors.get(0).getValue()); + emailText.append("\n ").append(labels.getString("org.dspace.eperson.Subscribe.authors")) + .append(" ").append( + authors.get(0).getValue()); for (int k = 1; k < authors.size(); k++) { emailText.append("\n ").append( - authors.get(k).getValue()); + authors.get(k).getValue()); } } - emailText.append("\n ").append(labels.getString("org.dspace.eperson.Subscribe.id")).append(" ").append( - handleService.getCanonicalForm(hii.handle)).append( - "\n\n"); + emailText.append("\n ").append(labels.getString("org.dspace.eperson.Subscribe.id")) + .append(" ").append( + handleService.getCanonicalForm(hii.handle)).append( + "\n\n"); } } } catch (ParseException pe) { @@ -317,14 +337,14 @@ public class SubscribeCLITool { private static List filterOutToday(List completeList) { log.debug("Filtering out all today item to leave new items list size=" - + completeList.size()); + + completeList.size()); List filteredList = new ArrayList(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String today = sdf.format(new Date()); // Get the start and end dates for yesterday Date thisTimeYesterday = new Date(System.currentTimeMillis() - - (24 * 60 * 60 * 1000)); + - (24 * 60 * 60 * 1000)); String yesterday = sdf.format(thisTimeYesterday); for (HarvestedItemInfo infoObject : completeList) { @@ -334,7 +354,7 @@ public class SubscribeCLITool { // has the item modified today? if (lastUpdateStr.equals(today)) { List dateAccArr = itemService.getMetadata(infoObject.item, "dc", - "date", "accessioned", Item.ANY); + "date", "accessioned", Item.ANY); // we need only the item archived yesterday if (dateAccArr != null && dateAccArr.size() > 0) { for (MetadataValue date : dateAccArr) { @@ -343,19 +363,19 @@ public class SubscribeCLITool { if (date.getValue().startsWith(yesterday)) { filteredList.add(infoObject); log.debug("adding : " + dateAccArr.get(0).getValue() - + " : " + today + " : " - + infoObject.handle); + + " : " + today + " : " + + infoObject.handle); break; } else { log.debug("ignoring : " + dateAccArr.get(0).getValue() - + " : " + today + " : " - + infoObject.handle); + + " : " + today + " : " + + infoObject.handle); } } } } else { log.debug("no date accessioned, adding : " - + infoObject.handle); + + infoObject.handle); filteredList.add(infoObject); } } else { @@ -374,11 +394,12 @@ public class SubscribeCLITool { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // Get the start and end dates for yesterday Date thisTimeYesterday = new Date(System.currentTimeMillis() - - (24 * 60 * 60 * 1000)); + - (24 * 60 * 60 * 1000)); String yesterday = sdf.format(thisTimeYesterday); for (HarvestedItemInfo infoObject : completeList) { - List dateAccArr = itemService.getMetadata(infoObject.item, "dc", "date", "accessioned", Item.ANY); + List dateAccArr = itemService + .getMetadata(infoObject.item, "dc", "date", "accessioned", Item.ANY); if (dateAccArr != null && dateAccArr.size() > 0) { for (MetadataValue date : dateAccArr) { @@ -386,10 +407,14 @@ public class SubscribeCLITool { // if it has been archived yesterday if (date.getValue().startsWith(yesterday)) { filteredList.add(infoObject); - log.debug("adding : " + dateAccArr.get(0).getValue() + " : " + yesterday + " : " + infoObject.handle); + log.debug("adding : " + dateAccArr.get(0) + .getValue() + " : " + yesterday + " : " + infoObject + .handle); break; } else { - log.debug("ignoring : " + dateAccArr.get(0).getValue() + " : " + yesterday + " : " + infoObject.handle); + log.debug("ignoring : " + dateAccArr.get(0) + .getValue() + " : " + yesterday + " : " + infoObject + .handle); } } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/SubscribeServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/SubscribeServiceImpl.java index 1030ec476e..cd9e078463 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/SubscribeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/SubscribeServiceImpl.java @@ -28,9 +28,10 @@ import org.springframework.beans.factory.annotation.Autowired; * @author Robert Tansley * @version $Revision$ */ -public class SubscribeServiceImpl implements SubscribeService -{ - /** log4j logger */ +public class SubscribeServiceImpl implements SubscribeService { + /** + * log4j logger + */ private Logger log = Logger.getLogger(SubscribeServiceImpl.class); @Autowired(required = true) @@ -41,8 +42,7 @@ public class SubscribeServiceImpl implements SubscribeService @Autowired(required = true) protected CollectionService collectionService; - protected SubscribeServiceImpl() - { + protected SubscribeServiceImpl() { } @@ -53,77 +53,62 @@ public class SubscribeServiceImpl implements SubscribeService @Override public void subscribe(Context context, EPerson eperson, - Collection collection) throws SQLException, AuthorizeException - { + Collection collection) throws SQLException, AuthorizeException { // Check authorisation. Must be administrator, or the eperson. if (authorizeService.isAdmin(context) - || ((context.getCurrentUser() != null) && (context - .getCurrentUser().getID().equals(eperson.getID())))) - { + || ((context.getCurrentUser() != null) && (context + .getCurrentUser().getID().equals(eperson.getID())))) { if (!isSubscribed(context, eperson, collection)) { Subscription subscription = subscriptionDAO.create(context, new Subscription()); subscription.setCollection(collection); subscription.setePerson(eperson); } - } - else - { + } else { throw new AuthorizeException( - "Only admin or e-person themselves can subscribe"); + "Only admin or e-person themselves can subscribe"); } } @Override public void unsubscribe(Context context, EPerson eperson, - Collection collection) throws SQLException, AuthorizeException - { + Collection collection) throws SQLException, AuthorizeException { // Check authorisation. Must be administrator, or the eperson. if (authorizeService.isAdmin(context) - || ((context.getCurrentUser() != null) && (context - .getCurrentUser().getID().equals(eperson.getID())))) - { - if (collection == null) - { + || ((context.getCurrentUser() != null) && (context + .getCurrentUser().getID().equals(eperson.getID())))) { + if (collection == null) { // Unsubscribe from all subscriptionDAO.deleteByEPerson(context, eperson); - } - else - { + } else { subscriptionDAO.deleteByCollectionAndEPerson(context, collection, eperson); log.info(LogManager.getHeader(context, "unsubscribe", - "eperson_id=" + eperson.getID() + ",collection_id=" - + collection.getID())); + "eperson_id=" + eperson.getID() + ",collection_id=" + + collection.getID())); } - } - else - { + } else { throw new AuthorizeException( - "Only admin or e-person themselves can unsubscribe"); + "Only admin or e-person themselves can unsubscribe"); } } @Override public List getSubscriptions(Context context, EPerson eperson) - throws SQLException - { + throws SQLException { return subscriptionDAO.findByEPerson(context, eperson); } @Override public List getAvailableSubscriptions(Context context) - throws SQLException - { + throws SQLException { return getAvailableSubscriptions(context, null); } - + @Override public List getAvailableSubscriptions(Context context, EPerson eperson) - throws SQLException - { + throws SQLException { List collections; - if (eperson != null) - { + if (eperson != null) { context.setCurrentUser(eperson); } collections = collectionService.findAuthorized(context, null, Constants.ADD); @@ -133,8 +118,7 @@ public class SubscribeServiceImpl implements SubscribeService @Override public boolean isSubscribed(Context context, EPerson eperson, - Collection collection) throws SQLException - { + Collection collection) throws SQLException { return subscriptionDAO.findByCollectionAndEPerson(context, eperson, collection) != null; } @@ -147,4 +131,4 @@ public class SubscribeServiceImpl implements SubscribeService public void deleteByEPerson(Context context, EPerson ePerson) throws SQLException { subscriptionDAO.deleteByEPerson(context, ePerson); } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/eperson/Subscription.java b/dspace-api/src/main/java/org/dspace/eperson/Subscription.java index b0438db872..abe8ad481c 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/Subscription.java +++ b/dspace-api/src/main/java/org/dspace/eperson/Subscription.java @@ -7,12 +7,21 @@ */ package org.dspace.eperson; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; -import javax.persistence.*; - /** * Database entity representation of the subscription table * @@ -24,8 +33,8 @@ public class Subscription implements ReloadableEntity { @Id @Column(name = "subscription_id", unique = true, nullable = false) - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="subscription_seq") - @SequenceGenerator(name="subscription_seq", sequenceName="subscription_seq", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "subscription_seq") + @SequenceGenerator(name = "subscription_seq", sequenceName = "subscription_seq", allocationSize = 1) private Integer id; @ManyToOne(fetch = FetchType.LAZY) @@ -39,10 +48,8 @@ public class Subscription implements ReloadableEntity { /** * Protected constructor, create object using: * {@link org.dspace.eperson.service.SubscribeService#subscribe(Context, EPerson, Collection)} - * */ - protected Subscription() - { + protected Subscription() { } @@ -65,4 +72,4 @@ public class Subscription implements ReloadableEntity { void setePerson(EPerson ePerson) { this.ePerson = ePerson; } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/eperson/SupervisorServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/SupervisorServiceImpl.java index 9df4b55cb8..64180a5e22 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/SupervisorServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/SupervisorServiceImpl.java @@ -20,28 +20,25 @@ import org.dspace.core.Context; import org.dspace.eperson.service.SupervisorService; import org.springframework.beans.factory.annotation.Autowired; -public class SupervisorServiceImpl implements SupervisorService{ +public class SupervisorServiceImpl implements SupervisorService { @Autowired(required = true) protected ItemService itemService; @Autowired(required = true) protected ResourcePolicyService resourcePolicyService; - protected SupervisorServiceImpl() - { + protected SupervisorServiceImpl() { } @Override public boolean isOrder(Context context, WorkspaceItem workspaceItem, Group group) - throws SQLException - { + throws SQLException { return workspaceItem.getSupervisorGroups().contains(group); } @Override public void remove(Context context, WorkspaceItem workspaceItem, Group group) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { // get the workspace item and the group from the request values workspaceItem.getSupervisorGroups().remove(group); @@ -52,8 +49,7 @@ public class SupervisorServiceImpl implements SupervisorService{ @Override public void add(Context context, Group group, WorkspaceItem workspaceItem, int policy) - throws SQLException, AuthorizeException - { + throws SQLException, AuthorizeException { // make a table row in the database table, and update with the relevant // details workspaceItem.getSupervisorGroups().add(group); @@ -61,35 +57,31 @@ public class SupervisorServiceImpl implements SupervisorService{ // If a default policy type has been requested, apply the policies using // the DSpace API for doing so - if (policy != POLICY_NONE) - { + if (policy != POLICY_NONE) { Item item = workspaceItem.getItem(); // "Editor" implies READ, WRITE, ADD permissions // "Observer" implies READ permissions - if (policy == POLICY_EDITOR) - { + if (policy == POLICY_EDITOR) { ResourcePolicy r = resourcePolicyService.create(context); r.setdSpaceObject(item); r.setGroup(group); r.setAction(Constants.READ); resourcePolicyService.update(context, r); - + r = resourcePolicyService.create(context); r.setdSpaceObject(item); r.setGroup(group); r.setAction(Constants.WRITE); resourcePolicyService.update(context, r); - + r = resourcePolicyService.create(context); r.setdSpaceObject(item); r.setGroup(group); r.setAction(Constants.ADD); resourcePolicyService.update(context, r); - - } - else if (policy == POLICY_OBSERVER) - { + + } else if (policy == POLICY_OBSERVER) { ResourcePolicy r = resourcePolicyService.create(context); r.setdSpaceObject(item); r.setGroup(group); diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/EPersonDAO.java b/dspace-api/src/main/java/org/dspace/eperson/dao/EPersonDAO.java index 90f0877147..51ab89ef7e 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/EPersonDAO.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/EPersonDAO.java @@ -7,6 +7,11 @@ */ package org.dspace.eperson.dao; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.Set; + import org.dspace.content.MetadataField; import org.dspace.content.dao.DSpaceObjectDAO; import org.dspace.content.dao.DSpaceObjectLegacySupportDAO; @@ -14,14 +19,10 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; -import java.util.Set; - /** * Database Access Object interface class for the EPerson object. - * The implementation of this class is responsible for all database calls for the EPerson object and is autowired by spring + * The implementation of this class is responsible for all database calls for the EPerson object and is autowired by + * spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -32,7 +33,8 @@ public interface EPersonDAO extends DSpaceObjectDAO, DSpaceObjectLegacy public EPerson findByNetid(Context context, String netid) throws SQLException; - public List search(Context context, String query, List queryFields, List sortFields, int offset, int limit) throws SQLException; + public List search(Context context, String query, List queryFields, + List sortFields, int offset, int limit) throws SQLException; public int searchResultCount(Context context, String query, List queryFields) throws SQLException; @@ -42,7 +44,8 @@ public interface EPersonDAO extends DSpaceObjectDAO, DSpaceObjectLegacy public List findNotActiveSince(Context context, Date date) throws SQLException; - public List findAll(Context context, MetadataField metadataFieldSort, String sortColumn, int pageSize, int offset) throws SQLException; + public List findAll(Context context, MetadataField metadataFieldSort, String sortColumn, int pageSize, + int offset) throws SQLException; public List findAllSubscribers(Context context) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/Group2GroupCacheDAO.java b/dspace-api/src/main/java/org/dspace/eperson/dao/Group2GroupCacheDAO.java index 8532d67c0c..7db569a59e 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/Group2GroupCacheDAO.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/Group2GroupCacheDAO.java @@ -7,17 +7,18 @@ */ package org.dspace.eperson.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.Group; import org.dspace.eperson.Group2GroupCache; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the Group2GroupCache object. - * The implementation of this class is responsible for all database calls for the Group2GroupCache object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Group2GroupCache object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/GroupDAO.java b/dspace-api/src/main/java/org/dspace/eperson/dao/GroupDAO.java index 0be19068f2..ab37aa4047 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/GroupDAO.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/GroupDAO.java @@ -7,6 +7,10 @@ */ package org.dspace.eperson.dao; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + import org.apache.commons.lang3.tuple.Pair; import org.dspace.content.MetadataField; import org.dspace.content.dao.DSpaceObjectDAO; @@ -15,13 +19,10 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; - /** * Database Access Object interface class for the Group object. - * The implementation of this class is responsible for all database calls for the Group object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Group object and is autowired by + * spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -30,41 +31,43 @@ public interface GroupDAO extends DSpaceObjectDAO, DSpaceObjectLegacySupp /** * Look up groups based on their value for a certain metadata field (NOTE: name is not stored as metadata) - * @param context The DSpace context - * @param searchValue The value to match + * + * @param context The DSpace context + * @param searchValue The value to match * @param metadataField The metadata field to search in * @return The groups that have a matching value for specified metadata field * @throws SQLException if database error */ - List findByMetadataField(Context context, String searchValue, MetadataField metadataField) throws SQLException; + List findByMetadataField(Context context, String searchValue, MetadataField metadataField) + throws SQLException; /** * Find all groups ordered by the specified metadata fields ascending - * @param context The DSpace context + * + * @param context The DSpace context * @param sortMetadataFields The metadata fields to sort on - * @param pageSize - * how many results return - * @param offset - * the position of the first result to return + * @param pageSize how many results return + * @param offset the position of the first result to return * @return A list of all groups, ordered by metadata fields * @throws SQLException if database error */ - List findAll(Context context, List metadataSortFields, int pageSize, int offset) throws SQLException; + List findAll(Context context, List metadataSortFields, int pageSize, int offset) + throws SQLException; /** * Find all groups ordered by name ascending - * @param context The DSpace context - * @param pageSize - * how many results return - * @param offset - * the position of the first result to return + * + * @param context The DSpace context + * @param pageSize how many results return + * @param offset the position of the first result to return * @return A list of all groups, ordered by name * @throws SQLException if database error */ List findAll(Context context, int pageSize, int offset) throws SQLException; - + /** * Find all groups that the given ePerson belongs to + * * @param context The DSpace context * @param ePerson The EPerson to match * @return A list of all groups to which the given EPerson belongs @@ -74,7 +77,8 @@ public interface GroupDAO extends DSpaceObjectDAO, DSpaceObjectLegacySupp /** * Get a list of all direct parent - child group relations in the database - * @param context The DSpace context + * + * @param context The DSpace context * @param flushQueries Flush all pending queries * @return A list of pairs indicating parent - child * @throws SQLException if database error @@ -83,6 +87,7 @@ public interface GroupDAO extends DSpaceObjectDAO, DSpaceObjectLegacySupp /** * Return all empty groups + * * @param context The DSpace context * @return All empty groups * @throws SQLException if database error @@ -91,6 +96,7 @@ public interface GroupDAO extends DSpaceObjectDAO, DSpaceObjectLegacySupp /** * Count the number of groups in DSpace + * * @param context The DSpace context * @return The number of groups * @throws SQLException if database error @@ -99,8 +105,9 @@ public interface GroupDAO extends DSpaceObjectDAO, DSpaceObjectLegacySupp /** * Find a group by its name (exact match) + * * @param context The DSpace context - * @param name The name of the group to look for + * @param name The name of the group to look for * @return The group with the specified name * @throws SQLException if database error */ @@ -108,10 +115,11 @@ public interface GroupDAO extends DSpaceObjectDAO, DSpaceObjectLegacySupp /** * Find a group by its name (fuzzy match) - * @param context The DSpace context + * + * @param context The DSpace context * @param groupName Part of the group's name to search for - * @param offset Offset to use for pagination (-1 to disable) - * @param limit The maximum number of results to return (-1 to disable) + * @param offset Offset to use for pagination (-1 to disable) + * @param limit The maximum number of results to return (-1 to disable) * @return Groups matching the query * @throws SQLException if database error */ @@ -119,7 +127,8 @@ public interface GroupDAO extends DSpaceObjectDAO, DSpaceObjectLegacySupp /** * Count the number of groups that have a name that contains the given string - * @param context The DSpace context + * + * @param context The DSpace context * @param groupName Part of the group's name to search for * @return The number of matching groups * @throws SQLException if database error @@ -128,8 +137,9 @@ public interface GroupDAO extends DSpaceObjectDAO, DSpaceObjectLegacySupp /** * Find a group by its name and the membership of the given EPerson + * * @param context The DSpace context - * @param id The id of the group to look for + * @param id The id of the group to look for * @param ePerson The EPerson which has to be a member * @return The group with the specified name * @throws SQLException if database error diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/RegistrationDataDAO.java b/dspace-api/src/main/java/org/dspace/eperson/dao/RegistrationDataDAO.java index d25f234408..5650c5e5b2 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/RegistrationDataDAO.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/RegistrationDataDAO.java @@ -7,15 +7,16 @@ */ package org.dspace.eperson.dao; +import java.sql.SQLException; + import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.RegistrationData; -import java.sql.SQLException; - /** * Database Access Object interface class for the RegistrationData object. - * The implementation of this class is responsible for all database calls for the RegistrationData object and is autowired by spring + * The implementation of this class is responsible for all database calls for the RegistrationData object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionDAO.java b/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionDAO.java index 6f8f92a836..e9f2d57059 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionDAO.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/SubscriptionDAO.java @@ -7,18 +7,19 @@ */ package org.dspace.eperson.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; import org.dspace.eperson.Subscription; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the Subscription object. - * The implementation of this class is responsible for all database calls for the Subscription object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Subscription object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -29,11 +30,13 @@ public interface SubscriptionDAO extends GenericDAO { public List findByEPerson(Context context, EPerson eperson) throws SQLException; - public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection) throws SQLException; + public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection) + throws SQLException; public void deleteByEPerson(Context context, EPerson eperson) throws SQLException; - public void deleteByCollectionAndEPerson(Context context, Collection collection, EPerson eperson) throws SQLException; + public void deleteByCollectionAndEPerson(Context context, Collection collection, EPerson eperson) + throws SQLException; public List findAllOrderedByEPerson(Context context) throws SQLException; -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/EPersonDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/EPersonDAOImpl.java index eb7adb097b..fd4c6f59d9 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/EPersonDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/EPersonDAOImpl.java @@ -7,6 +7,19 @@ */ package org.dspace.eperson.dao.impl; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.ListUtils; import org.apache.commons.lang3.StringUtils; @@ -14,14 +27,9 @@ import org.dspace.content.MetadataField; import org.dspace.core.AbstractHibernateDSODAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; +import org.dspace.eperson.EPerson_; import org.dspace.eperson.Group; import org.dspace.eperson.dao.EPersonDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.*; /** * Hibernate implementation of the Database Access Object interface class for the EPerson object. @@ -30,73 +38,75 @@ import java.util.*; * * @author kevinvandevelde at atmire.com */ -public class EPersonDAOImpl extends AbstractHibernateDSODAO implements EPersonDAO -{ - protected EPersonDAOImpl() - { +public class EPersonDAOImpl extends AbstractHibernateDSODAO implements EPersonDAO { + protected EPersonDAOImpl() { super(); } @Override - public EPerson findByEmail(Context context, String email) throws SQLException - { - // All email addresses are stored as lowercase, so ensure that the email address is lowercased for the lookup - Criteria criteria = createCriteria(context, EPerson.class); - criteria.add(Restrictions.eq("email", email.toLowerCase())); - - criteria.setCacheable(true); - return uniqueResult(criteria); + public EPerson findByEmail(Context context, String email) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EPerson.class); + Root ePersonRoot = criteriaQuery.from(EPerson.class); + criteriaQuery.select(ePersonRoot); + criteriaQuery.where(criteriaBuilder.equal(ePersonRoot.get(EPerson_.email), email.toLowerCase())); + return uniqueResult(context, criteriaQuery, true, EPerson.class, -1, -1); } @Override - public EPerson findByNetid(Context context, String netid) throws SQLException - { - Criteria criteria = createCriteria(context, EPerson.class); - criteria.add(Restrictions.eq("netid", netid)); - - criteria.setCacheable(true); - return uniqueResult(criteria); + public EPerson findByNetid(Context context, String netid) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EPerson.class); + Root ePersonRoot = criteriaQuery.from(EPerson.class); + criteriaQuery.select(ePersonRoot); + criteriaQuery.where((criteriaBuilder.equal(ePersonRoot.get(EPerson_.netid), netid))); + return uniqueResult(context, criteriaQuery, true, EPerson.class, -1, -1); } @Override - public List search(Context context, String query, List queryFields, List sortFields, int offset, int limit) throws SQLException - { - String queryString = "SELECT " + EPerson.class.getSimpleName().toLowerCase() + " FROM EPerson as " + EPerson.class.getSimpleName().toLowerCase() + " "; - if(query != null) query= "%"+query.toLowerCase()+"%"; + public List search(Context context, String query, List queryFields, + List sortFields, int offset, int limit) throws SQLException { + String queryString = "SELECT " + EPerson.class.getSimpleName() + .toLowerCase() + " FROM EPerson as " + EPerson.class + .getSimpleName().toLowerCase() + " "; + if (query != null) { + query = "%" + query.toLowerCase() + "%"; + } Query hibernateQuery = getSearchQuery(context, queryString, query, queryFields, sortFields, null); - if(0 <= offset) - { + if (0 <= offset) { hibernateQuery.setFirstResult(offset); } - if(0 <= limit) - { + if (0 <= limit) { hibernateQuery.setMaxResults(limit); } return list(hibernateQuery); } @Override - public int searchResultCount(Context context, String query, List queryFields) throws SQLException - { + public int searchResultCount(Context context, String query, List queryFields) throws SQLException { String queryString = "SELECT count(*) FROM EPerson as " + EPerson.class.getSimpleName().toLowerCase(); - Query hibernateQuery = getSearchQuery(context, queryString, query, queryFields, ListUtils.EMPTY_LIST, null); + Query hibernateQuery = getSearchQuery(context, queryString, query, queryFields, Collections.EMPTY_LIST, null); return count(hibernateQuery); } @Override - public List findAll(Context context, MetadataField metadataSortField, String sortField, int pageSize, int offset) throws SQLException { - String queryString = "SELECT " + EPerson.class.getSimpleName().toLowerCase() + " FROM EPerson as " + EPerson.class.getSimpleName().toLowerCase(); + public List findAll(Context context, MetadataField metadataSortField, String sortField, int pageSize, + int offset) throws SQLException { + String queryString = "SELECT " + EPerson.class.getSimpleName() + .toLowerCase() + " FROM EPerson as " + EPerson.class + .getSimpleName().toLowerCase(); - List sortFields = ListUtils.EMPTY_LIST; + List sortFields = Collections.EMPTY_LIST; - if(metadataSortField!=null){ - sortFields = Collections.singletonList(metadataSortField); + if (metadataSortField != null) { + sortFields = Collections.singletonList(metadataSortField); } - Query query = getSearchQuery(context, queryString, null, ListUtils.EMPTY_LIST, sortFields, sortField, pageSize, offset); + Query query = getSearchQuery(context, queryString, null, ListUtils.EMPTY_LIST, sortFields, sortField, pageSize, + offset); return list(query); } @@ -104,42 +114,52 @@ public class EPersonDAOImpl extends AbstractHibernateDSODAO implements @Override public List findByGroups(Context context, Set groups) throws SQLException { Query query = createQuery(context, - "SELECT DISTINCT e FROM EPerson e " + - "JOIN e.groups g " + - "WHERE g.id IN (:idList) "); + "SELECT DISTINCT e FROM EPerson e " + + "JOIN e.groups g " + + "WHERE g.id IN (:idList) "); List idList = new ArrayList<>(groups.size()); for (Group group : groups) { idList.add(group.getID()); } - query.setParameterList("idList", idList); + query.setParameter("idList", idList); return list(query); } @Override public List findWithPasswordWithoutDigestAlgorithm(Context context) throws SQLException { - Criteria criteria = createCriteria(context, EPerson.class); - criteria.add(Restrictions.and( - Restrictions.isNotNull("password"), - Restrictions.isNull("digestAlgorithm") - )); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EPerson.class); + Root ePersonRoot = criteriaQuery.from(EPerson.class); + criteriaQuery.select(ePersonRoot); + criteriaQuery.where(criteriaBuilder.and(criteriaBuilder.isNotNull(ePersonRoot.get(EPerson_.password)), + criteriaBuilder.isNull(ePersonRoot.get(EPerson_.digestAlgorithm)) + ) + ); + return list(context, criteriaQuery, false, EPerson.class, -1, -1); } @Override public List findNotActiveSince(Context context, Date date) throws SQLException { - Criteria criteria = createCriteria(context, EPerson.class); - criteria.add(Restrictions.le("lastActive", date)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EPerson.class); + Root ePersonRoot = criteriaQuery.from(EPerson.class); + criteriaQuery.select(ePersonRoot); + criteriaQuery.where(criteriaBuilder.lessThanOrEqualTo(ePersonRoot.get(EPerson_.lastActive), date)); + return list(context, criteriaQuery, false, EPerson.class, -1, -1); } - protected Query getSearchQuery(Context context, String queryString, String queryParam, List queryFields, List sortFields, String sortField) throws SQLException { - return getSearchQuery(context, queryString, queryParam, queryFields, sortFields, sortField, -1, -1); + protected Query getSearchQuery(Context context, String queryString, String queryParam, + List queryFields, List sortFields, String sortField) + throws SQLException { + return getSearchQuery(context, queryString, queryParam, queryFields, sortFields, sortField, -1, -1); } - - protected Query getSearchQuery(Context context, String queryString, String queryParam, List queryFields, List sortFields, String sortField, int pageSize, int offset) throws SQLException { + + protected Query getSearchQuery(Context context, String queryString, String queryParam, + List queryFields, List sortFields, String sortField, + int pageSize, int offset) throws SQLException { StringBuilder queryBuilder = new StringBuilder(); queryBuilder.append(queryString); @@ -147,25 +167,26 @@ public class EPersonDAOImpl extends AbstractHibernateDSODAO implements metadataFieldsToJoin.addAll(queryFields); metadataFieldsToJoin.addAll(sortFields); - if(!CollectionUtils.isEmpty(metadataFieldsToJoin)) { + if (!CollectionUtils.isEmpty(metadataFieldsToJoin)) { addMetadataLeftJoin(queryBuilder, EPerson.class.getSimpleName().toLowerCase(), metadataFieldsToJoin); } - if(queryParam != null) { - addMetadataValueWhereQuery(queryBuilder, queryFields, "like", EPerson.class.getSimpleName().toLowerCase() + ".email like :queryParam"); + if (queryParam != null) { + addMetadataValueWhereQuery(queryBuilder, queryFields, "like", + EPerson.class.getSimpleName().toLowerCase() + ".email like :queryParam"); } - if(!CollectionUtils.isEmpty(sortFields)) { + if (!CollectionUtils.isEmpty(sortFields) || StringUtils.isNotBlank(sortField)) { addMetadataSortQuery(queryBuilder, sortFields, Collections.singletonList(sortField)); } Query query = createQuery(context, queryBuilder.toString()); if (pageSize > 0) { - query.setMaxResults(pageSize); + query.setMaxResults(pageSize); } if (offset > 0) { - query.setFirstResult(offset); + query.setFirstResult(offset); } - if(StringUtils.isNotBlank(queryParam)) { - query.setParameter("queryParam", "%"+queryParam.toLowerCase()+"%"); + if (StringUtils.isNotBlank(queryParam)) { + query.setParameter("queryParam", "%" + queryParam.toLowerCase() + "%"); } for (MetadataField metadataField : metadataFieldsToJoin) { query.setParameter(metadataField.toString(), metadataField.getID()); diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/Group2GroupCacheDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/Group2GroupCacheDAOImpl.java index 7c724819a3..717b41e8b9 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/Group2GroupCacheDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/Group2GroupCacheDAOImpl.java @@ -7,19 +7,21 @@ */ package org.dspace.eperson.dao.impl; -import org.dspace.core.Context; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; import org.dspace.eperson.Group; import org.dspace.eperson.Group2GroupCache; +import org.dspace.eperson.Group2GroupCache_; import org.dspace.eperson.dao.Group2GroupCacheDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.List; -import java.util.Set; /** * Hibernate implementation of the Database Access Object interface class for the Group2GroupCache object. @@ -28,58 +30,60 @@ import java.util.Set; * * @author kevinvandevelde at atmire.com */ -public class Group2GroupCacheDAOImpl extends AbstractHibernateDAO implements Group2GroupCacheDAO -{ - protected Group2GroupCacheDAOImpl() - { +public class Group2GroupCacheDAOImpl extends AbstractHibernateDAO implements Group2GroupCacheDAO { + protected Group2GroupCacheDAOImpl() { super(); } @Override public List findByParent(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, Group2GroupCache.class); - criteria.add(Restrictions.eq("parent.id", group.getID())); - criteria.setCacheable(true); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Group2GroupCache.class); + Root group2GroupCacheRoot = criteriaQuery.from(Group2GroupCache.class); + criteriaQuery.select(group2GroupCacheRoot); + criteriaQuery.where(criteriaBuilder.equal(group2GroupCacheRoot.get(Group2GroupCache_.parent), group)); + return list(context, criteriaQuery, true, Group2GroupCache.class, -1, -1); } @Override public List findByChildren(Context context, Iterable groups) throws SQLException { - Criteria criteria = createCriteria(context, Group2GroupCache.class); - - Disjunction orDisjunction = Restrictions.or(); - for(Group group : groups) - { - orDisjunction.add(Restrictions.eq("child.id", group.getID())); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Group2GroupCache.class); + Root group2GroupCacheRoot = criteriaQuery.from(Group2GroupCache.class); + List eqPredicates = new LinkedList<>(); + for (Group group : groups) { + eqPredicates.add(criteriaBuilder.equal(group2GroupCacheRoot.get(Group2GroupCache_.child), group)); } - - criteria.add(orDisjunction); - criteria.setCacheable(true); - - return list(criteria); + Predicate orPredicate = criteriaBuilder.or(eqPredicates.toArray(new Predicate[] {})); + criteriaQuery.select(group2GroupCacheRoot); + criteriaQuery.where(orPredicate); + return list(context, criteriaQuery, true, Group2GroupCache.class, -1, -1); } @Override public Group2GroupCache findByParentAndChild(Context context, Group parent, Group child) throws SQLException { Query query = createQuery(context, - "FROM Group2GroupCache g WHERE g.parent = :parentGroup AND g.child = :childGroup"); + "FROM Group2GroupCache g WHERE g.parent = :parentGroup AND g.child = :childGroup"); query.setParameter("parentGroup", parent); query.setParameter("childGroup", child); - - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query); } @Override public Group2GroupCache find(Context context, Group parent, Group child) throws SQLException { - Criteria criteria = createCriteria(context, Group2GroupCache.class); - criteria.add(Restrictions.eq("parent.id", parent.getID())); - criteria.add(Restrictions.eq("child.id", child.getID())); - criteria.setCacheable(true); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Group2GroupCache.class); + Root group2GroupCacheRoot = criteriaQuery.from(Group2GroupCache.class); + criteriaQuery.select(group2GroupCacheRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(group2GroupCacheRoot.get(Group2GroupCache_.parent), parent), + criteriaBuilder.equal(group2GroupCacheRoot.get(Group2GroupCache_.child), child) + ) + ); + return uniqueResult(context, criteriaQuery, true, Group2GroupCache.class, -1, -1); } @Override diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/GroupDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/GroupDAOImpl.java index d476a57943..8050bd9755 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/GroupDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/GroupDAOImpl.java @@ -7,6 +7,12 @@ */ package org.dspace.eperson.dao.impl; +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import javax.persistence.Query; + import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.dspace.content.MetadataField; @@ -15,12 +21,6 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.dao.GroupDAO; -import org.hibernate.Query; - -import java.sql.SQLException; -import java.util.Collections; -import java.util.List; -import java.util.UUID; /** * Hibernate implementation of the Database Access Object interface class for the Group object. @@ -29,16 +29,14 @@ import java.util.UUID; * * @author kevinvandevelde at atmire.com */ -public class GroupDAOImpl extends AbstractHibernateDSODAO implements GroupDAO -{ - protected GroupDAOImpl() - { +public class GroupDAOImpl extends AbstractHibernateDSODAO implements GroupDAO { + protected GroupDAOImpl() { super(); } @Override - public List findByMetadataField(Context context, String searchValue, MetadataField metadataField) throws SQLException - { + public List findByMetadataField(Context context, String searchValue, MetadataField metadataField) + throws SQLException { StringBuilder queryBuilder = new StringBuilder(); String groupTableName = "g"; queryBuilder.append("SELECT ").append(groupTableName).append(" FROM Group as ").append(groupTableName); @@ -54,8 +52,8 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou } @Override - public List findAll(Context context, List sortMetadataFields, int pageSize, int offset) throws SQLException - { + public List findAll(Context context, List sortMetadataFields, int pageSize, int offset) + throws SQLException { StringBuilder queryBuilder = new StringBuilder(); String groupTableName = "g"; queryBuilder.append("SELECT ").append(groupTableName).append(" FROM Group as ").append(groupTableName); @@ -65,10 +63,10 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou Query query = createQuery(context, queryBuilder.toString()); if (pageSize > 0) { - query.setMaxResults(pageSize); + query.setMaxResults(pageSize); } if (offset > 0) { - query.setFirstResult(offset); + query.setFirstResult(offset); } for (MetadataField sortField : sortMetadataFields) { query.setParameter(sortField.toString(), sortField.getID()); @@ -79,23 +77,24 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou @Override public List findAll(Context context, int pageSize, int offset) throws SQLException { Query query = createQuery(context, - "SELECT g FROM Group g ORDER BY g.name ASC"); + "SELECT g FROM Group g ORDER BY g.name ASC"); if (pageSize > 0) { - query.setMaxResults(pageSize); + query.setMaxResults(pageSize); } if (offset > 0) { - query.setFirstResult(offset); + query.setFirstResult(offset); } - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return list(query); } @Override public List findByEPerson(Context context, EPerson ePerson) throws SQLException { - Query query = createQuery(context, "from Group where (from EPerson e where e.id = :eperson_id) in elements(epeople)"); + Query query = createQuery(context, + "from Group where (from EPerson e where e.id = :eperson_id) in elements(epeople)"); query.setParameter("eperson_id", ePerson.getID()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return list(query); } @@ -103,54 +102,53 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou @Override public Group findByName(final Context context, final String name) throws SQLException { Query query = createQuery(context, - "SELECT g from Group g " + - "where g.name = :name "); + "SELECT g from Group g " + + "where g.name = :name "); query.setParameter("name", name); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query); } @Override public Group findByIdAndMembership(Context context, UUID id, EPerson ePerson) throws SQLException { - if(id == null || ePerson == null) { + if (id == null || ePerson == null) { return null; } else { Query query = createQuery(context, - "SELECT DISTINCT g FROM Group g " + - "LEFT JOIN g.epeople p " + - "WHERE g.id = :id AND " + - "(p.id = :eperson_id OR " + - "EXISTS ( " + - "SELECT 1 FROM Group2GroupCache gc " + - "JOIN gc.parent parent " + - "JOIN gc.child child " + - "JOIN child.epeople cp " + - "WHERE parent.id = g.id AND cp.id = :eperson_id " + - ") " + - ")"); + "SELECT DISTINCT g FROM Group g " + + "LEFT JOIN g.epeople p " + + "WHERE g.id = :id AND " + + "(p.id = :eperson_id OR " + + "EXISTS ( " + + "SELECT 1 FROM Group2GroupCache gc " + + "JOIN gc.parent parent " + + "JOIN gc.child child " + + "JOIN child.epeople cp " + + "WHERE parent.id = g.id AND cp.id = :eperson_id " + + ") " + + ")"); query.setParameter("id", id); query.setParameter("eperson_id", ePerson.getID()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query); } } @Override - public List findByNameLike(final Context context, final String groupName, final int offset, final int limit) throws SQLException { + public List findByNameLike(final Context context, final String groupName, final int offset, final int limit) + throws SQLException { Query query = createQuery(context, - "SELECT g FROM Group g WHERE lower(g.name) LIKE lower(:name)"); + "SELECT g FROM Group g WHERE lower(g.name) LIKE lower(:name)"); query.setParameter("name", "%" + StringUtils.trimToEmpty(groupName) + "%"); - if(0 <= offset) - { + if (0 <= offset) { query.setFirstResult(offset); } - if(0 <= limit) - { + if (0 <= limit) { query.setMaxResults(limit); } @@ -160,7 +158,7 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou @Override public int countByNameLike(final Context context, final String groupName) throws SQLException { Query query = createQuery(context, - "SELECT count(*) FROM Group g WHERE lower(g.name) LIKE lower(:name)"); + "SELECT count(*) FROM Group g WHERE lower(g.name) LIKE lower(:name)"); query.setParameter("name", "%" + groupName + "%"); return count(query); @@ -168,7 +166,8 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou @Override public void delete(Context context, Group group) throws SQLException { - Query query = getHibernateSession(context).createSQLQuery("DELETE FROM group2group WHERE parent_id=:groupId or child_id=:groupId"); + Query query = getHibernateSession(context) + .createSQLQuery("DELETE FROM group2group WHERE parent_id=:groupId or child_id=:groupId"); query.setParameter("groupId", group.getID()); query.executeUpdate(); super.delete(context, group); @@ -179,11 +178,11 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou public List> getGroup2GroupResults(Context context, boolean flushQueries) throws SQLException { Query query = createQuery(context, "SELECT new org.apache.commons.lang3.tuple.ImmutablePair(g.id, c.id) " + - "FROM Group g " + - "JOIN g.groups c "); + "FROM Group g " + + "JOIN g.groups c "); @SuppressWarnings("unchecked") - List> results = query.list(); + List> results = query.getResultList(); return results; } diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/RegistrationDataDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/RegistrationDataDAOImpl.java index 6ee611dc33..35fda4b62f 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/RegistrationDataDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/RegistrationDataDAOImpl.java @@ -7,15 +7,17 @@ */ package org.dspace.eperson.dao.impl; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.eperson.RegistrationData; -import org.dspace.eperson.dao.RegistrationDataDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.eperson.RegistrationData; +import org.dspace.eperson.RegistrationData_; +import org.dspace.eperson.dao.RegistrationDataDAO; /** * Hibernate implementation of the Database Access Object interface class for the RegistrationData object. @@ -24,26 +26,30 @@ import java.sql.SQLException; * * @author kevinvandevelde at atmire.com */ -public class RegistrationDataDAOImpl extends AbstractHibernateDAO implements RegistrationDataDAO -{ +public class RegistrationDataDAOImpl extends AbstractHibernateDAO implements RegistrationDataDAO { - protected RegistrationDataDAOImpl() - { + protected RegistrationDataDAOImpl() { super(); } @Override public RegistrationData findByEmail(Context context, String email) throws SQLException { - Criteria criteria = createCriteria(context, RegistrationData.class); - criteria.add(Restrictions.eq("email", email)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RegistrationData.class); + Root registrationDataRoot = criteriaQuery.from(RegistrationData.class); + criteriaQuery.select(registrationDataRoot); + criteriaQuery.where(criteriaBuilder.equal(registrationDataRoot.get(RegistrationData_.email), email)); + return uniqueResult(context, criteriaQuery, false, RegistrationData.class, -1, -1); } @Override public RegistrationData findByToken(Context context, String token) throws SQLException { - Criteria criteria = createCriteria(context, RegistrationData.class); - criteria.add(Restrictions.eq("token", token)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RegistrationData.class); + Root registrationDataRoot = criteriaQuery.from(RegistrationData.class); + criteriaQuery.select(registrationDataRoot); + criteriaQuery.where(criteriaBuilder.equal(registrationDataRoot.get(RegistrationData_.token), token)); + return uniqueResult(context, criteriaQuery, false, RegistrationData.class, -1, -1); } @Override diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java index e1d0d5e616..a90c5da5a1 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java @@ -7,19 +7,21 @@ */ package org.dspace.eperson.dao.impl; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.dspace.content.Collection; -import org.dspace.core.Context; import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Subscription; +import org.dspace.eperson.Subscription_; import org.dspace.eperson.dao.SubscriptionDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the Subscription object. @@ -28,35 +30,35 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class SubscriptionDAOImpl extends AbstractHibernateDAO implements SubscriptionDAO -{ - protected SubscriptionDAOImpl() - { +public class SubscriptionDAOImpl extends AbstractHibernateDAO implements SubscriptionDAO { + protected SubscriptionDAOImpl() { super(); } @Override public List findByEPerson(Context context, EPerson eperson) throws SQLException { - Criteria criteria = createCriteria(context, Subscription.class); - criteria.add( - Restrictions.and( - Restrictions.eq("ePerson", eperson) - ) - ); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + javax.persistence.criteria.CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class); + Root subscriptionRoot = criteriaQuery.from(Subscription.class); + criteriaQuery.select(subscriptionRoot); + criteriaQuery.where(criteriaBuilder.equal(subscriptionRoot.get(Subscription_.ePerson), eperson)); + return list(context, criteriaQuery, false, Subscription.class, -1, -1); } @Override - public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, Subscription.class); - criteria.add( - Restrictions.and( - Restrictions.eq("ePerson", eperson), - Restrictions.eq("collection", collection) - ) + public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + javax.persistence.criteria.CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class); + Root subscriptionRoot = criteriaQuery.from(Subscription.class); + criteriaQuery.select(subscriptionRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(subscriptionRoot.get(Subscription_.ePerson), eperson), + criteriaBuilder.equal(subscriptionRoot.get(Subscription_.collection), collection) + ) ); - return singleResult(criteria); + return singleResult(context, criteriaQuery); } @@ -77,7 +79,8 @@ public class SubscriptionDAOImpl extends AbstractHibernateDAO impl } @Override - public void deleteByCollectionAndEPerson(Context context, Collection collection, EPerson eperson) throws SQLException { + public void deleteByCollectionAndEPerson(Context context, Collection collection, EPerson eperson) + throws SQLException { String hqlQuery = "delete from Subscription where collection=:collection AND ePerson=:ePerson"; Query query = createQuery(context, hqlQuery); query.setParameter("collection", collection); @@ -87,8 +90,17 @@ public class SubscriptionDAOImpl extends AbstractHibernateDAO impl @Override public List findAllOrderedByEPerson(Context context) throws SQLException { - Criteria criteria = createCriteria(context, Subscription.class); - criteria.addOrder(Order.asc("eperson.id")); - return list(criteria); + + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class); + Root subscriptionRoot = criteriaQuery.from(Subscription.class); + criteriaQuery.select(subscriptionRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(subscriptionRoot.get(Subscription_.ePerson))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, false, Subscription.class, -1, -1); } } \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/eperson/factory/EPersonServiceFactory.java b/dspace-api/src/main/java/org/dspace/eperson/factory/EPersonServiceFactory.java index 987a14e92a..f7ce13a8a3 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/factory/EPersonServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/eperson/factory/EPersonServiceFactory.java @@ -7,11 +7,17 @@ */ package org.dspace.eperson.factory; -import org.dspace.eperson.service.*; +import org.dspace.eperson.service.AccountService; +import org.dspace.eperson.service.EPersonService; +import org.dspace.eperson.service.GroupService; +import org.dspace.eperson.service.RegistrationDataService; +import org.dspace.eperson.service.SubscribeService; +import org.dspace.eperson.service.SupervisorService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the eperson package, use EPersonServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the eperson package, use EPersonServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -29,7 +35,8 @@ public abstract class EPersonServiceFactory { public abstract SupervisorService getSupervisorService(); - public static EPersonServiceFactory getInstance(){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("ePersonServiceFactory", EPersonServiceFactory.class); + public static EPersonServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("ePersonServiceFactory", EPersonServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/eperson/factory/EPersonServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/eperson/factory/EPersonServiceFactoryImpl.java index e3ce2d2037..33d9249b6b 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/factory/EPersonServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/factory/EPersonServiceFactoryImpl.java @@ -7,11 +7,17 @@ */ package org.dspace.eperson.factory; -import org.dspace.eperson.service.*; +import org.dspace.eperson.service.AccountService; +import org.dspace.eperson.service.EPersonService; +import org.dspace.eperson.service.GroupService; +import org.dspace.eperson.service.RegistrationDataService; +import org.dspace.eperson.service.SubscribeService; +import org.dspace.eperson.service.SupervisorService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the eperson package, use EPersonServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the eperson package, use EPersonServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/eperson/service/AccountService.java b/dspace-api/src/main/java/org/dspace/eperson/service/AccountService.java index 714d5faa8a..c8ecb0cc67 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/service/AccountService.java +++ b/dspace-api/src/main/java/org/dspace/eperson/service/AccountService.java @@ -7,16 +7,15 @@ */ package org.dspace.eperson.service; +import java.io.IOException; +import java.sql.SQLException; +import javax.mail.MessagingException; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import javax.mail.MessagingException; -import java.io.IOException; -import java.sql.SQLException; - /** - * * Methods for handling registration by email and forgotten passwords. When * someone registers as a user, or forgets their password, the * sendRegistrationInfo or sendForgotPasswordInfo methods can be used to send an @@ -32,17 +31,19 @@ import java.sql.SQLException; */ public interface AccountService { - public void sendRegistrationInfo(Context context, String email) throws SQLException, IOException, MessagingException, AuthorizeException; + public void sendRegistrationInfo(Context context, String email) + throws SQLException, IOException, MessagingException, AuthorizeException; - public void sendForgotPasswordInfo(Context context, String email) throws SQLException, IOException, MessagingException, AuthorizeException; + public void sendForgotPasswordInfo(Context context, String email) + throws SQLException, IOException, MessagingException, AuthorizeException; public EPerson getEPerson(Context context, String token) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; public String getEmail(Context context, String token) - throws SQLException; + throws SQLException; public void deleteToken(Context context, String token) - throws SQLException; + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/eperson/service/EPersonService.java b/dspace-api/src/main/java/org/dspace/eperson/service/EPersonService.java index 9bf7035153..2c37a7a23a 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/service/EPersonService.java +++ b/dspace-api/src/main/java/org/dspace/eperson/service/EPersonService.java @@ -7,6 +7,11 @@ */ package org.dspace.eperson.service; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.Set; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.service.DSpaceObjectLegacySupportService; import org.dspace.content.service.DSpaceObjectService; @@ -15,14 +20,10 @@ import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.PasswordHash; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; -import java.util.Set; - /** * Service interface class for the EPerson object. - * The implementation of this class is responsible for all business logic calls for the EPerson object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the EPerson object and is + * autowired by spring * * Methods for handling registration by email and forgotten passwords. When * someone registers as a user, or forgets their password, the @@ -36,94 +37,75 @@ import java.util.Set; * * @author Peter Breton * @author kevinvandevelde at atmire.com - * * @version $Revision$ */ -public interface EPersonService extends DSpaceObjectService, DSpaceObjectLegacySupportService -{ +public interface EPersonService extends DSpaceObjectService, DSpaceObjectLegacySupportService { /** * Find the eperson by their email address. * - * @param context - * The relevant DSpace Context. - * @param email - * EPerson's email to search by + * @param context The relevant DSpace Context. + * @param email EPerson's email to search by * @return EPerson, or {@code null} if none such exists. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public EPerson findByEmail(Context context, String email) - throws SQLException; + throws SQLException; /** * Find the eperson by their netid. * - * @param context - * The relevant DSpace Context. - * @param netId - * Network ID - * + * @param context The relevant DSpace Context. + * @param netId Network ID * @return corresponding EPerson, or null - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public EPerson findByNetid(Context context, String netId) - throws SQLException; + throws SQLException; /** * Find the epeople that match the search query across firstname, lastname or email. * - * @param context - * The relevant DSpace Context. - * @param query - * The search string - * + * @param context The relevant DSpace Context. + * @param query The search string * @return array of EPerson objects - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List search(Context context, String query) - throws SQLException; + throws SQLException; /** * Find the epeople that match the search query across firstname, lastname or email. * This method also allows offsets and limits for pagination purposes. * - * @param context - * The relevant DSpace Context. - * @param query - * The search string - * @param offset - * Inclusive offset - * @param limit - * Maximum number of matches returned - * + * @param context The relevant DSpace Context. + * @param query The search string + * @param offset Inclusive offset + * @param limit Maximum number of matches returned * @return array of EPerson objects - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List search(Context context, String query, int offset, int limit) - throws SQLException; + throws SQLException; /** * Returns the total number of epeople returned by a specific query, without the overhead * of creating the EPerson objects to store the results. * - * @param context - * The relevant DSpace Context. - * @param query - * The search string - * + * @param context The relevant DSpace Context. + * @param query The search string * @return the number of epeople matching the query - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public int searchResultCount(Context context, String query) - throws SQLException; + throws SQLException; /** + * @param context The relevant DSpace Context. + * @param sortField which field to sort EPersons by + * @return list of EPerson objects + * @throws SQLException An exception that provides information on a database access error or other errors. * @deprecated use the paginated method. Find all the epeople in a specific order *
      *
    • ID
    • @@ -131,19 +113,11 @@ public interface EPersonService extends DSpaceObjectService, DSpaceObje *
    • EMAIL
    • *
    • NETID
    • *
    - * - * @param context - * The relevant DSpace Context. - * @param sortField - * which field to sort EPersons by - * @return list of EPerson objects - * @throws SQLException - * An exception that provides information on a database access error or other errors. */ @Deprecated public List findAll(Context context, int sortField) - throws SQLException; - + throws SQLException; + /** * Find all the epeople in a specific order *
      @@ -153,61 +127,48 @@ public interface EPersonService extends DSpaceObjectService, DSpaceObje *
    • NETID
    • *
    * - * @param context - * The relevant DSpace Context. - * @param sortField - * which field to sort EPersons by - * @param pageSize - * how many results return - * @param offset - * the position of the first result to return + * @param context The relevant DSpace Context. + * @param sortField which field to sort EPersons by + * @param pageSize how many results return + * @param offset the position of the first result to return * @return list of EPerson objects - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findAll(Context context, int sortField, int pageSize, int offset) - throws SQLException; + throws SQLException; /** * Create a new eperson * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return the created EPerson - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public EPerson create(Context context) throws SQLException, - AuthorizeException; + AuthorizeException; /** * Set the EPerson's password. * - * @param ePerson - * EPerson whose password we want to set. - * @param password - * the new password. + * @param ePerson EPerson whose password we want to set. + * @param password the new password. */ public void setPassword(EPerson ePerson, String password); /** * Set the EPerson's password hash. * - * @param ePerson - * EPerson whose password hash we want to set. - * @param password - * hashed password, or null to set row data to NULL. + * @param ePerson EPerson whose password hash we want to set. + * @param password hashed password, or null to set row data to NULL. */ public void setPasswordHash(EPerson ePerson, PasswordHash password); /** * Return the EPerson's password hash. * - * @param ePerson - * EPerson whose password hash we want to get. + * @param ePerson EPerson whose password hash we want to get. * @return hash of the password, or null on failure (such as no password). */ public PasswordHash getPasswordHash(EPerson ePerson); @@ -216,12 +177,9 @@ public interface EPersonService extends DSpaceObjectService, DSpaceObje * Check EPerson's password. Side effect: original unsalted MD5 hashes are * converted using the current algorithm. * - * @param context - * The relevant DSpace Context. - * @param ePerson - * EPerson whose password we want to check - * @param attempt - * the password attempt + * @param context The relevant DSpace Context. + * @param ePerson EPerson whose password we want to check + * @param attempt the password attempt * @return boolean successful/unsuccessful */ public boolean checkPassword(Context context, EPerson ePerson, String attempt); @@ -230,16 +188,11 @@ public interface EPersonService extends DSpaceObjectService, DSpaceObje * Set a metadata value (in the metadatavalue table) of the metadata field * specified by 'field'. * - * @param context - * The relevant DSpace Context. - * @param ePerson - * EPerson whose metadata we want to set. - * @param field - * Metadata field we want to set (e.g. "phone"). - * @param value - * Metadata value we want to set - * @throws SQLException - * if the requested metadata field doesn't exist + * @param context The relevant DSpace Context. + * @param ePerson EPerson whose metadata we want to set. + * @param field Metadata field we want to set (e.g. "phone"). + * @param value Metadata value we want to set + * @throws SQLException if the requested metadata field doesn't exist */ @Deprecated public void setMetadata(Context context, EPerson ePerson, String field, String value) throws SQLException; @@ -247,24 +200,19 @@ public interface EPersonService extends DSpaceObjectService, DSpaceObje /** * Retrieve all accounts which have a password but do not have a digest algorithm * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return a list of epeople - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findUnsalted(Context context) throws SQLException; /** * Retrieve all accounts which have not logged in since the specified date * - * @param context - * The relevant DSpace Context. - * @param date - * from which date + * @param context The relevant DSpace Context. + * @param date from which date * @return a list of epeople - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findNotActiveSince(Context context, Date date) throws SQLException; @@ -276,48 +224,38 @@ public interface EPersonService extends DSpaceObjectService, DSpaceObje * An EPerson cannot be deleted if it exists in the item, workflowitem, or * tasklistitem tables. * - * @param context - * The relevant DSpace Context. - * @param ePerson - * EPerson to find + * @param context The relevant DSpace Context. + * @param ePerson EPerson to find * @return List of tables that contain a reference to the eperson. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List getDeleteConstraints(Context context, EPerson ePerson) throws SQLException; /** * Retrieve all accounts which belong to at least one of the specified groups. * - * @param c - * The relevant DSpace Context. - * @param groups - * set of eperson groups + * @param c The relevant DSpace Context. + * @param groups set of eperson groups * @return a list of epeople - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findByGroups(Context c, Set groups) throws SQLException; /** * Retrieve all accounts which are subscribed to receive information about new items. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return a list of epeople - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ List findEPeopleWithSubscription(Context context) throws SQLException; /** * Count all accounts. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return the total number of epeople - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ int countTotal(Context context) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/eperson/service/GroupService.java b/dspace-api/src/main/java/org/dspace/eperson/service/GroupService.java index 959c0497ba..f750419af1 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/service/GroupService.java +++ b/dspace-api/src/main/java/org/dspace/eperson/service/GroupService.java @@ -7,6 +7,10 @@ */ package org.dspace.eperson.service; +import java.sql.SQLException; +import java.util.List; +import java.util.Set; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.MetadataField; import org.dspace.content.service.DSpaceObjectLegacySupportService; @@ -15,13 +19,10 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import java.sql.SQLException; -import java.util.List; -import java.util.Set; - /** * Service interface class for the Group object. - * The implementation of this class is responsible for all business logic calls for the Group object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Group object and is autowired + * by spring * * @author kevinvandevelde at atmire.com */ @@ -33,10 +34,9 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * Create a new group * - * @param context - * DSpace context object + * @param context DSpace context object * @return group - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public Group create(Context context) throws SQLException, AuthorizeException; @@ -45,8 +45,7 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * set name of group * * @param group DSpace group - * @param name - * new group name + * @param name new group name * @throws SQLException if database error */ public void setName(Group group, String name) throws SQLException; @@ -54,21 +53,18 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * add an eperson member * - * @param context - * DSpace context object - * @param group DSpace group - * @param e - * eperson + * @param context DSpace context object + * @param group DSpace group + * @param e eperson */ public void addMember(Context context, Group group, EPerson e); /** * add group to this group * - * @param context - * DSpace context object + * @param context DSpace context object * @param groupParent parent group - * @param groupChild child group + * @param groupChild child group * @throws SQLException if database error */ public void addMember(Context context, Group groupParent, Group groupChild) throws SQLException; @@ -76,11 +72,9 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * remove an eperson from a group * - * @param context - * DSpace context object - * @param group DSpace group - * @param ePerson - * eperson + * @param context DSpace context object + * @param group DSpace group + * @param ePerson eperson */ public void removeMember(Context context, Group group, EPerson ePerson); @@ -88,10 +82,9 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * remove group from this group * - * @param context - * DSpace context object + * @param context DSpace context object * @param groupParent parent group - * @param childGroup child group + * @param childGroup child group * @throws SQLException if database error */ public void removeMember(Context context, Group groupParent, Group childGroup) throws SQLException; @@ -100,9 +93,8 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * check to see if an eperson is a direct member. * If the eperson is a member via a subgroup will be returned false * - * @param group DSpace group - * @param ePerson - * eperson to check membership + * @param group DSpace group + * @param ePerson eperson to check membership * @return true or false */ public boolean isDirectMember(Group group, EPerson ePerson); @@ -112,7 +104,7 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * If childGroup is a subgroup via another group will be returned false * * @param owningGroup parent group - * @param childGroup child group + * @param childGroup child group * @return true or false */ public boolean isMember(Group owningGroup, Group childGroup); @@ -121,7 +113,7 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * Check to see if parentGroup is a direct or in-direct parent of a childGroup. * * @param parentGroup parent group - * @param childGroup child group + * @param childGroup child group * @return true or false */ public boolean isParentOf(Context context, Group parentGroup, Group childGroup) throws SQLException; @@ -131,10 +123,8 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * database lookup without instantiating all of the epeople objects and is * thus a static method * - * @param context - * context - * @param group - * group to check + * @param context context + * @param group group to check * @return true or false * @throws SQLException if database error */ @@ -146,10 +136,8 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * thus a static method. This method uses context.getCurrentUser() as * eperson whos membership should be checked. * - * @param context - * context - * @param groupName - * the name of the group to check + * @param context context + * @param groupName the name of the group to check * @return true or false * @throws SQLException if database error */ @@ -161,10 +149,8 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * thus a static method. The eperson whos membership should be checked must * be defined as method attribute. * - * @param context - * context - * @param groupName - * the name of the group to check + * @param context context + * @param groupName the name of the group to check * @return true or false * @throws SQLException if database error */ @@ -177,7 +163,7 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * * @param context DSpace context object. * @param eperson EPerson whos membership should be checked. - * @param group The group to check against. + * @param group The group to check against. * @return true or false * @throws SQLException if database error */ @@ -200,10 +186,8 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * specified group, or a member of a sub-group of the * specified group, etc. * - * @param context - * The relevant DSpace Context. - * @param group - * Group object + * @param context The relevant DSpace Context. + * @param group Group object * @return List of EPerson objects * @throws SQLException if error */ @@ -212,11 +196,8 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * Find the group by its name - assumes name is unique * - * @param context - * The relevant DSpace Context. - * @param name - * Group name to search for - * + * @param context The relevant DSpace Context. + * @param name Group name to search for * @return the named Group, or null if not found * @throws SQLException if error */ @@ -225,35 +206,30 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * Finds all groups in the site * - * @param context - * The relevant DSpace Context. - * @param metadataSortFields - * metadata fields to sort by, leave empty to sort by Name - * @param pageSize - * how many results return - * @param offset - * the position of the first result to return + * @param context The relevant DSpace Context. + * @param metadataSortFields metadata fields to sort by, leave empty to sort by Name + * @param pageSize how many results return + * @param offset the position of the first result to return * @return List of all groups in the site * @throws SQLException if error */ - public List findAll(Context context, List metadataSortFields, int pageSize, int offset) throws SQLException; + public List findAll(Context context, List metadataSortFields, int pageSize, int offset) + throws SQLException; /** - * @deprecated Please use {@code findAll(Context context, List metadataFieldsSort, int pageSize, int offset)} instead - * - * @param context - * The relevant DSpace Context. - * @param metadataSortFields - * metadata fields to sort by, leave empty to sort by Name - * + * @param context The relevant DSpace Context. + * @param metadataSortFields metadata fields to sort by, leave empty to sort by Name * @return List of all groups in the site * @throws SQLException if error + * @deprecated Please use {@code findAll(Context context, List metadataFieldsSort, int pageSize, + * int offset)} instead */ public List findAll(Context context, List metadataSortFields) throws SQLException; /** * DEPRECATED: Please use {@code findAll(Context context, List metadataFieldsSort)} instead - * @param context DSpace context + * + * @param context DSpace context * @param sortField sort field index * @return List of all groups in the site * @throws SQLException if error @@ -265,11 +241,8 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * Find the groups that match the search query across eperson_group_id or name * - * @param context - * DSpace context - * @param groupIdentifier - * The group name or group ID - * + * @param context DSpace context + * @param groupIdentifier The group name or group ID * @return array of Group objects * @throws SQLException if error */ @@ -278,15 +251,10 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * Find the groups that match the search query across eperson_group_id or name * - * @param context - * DSpace context - * @param groupIdentifier - * The group name or group ID - * @param offset - * Inclusive offset - * @param limit - * Maximum number of matches returned - * + * @param context DSpace context + * @param groupIdentifier The group name or group ID + * @param offset Inclusive offset + * @param limit Maximum number of matches returned * @return array of Group objects * @throws SQLException if error */ @@ -296,18 +264,16 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * Returns the total number of groups returned by a specific query, without the overhead * of creating the Group objects to store the results. * - * @param context - * DSpace context - * @param query - * The search string - * + * @param context DSpace context + * @param query The search string * @return the number of groups matching the query * @throws SQLException if error */ - public int searchResultCount(Context context, String query) throws SQLException; + public int searchResultCount(Context context, String query) throws SQLException; /** * Return true if group has no direct or indirect members + * * @param group DSpace group * @return true or false */ @@ -318,13 +284,14 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * "permanent". * * @param context the DSpace context - * @throws SQLException database exception + * @throws SQLException database exception * @throws AuthorizeException authorization error */ public void initDefaultGroupNames(Context context) throws SQLException, AuthorizeException; /** * Find all empty groups in DSpace + * * @param context The DSpace context * @return All empty groups * @throws SQLException database exception @@ -333,6 +300,7 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe /** * Count the total number of groups in DSpace + * * @param context The DSpace context * @return The total number of groups * @throws SQLException database exception @@ -343,11 +311,12 @@ public interface GroupService extends DSpaceObjectService, DSpaceObjectLe * Look up groups based on their value for a certain metadata field * (NOTE: name is not stored as metadata) * - * @param context The DSpace context - * @param searchValue The value to match + * @param context The DSpace context + * @param searchValue The value to match * @param metadataField The metadata field to search in * @return The groups that have a matching value for specified metadata field * @throws SQLException database exception */ - List findByMetadataField(Context context, String searchValue, MetadataField metadataField) throws SQLException; + List findByMetadataField(Context context, String searchValue, MetadataField metadataField) + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/eperson/service/RegistrationDataService.java b/dspace-api/src/main/java/org/dspace/eperson/service/RegistrationDataService.java index 0a1df4d560..d1e78fa2bc 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/service/RegistrationDataService.java +++ b/dspace-api/src/main/java/org/dspace/eperson/service/RegistrationDataService.java @@ -7,15 +7,16 @@ */ package org.dspace.eperson.service; +import java.sql.SQLException; + import org.dspace.core.Context; import org.dspace.eperson.RegistrationData; import org.dspace.service.DSpaceCRUDService; -import java.sql.SQLException; - /** * Service interface class for the RegistrationData object. - * The implementation of this class is responsible for all business logic calls for the RegistrationData object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the RegistrationData object and + * is autowired by spring * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/eperson/service/SubscribeService.java b/dspace-api/src/main/java/org/dspace/eperson/service/SubscribeService.java index 125d8cd008..347c69bf5b 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/service/SubscribeService.java +++ b/dspace-api/src/main/java/org/dspace/eperson/service/SubscribeService.java @@ -7,18 +7,19 @@ */ package org.dspace.eperson.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Subscription; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the Subscription object. - * The implementation of this class is responsible for all business logic calls for the Subscription object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Subscription object and is + * autowired by spring * Class defining methods for sending new item e-mail alerts to users * * @author kevinvandevelde at atmire.com @@ -29,11 +30,9 @@ public interface SubscribeService { * Subscribe an e-person to a collection. An e-mail will be sent every day a * new item appears in the collection. * - * @param context - * DSpace context + * @param context DSpace context * @return list of Subscription objects - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findAll(Context context) throws SQLException; @@ -41,117 +40,89 @@ public interface SubscribeService { * Subscribe an e-person to a collection. An e-mail will be sent every day a * new item appears in the collection. * - * @param context - * DSpace context - * @param eperson - * EPerson to subscribe - * @param collection - * Collection to subscribe to - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context DSpace context + * @param eperson EPerson to subscribe + * @param collection Collection to subscribe to + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void subscribe(Context context, EPerson eperson, - Collection collection) throws SQLException, AuthorizeException; + Collection collection) throws SQLException, AuthorizeException; /** * Unsubscribe an e-person to a collection. Passing in null * for the collection unsubscribes the e-person from all collections they * are subscribed to. * - * @param context - * DSpace context - * @param eperson - * EPerson to unsubscribe - * @param collection - * Collection to unsubscribe from - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context DSpace context + * @param eperson EPerson to unsubscribe + * @param collection Collection to unsubscribe from + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void unsubscribe(Context context, EPerson eperson, - Collection collection) throws SQLException, AuthorizeException; + Collection collection) throws SQLException, AuthorizeException; /** * Find out which collections an e-person is subscribed to * - * @param context - * DSpace context - * @param eperson - * EPerson + * @param context DSpace context + * @param eperson EPerson * @return array of collections e-person is subscribed to - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List getSubscriptions(Context context, EPerson eperson) throws SQLException; /** * Find out which collections the currently logged in e-person can subscribe to * - * @param context - * DSpace context + * @param context DSpace context * @return array of collections the currently logged in e-person can subscribe to - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List getAvailableSubscriptions(Context context) - throws SQLException; + throws SQLException; /** * Find out which collections an e-person can subscribe to * - * @param context - * DSpace context - * @param eperson - * EPerson + * @param context DSpace context + * @param eperson EPerson * @return array of collections e-person can subscribe to - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List getAvailableSubscriptions(Context context, EPerson eperson) - throws SQLException; + throws SQLException; /** * Is that e-person subscribed to that collection? * - * @param context - * DSpace context - * @param eperson - * find out if this e-person is subscribed - * @param collection - * find out if subscribed to this collection + * @param context DSpace context + * @param eperson find out if this e-person is subscribed + * @param collection find out if subscribed to this collection * @return true if they are subscribed - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean isSubscribed(Context context, EPerson eperson, - Collection collection) throws SQLException; + Collection collection) throws SQLException; /** * Delete subscription by collection. * - * @param context - * DSpace context - * @param collection - * find out if subscribed to this collection - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param context DSpace context + * @param collection find out if subscribed to this collection + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void deleteByCollection(Context context, Collection collection) throws SQLException; /** * Delete subscription by eperson (subscriber). * - * @param context - * DSpace context - * @param ePerson - * find out if this e-person is subscribed - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param context DSpace context + * @param ePerson find out if this e-person is subscribed + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void deleteByEPerson(Context context, EPerson ePerson) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/eperson/service/SupervisorService.java b/dspace-api/src/main/java/org/dspace/eperson/service/SupervisorService.java index 8a20c19fa0..470c9133e5 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/service/SupervisorService.java +++ b/dspace-api/src/main/java/org/dspace/eperson/service/SupervisorService.java @@ -7,43 +7,47 @@ */ package org.dspace.eperson.service; +import java.sql.SQLException; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.WorkspaceItem; import org.dspace.core.Context; import org.dspace.eperson.Group; -import java.sql.SQLException; - /** * Class to represent the supervisor, primarily for use in applying supervisor * activities to the database, such as setting and unsetting supervision * orders and so forth. * - * @author Richard Jones + * @author Richard Jones * @version $Revision$ */ public interface SupervisorService { - /** value to use for no policy set */ + /** + * value to use for no policy set + */ public static final int POLICY_NONE = 0; - /** value to use for editor policies */ + /** + * value to use for editor policies + */ public static final int POLICY_EDITOR = 1; - /** value to use for observer policies */ + /** + * value to use for observer policies + */ public static final int POLICY_OBSERVER = 2; /** * finds out if there is a supervision order that matches this set * of values * - * @param context the context this object exists in - * @param workspaceItem the workspace item to be supervised - * @param group the group to be doing the supervising - * + * @param context the context this object exists in + * @param workspaceItem the workspace item to be supervised + * @param group the group to be doing the supervising * @return boolean true if there is an order that matches, false if not - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean isOrder(Context context, WorkspaceItem workspaceItem, Group group) throws SQLException; @@ -53,14 +57,12 @@ public interface SupervisorService { * of supervision. This also removes all the policies that group has * associated with the item * - * @param context the context this object exists in - * @param workspaceItem the ID of the workspace item - * @param group the ID of the group to be removed from the item - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context the context this object exists in + * @param workspaceItem the ID of the workspace item + * @param group the ID of the group to be removed from the item + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void remove(Context context, WorkspaceItem workspaceItem, Group group) throws SQLException, AuthorizeException; @@ -68,15 +70,13 @@ public interface SupervisorService { /** * adds a supervision order to the database * - * @param context the context this object exists in - * @param group the ID of the group which will supervise - * @param workspaceItem the ID of the workspace item to be supervised - * @param policy String containing the policy type to be used - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context the context this object exists in + * @param group the ID of the group which will supervise + * @param workspaceItem the ID of the workspace item to be supervised + * @param policy String containing the policy type to be used + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void add(Context context, Group group, WorkspaceItem workspaceItem, int policy) throws SQLException, AuthorizeException; diff --git a/dspace-api/src/main/java/org/dspace/event/BasicDispatcher.java b/dspace-api/src/main/java/org/dspace/event/BasicDispatcher.java index 0712119657..63b2dab1a9 100644 --- a/dspace-api/src/main/java/org/dspace/event/BasicDispatcher.java +++ b/dspace-api/src/main/java/org/dspace/event/BasicDispatcher.java @@ -17,45 +17,41 @@ import org.dspace.core.Utils; * BasicDispatcher implements the primary task of a Dispatcher: it delivers a * filtered list of events, synchronously, to a configured list of consumers. It * may be extended for more elaborate behavior. - * + * * @version $Revision$ */ -public class BasicDispatcher extends Dispatcher -{ +public class BasicDispatcher extends Dispatcher { - public BasicDispatcher(String name) - { + public BasicDispatcher(String name) { super(name); } - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(BasicDispatcher.class); @Override public void addConsumerProfile(ConsumerProfile cp) - throws IllegalArgumentException - { - if (consumers.containsKey(cp.getName())) - { + throws IllegalArgumentException { + if (consumers.containsKey(cp.getName())) { throw new IllegalArgumentException( - "This dispatcher already has a consumer named \"" - + cp.getName() + "\""); + "This dispatcher already has a consumer named \"" + + cp.getName() + "\""); } consumers.put(cp.getName(), cp); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { int n = 0; - for (Iterator i = cp.getFilters().iterator(); i.hasNext(); ++n) - { + for (Iterator i = cp.getFilters().iterator(); i.hasNext(); ++n) { int f[] = (int[]) i.next(); log.debug("Adding Consumer=\"" + cp.getName() + "\", instance=" - + cp.getConsumer().toString() + ", filter[" - + String.valueOf(n) + "]=(ObjMask=" - + String.valueOf(f[Event.SUBJECT_MASK]) - + ", EventMask=" + String.valueOf(f[Event.EVENT_MASK]) - + ")"); + + cp.getConsumer().toString() + ", filter[" + + String.valueOf(n) + "]=(ObjMask=" + + String.valueOf(f[Event.SUBJECT_MASK]) + + ", EventMask=" + String.valueOf(f[Event.EVENT_MASK]) + + ")"); } } } @@ -63,25 +59,20 @@ public class BasicDispatcher extends Dispatcher /** * Dispatch all events added to this Context according to configured * consumers. - * - * @param ctx - * the execution context + * + * @param ctx the execution context */ @Override - public void dispatch(Context ctx) - { - if (!consumers.isEmpty()) - { + public void dispatch(Context ctx) { + if (!consumers.isEmpty()) { - if (!ctx.hasEvents()) - { + if (!ctx.hasEvents()) { return; } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Processing queue of " - + String.valueOf(ctx.getEvents().size()) + " events."); + + String.valueOf(ctx.getEvents().size()) + " events."); } // transaction identifier applies to all events created in @@ -89,43 +80,35 @@ public class BasicDispatcher extends Dispatcher // some letters so RDF readers don't mistake it for an integer. String tid = "TX" + Utils.generateKey(); - while (ctx.hasEvents()) - { + while (ctx.hasEvents()) { Event event = ctx.pollEvent(); event.setDispatcher(getIdentifier()); event.setTransactionID(tid); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Iterating over " - + String.valueOf(consumers.values().size()) - + " consumers..."); + + String.valueOf(consumers.values().size()) + + " consumers..."); } - for (Iterator ci = consumers.values().iterator(); ci.hasNext();) - { + for (Iterator ci = consumers.values().iterator(); ci.hasNext(); ) { ConsumerProfile cp = (ConsumerProfile) ci.next(); - if (event.pass(cp.getFilters())) - { - if (log.isDebugEnabled()) - { + if (event.pass(cp.getFilters())) { + if (log.isDebugEnabled()) { log.debug("Sending event to \"" + cp.getName() - + "\": " + event.toString()); + + "\": " + event.toString()); } - try - { + try { cp.getConsumer().consume(ctx, event); // Record that the event has been consumed by this // consumer event.setBitSet(cp.getName()); - } - catch (Exception e) - { + } catch (Exception e) { log.error("Consumer(\"" + cp.getName() - + "\").consume threw: " + e.toString(), e); + + "\").consume threw: " + e.toString(), e); } } @@ -133,25 +116,19 @@ public class BasicDispatcher extends Dispatcher } // Call end on the consumers that got synchronous events. - for (Iterator ci = consumers.values().iterator(); ci.hasNext();) - { + for (Iterator ci = consumers.values().iterator(); ci.hasNext(); ) { ConsumerProfile cp = (ConsumerProfile) ci.next(); - if (cp != null) - { - if (log.isDebugEnabled()) - { + if (cp != null) { + if (log.isDebugEnabled()) { log.debug("Calling end for consumer \"" + cp.getName() - + "\""); + + "\""); } - try - { + try { cp.getConsumer().end(ctx); - } - catch (Exception e) - { + } catch (Exception e) { log.error("Error in Consumer(\"" + cp.getName() - + "\").end: " + e.toString(), e); + + "\").end: " + e.toString(), e); } } } diff --git a/dspace-api/src/main/java/org/dspace/event/Consumer.java b/dspace-api/src/main/java/org/dspace/event/Consumer.java index 86ca537eef..1a8b16e98a 100644 --- a/dspace-api/src/main/java/org/dspace/event/Consumer.java +++ b/dspace-api/src/main/java/org/dspace/event/Consumer.java @@ -16,11 +16,10 @@ import org.dspace.core.Context; * consume() calls between the start and end of the event stream, if they are * invoked asynchronously, once in a long time period, rather than synchronously * after every Context.commit(). - * + * * @version $Revision$ */ -public interface Consumer -{ +public interface Consumer { /** * Initialize - allocate any resources required to operate. This may include * initializing any pooled JMS resources. Called ONCE when created by the @@ -36,11 +35,9 @@ public interface Consumer * it from the consumer. This behavior is based on the dispatcher/consumer * configuration. Should include logic to initialize any resources required * for a batch of events. - * - * @param ctx - * the execution context object - * @param event - * the content event + * + * @param ctx the execution context object + * @param event the content event * @throws Exception if error */ public void consume(Context ctx, Event event) throws Exception; @@ -48,9 +45,8 @@ public interface Consumer /** * Signal that there are no more events queued in this event stream and * event processing for the preceding consume calls should be finished up. - * - * @param ctx - * the execution context object + * + * @param ctx the execution context object * @throws Exception if error */ public void end(Context ctx) throws Exception; @@ -58,9 +54,8 @@ public interface Consumer /** * Finish - free any allocated resources. Called when consumer (via it's * parent dispatcher) is going to be destroyed by the dispatcher pool. - * - * @param ctx - * the execution context object + * + * @param ctx the execution context object * @throws Exception if error */ public void finish(Context ctx) throws Exception; diff --git a/dspace-api/src/main/java/org/dspace/event/ConsumerProfile.java b/dspace-api/src/main/java/org/dspace/event/ConsumerProfile.java index af012cc6c7..f43cc370f1 100644 --- a/dspace-api/src/main/java/org/dspace/event/ConsumerProfile.java +++ b/dspace-api/src/main/java/org/dspace/event/ConsumerProfile.java @@ -18,21 +18,28 @@ import org.dspace.core.ConfigurationManager; * named Consumer, in the context of a specific Dispatcher. This * includes the name, the class to instantiate and event filters. Note that all * characteristics are "global" and the same for all dispatchers. - * + * * @version $Revision$ */ -public class ConsumerProfile -{ - /** log4j category */ +public class ConsumerProfile { + /** + * log4j category + */ private static Logger log = Logger.getLogger(ConsumerProfile.class); - /** Name matching the key in DSpace Configuration */ + /** + * Name matching the key in DSpace Configuration + */ private String name; - /** Instance of configured consumer class */ + /** + * Instance of configured consumer class + */ private Consumer consumer; - /** Filters - each is an array of 2 bitmasks, action mask and subject mask */ + /** + * Filters - each is an array of 2 bitmasks, action mask and subject mask + */ private List filters; // Prefix of keys in DSpace Configuration. @@ -41,29 +48,23 @@ public class ConsumerProfile /** * Constructor. */ - private ConsumerProfile(String name) - { + private ConsumerProfile(String name) { this.name = name; } /** * Factory method, create new profile from configuration. - * - * @param name - * configuration name of the consumer profile + * + * @param name configuration name of the consumer profile * @return a new ConsumerProfile; never null. * @throws IllegalArgumentException if no class or no filters configured for the specified consumer - * @throws ClassNotFoundException passed through. - * - * @throws InstantiationException passed through. - * - * @throws IllegalAccessException passed through. - * + * @throws ClassNotFoundException passed through. + * @throws InstantiationException passed through. + * @throws IllegalAccessException passed through. */ public static ConsumerProfile makeConsumerProfile(String name) throws IllegalArgumentException, ClassNotFoundException, - InstantiationException, IllegalAccessException - { + InstantiationException, IllegalAccessException { ConsumerProfile result = new ConsumerProfile(name); result.readConfiguration(); return result; @@ -71,34 +72,28 @@ public class ConsumerProfile /** * Get class and filters from DSpace Configuration. - * + * * @throws IllegalArgumentException if no class or no filters configured for the specified consumer - * @throws ClassNotFoundException passed through. - * - * @throws InstantiationException passed through. - * - * @throws IllegalAccessException passed through. - * + * @throws ClassNotFoundException passed through. + * @throws InstantiationException passed through. + * @throws IllegalAccessException passed through. */ - + private void readConfiguration() throws IllegalArgumentException, ClassNotFoundException, - InstantiationException, IllegalAccessException - { + InstantiationException, IllegalAccessException { String className = ConfigurationManager.getProperty(CONSUMER_PREFIX - + name + ".class"); + + name + ".class"); String filterString = ConfigurationManager.getProperty(CONSUMER_PREFIX - + name + ".filters"); + + name + ".filters"); - if (className == null) - { + if (className == null) { throw new IllegalArgumentException( - "No class configured for consumer named: " + name); + "No class configured for consumer named: " + name); } - if (filterString == null) - { + if (filterString == null) { throw new IllegalArgumentException( - "No filters configured for consumer named: " + name); + "No filters configured for consumer named: " + name); } consumer = (Consumer) Class.forName(className.trim()).newInstance(); @@ -106,51 +101,39 @@ public class ConsumerProfile // Each "filter" is + : ... filters = new ArrayList(); String part[] = filterString.trim().split(":"); - for (int j = 0; j < part.length; ++j) - { + for (int j = 0; j < part.length; ++j) { String fpart[] = part[j].split("\\+"); - if (fpart.length != 2) - { + if (fpart.length != 2) { log.error("Bad Filter clause in consumer stanza in Configuration entry for " - + CONSUMER_PREFIX - + name - + ".consumers: " - + part[j]); - } - else - { + + CONSUMER_PREFIX + + name + + ".consumers: " + + part[j]); + } else { int filter[] = new int[2]; filter[0] = 0; filter[1] = 0; String objectNames[] = fpart[0].split("\\|"); - for (int k = 0; k < objectNames.length; ++k) - { + for (int k = 0; k < objectNames.length; ++k) { int ot = Event.parseObjectType(objectNames[k]); - if (ot == 0) - { + if (ot == 0) { log.error("Bad ObjectType in Consumer Stanza in Configuration entry for " - + CONSUMER_PREFIX - + name - + ".consumers: " + objectNames[k]); - } - else - { + + CONSUMER_PREFIX + + name + + ".consumers: " + objectNames[k]); + } else { filter[Event.SUBJECT_MASK] |= ot; } } String eventNames[] = fpart[1].split("\\|"); - for (int k = 0; k < eventNames.length; ++k) - { + for (int k = 0; k < eventNames.length; ++k) { int et = Event.parseEventType(eventNames[k]); - if (et == 0) - { + if (et == 0) { log.error("Bad EventType in Consumer Stanza in Configuration entry for " - + CONSUMER_PREFIX - + name - + ".consumers: " + eventNames[k]); - } - else - { + + CONSUMER_PREFIX + + name + + ".consumers: " + eventNames[k]); + } else { filter[Event.EVENT_MASK] |= et; } } @@ -159,18 +142,15 @@ public class ConsumerProfile } } - public Consumer getConsumer() - { + public Consumer getConsumer() { return consumer; } - public List getFilters() - { + public List getFilters() { return filters; } - public String getName() - { + public String getName() { return name; } } diff --git a/dspace-api/src/main/java/org/dspace/event/Dispatcher.java b/dspace-api/src/main/java/org/dspace/event/Dispatcher.java index 2f87fd533e..0c7793d7c8 100644 --- a/dspace-api/src/main/java/org/dspace/event/Dispatcher.java +++ b/dspace-api/src/main/java/org/dspace/event/Dispatcher.java @@ -18,14 +18,15 @@ import org.dspace.core.Context; * deliver a set of events to a configured list of consumers. It may also * transform, consolidate, and otherwise optimize the event stream prior to * delivering events to its consumers. - * + * * @version $Revision$ */ -public abstract class Dispatcher -{ +public abstract class Dispatcher { protected String name; - /** unique identifier of this dispatcher - cached hash of its text Name */ + /** + * unique identifier of this dispatcher - cached hash of its text Name + */ protected int identifier; /** @@ -33,41 +34,36 @@ public abstract class Dispatcher */ protected Map consumers = new LinkedHashMap(); - protected Dispatcher(String name) - { + protected Dispatcher(String name) { super(); this.name = name; this.identifier = name.hashCode(); } - public Collection getConsumers() - { + public Collection getConsumers() { return consumers.values(); } /** * @return unique integer that identifies this Dispatcher configuration. */ - public int getIdentifier() - { + public int getIdentifier() { return identifier; } /** * Add a consumer profile to the end of the list. - * - * @param cp - * the event consumer profile to add + * + * @param cp the event consumer profile to add */ public abstract void addConsumerProfile(ConsumerProfile cp) - throws IllegalArgumentException; + throws IllegalArgumentException; /** * Dispatch all events added to this Context according to configured * consumers. - * - * @param ctx - * the execution context object + * + * @param ctx the execution context object */ public abstract void dispatch(Context ctx); diff --git a/dspace-api/src/main/java/org/dspace/event/Event.java b/dspace-api/src/main/java/org/dspace/event/Event.java index d3ab5af28f..45b54362d6 100644 --- a/dspace-api/src/main/java/org/dspace/event/Event.java +++ b/dspace-api/src/main/java/org/dspace/event/Event.java @@ -9,7 +9,12 @@ package org.dspace.event; import java.io.Serializable; import java.sql.SQLException; -import java.util.*; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.log4j.Logger; @@ -43,16 +48,17 @@ import org.dspace.event.factory.EventServiceFactory; * significance varies by the combination of action and subject type. *
  • - timestamp -- exact millisecond timestamp at which event was logged.
  • * - * + * * @version $Revision$ */ -public class Event implements Serializable -{ +public class Event implements Serializable { private static final long serialVersionUID = 1L; /** ---------- Constants ------------- * */ - /** Event (Action) types */ + /** + * Event (Action) types + */ public static final int CREATE = 1 << 0; // create new object public static final int MODIFY = 1 << 1; // modify object @@ -67,17 +73,21 @@ public class Event implements Serializable public static final int INSTALL = 1 << 6; // object exits workspace/flow - /** Index of filter parts in their array: */ + /** + * Index of filter parts in their array: + */ public static final int SUBJECT_MASK = 0; // mask of subject types public static final int EVENT_MASK = 1; // mask of event type // XXX NOTE: keep this up to date with any changes to event (action) types. - protected static final String eventTypeText[] = { "CREATE", "MODIFY", - "MODIFY_METADATA", "ADD", "REMOVE", "DELETE", "INSTALL" }; + protected static final String eventTypeText[] = {"CREATE", "MODIFY", + "MODIFY_METADATA", "ADD", "REMOVE", "DELETE", "INSTALL"}; /** XXX NOTE: These constants must be kept synchronized * */ - /** XXX NOTE: with ALL_OBJECTS_MASK *AND* objTypeToMask hash * */ + /** + * XXX NOTE: with ALL_OBJECTS_MASK *AND* objTypeToMask hash * + */ protected static final int NONE = 0; protected static final int BITSTREAM = 1 << Constants.BITSTREAM; // 0 @@ -97,13 +107,13 @@ public class Event implements Serializable protected static final int EPERSON = 1 << Constants.EPERSON; // 7 protected static final int ALL_OBJECTS_MASK = BITSTREAM | BUNDLE | ITEM - | COLLECTION | COMMUNITY | SITE | GROUP | EPERSON; + | COLLECTION | COMMUNITY | SITE | GROUP | EPERSON; protected static Map objTypeToMask = new HashMap(); protected static Map objMaskToType = new HashMap(); - static - { + + static { objTypeToMask.put(Constants.BITSTREAM, BITSTREAM); objMaskToType.put(BITSTREAM, Constants.BITSTREAM); @@ -131,25 +141,39 @@ public class Event implements Serializable /** ---------- Event Fields ------------- * */ - /** identifier of Dispatcher that created this event (hash of its name) */ + /** + * identifier of Dispatcher that created this event (hash of its name) + */ private int dispatcher; - /** event (action) type - above enumeration */ + /** + * event (action) type - above enumeration + */ private int eventType; - /** object-type of SUBJECT - see above enumeration */ + /** + * object-type of SUBJECT - see above enumeration + */ private int subjectType; - /** content model identifier */ + /** + * content model identifier + */ private UUID subjectID; - /** object-type of SUBJECT - see above enumeration */ + /** + * object-type of SUBJECT - see above enumeration + */ private int objectType = NONE; - /** content model identifier */ + /** + * content model identifier + */ private UUID objectID = null; - /** timestamp */ + /** + * timestamp + */ private long timeStamp; /** "detail" - arbitrary field for relevant detail, */ @@ -178,58 +202,55 @@ public class Event implements Serializable */ private ArrayList identifiers; - /** unique key to bind together events from one context's transaction */ + /** + * unique key to bind together events from one context's transaction + */ private String transactionID; /** identity of authenticated user, i.e. context.getCurrentUser(). */ - /** Only needed in the event for marshalling for asynch event messages */ + /** + * Only needed in the event for marshalling for asynch event messages + */ private int currentUser = -1; /** copy of context's "extraLogInfo" field. Used only for */ - /** marshalling for asynch event messages. */ + /** + * marshalling for asynch event messages. + */ private String extraLogInfo = null; private BitSet consumedBy = new BitSet(); - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(Event.class); /** * Constructor. - * - * You should consider to use + * + * You should consider to use * {@link Event#Event(int, int, UUID, java.lang.String)}. - * - * @param eventType - * action type, e.g. Event.ADD. - * @param subjectType - * DSpace Object Type of subject e.g. Constants.ITEM. - * @param subjectID - * database ID of subject instance. - * @param detail - * detail information that depends on context. + * + * @param eventType action type, e.g. Event.ADD. + * @param subjectType DSpace Object Type of subject e.g. Constants.ITEM. + * @param subjectID database ID of subject instance. + * @param detail detail information that depends on context. */ - public Event(int eventType, int subjectType, UUID subjectID, String detail) - { + public Event(int eventType, int subjectType, UUID subjectID, String detail) { this(eventType, subjectType, subjectID, detail, new ArrayList()); } - + /** * Constructor. - * - * @param eventType - * action type, e.g. Event.ADD. - * @param subjectType - * DSpace Object Type of subject e.g. Constants.ITEM. - * @param subjectID - * database ID of subject instance. - * @param detail - * detail information that depends on context. - * @param identifiers - * array containing all identifiers of the dso or an empty array + * + * @param eventType action type, e.g. Event.ADD. + * @param subjectType DSpace Object Type of subject e.g. Constants.ITEM. + * @param subjectID database ID of subject instance. + * @param detail detail information that depends on context. + * @param identifiers array containing all identifiers of the dso or an empty array */ - public Event(int eventType, int subjectType, UUID subjectID, String detail, ArrayList identifiers) - { + public Event(int eventType, int subjectType, UUID subjectID, String detail, ArrayList identifiers) { this.eventType = eventType; this.subjectType = coreTypeToMask(subjectType); this.subjectID = subjectID; @@ -237,54 +258,39 @@ public class Event implements Serializable this.detail = detail; this.identifiers = (ArrayList) identifiers.clone(); } - + /** * Constructor. - * - * You should consider to use + * + * You should consider to use * {@link Event#Event(int, int, UUID, int, UUID, java.lang.String)} instead. - * - * @param eventType - * action type, e.g. Event.ADD. - * @param subjectType - * DSpace Object Type of subject e.g. Constants.ITEM. - * @param subjectID - * database ID of subject instance. - * @param objectType - * DSpace Object Type of object e.g. Constants.BUNDLE. - * @param objectID - * database ID of object instance. - * @param detail - * detail information that depends on context. + * + * @param eventType action type, e.g. Event.ADD. + * @param subjectType DSpace Object Type of subject e.g. Constants.ITEM. + * @param subjectID database ID of subject instance. + * @param objectType DSpace Object Type of object e.g. Constants.BUNDLE. + * @param objectID database ID of object instance. + * @param detail detail information that depends on context. */ public Event(int eventType, int subjectType, UUID subjectID, int objectType, - UUID objectID, String detail) - { - this(eventType, subjectType, subjectID, objectType, objectID, detail, - new ArrayList()); + UUID objectID, String detail) { + this(eventType, subjectType, subjectID, objectType, objectID, detail, + new ArrayList()); } /** * Constructor. - * - * @param eventType - * action type, e.g. Event.ADD. - * @param subjectType - * DSpace Object Type of subject e.g. Constants.ITEM. - * @param subjectID - * database ID of subject instance. - * @param objectType - * DSpace Object Type of object e.g. Constants.BUNDLE. - * @param objectID - * database ID of object instance. - * @param detail - * detail information that depends on context. - * @param identifiers - * array containing all identifiers of the dso or an empty array + * + * @param eventType action type, e.g. Event.ADD. + * @param subjectType DSpace Object Type of subject e.g. Constants.ITEM. + * @param subjectID database ID of subject instance. + * @param objectType DSpace Object Type of object e.g. Constants.BUNDLE. + * @param objectID database ID of object instance. + * @param detail detail information that depends on context. + * @param identifiers array containing all identifiers of the dso or an empty array */ public Event(int eventType, int subjectType, UUID subjectID, int objectType, - UUID objectID, String detail, ArrayList identifiers) - { + UUID objectID, String detail, ArrayList identifiers) { this.eventType = eventType; this.subjectType = coreTypeToMask(subjectType); this.subjectID = subjectID; @@ -298,30 +304,26 @@ public class Event implements Serializable /** * Compare two events. Ignore any difference in the timestamps. Also ignore * transactionID since that is not always set initially. - * - * @param other - * the event to compare this one to + * + * @param other the event to compare this one to * @return true if events are "equal", false otherwise. */ - public boolean equals(Object other) - { - if (other instanceof Event) - { - Event otherEvent = (Event)other; + public boolean equals(Object other) { + if (other instanceof Event) { + Event otherEvent = (Event) other; return (this.detail == null ? otherEvent.detail == null : this.detail - .equals(otherEvent.detail)) - && this.eventType == otherEvent.eventType - && this.subjectType == otherEvent.subjectType - && this.subjectID == otherEvent.subjectID - && this.objectType == otherEvent.objectType - && this.objectID == otherEvent.objectID; + .equals(otherEvent.detail)) + && this.eventType == otherEvent.eventType + && this.subjectType == otherEvent.subjectType + && this.subjectID == otherEvent.subjectID + && this.objectType == otherEvent.objectType + && this.objectID == otherEvent.objectID; } return false; } - public int hashCode() - { + public int hashCode() { return new HashCodeBuilder().append(this.detail) .append(eventType) .append(subjectType) @@ -333,62 +335,46 @@ public class Event implements Serializable /** * Set the identifier of the dispatcher that first processed this event. - * - * @param id - * the unique (hash code) value characteristic of the dispatcher. + * + * @param id the unique (hash code) value characteristic of the dispatcher. */ - public void setDispatcher(int id) - { + public void setDispatcher(int id) { dispatcher = id; } // translate a "core.Constants" object type value to local bitmask value. - protected int coreTypeToMask(int core) - { + protected int coreTypeToMask(int core) { Integer mask = objTypeToMask.get(core); - if (mask == null) - { + if (mask == null) { return -1; - } - else - { + } else { return mask.intValue(); } } // translate bitmask object-type to "core.Constants" object type. - protected int maskTypeToCore(int mask) - { + protected int maskTypeToCore(int mask) { Integer core = objMaskToType.get(mask); - if (core == null) - { + if (core == null) { return -1; - } - else - { + } else { return core.intValue(); } } /** * Get the DSpace object which is the "object" of an event. - * - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. * @return DSpaceObject or null if none can be found or no object was set. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ - public DSpaceObject getObject(Context context) throws SQLException - { + public DSpaceObject getObject(Context context) throws SQLException { int type = getObjectType(); UUID id = getObjectID(); - if (type < 0 || id == null) - { + if (type < 0 || id == null) { return null; - } - else - { + } else { return ContentServiceFactory.getInstance().getDSpaceObjectService(type).find(context, id); } } @@ -396,63 +382,53 @@ public class Event implements Serializable /** * Syntactic sugar to get the DSpace object which is the "subject" of an * event. - * - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. * @return DSpaceObject or null if none can be found. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ - public DSpaceObject getSubject(Context context) throws SQLException - { - return ContentServiceFactory.getInstance().getDSpaceObjectService(getSubjectType()).find(context, getSubjectID()); + public DSpaceObject getSubject(Context context) throws SQLException { + return ContentServiceFactory.getInstance().getDSpaceObjectService(getSubjectType()) + .find(context, getSubjectID()); } /** * @return database ID of subject of this event. */ - public UUID getSubjectID() - { + public UUID getSubjectID() { return subjectID; } /** * @return database ID of object of this event, or -1 if none was set. */ - public UUID getObjectID() - { + public UUID getObjectID() { return objectID; } /** * @return type number (e.g. Constants.ITEM) of subject of this event. */ - public int getSubjectType() - { + public int getSubjectType() { return maskTypeToCore(subjectType); } /** * @return type number (e.g. Constants.ITEM) of object of this event, or -1 - * if none was set. + * if none was set. */ - public int getObjectType() - { + public int getObjectType() { return maskTypeToCore(objectType); } /** * @return type of subject of this event as a String, e.g. for logging. */ - public String getSubjectTypeAsString() - { + public String getSubjectTypeAsString() { int i = log2(subjectType); - if (i >= 0 && i < Constants.typeText.length) - { + if (i >= 0 && i < Constants.typeText.length) { return Constants.typeText[i]; - } - else - { + } else { return "(Unknown)"; } } @@ -460,15 +436,11 @@ public class Event implements Serializable /** * @return type of object of this event as a String, e.g. for logging. */ - public String getObjectTypeAsString() - { + public String getObjectTypeAsString() { int i = log2(objectType); - if (i >= 0 && i < Constants.typeText.length) - { + if (i >= 0 && i < Constants.typeText.length) { return Constants.typeText[i]; - } - else - { + } else { return "(Unknown)"; } } @@ -477,22 +449,16 @@ public class Event implements Serializable * Translate a textual DSpace Object type name into an event subject-type * mask. NOTE: This returns a BIT-MASK, not a numeric type value; the mask * is only used within the event system. - * - * @param s - * text name of object type. + * + * @param s text name of object type. * @return numeric value of object type or 0 for error. */ - public static int parseObjectType(String s) - { - if ("*".equals(s) || "all".equalsIgnoreCase(s)) - { + public static int parseObjectType(String s) { + if ("*".equals(s) || "all".equalsIgnoreCase(s)) { return ALL_OBJECTS_MASK; - } - else - { + } else { int id = Constants.getTypeID(s.toUpperCase()); - if (id >= 0) - { + if (id >= 0) { return 1 << id; } } @@ -501,55 +467,44 @@ public class Event implements Serializable /** * @return event-type (i.e. action) this event, one of the masks like - * Event.ADD defined above. + * Event.ADD defined above. */ - public int getEventType() - { + public int getEventType() { return eventType; } /** * Get the text name of event (action) type. - * + * * @return event-type (i.e. action) this event as a String, e.g. for - * logging. + * logging. */ - public String getEventTypeAsString() - { + public String getEventTypeAsString() { int i = log2(eventType); - if (i >= 0 && i < eventTypeText.length) - { + if (i >= 0 && i < eventTypeText.length) { return eventTypeText[i]; - } - else - { + } else { return "(Unknown)"; } } /** * Interpret named event type. - * - * @param s - * name of event type. + * + * @param s name of event type. * @return numeric value of event type or 0 for error. */ - public static int parseEventType(String s) - { - if ("*".equals(s) || "all".equalsIgnoreCase(s)) - { + public static int parseEventType(String s) { + if ("*".equals(s) || "all".equalsIgnoreCase(s)) { int result = 0; - for (int i = 0; i < eventTypeText.length; ++i) - { + for (int i = 0; i < eventTypeText.length; ++i) { result |= (1 << i); } return result; } - for (int i = 0; i < eventTypeText.length; ++i) - { - if (eventTypeText[i].equalsIgnoreCase(s)) - { + for (int i = 0; i < eventTypeText.length; ++i) { + if (eventTypeText[i].equalsIgnoreCase(s)) { return 1 << i; } } @@ -558,35 +513,31 @@ public class Event implements Serializable /** * @return timestamp at which event occurred, as a count of milliseconds - * since the epoch (standard Java format). + * since the epoch (standard Java format). */ - public long getTimeStamp() - { + public long getTimeStamp() { return timeStamp; } /** * @return hashcode identifier of name of Dispatcher which first dispatched - * this event. (Needed by asynch dispatch code.) + * this event. (Needed by asynch dispatch code.) */ - public int getDispatcher() - { + public int getDispatcher() { return dispatcher; } /** * @return value of detail element of the event. */ - public String getDetail() - { + public String getDetail() { return detail; } - + /** * @return array of identifiers of this event's subject. */ - public List getIdentifiers() - { + public List getIdentifiers() { // don't return a reference to our private array, clone it. return (List) identifiers.clone(); } @@ -594,84 +545,67 @@ public class Event implements Serializable /** * @return value of transactionID element of the event. */ - public String getTransactionID() - { + public String getTransactionID() { return transactionID; } /** * Sets value of transactionID element of the event. - * - * @param tid - * new value of transactionID. + * + * @param tid new value of transactionID. */ - public void setTransactionID(String tid) - { + public void setTransactionID(String tid) { transactionID = tid; } - public void setCurrentUser(int uid) - { + public void setCurrentUser(int uid) { currentUser = uid; } - public int getCurrentUser() - { + public int getCurrentUser() { return currentUser; } - public void setExtraLogInfo(String info) - { + public void setExtraLogInfo(String info) { extraLogInfo = info; } - public String getExtraLogInfo() - { + public String getExtraLogInfo() { return extraLogInfo; } /** * Test whether this event would pass through a list of filters. - * - * @param filters - * list of filter masks; each one is an Array of two ints. + * + * @param filters list of filter masks; each one is an Array of two ints. * @return true if this event would be passed through the given filter - * list. + * list. */ - public boolean pass(List filters) - { + public boolean pass(List filters) { boolean result = false; - for (int filter[] : filters) - { - if ((subjectType & filter[SUBJECT_MASK]) != 0 && (eventType & filter[EVENT_MASK]) != 0) - { + for (int filter[] : filters) { + if ((subjectType & filter[SUBJECT_MASK]) != 0 && (eventType & filter[EVENT_MASK]) != 0) { result = true; } } - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Filtering event: " + "eventType=" - + String.valueOf(eventType) + ", subjectType=" - + String.valueOf(subjectType) + ", result=" - + String.valueOf(result)); + + String.valueOf(eventType) + ", subjectType=" + + String.valueOf(subjectType) + ", result=" + + String.valueOf(result)); } return result; } // dumb integer "log base 2", returns -1 if there are no 1's in number. - protected int log2(int n) - { - for (int i = 0; i < 32; ++i) - { - if (n == 1) - { + protected int log2(int n) { + for (int i = 0; i < 32; ++i) { + if (n == 1) { return i; - } - else - { + } else { n = n >> 1; } } @@ -682,47 +616,43 @@ public class Event implements Serializable * Keeps track of which consumers have consumed the event. Should be * called by a dispatcher when calling consume(Context ctx, String name, * Event event) on an event. - * - * @param consumerName - * name of consumer which has consumed the event + * + * @param consumerName name of consumer which has consumed the event */ - public void setBitSet(String consumerName) - { + public void setBitSet(String consumerName) { consumedBy.set(EventServiceFactory.getInstance().getEventService().getConsumerIndex(consumerName)); } /** * @return the set of consumers which have consumed this Event. */ - public BitSet getBitSet() - { + public BitSet getBitSet() { return consumedBy; } /** * @return Detailed string representation of contents of this event, to - * help in logging and debugging. + * help in logging and debugging. */ - public String toString() - { + public String toString() { return "org.dspace.event.Event(eventType=" - + this.getEventTypeAsString() - + ", SubjectType=" - + this.getSubjectTypeAsString() - + ", SubjectID=" - + String.valueOf(subjectID) - + ", ObjectType=" - + this.getObjectTypeAsString() - + ", ObjectID=" - + String.valueOf(objectID) - + ", TimeStamp=" - + String.valueOf(timeStamp) - + ", dispatcher=" - + String.valueOf(dispatcher) - + ", detail=" - + (detail == null ? "[null]" : "\"" + detail + "\"") - + ", transactionID=" - + (transactionID == null ? "[null]" : "\"" + transactionID - + "\"") + ")"; + + this.getEventTypeAsString() + + ", SubjectType=" + + this.getSubjectTypeAsString() + + ", SubjectID=" + + String.valueOf(subjectID) + + ", ObjectType=" + + this.getObjectTypeAsString() + + ", ObjectID=" + + String.valueOf(objectID) + + ", TimeStamp=" + + String.valueOf(timeStamp) + + ", dispatcher=" + + String.valueOf(dispatcher) + + ", detail=" + + (detail == null ? "[null]" : "\"" + detail + "\"") + + ", transactionID=" + + (transactionID == null ? "[null]" : "\"" + transactionID + + "\"") + ")"; } } diff --git a/dspace-api/src/main/java/org/dspace/event/EventServiceImpl.java b/dspace-api/src/main/java/org/dspace/event/EventServiceImpl.java index ecdd4d7b8e..891148b672 100644 --- a/dspace-api/src/main/java/org/dspace/event/EventServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/event/EventServiceImpl.java @@ -13,8 +13,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.ArrayUtils; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.KeyedPooledObjectFactory; import org.apache.commons.pool2.PoolUtils; @@ -32,12 +32,13 @@ import org.dspace.services.factory.DSpaceServicesFactory; * Class for managing the content event environment. The EventManager mainly * acts as a factory for Dispatchers, which are used by the Context to send * events to consumers. It also contains generally useful utility methods. - * + * * Version: $Revision$ */ -public class EventServiceImpl implements EventService -{ - /** log4j category */ +public class EventServiceImpl implements EventService { + /** + * log4j category + */ private Logger log = Logger.getLogger(EventServiceImpl.class); @@ -51,21 +52,19 @@ public class EventServiceImpl implements EventService protected Map consumerIndicies = null; protected String CONSUMER_PFX = "event.consumer"; - - private static final ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + + private static final ConfigurationService configurationService = DSpaceServicesFactory.getInstance() + .getConfigurationService(); - protected EventServiceImpl() - { + protected EventServiceImpl() { initPool(); log.info("EventService dispatcher pool initialized"); } - private void initPool() - { + private void initPool() { - if (dispatcherPool == null) - { + if (dispatcherPool == null) { // TODO EVENT Some of these pool configuration // parameters can live in dspace.cfg or a @@ -78,20 +77,17 @@ public class EventServiceImpl implements EventService poolConfig.setMaxIdlePerKey(5); poolConfig.setMaxTotal(100); - try - { + try { dispatcherFactory = new DispatcherPoolFactory(); dispatcherPool = PoolUtils - .synchronizedPool(new GenericKeyedObjectPool( - dispatcherFactory, poolConfig)); + .synchronizedPool(new GenericKeyedObjectPool( + dispatcherFactory, poolConfig)); enumerateConsumers(); - } - catch (Exception e) - { + } catch (Exception e) { log.error("Could not initialize EventService dispatcher pool", e); } @@ -99,67 +95,52 @@ public class EventServiceImpl implements EventService } @Override - public Dispatcher getDispatcher(String name) - { - if (dispatcherPool == null) - { + public Dispatcher getDispatcher(String name) { + if (dispatcherPool == null) { initPool(); } - if (name == null) - { + if (name == null) { name = DEFAULT_DISPATCHER; } - try - { + try { return (Dispatcher) dispatcherPool.borrowObject(name); - } - catch (Exception e) - { + } catch (Exception e) { throw new IllegalStateException("Unable to aquire dispatcher named " + name, e); } } @Override - public void returnDispatcher(String key, Dispatcher disp) - { - try - { + public void returnDispatcher(String key, Dispatcher disp) { + try { dispatcherPool.returnObject(key, disp); - } - catch (Exception e) - { + } catch (Exception e) { throw new IllegalStateException("Unable to return dispatcher named " + key, e); } } @Override - public int getConsumerIndex(String consumerClass) - { + public int getConsumerIndex(String consumerClass) { Integer index = (Integer) consumerIndicies.get(consumerClass); return index != null ? index.intValue() : -1; } - protected void enumerateConsumers() - { + protected void enumerateConsumers() { // Get all configs starting with CONSUMER_PFX List propertyNames = configurationService.getPropertyKeys(CONSUMER_PFX); int bitSetIndex = 0; - if (consumerIndicies == null) - { + if (consumerIndicies == null) { consumerIndicies = new HashMap(); } - for(String ckey : propertyNames) - { - if (ckey.endsWith(".class")) - { - String consumerName = ckey.substring(CONSUMER_PFX.length()+1, - ckey.length() - 6); + for (String ckey : propertyNames) { + if (ckey.endsWith(".class")) { + String consumerName = ckey.substring(CONSUMER_PFX.length() + 1, + ckey.length() - 6); consumerIndicies.put(consumerName, (Integer) bitSetIndex); bitSetIndex++; @@ -167,8 +148,7 @@ public class EventServiceImpl implements EventService } } - protected class DispatcherPoolFactory implements KeyedPooledObjectFactory - { + protected class DispatcherPoolFactory implements KeyedPooledObjectFactory { // Prefix of keys in DSpace Configuration private static final String PROP_PFX = "event.dispatcher"; @@ -176,91 +156,73 @@ public class EventServiceImpl implements EventService // Cache of event dispatchers, keyed by name, for re-use. protected Map dispatchers = new HashMap(); - public DispatcherPoolFactory() - { + public DispatcherPoolFactory() { parseEventConfig(); } public PooledObject wrap(Dispatcher d) { - return new DefaultPooledObject<>(d); + return new DefaultPooledObject<>(d); } @Override - public PooledObject makeObject(String dispatcherName) throws Exception - { + public PooledObject makeObject(String dispatcherName) throws Exception { Dispatcher dispatcher = null; String dispClass = dispatchers.get(dispatcherName); - if (dispClass != null) - { - try - { + if (dispClass != null) { + try { // all this to call a constructor with an argument - final Class argTypes[] = { String.class }; + final Class argTypes[] = {String.class}; Constructor dc = Class.forName(dispClass).getConstructor( - argTypes); + argTypes); Object args[] = new Object[1]; args[0] = dispatcherName; dispatcher = (Dispatcher) dc.newInstance(args); // OK, now get its list of consumers/filters String consumerKey = PROP_PFX + "." + dispatcherName - + ".consumers"; + + ".consumers"; String[] consumers = configurationService - .getArrayProperty(consumerKey); - if (ArrayUtils.isEmpty(consumers)) - { + .getArrayProperty(consumerKey); + if (ArrayUtils.isEmpty(consumers)) { throw new IllegalStateException( - "No Configuration entry found for consumer list of event Dispatcher: \"" - + consumerKey + "\""); + "No Configuration entry found for consumer list of event Dispatcher: \"" + + consumerKey + "\""); } ConsumerProfile consumerProfile = null; - for (String consumer : consumers) - { + for (String consumer : consumers) { consumerProfile = ConsumerProfile - .makeConsumerProfile(consumer); + .makeConsumerProfile(consumer); consumerProfile.getConsumer().initialize(); dispatcher.addConsumerProfile(consumerProfile); } - } - catch (NoSuchMethodException e) - { + } catch (NoSuchMethodException e) { throw new IllegalStateException( - "Constructor not found for event dispatcher=" - + dispatcherName, e); - } - catch (InvocationTargetException e) - { + "Constructor not found for event dispatcher=" + + dispatcherName, e); + } catch (InvocationTargetException e) { throw new IllegalStateException( - "Error creating event dispatcher=" + dispatcherName, - e); - } - catch (ClassNotFoundException e) - { + "Error creating event dispatcher=" + dispatcherName, + e); + } catch (ClassNotFoundException e) { throw new IllegalStateException( - "Dispatcher/Consumer class not found for event dispatcher=" - + dispatcherName, e); - } - catch (InstantiationException e) - { + "Dispatcher/Consumer class not found for event dispatcher=" + + dispatcherName, e); + } catch (InstantiationException e) { throw new IllegalStateException( - "Dispatcher/Consumer instantiation failure for event dispatcher=" - + dispatcherName, e); - } - catch (IllegalAccessException e) - { + "Dispatcher/Consumer instantiation failure for event dispatcher=" + + dispatcherName, e); + } catch (IllegalAccessException e) { throw new IllegalStateException( - "Dispatcher/Consumer access failure for event dispatcher=" - + dispatcherName, e); + "Dispatcher/Consumer access failure for event dispatcher=" + + dispatcherName, e); } - } - else - { + } else { throw new IllegalStateException( - "Requested Dispatcher Does Not Exist In DSpace Configuration!"); + "Requested Dispatcher Does Not Exist In DSpace Configuration!"); } return wrap(dispatcher); @@ -268,8 +230,7 @@ public class EventServiceImpl implements EventService } @Override - public void activateObject(String arg0, PooledObject arg1) throws Exception - { + public void activateObject(String arg0, PooledObject arg1) throws Exception { // No-op return; @@ -277,19 +238,16 @@ public class EventServiceImpl implements EventService @Override public void destroyObject(String key, PooledObject pooledDispatcher) - throws Exception - { + throws Exception { Context ctx = new Context(); try { Dispatcher dispatcher = pooledDispatcher.getObject(); for (Iterator ci = dispatcher.getConsumers() - .iterator(); ci.hasNext();) - { + .iterator(); ci.hasNext(); ) { ConsumerProfile cp = (ConsumerProfile) ci.next(); - if (cp != null) - { + if (cp != null) { cp.getConsumer().finish(ctx); } } @@ -300,16 +258,14 @@ public class EventServiceImpl implements EventService } @Override - public void passivateObject(String arg0, PooledObject arg1) throws Exception - { + public void passivateObject(String arg0, PooledObject arg1) throws Exception { // No-op return; } @Override - public boolean validateObject(String arg0, PooledObject arg1) - { + public boolean validateObject(String arg0, PooledObject arg1) { // No-op return false; } @@ -318,29 +274,25 @@ public class EventServiceImpl implements EventService * Looks through the configuration for dispatcher configurations and * loads one of each into a HashMap. This Map will be used to clone new * objects when the pool needs them. - * + * * Looks for configuration properties like: - * + * *
              *  # class of dispatcher "default"
              *  event.dispatcher.default.class = org.dspace.event.BasicDispatcher
              * 
    - * */ - private void parseEventConfig() - { + private void parseEventConfig() { // Get all configs starting with PROP_PFX List propertyNames = configurationService.getPropertyKeys(PROP_PFX); - - for(String ckey : propertyNames) - { + + for (String ckey : propertyNames) { // If it ends with ".class", append it to our list of dispatcher classes - if (ckey.endsWith(".class")) - { - String name = ckey.substring(PROP_PFX.length()+1, ckey - .length() - 6); + if (ckey.endsWith(".class")) { + String name = ckey.substring(PROP_PFX.length() + 1, ckey + .length() - 6); String dispatcherClass = configurationService - .getProperty(ckey); + .getProperty(ckey); dispatchers.put(name, dispatcherClass); @@ -348,4 +300,4 @@ public class EventServiceImpl implements EventService } } } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/event/TestConsumer.java b/dspace-api/src/main/java/org/dspace/event/TestConsumer.java index 3eef5dba8e..379276ccda 100644 --- a/dspace-api/src/main/java/org/dspace/event/TestConsumer.java +++ b/dspace-api/src/main/java/org/dspace/event/TestConsumer.java @@ -10,8 +10,8 @@ package org.dspace.event; import java.io.PrintStream; import java.text.SimpleDateFormat; import java.util.Date; -import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.log4j.Logger; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; @@ -22,102 +22,90 @@ import org.dspace.eperson.EPerson; * makes an entry in the log, and on an output stream, for each event it * receives. It also logs when consume() and end() get called. It is intended * for testing, exploring, and debugging the event system. - * + * * @version $Revision$ */ -public class TestConsumer implements Consumer -{ +public class TestConsumer implements Consumer { // Log4j logger private static Logger log = Logger.getLogger(TestConsumer.class); // Send diagnostic output here - set to null to turn it off. private static PrintStream out = ConfigurationManager - .getBooleanProperty("testConsumer.verbose") ? System.out : null; + .getBooleanProperty("testConsumer.verbose") ? System.out : null; @Override - public void initialize() throws Exception - { + public void initialize() throws Exception { log.info("EVENT: called TestConsumer.initialize();"); - if (out != null) - { + if (out != null) { out.println("TestConsumer.initialize();"); } } /** * Consume a content event - display it in detail. - * - * @param ctx - * DSpace context - * @param event - * Content event + * + * @param ctx DSpace context + * @param event Content event */ @Override - public void consume(Context ctx, Event event) throws Exception - { + public void consume(Context ctx, Event event) throws Exception { EPerson ep = ctx.getCurrentUser(); String user = (ep == null) ? "(none)" : ep.getEmail(); String detail = event.getDetail(); String msg = "EVENT: called TestConsumer.consume(): EventType=" - + event.getEventTypeAsString() - + ", SubjectType=" - + event.getSubjectTypeAsString() - + ", SubjectID=" - + String.valueOf(event.getSubjectID()) - + ", ObjectType=" - + event.getObjectTypeAsString() - + ", ObjectID=" - + String.valueOf(event.getObjectID()) - + ", Identifiers=" - + ArrayUtils.toString(event.getIdentifiers()) - + ", TimeStamp=" - + applyDateFormat(new Date(event.getTimeStamp())) - + ", user=\"" - + user - + "\"" - + ", extraLog=\"" - + ctx.getExtraLogInfo() - + "\"" - + ", dispatcher=" - + String.valueOf(event.getDispatcher()) - + ", detail=" - + (detail == null ? "[null]" : "\"" + detail + "\"") - + ", transactionID=" - + (event.getTransactionID() == null ? "[null]" : "\"" - + event.getTransactionID() + "\"") + ", context=" - + ctx.toString(); + + event.getEventTypeAsString() + + ", SubjectType=" + + event.getSubjectTypeAsString() + + ", SubjectID=" + + String.valueOf(event.getSubjectID()) + + ", ObjectType=" + + event.getObjectTypeAsString() + + ", ObjectID=" + + String.valueOf(event.getObjectID()) + + ", Identifiers=" + + ArrayUtils.toString(event.getIdentifiers()) + + ", TimeStamp=" + + applyDateFormat(new Date(event.getTimeStamp())) + + ", user=\"" + + user + + "\"" + + ", extraLog=\"" + + ctx.getExtraLogInfo() + + "\"" + + ", dispatcher=" + + String.valueOf(event.getDispatcher()) + + ", detail=" + + (detail == null ? "[null]" : "\"" + detail + "\"") + + ", transactionID=" + + (event.getTransactionID() == null ? "[null]" : "\"" + + event.getTransactionID() + "\"") + ", context=" + + ctx.toString(); log.info(msg); - if (out != null) - { + if (out != null) { out.println("TestConsumer.consume(): " + msg); } } @Override - public void end(Context ctx) throws Exception - { + public void end(Context ctx) throws Exception { log.info("EVENT: called TestConsumer.end();"); - if (out != null) - { + if (out != null) { out.println("TestConsumer.end();"); } } @Override - public void finish(Context ctx) throws Exception - { + public void finish(Context ctx) throws Exception { log.info("EVENT: called TestConsumer.finish();"); - if (out != null) - { + if (out != null) { out.println("TestConsumer.finish();"); } } - private String applyDateFormat(Date thisDate) - { + private String applyDateFormat(Date thisDate) { return new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss.SSS Z").format(thisDate); } diff --git a/dspace-api/src/main/java/org/dspace/event/factory/EventServiceFactory.java b/dspace-api/src/main/java/org/dspace/event/factory/EventServiceFactory.java index 5052884a29..76aa464301 100644 --- a/dspace-api/src/main/java/org/dspace/event/factory/EventServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/event/factory/EventServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.event.service.EventService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the event package, use EventServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the event package, use EventServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class EventServiceFactory { public abstract EventService getEventService(); - public static EventServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("eventServiceFactory", EventServiceFactory.class); + public static EventServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("eventServiceFactory", EventServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/event/factory/EventServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/event/factory/EventServiceFactoryImpl.java index 36721eb2fc..4f15b6ddcd 100644 --- a/dspace-api/src/main/java/org/dspace/event/factory/EventServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/event/factory/EventServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.event.service.EventService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the event package, use EventServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the event package, use EventServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/google/GoogleAccount.java b/dspace-api/src/main/java/org/dspace/google/GoogleAccount.java index ada473afd9..6c95a89e25 100644 --- a/dspace-api/src/main/java/org/dspace/google/GoogleAccount.java +++ b/dspace-api/src/main/java/org/dspace/google/GoogleAccount.java @@ -8,6 +8,10 @@ package org.dspace.google; +import java.io.File; +import java.util.HashSet; +import java.util.Set; + import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; @@ -19,10 +23,6 @@ import com.google.api.services.analytics.AnalyticsScopes; import org.apache.log4j.Logger; import org.dspace.services.factory.DSpaceServicesFactory; -import java.io.File; -import java.util.HashSet; -import java.util.Set; - /** * User: Robin Taylor * Date: 11/07/2014 @@ -51,10 +51,14 @@ public class GoogleAccount { private GoogleAccount() { - applicationName = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("google-analytics.application.name"); - tableId = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("google-analytics.table.id"); - emailAddress = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("google-analytics.account.email"); - certificateLocation = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("google-analytics.certificate.location"); + applicationName = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("google-analytics.application.name"); + tableId = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("google-analytics.table.id"); + emailAddress = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("google-analytics.account.email"); + certificateLocation = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("google-analytics.certificate.location"); jsonFactory = JacksonFactory.getDefaultInstance(); @@ -66,7 +70,8 @@ public class GoogleAccount { } // Create an Analytics instance - client = new Analytics.Builder(httpTransport, jsonFactory, credential).setApplicationName(applicationName).build(); + client = new Analytics.Builder(httpTransport, jsonFactory, credential).setApplicationName(applicationName) + .build(); log.info("Google Analytics client successfully initialised"); } @@ -91,13 +96,13 @@ public class GoogleAccount { scopes.add(AnalyticsScopes.ANALYTICS_PROVISION); scopes.add(AnalyticsScopes.ANALYTICS_READONLY); - credential = new GoogleCredential.Builder() - .setTransport(httpTransport) - .setJsonFactory(jsonFactory) - .setServiceAccountId(emailAddress) - .setServiceAccountScopes(scopes) - .setServiceAccountPrivateKeyFromP12File(new File(certificateLocation)) - .build(); + credential = new GoogleCredential.Builder() + .setTransport(httpTransport) + .setJsonFactory(jsonFactory) + .setServiceAccountId(emailAddress) + .setServiceAccountScopes(scopes) + .setServiceAccountPrivateKeyFromP12File(new File(certificateLocation)) + .build(); return credential; } diff --git a/dspace-api/src/main/java/org/dspace/google/GoogleQueryManager.java b/dspace-api/src/main/java/org/dspace/google/GoogleQueryManager.java index b93e59def8..2719aef04d 100644 --- a/dspace-api/src/main/java/org/dspace/google/GoogleQueryManager.java +++ b/dspace-api/src/main/java/org/dspace/google/GoogleQueryManager.java @@ -8,10 +8,10 @@ package org.dspace.google; -import com.google.api.services.analytics.model.GaData; - import java.io.IOException; +import com.google.api.services.analytics.model.GaData; + /** * User: Robin Taylor @@ -22,26 +22,27 @@ public class GoogleQueryManager { public GaData getPageViews(String startDate, String endDate, String handle) throws IOException { return GoogleAccount.getInstance().getClient().data().ga().get( - GoogleAccount.getInstance().getTableId(), - startDate, - endDate, - "ga:pageviews") // Metrics. - .setDimensions("ga:year,ga:month") - .setSort("-ga:year,-ga:month") - .setFilters("ga:pagePath=~/handle/" + handle + "$") - .execute(); + GoogleAccount.getInstance().getTableId(), + startDate, + endDate, + "ga:pageviews") // Metrics. + .setDimensions("ga:year,ga:month") + .setSort("-ga:year,-ga:month") + .setFilters("ga:pagePath=~/handle/" + handle + "$") + .execute(); } public GaData getBitstreamDownloads(String startDate, String endDate, String handle) throws IOException { return GoogleAccount.getInstance().getClient().data().ga().get( - GoogleAccount.getInstance().getTableId(), - startDate, - endDate, - "ga:totalEvents") // Metrics. - .setDimensions("ga:year,ga:month") - .setSort("-ga:year,-ga:month") - .setFilters("ga:eventCategory==bitstream;ga:eventAction==download;ga:pagePath=~" + handle + "/") - .execute(); + GoogleAccount.getInstance().getTableId(), + startDate, + endDate, + "ga:totalEvents") // Metrics. + .setDimensions("ga:year,ga:month") + .setSort("-ga:year,-ga:month") + .setFilters( + "ga:eventCategory==bitstream;ga:eventAction==download;ga:pagePath=~" + handle + "/") + .execute(); } } diff --git a/dspace-api/src/main/java/org/dspace/google/GoogleRecorderEventListener.java b/dspace-api/src/main/java/org/dspace/google/GoogleRecorderEventListener.java index b9fac9482b..f7ebaebb4d 100644 --- a/dspace-api/src/main/java/org/dspace/google/GoogleRecorderEventListener.java +++ b/dspace-api/src/main/java/org/dspace/google/GoogleRecorderEventListener.java @@ -8,6 +8,14 @@ package org.dspace.google; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; @@ -19,17 +27,11 @@ import org.apache.log4j.Logger; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; -import org.dspace.services.factory.DSpaceServicesFactory; +import org.dspace.services.ConfigurationService; import org.dspace.services.model.Event; import org.dspace.usage.AbstractUsageEventListener; import org.dspace.usage.UsageEvent; - -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import org.springframework.beans.factory.annotation.Autowired; /** @@ -38,7 +40,6 @@ import java.util.UUID; * Time: 10:05 * * Notify Google Analytics of... well anything we want really. - * */ public class GoogleRecorderEventListener extends AbstractUsageEventListener { @@ -46,48 +47,55 @@ public class GoogleRecorderEventListener extends AbstractUsageEventListener { private CloseableHttpClient httpclient; private String GoogleURL = "https://www.google-analytics.com/collect"; private static Logger log = Logger.getLogger(GoogleRecorderEventListener.class); - protected ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance(); + protected ContentServiceFactory contentServiceFactory; + protected ConfigurationService configurationService; public GoogleRecorderEventListener() { // httpclient is threadsafe so we only need one. httpclient = HttpClients.createDefault(); } + @Autowired + public void setContentServiceFactory(ContentServiceFactory contentServiceFactory) { + this.contentServiceFactory = contentServiceFactory; + } + + @Autowired + public void setConfigurationService(final ConfigurationService configurationService) { + this.configurationService = configurationService; + } + @Override public void receiveEvent(Event event) { - if((event instanceof UsageEvent)) - { + if ((event instanceof UsageEvent)) { log.debug("Usage event received " + event.getName()); // This is a wee bit messy but these keys should be combined in future. - analyticsKey = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("jspui.google.analytics.key"); - if (analyticsKey == null ) { - analyticsKey = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("xmlui.google.analytics.key"); - } + analyticsKey = configurationService.getProperty("google.analytics.key"); - if (analyticsKey != null ) { + if (StringUtils.isNotBlank(analyticsKey)) { try { - UsageEvent ue = (UsageEvent)event; + UsageEvent ue = (UsageEvent) event; if (ue.getAction() == UsageEvent.Action.VIEW) { if (ue.getObject().getType() == Constants.BITSTREAM) { logEvent(ue, "bitstream", "download"); - // Note: I've left this commented out code here to show how we could record page views as events, - // but since they are already taken care of by the Google Analytics Javascript there is not much point. + // Note: I've left this commented out code here to show how we could record page views + // as events, + // but since they are already taken care of by the Google Analytics Javascript there is + // not much point. - //} else if (ue.getObject().getType() == Constants.ITEM) { - // logEvent(ue, "item", "view"); - //} else if (ue.getObject().getType() == Constants.COLLECTION) { - // logEvent(ue, "collection", "view"); - //} else if (ue.getObject().getType() == Constants.COMMUNITY) { - // logEvent(ue, "community", "view"); + //} else if (ue.getObject().getType() == Constants.ITEM) { + // logEvent(ue, "item", "view"); + //} else if (ue.getObject().getType() == Constants.COLLECTION) { + // logEvent(ue, "collection", "view"); + //} else if (ue.getObject().getType() == Constants.COMMUNITY) { + // logEvent(ue, "community", "view"); } } - } - catch(Exception e) - { + } catch (Exception e) { log.error(e.getMessage()); } } @@ -136,17 +144,20 @@ public class GoogleRecorderEventListener extends AbstractUsageEventListener { private String getParentType(UsageEvent ue) { try { - int parentType = contentServiceFactory.getDSpaceObjectService(ue.getObject()).getParentObject(ue.getContext(), ue.getObject()).getType(); + int parentType = contentServiceFactory.getDSpaceObjectService(ue.getObject()) + .getParentObject(ue.getContext(), ue.getObject()).getType(); if (parentType == Constants.ITEM) { return "item"; } else if (parentType == Constants.COLLECTION) { return "collection"; - } else if (parentType == Constants.COMMUNITY) { + } else if (parentType == Constants.COMMUNITY) { return "community"; } } catch (SQLException e) { // This shouldn't merit interrupting the user's transaction so log the error and continue. - log.error("Error in Google Analytics recording - can't determine ParentObjectType for bitstream " + ue.getObject().getID()); + log.error( + "Error in Google Analytics recording - can't determine ParentObjectType for bitstream " + ue.getObject() + .getID()); e.printStackTrace(); } @@ -156,14 +167,18 @@ public class GoogleRecorderEventListener extends AbstractUsageEventListener { private String getObjectName(UsageEvent ue) { try { if (ue.getObject().getType() == Constants.BITSTREAM) { - // For a bitstream download we really want to know the title of the owning item rather than the bitstream name. - return contentServiceFactory.getDSpaceObjectService(ue.getObject()).getParentObject(ue.getContext(), ue.getObject()).getName(); - } else { + // For a bitstream download we really want to know the title of the owning item rather than the + // bitstream name. + return contentServiceFactory.getDSpaceObjectService(ue.getObject()) + .getParentObject(ue.getContext(), ue.getObject()).getName(); + } else { return ue.getObject().getName(); } } catch (SQLException e) { // This shouldn't merit interrupting the user's transaction so log the error and continue. - log.error("Error in Google Analytics recording - can't determine ParentObjectName for bitstream " + ue.getObject().getID()); + log.error( + "Error in Google Analytics recording - can't determine ParentObjectName for bitstream " + ue.getObject() + .getID()); e.printStackTrace(); } @@ -173,7 +188,8 @@ public class GoogleRecorderEventListener extends AbstractUsageEventListener { private String getIPAddress(HttpServletRequest request) { String clientIP = request.getRemoteAddr(); - if (ConfigurationManager.getBooleanProperty("useProxies", false) && request.getHeader("X-Forwarded-For") != null) { + if (ConfigurationManager.getBooleanProperty("useProxies", false) && request + .getHeader("X-Forwarded-For") != null) { /* This header is a comma delimited list */ for (String xfip : request.getHeader("X-Forwarded-For").split(",")) { /* proxy itself will sometime populate this header with the same value in diff --git a/dspace-api/src/main/java/org/dspace/handle/Handle.java b/dspace-api/src/main/java/org/dspace/handle/Handle.java index 36ce189cd9..76fed105b9 100644 --- a/dspace-api/src/main/java/org/dspace/handle/Handle.java +++ b/dspace-api/src/main/java/org/dspace/handle/Handle.java @@ -7,33 +7,42 @@ */ package org.dspace.handle; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; -import javax.persistence.*; - /** * Database entity representation of the handle table * * @author kevinvandevelde at atmire.com */ @Entity -@Table(name="handle") +@Table(name = "handle") public class Handle implements ReloadableEntity { @Id - @Column(name="handle_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="handle_id_seq") - @SequenceGenerator(name="handle_id_seq", sequenceName="handle_id_seq", allocationSize = 1) + @Column(name = "handle_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "handle_id_seq") + @SequenceGenerator(name = "handle_id_seq", sequenceName = "handle_id_seq", allocationSize = 1) private Integer id; @Column(name = "handle", unique = true) private String handle; - @ManyToOne(fetch = FetchType.EAGER) + @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "resource_id") private DSpaceObject dso; @@ -50,10 +59,8 @@ public class Handle implements ReloadableEntity { * {@link org.dspace.handle.service.HandleService#createHandle(Context, DSpaceObject, String)} * or * {@link org.dspace.handle.service.HandleService#createHandle(Context, DSpaceObject, String, boolean)} - * */ - protected Handle() - { + protected Handle() { } @@ -94,25 +101,29 @@ public class Handle implements ReloadableEntity { @Override public boolean equals(final Object o) { - if (this == o) return true; + if (this == o) { + return true; + } - if (o == null || getClass() != o.getClass()) return false; + if (o == null || getClass() != o.getClass()) { + return false; + } Handle handle1 = (Handle) o; return new EqualsBuilder() - .append(id, handle1.id) - .append(handle, handle1.handle) - .append(resourceTypeId, handle1.resourceTypeId) - .isEquals(); + .append(id, handle1.id) + .append(handle, handle1.handle) + .append(resourceTypeId, handle1.resourceTypeId) + .isEquals(); } @Override public int hashCode() { return new HashCodeBuilder(17, 37) - .append(id) - .append(handle) - .append(resourceTypeId) - .toHashCode(); + .append(id) + .append(handle) + .append(resourceTypeId) + .toHashCode(); } } diff --git a/dspace-api/src/main/java/org/dspace/handle/HandlePlugin.java b/dspace-api/src/main/java/org/dspace/handle/HandlePlugin.java index 06e984514b..a965ade577 100644 --- a/dspace-api/src/main/java/org/dspace/handle/HandlePlugin.java +++ b/dspace-api/src/main/java/org/dspace/handle/HandlePlugin.java @@ -21,7 +21,6 @@ import net.handle.hdllib.HandleValue; import net.handle.hdllib.ScanCallback; import net.handle.hdllib.Util; import net.handle.util.StreamTable; - import org.apache.log4j.Logger; import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; @@ -38,25 +37,30 @@ import org.dspace.services.factory.DSpaceServicesFactory; * {@link HandleService}. This only provides some of the * functionality (namely, the resolving of handles to URLs) of the CNRI * HandleStorage interface. - * + * *

    * This class is intended to be embedded in the CNRI Handle Server. It conforms * to the HandleStorage interface that was delivered with Handle Server version * 6.2.0. *

    - * + * * @author Peter Breton * @version $Revision$ */ -public class HandlePlugin implements HandleStorage -{ - /** log4j category */ +public class HandlePlugin implements HandleStorage { + /** + * log4j category + */ private static Logger log = Logger.getLogger(HandlePlugin.class); - /** The DSpace service manager kernel **/ + /** + * The DSpace service manager kernel + **/ private static transient DSpaceKernelImpl kernelImpl; - /** References to DSpace Services **/ + /** + * References to DSpace Services + **/ protected HandleService handleService; protected ConfigurationService configurationService; @@ -70,34 +74,27 @@ public class HandlePlugin implements HandleStorage * For DSpace, we have to startup the DSpace Kernel when HandlePlugin * initializes, as the HandlePlugin relies on HandleService (and other services) * which are loaded by the Kernel. + * * @param st StreamTable * @throws Exception if DSpace Kernel fails to startup */ @Override - public void init(StreamTable st) throws Exception - { - if (log.isInfoEnabled()) - { + public void init(StreamTable st) throws Exception { + if (log.isInfoEnabled()) { log.info("Called init (Starting DSpace Kernel)"); } // Initialise the service manager kernel - try - { + try { kernelImpl = DSpaceKernelInit.getKernel(null); - if (!kernelImpl.isRunning()) - { + if (!kernelImpl.isRunning()) { kernelImpl.start(); } - } catch (Exception e) - { + } catch (Exception e) { // Failed to start so destroy it and log and throw an exception - try - { + try { kernelImpl.destroy(); - } - catch (Exception e1) - { + } catch (Exception e1) { // Nothing to do } String message = "Failed to startup DSpace Kernel: " + e.getMessage(); @@ -116,11 +113,9 @@ public class HandlePlugin implements HandleStorage */ @Override public void setHaveNA(byte[] theHandle, boolean haveit) - throws HandleException - { + throws HandleException { // Not implemented - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called setHaveNA (not implemented)"); } } @@ -130,11 +125,9 @@ public class HandlePlugin implements HandleStorage */ @Override public void createHandle(byte[] theHandle, HandleValue[] values) - throws HandleException - { + throws HandleException { // Not implemented - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called createHandle (not implemented)"); } } @@ -143,11 +136,9 @@ public class HandlePlugin implements HandleStorage * HandleStorage interface method - not implemented. */ @Override - public boolean deleteHandle(byte[] theHandle) throws HandleException - { + public boolean deleteHandle(byte[] theHandle) throws HandleException { // Not implemented - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called deleteHandle (not implemented)"); } @@ -159,11 +150,9 @@ public class HandlePlugin implements HandleStorage */ @Override public void updateValue(byte[] theHandle, HandleValue[] values) - throws HandleException - { + throws HandleException { // Not implemented - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called updateValue (not implemented)"); } } @@ -172,11 +161,9 @@ public class HandlePlugin implements HandleStorage * HandleStorage interface method - not implemented. */ @Override - public void deleteAllRecords() throws HandleException - { + public void deleteAllRecords() throws HandleException { // Not implemented - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called deleteAllRecords (not implemented)"); } } @@ -185,11 +172,9 @@ public class HandlePlugin implements HandleStorage * HandleStorage interface method - not implemented. */ @Override - public void checkpointDatabase() throws HandleException - { + public void checkpointDatabase() throws HandleException { // Not implemented - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called checkpointDatabase (not implemented)"); } } @@ -200,16 +185,13 @@ public class HandlePlugin implements HandleStorage * For DSpace, we need to destroy the kernel created in init(). */ @Override - public void shutdown() - { - if (log.isInfoEnabled()) - { + public void shutdown() { + if (log.isInfoEnabled()) { log.info("Called shutdown (Destroying DSpace Kernel)"); } // Destroy the DSpace kernel if it is still alive - if (kernelImpl != null) - { + if (kernelImpl != null) { kernelImpl.destroy(); kernelImpl = null; } @@ -219,11 +201,9 @@ public class HandlePlugin implements HandleStorage * HandleStorage interface method - not implemented. */ @Override - public void scanHandles(ScanCallback callback) throws HandleException - { + public void scanHandles(ScanCallback callback) throws HandleException { // Not implemented - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called scanHandles (not implemented)"); } } @@ -232,11 +212,9 @@ public class HandlePlugin implements HandleStorage * HandleStorage interface method - not implemented. */ @Override - public void scanNAs(ScanCallback callback) throws HandleException - { + public void scanNAs(ScanCallback callback) throws HandleException { // Not implemented - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called scanNAs (not implemented)"); } } @@ -248,33 +226,25 @@ public class HandlePlugin implements HandleStorage /** * Return the raw values for this handle. This implementation returns a * single URL value. - * - * @param theHandle - * byte array representation of handle - * @param indexList - * ignored - * @param typeList - * ignored + * + * @param theHandle byte array representation of handle + * @param indexList ignored + * @param typeList ignored * @return A byte array with the raw data for this handle. Currently, this - * consists of a single URL value. - * @throws HandleException - * If an error occurs while calling the Handle API. + * consists of a single URL value. + * @throws HandleException If an error occurs while calling the Handle API. */ @Override public byte[][] getRawHandleValues(byte[] theHandle, int[] indexList, - byte[][] typeList) throws HandleException - { - if (log.isInfoEnabled()) - { + byte[][] typeList) throws HandleException { + if (log.isInfoEnabled()) { log.info("Called getRawHandleValues"); } Context context = null; - try - { - if (theHandle == null) - { + try { + if (theHandle == null) { throw new HandleException(HandleException.INTERNAL_ERROR); } @@ -284,8 +254,7 @@ public class HandlePlugin implements HandleStorage String url = handleService.resolveToURL(context, handle); - if (url == null) - { + if (url == null) { return null; } @@ -309,8 +278,7 @@ public class HandlePlugin implements HandleStorage byte[][] rawValues = new byte[values.size()][]; - for (int i = 0; i < values.size(); i++) - { + for (int i = 0; i < values.size(); i++) { HandleValue hvalue = values.get(i); rawValues[i] = new byte[Encoder.calcStorageSize(hvalue)]; @@ -318,31 +286,21 @@ public class HandlePlugin implements HandleStorage } return rawValues; - } - catch (HandleException he) - { + } catch (HandleException he) { throw he; - } - catch (Exception e) - { - if (log.isDebugEnabled()) - { + } catch (Exception e) { + if (log.isDebugEnabled()) { log.debug("Exception in getRawHandleValues", e); } // Stack loss as exception does not support cause throw new HandleException(HandleException.INTERNAL_ERROR); - } - finally - { - if (context != null) - { - try - { + } finally { + if (context != null) { + try { context.complete(); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { + // ignore } } } @@ -350,91 +308,78 @@ public class HandlePlugin implements HandleStorage /** * Return true if we have this handle in storage. - * - * @param theHandle - * byte array representation of handle + * + * @param theHandle byte array representation of handle * @return True if we have this handle in storage - * @throws HandleException - * If an error occurs while calling the Handle API. + * @throws HandleException If an error occurs while calling the Handle API. */ @Override - public boolean haveNA(byte[] theHandle) throws HandleException - { - if (log.isInfoEnabled()) - { + public boolean haveNA(byte[] theHandle) throws HandleException { + if (log.isInfoEnabled()) { log.info("Called haveNA"); } /* * Naming authority Handles are in the form: 0.NA/1721.1234 - * + * * 0.NA is basically the naming authority for naming authorities. For * this simple implementation, we will just check that the prefix * configured in dspace.cfg is the one in the request, returning true if * this is the case, false otherwise. - * + * * FIXME: For more complex Handle situations, this will need enhancing. */ - // This parameter allows the dspace handle server to be capable of having multiple - // name authorities assigned to it. So long as the handle table the alternative prefixes - // defined the dspace will answer for those handles prefixes. This is not ideal and only - // works if the dspace instances assumes control over all the items in a prefix, but it - // does allow the admin to merge together two previously separate dspace instances each + // This parameter allows the dspace handle server to be capable of having multiple + // name authorities assigned to it. So long as the handle table the alternative prefixes + // defined the dspace will answer for those handles prefixes. This is not ideal and only + // works if the dspace instances assumes control over all the items in a prefix, but it + // does allow the admin to merge together two previously separate dspace instances each // with their own prefixes and have the one instance handle both prefixes. In this case - // all new handle would be given a unified prefix but all old handles would still be + // all new handle would be given a unified prefix but all old handles would still be // resolvable. - if (configurationService.getBooleanProperty("handle.plugin.checknameauthority",true)) - { - // First, construct a string representing the naming authority Handle - // we'd expect. - String expected = "0.NA/" + handleService.getPrefix(); - - // Which authority does the request pertain to? - String received = Util.decodeString(theHandle); - - // Return true if they match - return expected.equals(received); - } - else - { - return true; + if (configurationService.getBooleanProperty("handle.plugin.checknameauthority", true)) { + // First, construct a string representing the naming authority Handle + // we'd expect. + String expected = "0.NA/" + handleService.getPrefix(); + + // Which authority does the request pertain to? + String received = Util.decodeString(theHandle); + + // Return true if they match + return expected.equals(received); + } else { + return true; } } /** * Return all handles in local storage which start with the naming authority * handle. - * - * @param theNAHandle - * byte array representation of naming authority handle + * + * @param theNAHandle byte array representation of naming authority handle * @return All handles in local storage which start with the naming - * authority handle. - * @throws HandleException - * If an error occurs while calling the Handle API. + * authority handle. + * @throws HandleException If an error occurs while calling the Handle API. */ @Override public Enumeration getHandlesForNA(byte[] theNAHandle) - throws HandleException - { + throws HandleException { String naHandle = Util.decodeString(theNAHandle); - if (log.isInfoEnabled()) - { + if (log.isInfoEnabled()) { log.info("Called getHandlesForNA for NA " + naHandle); } Context context = null; - try - { + try { context = new Context(); List handles = handleService.getHandlesForPrefix(context, naHandle); List results = new LinkedList(); - for (Iterator iterator = handles.iterator(); iterator.hasNext();) - { + for (Iterator iterator = handles.iterator(); iterator.hasNext(); ) { String handle = iterator.next(); // Transforms to byte array @@ -442,27 +387,19 @@ public class HandlePlugin implements HandleStorage } return Collections.enumeration(results); - } - catch (SQLException sqle) - { - if (log.isDebugEnabled()) - { + } catch (SQLException sqle) { + if (log.isDebugEnabled()) { log.debug("Exception in getHandlesForNA", sqle); } // Stack loss as exception does not support cause throw new HandleException(HandleException.INTERNAL_ERROR); - } - finally - { - if (context != null) - { - try - { + } finally { + if (context != null) { + try { context.complete(); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { + // ignore } } } diff --git a/dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java b/dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java index 8dd27c1bad..d322fdd5c2 100644 --- a/dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java @@ -7,7 +7,11 @@ */ package org.dspace.handle; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.DSpaceObject; @@ -19,10 +23,6 @@ import org.dspace.handle.service.HandleService; import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /** * Interface to the CNRI Handle @@ -37,12 +37,15 @@ import java.util.List; * @author Peter Breton * @version $Revision$ */ -public class HandleServiceImpl implements HandleService -{ - /** log4j category */ +public class HandleServiceImpl implements HandleService { + /** + * log4j category + */ private static Logger log = Logger.getLogger(HandleServiceImpl.class); - /** Prefix registered to no one */ + /** + * Prefix registered to no one + */ static final String EXAMPLE_PREFIX = "123456789"; @Autowired(required = true) @@ -54,27 +57,25 @@ public class HandleServiceImpl implements HandleService @Autowired protected SiteService siteService; - /** Public Constructor */ - protected HandleServiceImpl() - { + /** + * Public Constructor + */ + protected HandleServiceImpl() { } @Override public String resolveToURL(Context context, String handle) - throws SQLException - { + throws SQLException { Handle dbhandle = findHandleInternal(context, handle); - if (dbhandle == null) - { + if (dbhandle == null) { return null; } String url = configurationService.getProperty("dspace.url") - + "/handle/" + handle; + + "/handle/" + handle; - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Resolved " + handle + " to " + url); } @@ -83,32 +84,27 @@ public class HandleServiceImpl implements HandleService @Override public String resolveUrlToHandle(Context context, String url) - throws SQLException - { + throws SQLException { String dspaceUrl = configurationService.getProperty("dspace.url") - + "/handle/"; + + "/handle/"; String handleResolver = configurationService.getProperty("handle.canonical.prefix"); String handle = null; - if (url.startsWith(dspaceUrl)) - { + if (url.startsWith(dspaceUrl)) { handle = url.substring(dspaceUrl.length()); } - if (url.startsWith(handleResolver)) - { + if (url.startsWith(handleResolver)) { handle = url.substring(handleResolver.length()); } - if (null == handle) - { + if (null == handle) { return null; } // remove trailing slashes - while (handle.startsWith("/")) - { + while (handle.startsWith("/")) { handle = handle.substring(1); } Handle dbhandle = findHandleInternal(context, handle); @@ -117,25 +113,26 @@ public class HandleServiceImpl implements HandleService } @Override - public String getCanonicalForm(String handle) - { - + public String getCanonicalPrefix() { // Let the admin define a new prefix, if not then we'll use the // CNRI default. This allows the admin to use "hdl:" if they want to or // use a locally branded prefix handle.myuni.edu. String handlePrefix = configurationService.getProperty("handle.canonical.prefix"); - if (StringUtils.isBlank(handlePrefix)) - { + if (StringUtils.isBlank(handlePrefix)) { handlePrefix = "http://hdl.handle.net/"; } - return handlePrefix + handle; + return handlePrefix; + } + + @Override + public String getCanonicalForm(String handle) { + return getCanonicalPrefix() + handle; } @Override public String createHandle(Context context, DSpaceObject dso) - throws SQLException - { + throws SQLException { Handle handle = handleDAO.create(context, new Handle()); String handleId = createId(context); @@ -145,10 +142,9 @@ public class HandleServiceImpl implements HandleService handle.setResourceTypeId(dso.getType()); handleDAO.save(context, handle); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Created new handle for " - + Constants.typeText[dso.getType()] + " (ID=" + dso.getID() + ") " + handleId ); + + Constants.typeText[dso.getType()] + " (ID=" + dso.getID() + ") " + handleId); } return handleId; @@ -156,48 +152,40 @@ public class HandleServiceImpl implements HandleService @Override public String createHandle(Context context, DSpaceObject dso, - String suppliedHandle) throws SQLException, IllegalStateException - { + String suppliedHandle) throws SQLException, IllegalStateException { return createHandle(context, dso, suppliedHandle, false); } @Override public String createHandle(Context context, DSpaceObject dso, - String suppliedHandle, boolean force) throws SQLException, IllegalStateException - { + String suppliedHandle, boolean force) throws SQLException, IllegalStateException { //Check if the supplied handle is already in use -- cannot use the same handle twice Handle handle = findHandleInternal(context, suppliedHandle); - if (handle != null && handle.getDSpaceObject() != null) - { + if (handle != null && handle.getDSpaceObject() != null) { //Check if this handle is already linked up to this specified DSpace Object - if (handle.getDSpaceObject().getID().equals(dso.getID())) - { + if (handle.getDSpaceObject().getID().equals(dso.getID())) { //This handle already links to this DSpace Object -- so, there's nothing else we need to do return suppliedHandle; - } - else - { + } else { //handle found in DB table & already in use by another existing resource - throw new IllegalStateException("Attempted to create a handle which is already in use: " + suppliedHandle); + throw new IllegalStateException( + "Attempted to create a handle which is already in use: " + suppliedHandle); } - } - else if (handle!=null && handle.getResourceTypeId() != null) - { + } else if (handle != null && handle.getResourceTypeId() != null) { //If there is a 'resource_type_id' (but 'resource_id' is empty), then the object using // this handle was previously unbound (see unbindHandle() method) -- likely because object was deleted int previousType = handle.getResourceTypeId(); - //Since we are restoring an object to a pre-existing handle, double check we are restoring the same *type* of object + //Since we are restoring an object to a pre-existing handle, double check we are restoring the same + // *type* of object // (e.g. we will not allow an Item to be restored to a handle previously used by a Collection) - if (previousType != dso.getType()) - { + if (previousType != dso.getType()) { throw new IllegalStateException("Attempted to reuse a handle previously used by a " + - Constants.typeText[previousType] + " for a new " + - Constants.typeText[dso.getType()]); + Constants.typeText[previousType] + " for a new " + + Constants.typeText[dso.getType()]); } - } - else if (handle==null) //if handle not found, create it - { + } else if (handle == null) { + //if handle not found, create it //handle not found in DB table -- create a new table entry handle = handleDAO.create(context, new Handle()); handle.setHandle(suppliedHandle); @@ -208,10 +196,9 @@ public class HandleServiceImpl implements HandleService dso.addHandle(handle); handleDAO.save(context, handle); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Created new handle for " - + Constants.typeText[dso.getType()] + " (ID=" + dso.getID() + ") " + suppliedHandle ); + + Constants.typeText[dso.getType()] + " (ID=" + dso.getID() + ") " + suppliedHandle); } return suppliedHandle; @@ -219,13 +206,10 @@ public class HandleServiceImpl implements HandleService @Override public void unbindHandle(Context context, DSpaceObject dso) - throws SQLException - { + throws SQLException { List handles = getInternalHandles(context, dso); - if (CollectionUtils.isNotEmpty(handles)) - { - for (Handle handle: handles) - { + if (CollectionUtils.isNotEmpty(handles)) { + for (Handle handle : handles) { //Only set the "resouce_id" column to null when unbinding a handle. // We want to keep around the "resource_type_id" value, so that we // can verify during a restore whether the same *type* of resource @@ -234,32 +218,30 @@ public class HandleServiceImpl implements HandleService //Also remove the handle from the DSO list to keep a consistent model dso.getHandles().remove(handle); - + handleDAO.save(context, handle); - if (log.isDebugEnabled()) - { - log.debug("Unbound Handle " + handle.getHandle() + " from object " + Constants.typeText[dso.getType()] + " id=" + dso.getID()); + if (log.isDebugEnabled()) { + log.debug("Unbound Handle " + handle.getHandle() + " from object " + Constants.typeText[dso + .getType()] + " id=" + dso.getID()); } } - } - else - { - log.trace("Cannot find Handle entry to unbind for object " + Constants.typeText[dso.getType()] + " id=" + dso.getID() + ". Handle could have been unbinded before."); + } else { + log.trace( + "Cannot find Handle entry to unbind for object " + Constants.typeText[dso.getType()] + " id=" + dso + .getID() + ". Handle could have been unbinded before."); } } @Override public DSpaceObject resolveToObject(Context context, String handle) - throws IllegalStateException, SQLException - { + throws IllegalStateException, SQLException { Handle dbhandle = findHandleInternal(context, handle); // check if handle was allocated previously, but is currently not // associated with a DSpaceObject // (this may occur when 'unbindHandle()' is called for an obj that was removed) if (dbhandle == null || (dbhandle.getDSpaceObject() == null) - || (dbhandle.getResourceTypeId() == null)) - { + || (dbhandle.getResourceTypeId() == null)) { //if handle has been unbound, just return null (as this will result in a PageNotFound) return null; } @@ -269,24 +251,18 @@ public class HandleServiceImpl implements HandleService @Override public String findHandle(Context context, DSpaceObject dso) - throws SQLException - { + throws SQLException { List handles = getInternalHandles(context, dso); - if (CollectionUtils.isEmpty(handles)) - { + if (CollectionUtils.isEmpty(handles)) { return null; - } - else - { + } else { //TODO: Move this code away from the HandleService & into the Identifier provider //Attempt to retrieve a handle that does NOT look like {handle.part}/{handle.part}.{version} String result = handles.iterator().next().getHandle(); - for (Handle handle: handles) - { + for (Handle handle : handles) { //Ensure that the handle doesn't look like this 12346/213.{version} //If we find a match that indicates that we have a proper handle - if (!handle.getHandle().matches(".*/.*\\.\\d+")) - { + if (!handle.getHandle().matches(".*/.*\\.\\d+")) { result = handle.getHandle(); } } @@ -297,8 +273,7 @@ public class HandleServiceImpl implements HandleService @Override public List getHandlesForPrefix(Context context, String prefix) - throws SQLException - { + throws SQLException { List handles = handleDAO.findByPrefix(context, prefix); List handleStrings = new ArrayList(handles.size()); for (Handle handle : handles) { @@ -308,11 +283,9 @@ public class HandleServiceImpl implements HandleService } @Override - public String getPrefix() - { + public String getPrefix() { String prefix = configurationService.getProperty("handle.prefix"); - if (StringUtils.isBlank(prefix)) - { + if (StringUtils.isBlank(prefix)) { prefix = EXAMPLE_PREFIX; // XXX no good way to exit cleanly log.error("handle.prefix is not configured; using " + prefix); } @@ -332,12 +305,10 @@ public class HandleServiceImpl implements HandleService @Override public void modifyHandleDSpaceObject(Context context, String handle, DSpaceObject newOwner) throws SQLException { Handle dbHandle = findHandleInternal(context, handle); - if (dbHandle != null) - { + if (dbHandle != null) { // Check if we have to remove the handle from the current handle list // or if object is alreday deleted. - if (dbHandle.getDSpaceObject() != null) - { + if (dbHandle.getDSpaceObject() != null) { // Remove the old handle from the current handle list dbHandle.getDSpaceObject().getHandles().remove(dbHandle); } @@ -357,36 +328,27 @@ public class HandleServiceImpl implements HandleService /** * Return the handle for an Object, or null if the Object has no handle. * - * @param context - * DSpace context - * @param dso - * DSpaceObject for which we require our handles + * @param context DSpace context + * @param dso DSpaceObject for which we require our handles * @return The handle for object, or null if the object has no handle. - * @throws SQLException - * If a database error occurs + * @throws SQLException If a database error occurs */ protected List getInternalHandles(Context context, DSpaceObject dso) - throws SQLException - { + throws SQLException { return handleDAO.getHandlesByDSpaceObject(context, dso); } /** * Find the database row corresponding to handle. * - * @param context - * DSpace context - * @param handle - * The handle to resolve + * @param context DSpace context + * @param handle The handle to resolve * @return The database row corresponding to the handle - * @throws SQLException - * If a database error occurs + * @throws SQLException If a database error occurs */ protected Handle findHandleInternal(Context context, String handle) - throws SQLException - { - if (handle == null) - { + throws SQLException { + if (handle == null) { throw new IllegalArgumentException("Handle is null"); } @@ -398,11 +360,9 @@ public class HandleServiceImpl implements HandleService * * @param context DSpace Context * @return A new handle id - * @throws SQLException - * If a database error occurs + * @throws SQLException If a database error occurs */ - protected String createId(Context context) throws SQLException - { + protected String createId(Context context) throws SQLException { // Get configured prefix String handlePrefix = getPrefix(); diff --git a/dspace-api/src/main/java/org/dspace/handle/UpdateHandlePrefix.java b/dspace-api/src/main/java/org/dspace/handle/UpdateHandlePrefix.java index 2f062f5dba..333ac801f8 100644 --- a/dspace-api/src/main/java/org/dspace/handle/UpdateHandlePrefix.java +++ b/dspace-api/src/main/java/org/dspace/handle/UpdateHandlePrefix.java @@ -7,6 +7,11 @@ */ package org.dspace.handle; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.sql.SQLException; +import java.util.Iterator; + import org.apache.log4j.Logger; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; @@ -18,11 +23,6 @@ import org.dspace.handle.service.HandleService; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.sql.SQLException; -import java.util.Iterator; - /** * A script to update the handle values in the database. This is typically used * when moving from a test machine (handle = 123456789) to a production service @@ -31,31 +31,31 @@ import java.util.Iterator; * @author Stuart Lewis * @author Ivo Prajer (Czech Technical University in Prague) */ -public class UpdateHandlePrefix -{ +public class UpdateHandlePrefix { private static final Logger log = Logger.getLogger(UpdateHandlePrefix.class); - private static final ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + private static final ConfigurationService configurationService = DSpaceServicesFactory.getInstance() + .getConfigurationService(); + + /** + * Default constructor + */ + private UpdateHandlePrefix() { } /** * When invoked as a command-line tool, updates handle prefix * * @param args the command-line arguments, none used * @throws Exception on generic exception - * */ - public static void main(String[] args) throws Exception - { + public static void main(String[] args) throws Exception { // There should be two parameters - if (args.length < 2) - { + if (args.length < 2) { System.out.println("\nUsage: update-handle-prefix \n"); System.exit(1); - } - else - { + } else { HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - + String oldH = args[0]; String newH = args[1]; @@ -65,26 +65,24 @@ public class UpdateHandlePrefix long count = handleService.countHandlesByPrefix(context, oldH); - if (count > 0) - { + if (count > 0) { // Print info text about changes System.out.println( - "In your repository will be updated " + count + " handle" + - ((count > 1) ? "s" : "") + " to new prefix " + newH + - " from original " + oldH + "!\n" + "In your repository will be updated " + count + " handle" + + ((count > 1) ? "s" : "") + " to new prefix " + newH + + " from original " + oldH + "!\n" ); // Confirm with the user that this is what they want to do System.out.print( - "Servlet container (e.g. Apache Tomcat, Jetty, Caucho Resin) must be running.\n" + - "If it is necessary, please make a backup of the database.\n" + - "Are you ready to continue? [y/n]: " + "Servlet container (e.g. Apache Tomcat, Jetty, Caucho Resin) must be running.\n" + + "If it is necessary, please make a backup of the database.\n" + + "Are you ready to continue? [y/n]: " ); BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); String choiceString = input.readLine(); - if (choiceString.equalsIgnoreCase("y")) - { + if (choiceString.equalsIgnoreCase("y")) { context.turnOffAuthorisationSystem(); try { log.info("Updating handle prefix from " + oldH + " to " + newH); @@ -93,42 +91,42 @@ public class UpdateHandlePrefix System.out.print("\nUpdating handle table... "); int updHdl = handleService.updateHandlesWithNewPrefix(context, newH, oldH); System.out.println( - updHdl + " item" + ((updHdl > 1) ? "s" : "") + " updated" + updHdl + " item" + ((updHdl > 1) ? "s" : "") + " updated" ); System.out.print("Updating metadatavalues table... "); - MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService(); + MetadataValueService metadataValueService = ContentServiceFactory.getInstance() + .getMetadataValueService(); - String handlePrefix = configurationService.getProperty("handle.canonical.prefix"); - Iterator metadataValues = metadataValueService.findByValueLike(context, handlePrefix + oldH); + String handlePrefix = handleService.getCanonicalPrefix(); + Iterator metadataValues = metadataValueService + .findByValueLike(context, handlePrefix + oldH); int updMeta = 0; - while(metadataValues.hasNext()) { + while (metadataValues.hasNext()) { MetadataValue metadataValue = metadataValues.next(); - metadataValue.setValue(metadataValue.getValue().replace(handlePrefix + oldH, handlePrefix + newH)); + metadataValue + .setValue(metadataValue.getValue().replace(handlePrefix + oldH, handlePrefix + newH)); metadataValueService.update(context, metadataValue, true); context.uncacheEntity(metadataValue); updMeta++; } System.out.println( - updMeta + " metadata value" + ((updMeta > 1) ? "s" : "") + " updated" + updMeta + " metadata value" + ((updMeta > 1) ? "s" : "") + " updated" ); - + // Commit the changes context.complete(); log.info( - "Done with updating handle prefix. " + - "It was changed " + updHdl + " handle" + ((updHdl > 1) ? "s" : "") + - " and " + updMeta + " metadata record" + ((updMeta > 1) ? "s" : "") + "Done with updating handle prefix. " + + "It was changed " + updHdl + " handle" + ((updHdl > 1) ? "s" : "") + + " and " + updMeta + " metadata record" + ((updMeta > 1) ? "s" : "") ); - } - catch (SQLException sqle) - { - if ((context != null) && (context.isValid())) - { + } catch (SQLException sqle) { + if ((context != null) && (context.isValid())) { context.abort(); context = null; } @@ -139,34 +137,27 @@ public class UpdateHandlePrefix System.out.println("Handles successfully updated in database.\n"); System.out.println("Re-creating browse and search indexes..."); - try - { + try { // Reinitialise the search and browse system IndexClient.main(new String[] {"-b"}); System.out.println("Browse and search indexes are ready now."); // All done System.out.println("\nAll done successfully. Please check the DSpace logs!\n"); - } - catch (Exception e) - { + } catch (Exception e) { // Not a lot we can do System.out.println("Error during re-indexing."); System.out.println( - "\n\nAutomatic re-indexing failed. Please perform it manually.\n\n" + - " [dspace]/bin/dspace index-discovery -b\n\n" + - "When launching this command, your servlet container must be running.\n" + "\n\nAutomatic re-indexing failed. Please perform it manually.\n\n" + + " [dspace]/bin/dspace index-discovery -b\n\n" + + "When launching this command, your servlet container must be running.\n" ); throw e; } context.restoreAuthSystemState(); - } - else - { + } else { System.out.println("No changes have been made to your data.\n"); } - } - else - { + } else { System.out.println("Nothing to do! All handles are up-to-date.\n"); } } diff --git a/dspace-api/src/main/java/org/dspace/handle/dao/HandleDAO.java b/dspace-api/src/main/java/org/dspace/handle/dao/HandleDAO.java index ebfd01b133..2b4d16447e 100644 --- a/dspace-api/src/main/java/org/dspace/handle/dao/HandleDAO.java +++ b/dspace-api/src/main/java/org/dspace/handle/dao/HandleDAO.java @@ -7,17 +7,18 @@ */ package org.dspace.handle.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.handle.Handle; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the Handle object. - * The implementation of this class is responsible for all database calls for the Handle object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Handle object and is autowired by + * spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -28,7 +29,7 @@ public interface HandleDAO extends GenericDAO { public List getHandlesByDSpaceObject(Context context, DSpaceObject dso) throws SQLException; - public Handle findByHandle(Context context, String handle)throws SQLException; + public Handle findByHandle(Context context, String handle) throws SQLException; public List findByPrefix(Context context, String prefix) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/handle/dao/impl/HandleDAOImpl.java b/dspace-api/src/main/java/org/dspace/handle/dao/impl/HandleDAOImpl.java index ed516de0b9..3bd702bf80 100644 --- a/dspace-api/src/main/java/org/dspace/handle/dao/impl/HandleDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/handle/dao/impl/HandleDAOImpl.java @@ -7,26 +7,28 @@ */ package org.dspace.handle.dao.impl; -import org.dspace.content.DSpaceObject; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.core.Context; -import org.dspace.handle.Handle; -import org.dspace.handle.dao.HandleDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; -import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver; -import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter; -import org.hibernate.engine.jdbc.dialect.spi.DialectResolver; -import org.hibernate.jdbc.ReturningWork; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.content.DSpaceObject; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.handle.Handle; +import org.dspace.handle.Handle_; +import org.dspace.handle.dao.HandleDAO; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver; +import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter; +import org.hibernate.engine.jdbc.dialect.spi.DialectResolver; +import org.hibernate.jdbc.ReturningWork; /** * Hibernate implementation of the Database Access Object interface class for the Handle object. @@ -35,30 +37,28 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class HandleDAOImpl extends AbstractHibernateDAO implements HandleDAO -{ +public class HandleDAOImpl extends AbstractHibernateDAO implements HandleDAO { // The name of the sequence used to determine next available handle private static final String HANDLE_SEQUENCE = "handle_seq"; - protected HandleDAOImpl() - { + protected HandleDAOImpl() { super(); } @Override public List getHandlesByDSpaceObject(Context context, DSpaceObject dso) throws SQLException { - if(dso == null) { + if (dso == null) { return Collections.emptyList(); } else { Query query = createQuery(context, - "SELECT h " + - "FROM Handle h " + - "LEFT JOIN FETCH h.dso " + - "WHERE h.dso.id = :id "); + "SELECT h " + + "FROM Handle h " + + "LEFT JOIN FETCH h.dso " + + "WHERE h.dso.id = :id "); query.setParameter("id", dso.getID()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return list(query); } } @@ -66,39 +66,49 @@ public class HandleDAOImpl extends AbstractHibernateDAO implements Handl @Override public Handle findByHandle(Context context, String handle) throws SQLException { Query query = createQuery(context, - "SELECT h " + - "FROM Handle h " + - "LEFT JOIN FETCH h.dso " + - "WHERE h.handle = :handle "); + "SELECT h " + + "FROM Handle h " + + "LEFT JOIN FETCH h.dso " + + "WHERE h.handle = :handle "); query.setParameter("handle", handle); - query.setCacheable(true); - return uniqueResult(query); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); + return singleResult(query); } @Override public List findByPrefix(Context context, String prefix) throws SQLException { - Criteria criteria = createCriteria(context, Handle.class); - criteria.add(Restrictions.like("handle", prefix + "%")); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Handle.class); + Root handleRoot = criteriaQuery.from(Handle.class); + criteriaQuery.select(handleRoot); + criteriaQuery.where(criteriaBuilder.like(handleRoot.get(Handle_.handle), prefix + "%")); + return list(context, criteriaQuery, false, Handle.class, -1, -1); } @Override public long countHandlesByPrefix(Context context, String prefix) throws SQLException { - Criteria criteria = createCriteria(context, Handle.class); - criteria.add(Restrictions.like("handle", prefix + "%")); - return countLong(criteria); + + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root handleRoot = criteriaQuery.from(Handle.class); + criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(Handle.class))); + criteriaQuery.where(criteriaBuilder.like(handleRoot.get(Handle_.handle), prefix + "%")); + return countLong(context, criteriaQuery, criteriaBuilder, handleRoot); } @Override - public int updateHandlesWithNewPrefix(Context context, String newPrefix, String oldPrefix) throws SQLException - { - String hql = "UPDATE Handle set handle = concat(:newPrefix, '/', substring(handle, :oldPrefixLength + 2)) WHERE handle like concat(:oldPrefix,'%')"; + public int updateHandlesWithNewPrefix(Context context, String newPrefix, String oldPrefix) throws SQLException { + String hql = "UPDATE Handle set handle = concat(:newPrefix, '/', substring(handle, :oldPrefixLength + 2)) " + + "WHERE handle like concat(:oldPrefix,'%')"; Query query = createQuery(context, hql); - query.setString("newPrefix", newPrefix); - query.setInteger("oldPrefixLength", oldPrefix.length()); - query.setString("oldPrefix", oldPrefix); + query.setParameter("newPrefix", newPrefix); + query.setParameter("oldPrefixLength", oldPrefix.length()); + query.setParameter("oldPrefix", oldPrefix); return query.executeUpdate(); } @@ -114,8 +124,7 @@ public class HandleDAOImpl extends AbstractHibernateDAO implements Handl * @throws SQLException if database error or sequence doesn't exist */ @Override - public Long getNextHandleSuffix(Context context) throws SQLException - { + public Long getNextHandleSuffix(Context context) throws SQLException { // Create a new Hibernate ReturningWork, which will return the // result of the next value in the Handle Sequence. ReturningWork nextValReturningWork = new ReturningWork() { @@ -125,16 +134,15 @@ public class HandleDAOImpl extends AbstractHibernateDAO implements Handl // Determine what dialect we are using for this DB DialectResolver dialectResolver = new StandardDialectResolver(); - Dialect dialect = dialectResolver.resolveDialect(new DatabaseMetaDataDialectResolutionInfoAdapter(connection.getMetaData())); + Dialect dialect = dialectResolver + .resolveDialect(new DatabaseMetaDataDialectResolutionInfoAdapter(connection.getMetaData())); // Find the next value in our sequence (based on DB dialect) - try (PreparedStatement preparedStatement = connection.prepareStatement(dialect.getSequenceNextValString(HANDLE_SEQUENCE))) - { + try (PreparedStatement preparedStatement = connection + .prepareStatement(dialect.getSequenceNextValString(HANDLE_SEQUENCE))) { // Execute query and return results - try(ResultSet resultSet = preparedStatement.executeQuery()) - { - if(resultSet.next()) - { + try (ResultSet resultSet = preparedStatement.executeQuery()) { + if (resultSet.next()) { // Return result of query (from first column) nextVal = resultSet.getLong(1); } diff --git a/dspace-api/src/main/java/org/dspace/handle/factory/HandleServiceFactory.java b/dspace-api/src/main/java/org/dspace/handle/factory/HandleServiceFactory.java index ad8394eed3..87322074c4 100644 --- a/dspace-api/src/main/java/org/dspace/handle/factory/HandleServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/handle/factory/HandleServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.handle.service.HandleService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the handle package, use HandleServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the handle package, use HandleServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class HandleServiceFactory { public abstract HandleService getHandleService(); - public static HandleServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("handleServiceFactory", HandleServiceFactory.class); + public static HandleServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("handleServiceFactory", HandleServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/handle/factory/HandleServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/handle/factory/HandleServiceFactoryImpl.java index f9e5847ca8..a5b9653349 100644 --- a/dspace-api/src/main/java/org/dspace/handle/factory/HandleServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/handle/factory/HandleServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.handle.service.HandleService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the handle package, use HandleServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the handle package, use HandleServiceFactory.getInstance() to retrieve + * an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/handle/service/HandleService.java b/dspace-api/src/main/java/org/dspace/handle/service/HandleService.java index c1780eadbe..47b469b91c 100644 --- a/dspace-api/src/main/java/org/dspace/handle/service/HandleService.java +++ b/dspace-api/src/main/java/org/dspace/handle/service/HandleService.java @@ -7,12 +7,12 @@ */ package org.dspace.handle.service; -import org.dspace.content.DSpaceObject; -import org.dspace.core.Context; - import java.sql.SQLException; import java.util.List; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; + /** * Interface to the CNRI Handle * System . @@ -34,37 +34,45 @@ public interface HandleService { * The returned URL is a (non-handle-based) location where a dissemination * of the object referred to by handle can be obtained. * - * @param context - * DSpace context - * @param handle - * The handle + * @param context DSpace context + * @param handle The handle * @return The local URL - * @throws SQLException - * If a database error occurs + * @throws SQLException If a database error occurs */ public String resolveToURL(Context context, String handle) - throws SQLException; + throws SQLException; /** * Try to detect a handle in a URL. + * * @param context DSpace context - * @param url The URL + * @param url The URL * @return The handle or null if the handle couldn't be extracted of a URL * or if the extracted handle couldn't be found. - * @throws SQLException If a database error occurs + * @throws SQLException If a database error occurs */ public String resolveUrlToHandle(Context context, String url) - throws SQLException; + throws SQLException; /** - * Transforms handle into a URI using http://hdl.handle.net if not + * Provides handle canonical prefix using http://hdl.handle.net if not * overridden by the configuration property handle.canonical.prefix. * * No attempt is made to verify that handle is in fact valid. * - * @param handle - * The handle + * @param handle The handle + * @return The canonical form + */ + public String getCanonicalPrefix(); + + /** + * Transforms handle into a URI using http://hdl.handle.net if not + * overridden by the configuration property handle.canonical.prefix. + * + * No attempt is made to verify that handle is in fact valid. + * + * @param handle The handle * @return The canonical form */ public String getCanonicalForm(String handle); @@ -72,54 +80,42 @@ public interface HandleService { /** * Creates a new handle in the database. * - * @param context - * DSpace context - * @param dso - * The DSpaceObject to create a handle for + * @param context DSpace context + * @param dso The DSpaceObject to create a handle for * @return The newly created handle - * @throws SQLException - * If a database error occurs + * @throws SQLException If a database error occurs */ public String createHandle(Context context, DSpaceObject dso) - throws SQLException; + throws SQLException; /** * Creates a handle entry, but with a handle supplied by the caller (new * Handle not generated) * - * @param context - * DSpace context - * @param dso - * DSpaceObject - * @param suppliedHandle - * existing handle value + * @param context DSpace context + * @param dso DSpaceObject + * @param suppliedHandle existing handle value * @return the Handle - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. * @throws IllegalStateException if specified handle is already in use by another object */ public String createHandle(Context context, DSpaceObject dso, String suppliedHandle) - throws SQLException, IllegalStateException; + throws SQLException, IllegalStateException; /** * Creates a handle entry, but with a handle supplied by the caller (new * Handle not generated) * - * @param context - * DSpace context - * @param dso - * DSpaceObject - * @param suppliedHandle - * existing handle value - * @param force - * FIXME: currently unused + * @param context DSpace context + * @param dso DSpaceObject + * @param suppliedHandle existing handle value + * @param force FIXME: currently unused * @return the Handle - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. * @throws IllegalStateException if specified handle is already in use by another object */ public String createHandle(Context context, DSpaceObject dso, String suppliedHandle, boolean force) - throws SQLException, IllegalStateException; + throws SQLException, IllegalStateException; /** * Removes binding of Handle to a DSpace object, while leaving the @@ -127,63 +123,53 @@ public interface HandleService { * implementation also needs it there for foreign key references. * * @param context DSpace context - * @param dso DSpaceObject whose Handle to unbind. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param dso DSpaceObject whose Handle to unbind. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void unbindHandle(Context context, DSpaceObject dso) - throws SQLException; + throws SQLException; /** * Return the object which handle maps to, or null. This is the object * itself, not a URL which points to it. * - * @param context - * DSpace context - * @param handle - * The handle to resolve + * @param context DSpace context + * @param handle The handle to resolve * @return The object which handle maps to, or null if handle is not mapped - * to any object. - * @throws IllegalStateException - * If handle was found but is not bound to an object - * @throws SQLException - * If a database error occurs + * to any object. + * @throws IllegalStateException If handle was found but is not bound to an object + * @throws SQLException If a database error occurs */ public DSpaceObject resolveToObject(Context context, String handle) - throws IllegalStateException, SQLException; + throws IllegalStateException, SQLException; /** * Return the handle for an Object, or null if the Object has no handle. * - * @param context - * DSpace context - * @param dso - * The object to obtain a handle for + * @param context DSpace context + * @param dso The object to obtain a handle for * @return The handle for object, or null if the object has no handle. - * @throws SQLException - * If a database error occurs + * @throws SQLException If a database error occurs */ public String findHandle(Context context, DSpaceObject dso) - throws SQLException; + throws SQLException; /** * Return all the handles which start with prefix. * - * @param context - * DSpace context - * @param prefix - * The handle prefix + * @param context DSpace context + * @param prefix The handle prefix * @return A list of the handles starting with prefix. The list is - * guaranteed to be non-null. Each element of the list is a String. - * @throws SQLException - * If a database error occurs + * guaranteed to be non-null. Each element of the list is a String. + * @throws SQLException If a database error occurs */ public List getHandlesForPrefix(Context context, String prefix) - throws SQLException; + throws SQLException; /** * Get the configured Handle prefix string, or a default + * * @return configured prefix or "123456789" */ public String getPrefix(); diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestConsumer.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestConsumer.java index 8d075f09dc..37690fa8d0 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestConsumer.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestConsumer.java @@ -7,30 +7,30 @@ */ package org.dspace.harvest; +import java.util.UUID; + import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.Item; -import org.dspace.core.*; +import org.dspace.core.Constants; +import org.dspace.core.Context; import org.dspace.event.Consumer; import org.dspace.event.Event; import org.dspace.harvest.factory.HarvestServiceFactory; import org.dspace.harvest.service.HarvestedCollectionService; import org.dspace.harvest.service.HarvestedItemService; -import java.util.UUID; - /** * Class for handling cleanup of harvest settings for collections and items * - * - * @version $Revision: 3705 $ - * * @author Stuart Lewis * @author Alexey Maslov + * @version $Revision: 3705 $ */ -public class HarvestConsumer implements Consumer -{ - /** log4j logger */ +public class HarvestConsumer implements Consumer { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(HarvestConsumer.class); protected HarvestedCollectionService harvestedCollectionService; @@ -43,57 +43,51 @@ public class HarvestConsumer implements Consumer */ @Override public void initialize() - throws Exception - { + throws Exception { harvestedItemService = HarvestServiceFactory.getInstance().getHarvestedItemService(); } /** * Consume the event * - * @param context - * The relevant DSpace Context. - * @param event - * DSpace event + * @param context The relevant DSpace Context. + * @param event DSpace event * @throws Exception if error */ @Override public void consume(Context context, Event event) - throws Exception - { + throws Exception { int st = event.getSubjectType(); int et = event.getEventType(); UUID id = event.getSubjectID(); - - switch (st) - { + + switch (st) { case Constants.ITEM: - if (et == Event.DELETE) - { + if (et == Event.DELETE) { HarvestedItem hi = harvestedItemService.find(context, (Item) event.getSubject(context)); if (hi != null) { - log.debug("Deleted item '" + id + "', also deleting associated harvested_item '" + hi.getOaiID() + "'."); + log.debug("Deleted item '" + id + "', also deleting associated harvested_item '" + hi + .getOaiID() + "'."); harvestedItemService.delete(context, hi); - } - else - { + } else { log.debug("Deleted item '" + id + "' and the associated harvested_item."); } - } + } break; case Constants.COLLECTION: - if (et == Event.DELETE) - { - HarvestedCollection hc = harvestedCollectionService.find(context, (Collection) event.getSubject(context)); + if (et == Event.DELETE) { + HarvestedCollection hc = harvestedCollectionService + .find(context, (Collection) event.getSubject(context)); if (hc != null) { - log.debug("Deleted collection '" + id + "', also deleting associated harvested_collection '" + hc.getOaiSource() + ":" + hc.getOaiSetId() + "'."); + log.debug( + "Deleted collection '" + id + "', also deleting associated harvested_collection '" + hc + .getOaiSource() + ":" + hc.getOaiSetId() + "'."); harvestedCollectionService.delete(context, hc); - } - else - { + } else { log.debug("Deleted collection '" + id + "' and the associated harvested_collection."); } } + break; default: log.warn("consume() got unrecognized event: " + event.toString()); } @@ -102,26 +96,22 @@ public class HarvestConsumer implements Consumer /** * Handle the end of the event * - * @param ctx - * The relevant DSpace Context. + * @param ctx The relevant DSpace Context. * @throws Exception if error */ @Override public void end(Context ctx) - throws Exception - { + throws Exception { } /** * Finish the event * - * @param ctx - * The relevant DSpace Context. + * @param ctx The relevant DSpace Context. */ @Override - public void finish(Context ctx) - { + public void finish(Context ctx) { } } diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestScheduler.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestScheduler.java index 2b6ce104d9..2867a804c9 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestScheduler.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestScheduler.java @@ -7,6 +7,14 @@ */ package org.dspace.harvest; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Stack; +import java.util.UUID; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.factory.ContentServiceFactory; @@ -18,16 +26,12 @@ import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.harvest.factory.HarvestServiceFactory; import org.dspace.harvest.service.HarvestedCollectionService; -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; - /** * The class responsible for scheduling harvesting cycles are regular intervals. + * * @author alexey */ -public class HarvestScheduler implements Runnable -{ +public class HarvestScheduler implements Runnable { protected static Logger log = Logger.getLogger(HarvestScheduler.class); @@ -73,8 +77,10 @@ public class HarvestScheduler implements Runnable protected static long maxHeartbeat; - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); - private static final HarvestedCollectionService harvestedCollectionService = HarvestServiceFactory.getInstance().getHarvestedCollectionService(); + private static final CollectionService collectionService = ContentServiceFactory.getInstance() + .getCollectionService(); + private static final HarvestedCollectionService harvestedCollectionService = + HarvestServiceFactory.getInstance().getHarvestedCollectionService(); public static boolean hasStatus(int statusToCheck) { return status == statusToCheck; @@ -98,17 +104,18 @@ public class HarvestScheduler implements Runnable case HARVESTER_STATUS_RUNNING: switch (interrupt) { case HARVESTER_INTERRUPT_PAUSE: - return("The scheduler is finishing active harvests before pausing. "); + return ("The scheduler is finishing active harvests before pausing. "); case HARVESTER_INTERRUPT_STOP: - return("The scheduler is shutting down. "); + return ("The scheduler is shutting down. "); + default: + return ("The scheduler is actively harvesting collections. "); } - return("The scheduler is actively harvesting collections. "); case HARVESTER_STATUS_SLEEPING: - return("The scheduler is waiting for collections to harvest. "); + return ("The scheduler is waiting for collections to harvest. "); case HARVESTER_STATUS_PAUSED: - return("The scheduler is paused. "); + return ("The scheduler is paused. "); default: - return("Automatic harvesting is not active. "); + return ("Automatic harvesting is not active. "); } } @@ -116,26 +123,23 @@ public class HarvestScheduler implements Runnable mainContext = new Context(); String harvestAdminParam = ConfigurationManager.getProperty("oai", "harvester.eperson"); harvestAdmin = null; - if (harvestAdminParam != null && harvestAdminParam.length() > 0) - { - harvestAdmin = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(mainContext, harvestAdminParam); + if (harvestAdminParam != null && harvestAdminParam.length() > 0) { + harvestAdmin = EPersonServiceFactory.getInstance().getEPersonService() + .findByEmail(mainContext, harvestAdminParam); } harvestThreads = new Stack(); maxActiveThreads = ConfigurationManager.getIntProperty("oai", "harvester.maxThreads"); - if (maxActiveThreads == 0) - { + if (maxActiveThreads == 0) { maxActiveThreads = 3; } minHeartbeat = ConfigurationManager.getIntProperty("oai", "harvester.minHeartbeat") * 1000; - if (minHeartbeat == 0) - { + if (minHeartbeat == 0) { minHeartbeat = 30000; } maxHeartbeat = ConfigurationManager.getIntProperty("oai", "harvester.maxHeartbeat") * 1000; - if (maxHeartbeat == 0) - { + if (maxHeartbeat == 0) { maxHeartbeat = 3600000; } } @@ -146,11 +150,9 @@ public class HarvestScheduler implements Runnable } protected void scheduleLoop() { - long i=0; - while(true) - { - try - { + long i = 0; + while (true) { + try { mainContext = new Context(); synchronized (HarvestScheduler.class) { @@ -159,7 +161,8 @@ public class HarvestScheduler implements Runnable break; case HARVESTER_INTERRUPT_INSERT_THREAD: interrupt = HARVESTER_INTERRUPT_NONE; - addThread(mainContext, harvestedCollectionService.find(mainContext, collectionService.find(mainContext, interruptValue))); + addThread(mainContext, harvestedCollectionService + .find(mainContext, collectionService.find(mainContext, interruptValue))); interruptValue = null; break; case HARVESTER_INTERRUPT_PAUSE: @@ -170,11 +173,13 @@ public class HarvestScheduler implements Runnable interrupt = HARVESTER_INTERRUPT_NONE; status = HARVESTER_STATUS_STOPPED; return; + default: + break; } } if (status == HARVESTER_STATUS_PAUSED) { - while(interrupt != HARVESTER_INTERRUPT_RESUME && interrupt != HARVESTER_INTERRUPT_STOP) { + while (interrupt != HARVESTER_INTERRUPT_RESUME && interrupt != HARVESTER_INTERRUPT_STOP) { Thread.sleep(1000); } @@ -195,7 +200,7 @@ public class HarvestScheduler implements Runnable // Stage #2: start up all the threads currently in the queue up to the maximum number while (!harvestThreads.isEmpty()) { - synchronized(HarvestScheduler.class) { + synchronized (HarvestScheduler.class) { activeThreads++; } Thread activeThread = new Thread(harvestThreads.pop()); @@ -215,23 +220,22 @@ public class HarvestScheduler implements Runnable // FIXME: also, this might lead to a situation when a single thread getting stuck without // throwing an exception would shut down the whole scheduler while (activeThreads != 0) { - /* Wait a second */ - Thread.sleep(1000); + /* Wait a second */ + Thread.sleep(1000); } // Commit everything try { - mainContext.complete(); - log.info("Done with iteration " + i); + mainContext.complete(); + log.info("Done with iteration " + i); } catch (SQLException e) { - e.printStackTrace(); - mainContext.abort(); + e.printStackTrace(); + mainContext.abort(); } - } - catch (Exception e) { - log.error("Exception on iteration: " + i); - e.printStackTrace(); + } catch (Exception e) { + log.error("Exception on iteration: " + i); + e.printStackTrace(); } // Stage #3: figure out how long until the next iteration and wait @@ -240,8 +244,7 @@ public class HarvestScheduler implements Runnable HarvestedCollection hc = harvestedCollectionService.findOldestHarvest(tempContext); int harvestInterval = ConfigurationManager.getIntProperty("oai", "harvester.harvestFrequency"); - if (harvestInterval == 0) - { + if (harvestInterval == 0) { harvestInterval = 720; } @@ -252,25 +255,23 @@ public class HarvestScheduler implements Runnable calendar.setTime(hc.getHarvestDate()); calendar.add(Calendar.MINUTE, harvestInterval); nextTime = calendar.getTime(); - nextHarvest = nextTime.getTime() + - new Date().getTime(); + nextHarvest = nextTime.getTime() + -new Date().getTime(); } - long upperBound = Math.min(nextHarvest,maxHeartbeat); + long upperBound = Math.min(nextHarvest, maxHeartbeat); long delay = Math.max(upperBound, minHeartbeat) + 1000; tempContext.complete(); status = HARVESTER_STATUS_SLEEPING; - synchronized(lock) { + synchronized (lock) { lock.wait(delay); } - } - catch (InterruptedException ie) { - log.warn("Interrupt: " + ie.getMessage()); - } - catch (SQLException e) { - e.printStackTrace(); + } catch (InterruptedException ie) { + log.warn("Interrupt: " + ie.getMessage()); + } catch (SQLException e) { + e.printStackTrace(); } i++; @@ -284,19 +285,15 @@ public class HarvestScheduler implements Runnable * from the UI that still "plays nice" with these thread mechanics instead of making an * asynchronous call to runHarvest(). * - * @param context - * The relevant DSpace Context. - * @param harvestedCollection - * collection to be harvested - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param harvestedCollection collection to be harvested + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ - public void addThread(Context context, HarvestedCollection harvestedCollection) throws SQLException, IOException, AuthorizeException { + public void addThread(Context context, HarvestedCollection harvestedCollection) + throws SQLException, IOException, AuthorizeException { log.debug("****** Entered the addThread method. Active threads: " + harvestThreads.toString()); context.setCurrentUser(harvestAdmin); diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestSchedulingServiceImpl.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestSchedulingServiceImpl.java index d76ed41e84..543ef4273d 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestSchedulingServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestSchedulingServiceImpl.java @@ -7,16 +7,16 @@ */ package org.dspace.harvest; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.harvest.service.HarvestSchedulingService; import org.dspace.harvest.service.HarvestedCollectionService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * Service implementation for the scheduling of harvesting tasks. * This class is responsible for all business logic calls for the harvesting tasks and is autowired by spring @@ -27,15 +27,14 @@ import java.util.List; public class HarvestSchedulingServiceImpl implements HarvestSchedulingService { /* The main harvesting thread */ - protected HarvestScheduler harvester; + protected HarvestScheduler harvester; protected Thread mainHarvestThread; protected HarvestScheduler harvestScheduler; @Autowired(required = true) protected HarvestedCollectionService harvestedCollectionService; - protected HarvestSchedulingServiceImpl() - { + protected HarvestSchedulingServiceImpl() { } @@ -46,47 +45,46 @@ public class HarvestSchedulingServiceImpl implements HarvestSchedulingService { c.complete(); if (mainHarvestThread != null && harvester != null) { - stopScheduler(); - } - harvester = new HarvestScheduler(); - HarvestScheduler.setInterrupt(HarvestScheduler.HARVESTER_INTERRUPT_NONE); - mainHarvestThread = new Thread(harvester); - mainHarvestThread.start(); + stopScheduler(); + } + harvester = new HarvestScheduler(); + HarvestScheduler.setInterrupt(HarvestScheduler.HARVESTER_INTERRUPT_NONE); + mainHarvestThread = new Thread(harvester); + mainHarvestThread.start(); } @Override public synchronized void stopScheduler() throws SQLException, AuthorizeException { - synchronized(HarvestScheduler.lock) { - HarvestScheduler.setInterrupt(HarvestScheduler.HARVESTER_INTERRUPT_STOP); - HarvestScheduler.lock.notify(); + synchronized (HarvestScheduler.lock) { + HarvestScheduler.setInterrupt(HarvestScheduler.HARVESTER_INTERRUPT_STOP); + HarvestScheduler.lock.notify(); } mainHarvestThread = null; - harvester = null; + harvester = null; } @Override - public void pauseScheduler() throws SQLException, AuthorizeException { - synchronized(HarvestScheduler.lock) { - HarvestScheduler.setInterrupt(HarvestScheduler.HARVESTER_INTERRUPT_PAUSE); - HarvestScheduler.lock.notify(); - } + public void pauseScheduler() throws SQLException, AuthorizeException { + synchronized (HarvestScheduler.lock) { + HarvestScheduler.setInterrupt(HarvestScheduler.HARVESTER_INTERRUPT_PAUSE); + HarvestScheduler.lock.notify(); + } } @Override - public void resumeScheduler() throws SQLException, AuthorizeException { - HarvestScheduler.setInterrupt(HarvestScheduler.HARVESTER_INTERRUPT_RESUME); + public void resumeScheduler() throws SQLException, AuthorizeException { + HarvestScheduler.setInterrupt(HarvestScheduler.HARVESTER_INTERRUPT_RESUME); } @Override - public void resetScheduler() throws SQLException, AuthorizeException, IOException { - Context context = new Context(); - List harvestedCollections = harvestedCollectionService.findAll(context); - for (HarvestedCollection hc : harvestedCollections) - { - hc.setHarvestStartTime(null); - hc.setHarvestStatus(HarvestedCollection.STATUS_READY); + public void resetScheduler() throws SQLException, AuthorizeException, IOException { + Context context = new Context(); + List harvestedCollections = harvestedCollectionService.findAll(context); + for (HarvestedCollection hc : harvestedCollections) { + hc.setHarvestStartTime(null); + hc.setHarvestStatus(HarvestedCollection.STATUS_READY); harvestedCollectionService.update(context, hc); - } + } } } diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestThread.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestThread.java index d2e394c437..c021d455bd 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestThread.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestThread.java @@ -7,6 +7,9 @@ */ package org.dspace.harvest; +import java.sql.SQLException; +import java.util.UUID; + import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.factory.ContentServiceFactory; @@ -15,11 +18,9 @@ import org.dspace.core.Context; import org.dspace.harvest.factory.HarvestServiceFactory; import org.dspace.harvest.service.HarvestedCollectionService; -import java.sql.SQLException; -import java.util.UUID; - /** * A harvester thread used to execute a single harvest cycle on a collection + * * @author alexey */ public class HarvestThread extends Thread { @@ -27,7 +28,8 @@ public class HarvestThread extends Thread { private static final Logger log = Logger.getLogger(HarvestThread.class); protected UUID collectionId; protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); - protected HarvestedCollectionService harvestedCollectionService = HarvestServiceFactory.getInstance().getHarvestedCollectionService(); + protected HarvestedCollectionService harvestedCollectionService = + HarvestServiceFactory.getInstance().getHarvestedCollectionService(); protected HarvestThread(UUID collectionId) throws SQLException { @@ -35,14 +37,12 @@ public class HarvestThread extends Thread { } @Override - public void run() - { + public void run() { log.info("Thread for collection " + collectionId + " starts."); runHarvest(); } - private void runHarvest() - { + private void runHarvest() { Context context; Collection dso; HarvestedCollection hc = null; @@ -88,4 +88,4 @@ public class HarvestThread extends Thread { log.info("Thread for collection " + hc.getCollection().getID() + " completes."); } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollection.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollection.java index c78a45cdea..9fe2bed67d 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollection.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollection.java @@ -7,25 +7,36 @@ */ package org.dspace.harvest; +import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; -import javax.persistence.*; -import java.util.Date; - /** * @author Alexey Maslov */ @Entity -@Table(name="harvested_collection") -public class HarvestedCollection implements ReloadableEntity -{ +@Table(name = "harvested_collection") +public class HarvestedCollection implements ReloadableEntity { @Id - @Column(name="id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="harvested_collection_seq") - @SequenceGenerator(name="harvested_collection_seq", sequenceName="harvested_collection_seq", allocationSize = 1) + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "harvested_collection_seq") + @SequenceGenerator(name = "harvested_collection_seq", sequenceName = "harvested_collection_seq", allocationSize = 1) private Integer id; @OneToOne(fetch = FetchType.EAGER) @@ -50,11 +61,11 @@ public class HarvestedCollection implements ReloadableEntity @Column(name = "harvest_status") private int harvestStatus; - @Column(name = "harvest_start_time", columnDefinition="timestamp with time zone") + @Column(name = "harvest_start_time", columnDefinition = "timestamp with time zone") @Temporal(TemporalType.TIMESTAMP) private Date harvestStartTime; - @Column(name = "last_harvested", columnDefinition="timestamp with time zone") + @Column(name = "last_harvested", columnDefinition = "timestamp with time zone") @Temporal(TemporalType.TIMESTAMP) private Date lastHarvested; @@ -81,33 +92,28 @@ public class HarvestedCollection implements ReloadableEntity /** * Protected constructor, create object using: * {@link org.dspace.harvest.service.HarvestedCollectionService#create(Context, Collection)} - * */ - protected HarvestedCollection() - { + protected HarvestedCollection() { } public Integer getID() { return id; } - /** - * A function to set all harvesting-related parameters at once - * @param type - * harvest type (TYPE_NONE, TYPE_DMD, TYPE_DMDREF, TYPE_FULL) - * @param oaiSource - * base URL of the OAI-PMH server - * @param oaiSetId - * OAI set identifier - * @param mdConfigId - * harvest metadata config ID + /** + * A function to set all harvesting-related parameters at once + * + * @param type harvest type (TYPE_NONE, TYPE_DMD, TYPE_DMDREF, TYPE_FULL) + * @param oaiSource base URL of the OAI-PMH server + * @param oaiSetId OAI set identifier + * @param mdConfigId harvest metadata config ID */ public void setHarvestParams(int type, String oaiSource, String oaiSetId, String mdConfigId) { setHarvestType(type); setOaiSource(oaiSource); - setOaiSetId(oaiSetId); + setOaiSetId(oaiSetId); setHarvestMetadataConfig(mdConfigId); - } + } /* * Setters for the appropriate harvesting-related columns @@ -118,31 +124,30 @@ public class HarvestedCollection implements ReloadableEntity public void setHarvestType(int type) { this.harvestType = type; } - - /** + + /** * Sets the current status of the collection. - * - * @param status a HarvestInstance.STATUS_... constant (STATUS_READY, STATUS_BUSY, STATUS_QUEUED, STATUS_OAI_ERROR, STATUS_UNKNOWN_ERROR) + * + * @param status a HarvestInstance.STATUS_... constant (STATUS_READY, STATUS_BUSY, STATUS_QUEUED, + * STATUS_OAI_ERROR, STATUS_UNKNOWN_ERROR) */ public void setHarvestStatus(int status) { this.harvestStatus = status; } - /** + /** * Sets the base URL of the OAI-PMH server. - * - * @param oaiSource base URL of the OAI-PMH server * + * @param oaiSource base URL of the OAI-PMH server */ public void setOaiSource(String oaiSource) { this.oaiSource = oaiSource; } - /** + /** * Sets the OAI set to harvest. - * - * @param oaiSetId OAI set to harvest * + * @param oaiSetId OAI set to harvest */ public void setOaiSetId(String oaiSetId) { this.oaiSetId = oaiSetId; @@ -159,11 +164,11 @@ public class HarvestedCollection implements ReloadableEntity public void setHarvestMessage(String message) { this.harvestMessage = message; } - + public void setHarvestStartTime(Date date) { this.harvestStartTime = date; } - + /* Getting for the appropriate harvesting-related columns */ public Collection getCollection() { @@ -177,7 +182,7 @@ public class HarvestedCollection implements ReloadableEntity public int getHarvestType() { return harvestType; } - + public int getHarvestStatus() { return harvestStatus; } @@ -193,7 +198,7 @@ public class HarvestedCollection implements ReloadableEntity public String getHarvestMetadataConfig() { return metadataConfigId; } - + public String getHarvestMessage() { return harvestMessage; } @@ -201,7 +206,7 @@ public class HarvestedCollection implements ReloadableEntity public Date getHarvestDate() { return lastHarvested; } - + public Date getHarvestStartTime() { return harvestStartTime; } diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java index aa6a2ef272..fadcfb6ea6 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.harvest; +import java.sql.SQLException; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; @@ -14,11 +19,6 @@ import org.dspace.harvest.dao.HarvestedCollectionDAO; import org.dspace.harvest.service.HarvestedCollectionService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - /** * Service implementation for the HarvestedCollection object. * This class is responsible for all business logic calls for the HarvestedCollection object and is autowired by spring. @@ -26,13 +26,11 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class HarvestedCollectionServiceImpl implements HarvestedCollectionService -{ +public class HarvestedCollectionServiceImpl implements HarvestedCollectionService { @Autowired(required = true) protected HarvestedCollectionDAO harvestedCollectionDAO; - protected HarvestedCollectionServiceImpl() - { + protected HarvestedCollectionServiceImpl() { } @Override @@ -46,13 +44,14 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic harvestedCollection.setCollection(collection); harvestedCollection.setHarvestType(HarvestedCollection.TYPE_NONE); update(context, harvestedCollection); - return harvestedCollection; } + return harvestedCollection; + } @Override public boolean isHarvestable(Context context, Collection collection) throws SQLException { HarvestedCollection hc = find(context, collection); if (hc != null && hc.getHarvestType() > 0 && hc.getOaiSource() != null && hc.getOaiSetId() != null && - hc.getHarvestStatus() != HarvestedCollection.STATUS_UNKNOWN_ERROR) { + hc.getHarvestStatus() != HarvestedCollection.STATUS_UNKNOWN_ERROR) { return true; } return false; @@ -60,8 +59,9 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic @Override public boolean isHarvestable(HarvestedCollection harvestedCollection) throws SQLException { - if (harvestedCollection.getHarvestType() > 0 && harvestedCollection.getOaiSource() != null && harvestedCollection.getOaiSetId() != null && - harvestedCollection.getHarvestStatus() != HarvestedCollection.STATUS_UNKNOWN_ERROR) { + if (harvestedCollection.getHarvestType() > 0 && harvestedCollection + .getOaiSource() != null && harvestedCollection.getOaiSetId() != null && + harvestedCollection.getHarvestStatus() != HarvestedCollection.STATUS_UNKNOWN_ERROR) { return true; } @@ -76,8 +76,9 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic @Override public boolean isReady(HarvestedCollection harvestedCollection) throws SQLException { - if (isHarvestable(harvestedCollection) && (harvestedCollection.getHarvestStatus() == HarvestedCollection.STATUS_READY || harvestedCollection.getHarvestStatus() == HarvestedCollection.STATUS_OAI_ERROR)) - { + if (isHarvestable(harvestedCollection) && (harvestedCollection + .getHarvestStatus() == HarvestedCollection.STATUS_READY || harvestedCollection + .getHarvestStatus() == HarvestedCollection.STATUS_OAI_ERROR)) { return true; } @@ -92,14 +93,12 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic @Override public List findReady(Context context) throws SQLException { int harvestInterval = ConfigurationManager.getIntProperty("oai", "harvester.harvestFrequency"); - if (harvestInterval == 0) - { + if (harvestInterval == 0) { harvestInterval = 720; } int expirationInterval = ConfigurationManager.getIntProperty("oai", "harvester.threadTimeout"); - if (expirationInterval == 0) - { + if (expirationInterval == 0) { expirationInterval = 24; } @@ -115,8 +114,12 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic calendar.add(Calendar.HOUR, -2 * expirationInterval); expirationTime = calendar.getTime(); - int[] statuses = new int[]{HarvestedCollection.STATUS_READY, HarvestedCollection.STATUS_OAI_ERROR}; - return harvestedCollectionDAO.findByLastHarvestedAndHarvestTypeAndHarvestStatusesAndHarvestTime(context, startTime, HarvestedCollection.TYPE_NONE, statuses, HarvestedCollection.STATUS_BUSY, expirationTime); + int[] statuses = new int[] {HarvestedCollection.STATUS_READY, HarvestedCollection.STATUS_OAI_ERROR}; + return harvestedCollectionDAO + .findByLastHarvestedAndHarvestTypeAndHarvestStatusesAndHarvestTime(context, startTime, + HarvestedCollection.TYPE_NONE, statuses, + HarvestedCollection.STATUS_BUSY, + expirationTime); } @Override @@ -126,12 +129,16 @@ public class HarvestedCollectionServiceImpl implements HarvestedCollectionServic @Override public HarvestedCollection findOldestHarvest(Context context) throws SQLException { - return harvestedCollectionDAO.findByStatusAndMinimalTypeOrderByLastHarvestedAsc(context, HarvestedCollection.STATUS_READY, HarvestedCollection.TYPE_NONE, 1); + return harvestedCollectionDAO + .findByStatusAndMinimalTypeOrderByLastHarvestedAsc(context, HarvestedCollection.STATUS_READY, + HarvestedCollection.TYPE_NONE, 1); } @Override public HarvestedCollection findNewestHarvest(Context context) throws SQLException { - return harvestedCollectionDAO.findByStatusAndMinimalTypeOrderByLastHarvestedDesc(context, HarvestedCollection.STATUS_READY, HarvestedCollection.TYPE_NONE, 1); + return harvestedCollectionDAO + .findByStatusAndMinimalTypeOrderByLastHarvestedDesc(context, HarvestedCollection.STATUS_READY, + HarvestedCollection.TYPE_NONE, 1); } @Override diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestedItem.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestedItem.java index 5b2f840665..87d2a58749 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestedItem.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestedItem.java @@ -8,31 +8,40 @@ package org.dspace.harvest; import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; -import javax.persistence.*; - /** * @author Alexey Maslov */ @Entity -@Table(name="harvested_item") -public class HarvestedItem implements ReloadableEntity -{ +@Table(name = "harvested_item") +public class HarvestedItem implements ReloadableEntity { @Id - @Column(name="id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="harvested_item_seq") - @SequenceGenerator(name="harvested_item_seq", sequenceName="harvested_item_seq", allocationSize = 1) + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "harvested_item_seq") + @SequenceGenerator(name = "harvested_item_seq", sequenceName = "harvested_item_seq", allocationSize = 1) private Integer id; @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name="item_id", unique = true) + @JoinColumn(name = "item_id", unique = true) private Item item; - @Column(name = "last_harvested", columnDefinition="timestamp with time zone") + @Column(name = "last_harvested", columnDefinition = "timestamp with time zone") @Temporal(TemporalType.TIMESTAMP) private Date lastHarvested; @@ -43,10 +52,8 @@ public class HarvestedItem implements ReloadableEntity /** * Protected constructor, create object using: * {@link org.dspace.harvest.service.HarvestedItemService#create(Context, Item, String)} - * */ - protected HarvestedItem() - { + protected HarvestedItem() { } public Integer getID() { @@ -57,8 +64,7 @@ public class HarvestedItem implements ReloadableEntity this.item = item; } - public Item getItem() - { + public Item getItem() { return item; } @@ -68,36 +74,34 @@ public class HarvestedItem implements ReloadableEntity } /** - * Get the oai_id associated with this item + * Get the oai_id associated with this item * * @return itemOaiID item's OAI identifier */ - public String getOaiID() - { + public String getOaiID() { return oaiId; } - + /** - * Set the oai_id associated with this item + * Set the oai_id associated with this item * * @param itemOaiID item's OAI identifier */ - public void setOaiID(String itemOaiID) - { - this.oaiId = itemOaiID; + public void setOaiID(String itemOaiID) { + this.oaiId = itemOaiID; return; } - - + + public void setHarvestDate(Date date) { - if (date == null) { - date = new Date(); - } - lastHarvested = date; + if (date == null) { + date = new Date(); + } + lastHarvested = date; } - + public Date getHarvestDate() { - return lastHarvested; + return lastHarvested; } } diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestedItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestedItemServiceImpl.java index 97ded2abe0..32cc3f8358 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestedItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestedItemServiceImpl.java @@ -7,6 +7,8 @@ */ package org.dspace.harvest; +import java.sql.SQLException; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.core.Context; @@ -14,8 +16,6 @@ import org.dspace.harvest.dao.HarvestedItemDAO; import org.dspace.harvest.service.HarvestedItemService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; - /** * Service implementation for the HarvestedItem object. * This class is responsible for all business logic calls for the HarvestedItem object and is autowired by spring. @@ -28,8 +28,7 @@ public class HarvestedItemServiceImpl implements HarvestedItemService { @Autowired(required = true) protected HarvestedItemDAO harvestedItemDAO; - protected HarvestedItemServiceImpl() - { + protected HarvestedItemServiceImpl() { } @@ -41,12 +40,9 @@ public class HarvestedItemServiceImpl implements HarvestedItemService { @Override public Item getItemByOAIId(Context context, String itemOaiID, Collection collection) throws SQLException { HarvestedItem harvestedItem = harvestedItemDAO.findByOAIId(context, itemOaiID, collection); - if(harvestedItem != null) - { + if (harvestedItem != null) { return harvestedItem.getItem(); - } - else - { + } else { return null; } } diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestingException.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestingException.java index 5c6c2b1950..4562b789ca 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestingException.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestingException.java @@ -8,14 +8,16 @@ package org.dspace.harvest; /** - * Exception class specifically assigned to recoverable errors that occur during harvesting. Throughout the harvest process, various exceptions + * Exception class specifically assigned to recoverable errors that occur during harvesting. Throughout the harvest + * process, various exceptions * are caught and turned into a HarvestingException. Uncaught exceptions are irrecoverable errors. + * * @author alexey */ -public class HarvestingException extends Exception{ +public class HarvestingException extends Exception { public HarvestingException() { - super(); - } + super(); + } public HarvestingException(String message, Throwable t) { super(message, t); diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java index cd728ac4a1..4593f10592 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java +++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java @@ -7,17 +7,57 @@ */ package org.dspace.harvest; -import ORG.oclc.oai.harvester2.verb.*; +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.ConnectException; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.TimeZone; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import ORG.oclc.oai.harvester2.verb.GetRecord; +import ORG.oclc.oai.harvester2.verb.Identify; +import ORG.oclc.oai.harvester2.verb.ListIdentifiers; +import ORG.oclc.oai.harvester2.verb.ListMetadataFormats; +import ORG.oclc.oai.harvester2.verb.ListRecords; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.WorkspaceItem; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.IngestionCrosswalk; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.dspace.core.*; +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.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; +import org.dspace.core.Utils; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.core.service.PluginService; import org.dspace.handle.factory.HandleServiceFactory; @@ -34,14 +74,6 @@ import org.jdom.input.DOMBuilder; import org.jdom.output.XMLOutputter; import org.xml.sax.SAXException; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; -import java.io.*; -import java.net.ConnectException; -import java.sql.SQLException; -import java.text.SimpleDateFormat; -import java.util.*; - /** * This class handles OAI harvesting of externally located records into this repository. @@ -53,7 +85,9 @@ import java.util.*; public class OAIHarvester { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(OAIHarvester.class); private static final Namespace ATOM_NS = Namespace.getNamespace("http://www.w3.org/2005/Atom"); @@ -100,8 +134,7 @@ public class OAIHarvester { // The point at which this thread should terminate itself /* Initialize the harvester with a collection object */ - public OAIHarvester(Context c, DSpaceObject dso, HarvestedCollection hc) throws HarvestingException, SQLException - { + public OAIHarvester(Context c, DSpaceObject dso, HarvestedCollection hc) throws HarvestingException, SQLException { bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); bundleService = ContentServiceFactory.getInstance().getBundleService(); @@ -118,17 +151,15 @@ public class OAIHarvester { configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - if (dso.getType() != Constants.COLLECTION) - { + if (dso.getType() != Constants.COLLECTION) { throw new HarvestingException("OAIHarvester can only harvest collections"); } ourContext = c; - targetCollection = (Collection)dso; + targetCollection = (Collection) dso; harvestRow = hc; - if (harvestRow == null || !harvestedCollection.isHarvestable(harvestRow)) - { + if (harvestRow == null || !harvestedCollection.isHarvestable(harvestRow)) { throw new HarvestingException("Provided collection is not set up for harvesting"); } @@ -144,7 +175,9 @@ public class OAIHarvester { metadataNS = OAIHarvester.getDMDNamespace(metadataKey); if (metadataNS == null) { - log.error("No matching metadata namespace found for \"" + metadataKey + "\", see oai.cfg option \"oai.harvester.metadataformats.{MetadataKey} = {MetadataNS},{Display Name}\""); + log.error( + "No matching metadata namespace found for \"" + metadataKey + "\", see oai.cfg option \"oai.harvester" + + ".metadataformats.{MetadataKey} = {MetadataNS},{Display Name}\""); throw new HarvestingException("Metadata declaration not found"); } } @@ -152,6 +185,7 @@ public class OAIHarvester { /** * Search the configuration options and find the ORE serialization string + * * @return Namespace of the supported ORE format. Returns null if not found. */ private static Namespace getORENamespace() { @@ -161,9 +195,8 @@ public class OAIHarvester { List keys = DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys(oreString); - for(String key : keys) - { - ORESeialKey = key.substring(oreString.length()+1); + for (String key : keys) { + ORESeialKey = key.substring(oreString.length() + 1); ORESerializationString = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(key); return Namespace.getNamespace(ORESeialKey, ORESerializationString); @@ -176,6 +209,7 @@ public class OAIHarvester { /** * Cycle through the options and find the metadata namespace matching the provided key. + * * @param metadataKey * @return Namespace of the designated metadata format. Returns null of not found. */ @@ -185,17 +219,13 @@ public class OAIHarvester { List keys = DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys(metaString); - for(String key : keys) - { - if (key.substring(metaString.length()+1).equals((metadataKey))) { + for (String key : keys) { + if (key.substring(metaString.length() + 1).equals((metadataKey))) { metadataString = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(key); String namespacePiece; - if (metadataString.indexOf(',') != -1) - { + if (metadataString.indexOf(',') != -1) { namespacePiece = metadataString.substring(0, metadataString.indexOf(',')); - } - else - { + } else { namespacePiece = metadataString; } @@ -207,19 +237,16 @@ public class OAIHarvester { /** - * Performs a harvest cycle on this collection. This will query the remote OAI-PMH provider, check for updates since last + * Performs a harvest cycle on this collection. This will query the remote OAI-PMH provider, check for updates + * since last * harvest, and ingest the returned items. * - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ - public void runHarvest() throws SQLException, IOException, AuthorizeException - { + public void runHarvest() throws SQLException, IOException, AuthorizeException { Context.Mode originalMode = ourContext.getCurrentMode(); ourContext.setMode(Context.Mode.BATCH_EDIT); @@ -228,56 +255,54 @@ public class OAIHarvester { String oaiSetId = harvestRow.getOaiSetId(); //If we have all selected then make sure that we do not include a set filter - if ("all".equals(oaiSetId)) - { + if ("all".equals(oaiSetId)) { oaiSetId = null; } Date lastHarvestDate = harvestRow.getHarvestDate(); String fromDate = null; - if (lastHarvestDate != null) - { + if (lastHarvestDate != null) { fromDate = processDate(harvestRow.getHarvestDate()); } long totalListSize = 0; long currentRecord = 0; Date startTime = new Date(); - String toDate = processDate(startTime,0); + String toDate = processDate(startTime, 0); String dateGranularity; - try - { + try { // obtain the desired descriptive metadata format and verify that the OAI server actually provides it // do the same thing for ORE, which should be encoded in Atom and carry its namespace String descMDPrefix = null; String OREPrefix; try { dateGranularity = oaiGetDateGranularity(oaiSource); - if (fromDate != null) - { + if (fromDate != null) { fromDate = fromDate.substring(0, dateGranularity.length()); } toDate = toDate.substring(0, dateGranularity.length()); descMDPrefix = oaiResolveNamespaceToPrefix(oaiSource, metadataNS.getURI()); OREPrefix = oaiResolveNamespaceToPrefix(oaiSource, ORESerialNS.getURI()); - } - catch (FileNotFoundException fe) { + } catch (FileNotFoundException fe) { log.error("The OAI server did not respond."); throw new HarvestingException("The OAI server did not respond.", fe); - } - catch (ConnectException fe) { + } catch (ConnectException fe) { log.error("The OAI server did not respond."); throw new HarvestingException("The OAI server did not respond.", fe); } if (descMDPrefix == null) { log.error("The OAI server does not support this metadata format"); - throw new HarvestingException("The OAI server does not support this metadata format: " + metadataNS.getURI()); + throw new HarvestingException( + "The OAI server does not support this metadata format: " + metadataNS.getURI()); } if (OREPrefix == null && harvestRow.getHarvestType() != HarvestedCollection.TYPE_DMD) { - throw new HarvestingException("The OAI server does not support ORE dissemination in the configured serialization format: " + ORESerialNS.getURI()); + throw new HarvestingException( + "The OAI server does not support ORE dissemination in the configured serialization format: " + + ORESerialNS + .getURI()); } Document oaiResponse = null; @@ -293,8 +318,7 @@ public class OAIHarvester { // expiration timer starts int expirationInterval = configurationService.getIntProperty("oai.harvester.threadTimeout"); - if (expirationInterval == 0) - { + if (expirationInterval == 0) { expirationInterval = 24; } @@ -308,26 +332,24 @@ public class OAIHarvester { Set errorSet = new HashSet(); ListRecords listRecords = new ListRecords(oaiSource, fromDate, toDate, oaiSetId, descMDPrefix); - log.debug("Harvesting request parameters: listRecords " + oaiSource + " " + fromDate + " " + toDate + " " + oaiSetId + " " + descMDPrefix); - if (listRecords != null) - { + log.debug( + "Harvesting request parameters: listRecords " + oaiSource + " " + fromDate + " " + toDate + " " + + oaiSetId + " " + descMDPrefix); + if (listRecords != null) { log.info("HTTP Request: " + listRecords.getRequestURL()); } - while (listRecords != null) - { + while (listRecords != null) { records = new ArrayList(); oaiResponse = db.build(listRecords.getDocument()); - if (listRecords.getErrors() != null && listRecords.getErrors().getLength() > 0) - { - for (int i=0; i 0) { + for (int i = 0; i < listRecords.getErrors().getLength(); i++) { + String errorCode = listRecords.getErrors().item(i).getAttributes().getNamedItem("code") + .getTextContent(); errorSet.add(errorCode); } - if (errorSet.contains("noRecordsMatch")) - { + if (errorSet.contains("noRecordsMatch")) { log.info("noRecordsMatch: OAI server did not contain any updates"); harvestRow.setHarvestStartTime(new Date()); harvestRow.setHarvestMessage("OAI server did not contain any updates"); @@ -337,13 +359,12 @@ public class OAIHarvester { } else { throw new HarvestingException(errorSet.toString()); } - } - else - { + } else { root = oaiResponse.getRootElement(); records.addAll(root.getChild("ListRecords", OAI_NS).getChildren("record", OAI_NS)); - Element resumptionElement = root.getChild("ListRecords", OAI_NS).getChild("resumptionToken", OAI_NS); + Element resumptionElement = root.getChild("ListRecords", OAI_NS) + .getChild("resumptionToken", OAI_NS); if (resumptionElement != null && resumptionElement.getAttribute("completeListSize") != null) { String value = resumptionElement.getAttribute("completeListSize").getValue(); if (StringUtils.isNotBlank(value)) { @@ -353,19 +374,18 @@ public class OAIHarvester { } // Process the obtained records - if (records != null && records.size()>0) - { + if (records != null && records.size() > 0) { log.info("Found " + records.size() + " records to process"); for (Element record : records) { // check for STOP interrupt from the scheduler - if (HarvestScheduler.getInterrupt() == HarvestScheduler.HARVESTER_INTERRUPT_STOP) - { - throw new HarvestingException("Harvest process for " + targetCollection.getID() + " interrupted by stopping the scheduler."); + if (HarvestScheduler.getInterrupt() == HarvestScheduler.HARVESTER_INTERRUPT_STOP) { + throw new HarvestingException("Harvest process for " + targetCollection + .getID() + " interrupted by stopping the scheduler."); } // check for timeout - if (expirationTime.before(new Date())) - { - throw new HarvestingException("runHarvest method timed out for collection " + targetCollection.getID()); + if (expirationTime.before(new Date())) { + throw new HarvestingException( + "runHarvest method timed out for collection " + targetCollection.getID()); } currentRecord++; @@ -381,15 +401,16 @@ public class OAIHarvester { resumptionToken = listRecords.getResumptionToken(); if (resumptionToken == null || resumptionToken.length() == 0) { listRecords = null; - } - else { + } else { listRecords = new ListRecords(oaiSource, resumptionToken); } ourContext.turnOffAuthorisationSystem(); try { collectionService.update(ourContext, targetCollection); - harvestRow.setHarvestMessage(String.format("Collection is currently being harvested (item %d of %d)", currentRecord, totalListSize)); + harvestRow.setHarvestMessage(String + .format("Collection is currently being harvested (item %d of %d)", + currentRecord, totalListSize)); harvestedCollection.update(ourContext, harvestRow); } finally { //In case of an exception, make sure to restore our authentication state to the previous state @@ -399,8 +420,7 @@ public class OAIHarvester { ourContext.dispatchEvents(); intermediateCommit(); } - } - catch (HarvestingException hex) { + } catch (HarvestingException hex) { log.error("Harvesting error occurred while processing an OAI record: " + hex.getMessage(), hex); harvestRow.setHarvestMessage("Error occurred while processing an OAI record"); @@ -412,8 +432,7 @@ public class OAIHarvester { harvestedCollection.update(ourContext, harvestRow); ourContext.complete(); return; - } - catch (Exception ex) { + } catch (Exception ex) { harvestRow.setHarvestMessage("Unknown error occurred while generating an OAI response"); harvestRow.setHarvestStatus(HarvestedCollection.STATUS_UNKNOWN_ERROR); harvestedCollection.update(ourContext, harvestRow); @@ -421,8 +440,7 @@ public class OAIHarvester { log.error("Error occurred while generating an OAI response: " + ex.getMessage() + " " + ex.getCause(), ex); ourContext.complete(); return; - } - finally { + } finally { harvestedCollection.update(ourContext, harvestRow); ourContext.turnOffAuthorisationSystem(); collectionService.update(ourContext, targetCollection); @@ -435,7 +453,9 @@ public class OAIHarvester { harvestRow.setHarvestStartTime(startTime); harvestRow.setHarvestMessage("Harvest from " + oaiSource + " successful"); harvestRow.setHarvestStatus(HarvestedCollection.STATUS_READY); - log.info("Harvest from " + oaiSource + " successful. The process took " + timeTaken + " milliseconds. Harvested " + currentRecord + " items."); + log.info( + "Harvest from " + oaiSource + " successful. The process took " + timeTaken + " milliseconds. Harvested " + + currentRecord + " items."); harvestedCollection.update(ourContext, harvestRow); ourContext.setMode(originalMode); @@ -455,33 +475,33 @@ public class OAIHarvester { /** * Process an individual PMH record, making (or updating) a corresponding DSpace Item. * - * @param record a JDOM Element containing the actual PMH record with descriptive metadata. - * @param OREPrefix the metadataprefix value used by the remote PMH server to disseminate ORE. Only used for collections set up to harvest content. + * @param record a JDOM Element containing the actual PMH record with descriptive metadata. + * @param OREPrefix the metadataprefix value used by the remote PMH server to disseminate ORE. Only used for + * collections set up to harvest content. * @param currentRecord current record number to log * @param totalListSize The total number of records that this Harvest contains - * - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws CrosswalkException if crosswalk error - * @throws HarvestingException if harvesting error + * @throws SQLException An exception that provides information on a database access error or + * other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have + * permission + * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O + * operations. + * @throws CrosswalkException if crosswalk error + * @throws HarvestingException if harvesting error * @throws ParserConfigurationException XML parsing error - * @throws SAXException if XML processing error - * @throws TransformerException if XML transformer error + * @throws SAXException if XML processing error + * @throws TransformerException if XML transformer error */ protected void processRecord(Element record, String OREPrefix, final long currentRecord, long totalListSize) - throws SQLException, AuthorizeException, IOException, CrosswalkException, HarvestingException, ParserConfigurationException, SAXException, TransformerException - { + throws SQLException, AuthorizeException, IOException, CrosswalkException, HarvestingException, + ParserConfigurationException, SAXException, TransformerException { WorkspaceItem wi = null; Date timeStart = new Date(); // grab the oai identifier String itemOaiID = record.getChild("header", OAI_NS).getChild("identifier", OAI_NS).getText(); - Element header = record.getChild("header",OAI_NS); + Element header = record.getChild("header", OAI_NS); // look up the item corresponding to the OAI identifier Item item = harvestedItemService.getItemByOAIId(ourContext, itemOaiID, targetCollection); @@ -489,8 +509,7 @@ public class OAIHarvester { // Make sure the item hasn't been deleted in the mean time if (header.getAttribute("status") != null && header.getAttribute("status").getValue().equals("deleted")) { log.info("Item " + itemOaiID + " has been marked as deleted on the OAI server."); - if (item != null) - { + if (item != null) { collectionService.removeItem(ourContext, targetCollection, item); } @@ -500,14 +519,15 @@ public class OAIHarvester { // If we are only harvesting descriptive metadata, the record should already contain all we need List descMD = record.getChild("metadata", OAI_NS).getChildren(); - IngestionCrosswalk MDxwalk = (IngestionCrosswalk)pluginService.getNamedPlugin(IngestionCrosswalk.class, this.metadataKey); + IngestionCrosswalk MDxwalk = (IngestionCrosswalk) pluginService + .getNamedPlugin(IngestionCrosswalk.class, this.metadataKey); // Otherwise, obtain the ORE ReM and initiate the ORE crosswalk IngestionCrosswalk ORExwalk = null; Element oreREM = null; if (harvestRow.getHarvestType() > 1) { oreREM = getMDrecord(harvestRow.getOaiSource(), itemOaiID, OREPrefix).get(0); - ORExwalk = (IngestionCrosswalk)pluginService.getNamedPlugin(IngestionCrosswalk.class, this.ORESerialKey); + ORExwalk = (IngestionCrosswalk) pluginService.getNamedPlugin(IngestionCrosswalk.class, this.ORESerialKey); } // Ignore authorization @@ -515,30 +535,30 @@ public class OAIHarvester { HarvestedItem hi; - if (item != null) // found an item so we modify - { + // found an item so we modify + if (item != null) { log.debug("Item " + item.getHandle() + " was found locally. Using it to harvest " + itemOaiID + "."); // FIXME: check for null pointer if for some odd reason we don't have a matching hi hi = harvestedItemService.find(ourContext, item); // Compare last-harvest on the item versus the last time the item was updated on the OAI provider side - // If ours is more recent, forgo this item, since it's probably a left-over from a previous harvesting attempt + // If ours is more recent, forgo this item, since it's probably a left-over from a previous harvesting + // attempt Date OAIDatestamp = Utils.parseISO8601Date(header.getChildText("datestamp", OAI_NS)); Date itemLastHarvest = hi.getHarvestDate(); if (itemLastHarvest != null && OAIDatestamp.before(itemLastHarvest)) { - log.info("Item " + item.getHandle() + " was harvested more recently than the last update time reported by the OAI server; skipping."); + log.info("Item " + item + .getHandle() + " was harvested more recently than the last update time reported by the OAI " + + "server; skipping."); return; } // Otherwise, clear and re-import the metadata and bitstreams itemService.clearMetadata(ourContext, item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - if (descMD.size() == 1) - { + if (descMD.size() == 1) { MDxwalk.ingest(ourContext, item, descMD.get(0), true); - } - else - { + } else { MDxwalk.ingest(ourContext, item, descMD, true); } @@ -552,23 +572,19 @@ public class OAIHarvester { } ORExwalk.ingest(ourContext, item, oreREM, true); } - } - else + } else { // NOTE: did not find, so we create (presumably, there will never be a case where an item already // exists in a harvest collection but does not have an OAI_id) - { + wi = workspaceItemService.create(ourContext, targetCollection, false); item = wi.getItem(); hi = harvestedItemService.create(ourContext, item, itemOaiID); //item.setOaiID(itemOaiID); - if (descMD.size() == 1) - { + if (descMD.size() == 1) { MDxwalk.ingest(ourContext, item, descMD.get(0), true); - } - else - { + } else { MDxwalk.ingest(ourContext, item, descMD, true); } @@ -579,37 +595,37 @@ public class OAIHarvester { // see if a handle can be extracted for the item String handle = extractHandle(item); - if (handle != null) - { + if (handle != null) { DSpaceObject dso = handleService.resolveToObject(ourContext, handle); - if (dso != null) - { - throw new HarvestingException("Handle collision: attempted to re-assign handle '" + handle + "' to an incoming harvested item '" + hi.getOaiID() + "'."); + if (dso != null) { + throw new HarvestingException( + "Handle collision: attempted to re-assign handle '" + handle + "' to an incoming harvested " + + "item '" + hi + .getOaiID() + "'."); } } try { item = installItemService.installItem(ourContext, wi, handle); //item = InstallItem.installItem(ourContext, wi); - } - // clean up the workspace item if something goes wrong before - catch(SQLException | IOException | AuthorizeException se) { + } catch (SQLException | IOException | AuthorizeException se) { + // clean up the workspace item if something goes wrong before workspaceItemService.deleteWrapper(ourContext, wi); throw se; } } // Now create the special ORE bundle and drop the ORE document in it - if (harvestRow.getHarvestType() == 2 || harvestRow.getHarvestType() == 3) - { + if (harvestRow.getHarvestType() == 2 || harvestRow.getHarvestType() == 3) { Bundle OREBundle = null; List OREBundles = itemService.getBundles(item, "ORE"); Bitstream OREBitstream = null; - if ( OREBundles.size() > 0 ) + if (OREBundles.size() > 0) { OREBundle = OREBundles.get(0); - else + } else { OREBundle = bundleService.create(ourContext, item, "ORE"); + } XMLOutputter outputter = new XMLOutputter(); String OREString = outputter.outputString(oreREM); @@ -617,8 +633,9 @@ public class OAIHarvester { OREBitstream = bundleService.getBitstreamByName(OREBundle, "ORE.xml"); - if ( OREBitstream != null ) + if (OREBitstream != null) { bundleService.removeBitstream(ourContext, OREBundle, OREBitstream); + } OREBitstream = bitstreamService.create(ourContext, OREBundle, OREStream); OREBitstream.setName(ourContext, "ORE.xml"); @@ -636,67 +653,62 @@ public class OAIHarvester { // Add provenance that this item was harvested via OAI String provenanceMsg = "Item created via OAI harvest from source: " - + this.harvestRow.getOaiSource() + " on " + new DCDate(hi.getHarvestDate()) - + " (GMT). Item's OAI Record identifier: " + hi.getOaiID(); + + this.harvestRow.getOaiSource() + " on " + new DCDate(hi.getHarvestDate()) + + " (GMT). Item's OAI Record identifier: " + hi.getOaiID(); itemService.addMetadata(ourContext, item, "dc", "description", "provenance", "en", provenanceMsg); itemService.update(ourContext, item); harvestedItemService.update(ourContext, hi); long timeTaken = new Date().getTime() - timeStart.getTime(); log.info(String.format("Item %s (%s) has been ingested (item %d of %d). The whole process took: %d ms.", - item.getHandle(), item.getID(), currentRecord, totalListSize, timeTaken)); + item.getHandle(), item.getID(), currentRecord, totalListSize, timeTaken)); - //Clear the context cache - ourContext.uncacheEntity(wi); - ourContext.uncacheEntity(hi); - ourContext.uncacheEntity(item); + //Clear the context cache + ourContext.uncacheEntity(wi); + ourContext.uncacheEntity(hi); + ourContext.uncacheEntity(item); - // Stop ignoring authorization - ourContext.restoreAuthSystemState(); + // Stop ignoring authorization + ourContext.restoreAuthSystemState(); } - /** - * Scan an item's metadata, looking for the value "identifier.*". If it meets the parameters that identify it as valid handle - * as set in dspace.cfg (harvester.acceptedHandleServer and harvester.rejectedHandlePrefix), use that handle instead of + * Scan an item's metadata, looking for the value "identifier.*". If it meets the parameters that identify it as + * valid handle + * as set in dspace.cfg (harvester.acceptedHandleServer and harvester.rejectedHandlePrefix), use that handle + * instead of * minting a new one. + * * @param item a newly created, but not yet installed, DSpace Item * @return null or the handle to be used. */ - protected String extractHandle(Item item) - { + protected String extractHandle(Item item) { String[] acceptedHandleServers = configurationService.getArrayProperty("oai.harvester.acceptedHandleServer"); - if (acceptedHandleServers == null) - { - acceptedHandleServers = new String[]{"hdl.handle.net"}; + if (acceptedHandleServers == null) { + acceptedHandleServers = new String[] {"hdl.handle.net"}; } String[] rejectedHandlePrefixes = configurationService.getArrayProperty("oai.harvester.rejectedHandlePrefix"); - if (rejectedHandlePrefixes == null) - { - rejectedHandlePrefixes = new String[]{"123456789"}; + if (rejectedHandlePrefixes == null) { + rejectedHandlePrefixes = new String[] {"123456789"}; } List values = itemService.getMetadata(item, "dc", "identifier", Item.ANY, Item.ANY); - if (values.size() > 0 && acceptedHandleServers != null) - { - for (MetadataValue value : values) - { + if (values.size() > 0 && acceptedHandleServers != null) { + for (MetadataValue value : values) { // 0 1 2 3 4 // http://hdl.handle.net/1234/12 String[] urlPieces = value.getValue().split("/"); - if (urlPieces.length != 5) - { + if (urlPieces.length != 5) { continue; } for (String server : acceptedHandleServers) { if (urlPieces[2].equals(server)) { for (String prefix : rejectedHandlePrefixes) { - if (!urlPieces[3].equals(prefix)) - { + if (!urlPieces[3].equals(prefix)) { return urlPieces[3] + "/" + urlPieces[4]; } } @@ -710,12 +722,13 @@ public class OAIHarvester { } - /** - * Process a date, converting it to RFC3339 format, setting the timezone to UTC and subtracting time padding - * from the config file. - * @param date source Date - * @return a string in the format 'yyyy-mm-ddThh:mm:ssZ' and converted to UTC timezone - */ + /** + * Process a date, converting it to RFC3339 format, setting the timezone to UTC and subtracting time padding + * from the config file. + * + * @param date source Date + * @return a string in the format 'yyyy-mm-ddThh:mm:ssZ' and converted to UTC timezone + */ private String processDate(Date date) { Integer timePad = configurationService.getIntProperty("oai.harvester.timePadding"); @@ -727,12 +740,13 @@ public class OAIHarvester { } /** - * Process a date, converting it to RFC3339 format, setting the timezone to UTC and subtracting time padding - * from the config file. - * @param date source Date - * @param secondsPad number of seconds to subtract from the date - * @return a string in the format 'yyyy-mm-ddThh:mm:ssZ' and converted to UTC timezone - */ + * Process a date, converting it to RFC3339 format, setting the timezone to UTC and subtracting time padding + * from the config file. + * + * @param date source Date + * @param secondsPad number of seconds to subtract from the date + * @return a string in the format 'yyyy-mm-ddThh:mm:ssZ' and converted to UTC timezone + */ private String processDate(Date date, int secondsPad) { SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); @@ -740,7 +754,7 @@ public class OAIHarvester { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); - calendar.add(Calendar.SECOND, -1*secondsPad); + calendar.add(Calendar.SECOND, -1 * secondsPad); date = calendar.getTime(); return formatter.format(date); @@ -749,33 +763,35 @@ public class OAIHarvester { /** * Query OAI-PMH server for the granularity of its datestamps. - * @throws IOException if IO error - * @throws SAXException if XML processing error + * + * @throws IOException if IO error + * @throws SAXException if XML processing error * @throws ParserConfigurationException XML parsing error - * @throws TransformerException if XML transformer error + * @throws TransformerException if XML transformer error */ - private String oaiGetDateGranularity(String oaiSource) throws IOException, ParserConfigurationException, SAXException, TransformerException - { + private String oaiGetDateGranularity(String oaiSource) + throws IOException, ParserConfigurationException, SAXException, TransformerException { Identify iden = new Identify(oaiSource); return iden.getDocument().getElementsByTagNameNS(OAI_NS.getURI(), "granularity").item(0).getTextContent(); } /** * Query the OAI-PMH server for its mapping of the supplied namespace and metadata prefix. - * For example for a typical OAI-PMH server a query "http://www.openarchives.org/OAI/2.0/oai_dc/" would return "oai_dc". - * @param oaiSource the address of the OAI-PMH provider + * For example for a typical OAI-PMH server a query "http://www.openarchives.org/OAI/2.0/oai_dc/" would return + * "oai_dc". + * + * @param oaiSource the address of the OAI-PMH provider * @param MDNamespace the namespace that we are trying to resolve to the metadataPrefix * @return metadataPrefix the OAI-PMH provider has assigned to the supplied namespace - * - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O + * operations. * @throws ParserConfigurationException XML parsing error - * @throws SAXException if XML processing error - * @throws TransformerException if XML transformer error - * @throws ConnectException if could not connect to OAI server + * @throws SAXException if XML processing error + * @throws TransformerException if XML transformer error + * @throws ConnectException if could not connect to OAI server */ - public static String oaiResolveNamespaceToPrefix(String oaiSource, String MDNamespace) throws IOException, ParserConfigurationException, SAXException, TransformerException, ConnectException - { + public static String oaiResolveNamespaceToPrefix(String oaiSource, String MDNamespace) + throws IOException, ParserConfigurationException, SAXException, TransformerException, ConnectException { String metaPrefix = null; // Query the OAI server for the metadata @@ -783,11 +799,11 @@ public class OAIHarvester { if (lmf != null) { Document lmfResponse = db.build(lmf.getDocument()); - List mdFormats = lmfResponse.getRootElement().getChild("ListMetadataFormats", OAI_NS).getChildren("metadataFormat", OAI_NS); + List mdFormats = lmfResponse.getRootElement().getChild("ListMetadataFormats", OAI_NS) + .getChildren("metadataFormat", OAI_NS); for (Element mdFormat : mdFormats) { - if (MDNamespace.equals(mdFormat.getChildText("metadataNamespace", OAI_NS))) - { + if (MDNamespace.equals(mdFormat.getChildText("metadataNamespace", OAI_NS))) { metaPrefix = mdFormat.getChildText("metadataPrefix", OAI_NS); break; } @@ -799,11 +815,12 @@ public class OAIHarvester { /** * Generate and send an email to the administrator. Prompted by errors encountered during harvesting. - * @param status the current status of the collection, usually HarvestedCollection.STATUS_OAI_ERROR or HarvestedCollection.STATUS_UNKNOWN_ERROR - * @param ex the Exception that prompted this action + * + * @param status the current status of the collection, usually HarvestedCollection.STATUS_OAI_ERROR or + * HarvestedCollection.STATUS_UNKNOWN_ERROR + * @param ex the Exception that prompted this action */ - protected void alertAdmin(int status, Exception ex) - { + protected void alertAdmin(int status, Exception ex) { try { String recipient = configurationService.getProperty("alert.recipient"); @@ -838,43 +855,44 @@ public class OAIHarvester { } - /** * Query the OAI-PMH provider for a specific metadata record. - * @param oaiSource the address of the OAI-PMH provider - * @param itemOaiId the OAI identifier of the target item + * + * @param oaiSource the address of the OAI-PMH provider + * @param itemOaiId the OAI identifier of the target item * @param metadataPrefix the OAI metadataPrefix of the desired metadata * @return list of JDOM elements corresponding to the metadata entries in the located record. - * - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O + * operations. * @throws ParserConfigurationException XML parsing error - * @throws SAXException if XML processing error - * @throws TransformerException if XML transformer error - * @throws HarvestingException if harvesting error + * @throws SAXException if XML processing error + * @throws TransformerException if XML transformer error + * @throws HarvestingException if harvesting error */ - protected List getMDrecord(String oaiSource, String itemOaiId, String metadataPrefix) throws IOException, ParserConfigurationException, SAXException, TransformerException, HarvestingException - { - GetRecord getRecord = new GetRecord(oaiSource,itemOaiId,metadataPrefix); + protected List getMDrecord(String oaiSource, String itemOaiId, String metadataPrefix) + throws IOException, ParserConfigurationException, SAXException, TransformerException, HarvestingException { + GetRecord getRecord = new GetRecord(oaiSource, itemOaiId, metadataPrefix); Set errorSet = new HashSet(); // If the metadata is not available for this item, can the whole thing if (getRecord != null && getRecord.getErrors() != null && getRecord.getErrors().getLength() > 0) { - for (int i=0; i verifyOAIharvester() { @@ -889,33 +907,27 @@ public class OAIHarvester { * Verify the existence of an OAI server with the specified set and * supporting the provided metadata formats. * - * @param oaiSource - * the address of the OAI-PMH provider - * @param oaiSetId - * OAI set identifier - * @param metaPrefix - * OAI metadataPrefix - * @param testORE whether the method should also check the PMH provider for ORE support + * @param oaiSource the address of the OAI-PMH provider + * @param oaiSetId OAI set identifier + * @param metaPrefix OAI metadataPrefix + * @param testORE whether the method should also check the PMH provider for ORE support * @return list of errors encountered during verification. Empty list indicates a "success" condition. */ public static List verifyOAIharvester(String oaiSource, - String oaiSetId, String metaPrefix, boolean testORE) - { + String oaiSetId, String metaPrefix, boolean testORE) { List errorSet = new ArrayList(); // First, see if we can contact the target server at all. try { new Identify(oaiSource); - } - catch (Exception ex) { + } catch (Exception ex) { errorSet.add(OAI_ADDRESS_ERROR + ": OAI server could not be reached."); return errorSet; } // Next, make sure the metadata we need is supported by the target server Namespace DMD_NS = OAIHarvester.getDMDNamespace(metaPrefix); - if (null == DMD_NS) - { + if (null == DMD_NS) { errorSet.add(OAI_DMD_ERROR + ": " + metaPrefix); return errorSet; } @@ -926,22 +938,19 @@ public class OAIHarvester { try { OREOAIPrefix = OAIHarvester.oaiResolveNamespaceToPrefix(oaiSource, getORENamespace().getURI()); DMDOAIPrefix = OAIHarvester.oaiResolveNamespaceToPrefix(oaiSource, DMD_NS.getURI()); - } - catch (Exception ex) { + } catch (Exception ex) { errorSet.add(OAI_ADDRESS_ERROR - + ": OAI did not respond to ListMetadataFormats query (" - + ORE_NS.getPrefix() + ":" + OREOAIPrefix + " ; " - + DMD_NS.getPrefix() + ":" + DMDOAIPrefix + "): " - + ex.getMessage()); + + ": OAI did not respond to ListMetadataFormats query (" + + ORE_NS.getPrefix() + ":" + OREOAIPrefix + " ; " + + DMD_NS.getPrefix() + ":" + DMDOAIPrefix + "): " + + ex.getMessage()); return errorSet; } - if (testORE && OREOAIPrefix == null) - { + if (testORE && OREOAIPrefix == null) { errorSet.add(OAI_ORE_ERROR + ": The OAI server does not support ORE dissemination"); } - if (DMDOAIPrefix == null) - { + if (DMDOAIPrefix == null) { errorSet.add(OAI_DMD_ERROR + ": The OAI server does not support dissemination in this format"); } @@ -954,29 +963,27 @@ public class OAIHarvester { // The only error we can really get here is "noSetHierarchy" if (ls.getErrors() != null && ls.getErrors().getLength() > 0) { - for (int i=0; i { - public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedDesc(Context context, int status, int type, int limit) throws SQLException; + public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedDesc(Context context, int status, int type, + int limit) throws SQLException; - public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedAsc(Context context, int status, int type, int limit) throws SQLException; + public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedAsc(Context context, int status, int type, + int limit) throws SQLException; public List findByStatus(Context context, int status) throws SQLException; public HarvestedCollection findByCollection(Context context, Collection collection) throws SQLException; - List findByLastHarvestedAndHarvestTypeAndHarvestStatusesAndHarvestTime(Context context, Date startTime, int minimalType, int[] statuses, int expirationStatus, Date expirationTime) throws SQLException; + List findByLastHarvestedAndHarvestTypeAndHarvestStatusesAndHarvestTime(Context context, + Date startTime, + int minimalType, + int[] statuses, + int expirationStatus, + Date expirationTime) + throws SQLException; public int count(Context context) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/harvest/dao/HarvestedItemDAO.java b/dspace-api/src/main/java/org/dspace/harvest/dao/HarvestedItemDAO.java index ae58b608aa..e20822decc 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/dao/HarvestedItemDAO.java +++ b/dspace-api/src/main/java/org/dspace/harvest/dao/HarvestedItemDAO.java @@ -7,17 +7,18 @@ */ package org.dspace.harvest.dao; +import java.sql.SQLException; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.harvest.HarvestedItem; -import java.sql.SQLException; - /** * Database Access Object interface class for the HarvestedItem object. - * The implementation of this class is responsible for all database calls for the HarvestedItem object and is autowired by spring + * The implementation of this class is responsible for all database calls for the HarvestedItem object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedCollectionDAOImpl.java b/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedCollectionDAOImpl.java index 401a6cc667..95a0bdf216 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedCollectionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedCollectionDAOImpl.java @@ -7,20 +7,21 @@ */ package org.dspace.harvest.dao.impl; -import org.dspace.content.Collection; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.harvest.HarvestedCollection; -import org.dspace.harvest.dao.HarvestedCollectionDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.LogicalExpression; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; import java.util.Date; +import java.util.LinkedList; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.dspace.content.Collection; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.harvest.HarvestedCollection; +import org.dspace.harvest.HarvestedCollection_; +import org.dspace.harvest.dao.HarvestedCollectionDAO; /** * Hibernate implementation of the Database Access Object interface class for the HarvestedCollection object. @@ -29,98 +30,146 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class HarvestedCollectionDAOImpl extends AbstractHibernateDAO implements HarvestedCollectionDAO -{ - protected HarvestedCollectionDAOImpl() - { +public class HarvestedCollectionDAOImpl extends AbstractHibernateDAO + implements HarvestedCollectionDAO { + protected HarvestedCollectionDAOImpl() { super(); } @Override - public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedDesc(Context context, int status, int type, int limit) throws SQLException { -// Old query: "select collection_id from harvested_collection where harvest_type > ? and harvest_status = ? order by last_harvested desc limit 1"; - Criteria criteria = getByStatusAndMinimalTypeCriteria(context, status, type, limit); - criteria.addOrder(Order.desc("lastHarvested")); - return singleResult(criteria); + public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedDesc(Context context, int status, int type, + int limit) throws SQLException { + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.desc(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested))); + criteriaQuery.orderBy(orderList); + + return singleResult(context, criteriaQuery); } @Override - public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedAsc(Context context, int status, int type, int limit) throws SQLException { -// Old query: "select collection_id from harvested_collection where harvest_type > ? and harvest_status = ? order by last_harvested asc limit 1"; - Criteria criteria = getByStatusAndMinimalTypeCriteria(context, status, type, limit); - criteria.addOrder(Order.asc("lastHarvested")); - return singleResult(criteria); + public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedAsc(Context context, int status, int type, + int limit) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested))); + criteriaQuery.orderBy(orderList); + + return singleResult(context, criteriaQuery); } @Override public List findByStatus(Context context, int status) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedCollection.class); - criteria.add(Restrictions.eq("harvestStatus", status)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + criteriaQuery + .where(criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.harvestStatus), status)); + return list(context, criteriaQuery, false, HarvestedCollection.class, -1, -1); } @Override public HarvestedCollection findByCollection(Context context, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedCollection.class); - criteria.add(Restrictions.eq("collection", collection)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + criteriaQuery + .where(criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.collection), collection)); + return singleResult(context, criteriaQuery); } @Override - public List findByLastHarvestedAndHarvestTypeAndHarvestStatusesAndHarvestTime(Context context, Date startTime, int minimalType, int[] statuses, int expirationStatus, Date expirationTime) throws SQLException { -// Old query: "SELECT * FROM harvested_collection WHERE -// (last_harvested < ? or last_harvested is null) and harvest_type > ? and (harvest_status = ? or harvest_status = ? or (harvest_status=? and harvest_start_time < ?)) ORDER BY last_harvested", -// new java.sql.Timestamp(startTime.getTime()), 0, HarvestedCollection.STATUS_READY, HarvestedCollection.STATUS_OAI_ERROR, HarvestedCollection.STATUS_BUSY, new java.sql.Timestamp(expirationTime.getTime())); - Criteria criteria = createCriteria(context, HarvestedCollection.class); - LogicalExpression lastHarvestedRestriction = Restrictions.or( - Restrictions.lt("lastHarvested", startTime), - Restrictions.isNull("lastHarvested") - ); - Disjunction statusRestriction = Restrictions.or(); + public List + findByLastHarvestedAndHarvestTypeAndHarvestStatusesAndHarvestTime(Context context, + Date startTime, + int minimalType, + int[] statuses, + int expirationStatus, + Date expirationTime) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + + Predicate wasNotHarvestedInCurrentRun = criteriaBuilder + .or(criteriaBuilder.lessThan(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested), startTime), + criteriaBuilder.isNull(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested)) + ); + + List hasCorrectStatusOrIsExpiredRestrictions = new LinkedList<>(); + for (int status : statuses) { - statusRestriction.add(Restrictions.eq("harvestStatus", status)); + hasCorrectStatusOrIsExpiredRestrictions + .add(criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.harvestStatus), status)); } - statusRestriction.add( - Restrictions.and( - Restrictions.eq("harvestStatus", expirationStatus), - Restrictions.gt("harvestStartTime", expirationTime) - ) + + Predicate harvestExpiredRestriction = criteriaBuilder.and( + criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.harvestStatus), expirationStatus), + criteriaBuilder + .greaterThan(harvestedCollectionRoot.get(HarvestedCollection_.harvestStartTime), expirationTime) ); - criteria.add( - Restrictions.and( - lastHarvestedRestriction, - Restrictions.gt("harvestType", minimalType), - statusRestriction + hasCorrectStatusOrIsExpiredRestrictions.add(harvestExpiredRestriction); - ) + Predicate hasCorrectStatusOrIsExpiredPredicate = criteriaBuilder.or(hasCorrectStatusOrIsExpiredRestrictions + .toArray(new Predicate[] {})); + + Predicate hasMinimalType = criteriaBuilder.greaterThan( + harvestedCollectionRoot.get(HarvestedCollection_.harvestType), + minimalType); + + criteriaQuery.where(criteriaBuilder.and(wasNotHarvestedInCurrentRun, + hasMinimalType, + hasCorrectStatusOrIsExpiredPredicate + ) ); - criteria.addOrder(Order.asc("lastHarvested")); - return list(criteria); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, HarvestedCollection.class, -1, -1); + } @Override public int count(Context context) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedCollection.class); - return count(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + return count(context, criteriaQuery, criteriaBuilder, harvestedCollectionRoot); } - protected Criteria getByStatusAndMinimalTypeCriteria(Context context, int status, int type, int limit) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedCollection.class); - criteria.add( - Restrictions.and( - Restrictions.gt("harvestType", type), - Restrictions.eq("harvestStatus", status) - ) + protected CriteriaQuery getByStatusAndMinimalTypeCriteria(Context context, int status, int type) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.greaterThan(harvestedCollectionRoot.get(HarvestedCollection_.harvestType), type), + criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.harvestStatus), status) + ) ); - if(limit != -1) - { - criteria.setMaxResults(1); - } - return criteria; + return criteriaQuery; } } diff --git a/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedItemDAOImpl.java index bf0f45cb2f..9e9838be6c 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedItemDAOImpl.java @@ -7,16 +7,20 @@ */ package org.dspace.harvest.dao.impl; +import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; + import org.dspace.content.Collection; import org.dspace.content.Item; -import org.dspace.core.Context; +import org.dspace.content.Item_; import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; import org.dspace.harvest.HarvestedItem; +import org.dspace.harvest.HarvestedItem_; import org.dspace.harvest.dao.HarvestedItemDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; /** * Hibernate implementation of the Database Access Object interface class for the HarvestedItem object. @@ -25,30 +29,35 @@ import java.sql.SQLException; * * @author kevinvandevelde at atmire.com */ -public class HarvestedItemDAOImpl extends AbstractHibernateDAO implements HarvestedItemDAO -{ - protected HarvestedItemDAOImpl() - { +public class HarvestedItemDAOImpl extends AbstractHibernateDAO implements HarvestedItemDAO { + protected HarvestedItemDAOImpl() { super(); } @Override public HarvestedItem findByItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedItem.class); - criteria.add(Restrictions.eq("item", item)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedItem.class); + Root harvestedItemRoot = criteriaQuery.from(HarvestedItem.class); + criteriaQuery.select(harvestedItemRoot); + criteriaQuery.where(criteriaBuilder.equal(harvestedItemRoot.get(HarvestedItem_.item), item)); + return singleResult(context, criteriaQuery); } @Override public HarvestedItem findByOAIId(Context context, String itemOaiID, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedItem.class); - criteria.createAlias("item", "i"); - criteria.add( - Restrictions.and( - Restrictions.eq("oaiId", itemOaiID), - Restrictions.eq("i.owningCollection", collection) - ) + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedItem.class); + Root harvestedItemRoot = criteriaQuery.from(HarvestedItem.class); + Join join = harvestedItemRoot.join("item"); + criteriaQuery.select(harvestedItemRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(harvestedItemRoot.get(HarvestedItem_.oaiId), itemOaiID), + criteriaBuilder.equal(join.get(Item_.owningCollection), collection) + ) ); - return singleResult(criteria); + return singleResult(context, criteriaQuery); + } } diff --git a/dspace-api/src/main/java/org/dspace/harvest/factory/HarvestServiceFactory.java b/dspace-api/src/main/java/org/dspace/harvest/factory/HarvestServiceFactory.java index 39845fda8b..90dd895c0d 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/factory/HarvestServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/harvest/factory/HarvestServiceFactory.java @@ -13,7 +13,8 @@ import org.dspace.harvest.service.HarvestedItemService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the harvest package, use HarvestServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the harvest package, use HarvestServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -25,8 +26,8 @@ public abstract class HarvestServiceFactory { public abstract HarvestSchedulingService getHarvestSchedulingService(); - public static HarvestServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("harvestServiceFactory", HarvestServiceFactory.class); + public static HarvestServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("harvestServiceFactory", HarvestServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/harvest/factory/HarvestServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/harvest/factory/HarvestServiceFactoryImpl.java index 1aadb03e4e..1dfe2df830 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/factory/HarvestServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/factory/HarvestServiceFactoryImpl.java @@ -13,7 +13,8 @@ import org.dspace.harvest.service.HarvestedItemService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the harvest package, use HarvestServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the harvest package, use HarvestServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/harvest/service/HarvestSchedulingService.java b/dspace-api/src/main/java/org/dspace/harvest/service/HarvestSchedulingService.java index 9e2ba5d8fc..24d1a06428 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/service/HarvestSchedulingService.java +++ b/dspace-api/src/main/java/org/dspace/harvest/service/HarvestSchedulingService.java @@ -7,14 +7,15 @@ */ package org.dspace.harvest.service; -import org.dspace.authorize.AuthorizeException; - import java.io.IOException; import java.sql.SQLException; +import org.dspace.authorize.AuthorizeException; + /** * Service interface class for the scheduling of harvesting tasks. - * The implementation of this class is responsible for all business logic calls for the harvesting tasks and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the harvesting tasks and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -23,57 +24,44 @@ public interface HarvestSchedulingService { /** * Start harvest scheduler. * - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ void startNewScheduler() throws SQLException, AuthorizeException; /** * Stop an active harvest scheduler. * - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ void stopScheduler() throws SQLException, AuthorizeException; /** * Pause an active harvest scheduler. * - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ void pauseScheduler() throws SQLException, AuthorizeException; /** * Resume a paused harvest scheduler. * - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ void resumeScheduler() throws SQLException, AuthorizeException; /** - * - * - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ void resetScheduler() throws SQLException, AuthorizeException, IOException; } diff --git a/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedCollectionService.java b/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedCollectionService.java index e8a45e3bf7..3b2220776f 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedCollectionService.java +++ b/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedCollectionService.java @@ -7,16 +7,17 @@ */ package org.dspace.harvest.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.harvest.HarvestedCollection; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the HarvestedCollection object. - * The implementation of this class is responsible for all business logic calls for the HarvestedCollection object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the HarvestedCollection object + * and is autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -25,10 +26,8 @@ public interface HarvestedCollectionService { /** * Find the harvest settings corresponding to this collection * - * @param context - * The relevant DSpace Context. - * @param collection - * target collection + * @param context The relevant DSpace Context. + * @param collection target collection * @return a HarvestInstance object corresponding to this collection's settings, null if not found. * @throws SQLException if database error */ @@ -37,10 +36,8 @@ public interface HarvestedCollectionService { /** * Create a new harvest instance row for a specified collection. * - * @param context - * The relevant DSpace Context. - * @param collection - * target collection + * @param context The relevant DSpace Context. + * @param collection target collection * @return a new HarvestInstance object * @throws SQLException if database error */ @@ -51,10 +48,8 @@ public interface HarvestedCollectionService { * options are set up correctly. This is distinct from "ready", since this collection may * be in process of being harvested. * - * @param context - * The relevant DSpace Context. - * @param collection - * target collection + * @param context The relevant DSpace Context. + * @param collection target collection * @return is collection harvestable? * @throws SQLException if database error */ @@ -65,8 +60,7 @@ public interface HarvestedCollectionService { * options are set up correctly. This is distinct from "ready", since this collection may * be in process of being harvested. * - * @param harvestedCollection - * collection to be harvested + * @param harvestedCollection collection to be harvested * @return is collection harvestable? * @throws SQLException if database error */ @@ -75,10 +69,8 @@ public interface HarvestedCollectionService { /** * Returns whether the specified collection is ready for immediate harvest. * - * @param context - * The relevant DSpace Context. - * @param collection - * collection to be harvested + * @param context The relevant DSpace Context. + * @param collection collection to be harvested * @return is collection ready for immediate harvest? * @throws SQLException if database error */ @@ -87,8 +79,7 @@ public interface HarvestedCollectionService { /** * Returns whether the specified collection is ready for immediate harvest. * - * @param harvestedCollection - * collection to be harvested + * @param harvestedCollection collection to be harvested * @return is collection ready for immediate harvest? * @throws SQLException if database error */ @@ -97,8 +88,7 @@ public interface HarvestedCollectionService { /** * Find all collections that are set up for harvesting * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return list of collection id's * @throws SQLException if database error */ @@ -107,8 +97,7 @@ public interface HarvestedCollectionService { /** * Find all collections that are ready for harvesting * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return list of collection id's * @throws SQLException if database error */ @@ -117,9 +106,8 @@ public interface HarvestedCollectionService { /** * Find all collections with the specified status flag. * - * @param context - * The relevant DSpace Context. - * @param status see HarvestInstance.STATUS_... + * @param context The relevant DSpace Context. + * @param status see HarvestInstance.STATUS_... * @return all collections with the specified status flag * @throws SQLException if database error */ @@ -128,8 +116,7 @@ public interface HarvestedCollectionService { /** * Find the collection that was harvested the longest time ago. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return collection that was harvested the longest time ago * @throws SQLException if database error */ @@ -139,8 +126,7 @@ public interface HarvestedCollectionService { /** * Find the collection that was harvested most recently. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return collection that was harvested most recently * @throws SQLException if database error */ diff --git a/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedItemService.java b/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedItemService.java index 6c5f3bf06e..4b7b106f42 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedItemService.java +++ b/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedItemService.java @@ -7,16 +7,17 @@ */ package org.dspace.harvest.service; +import java.sql.SQLException; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.harvest.HarvestedItem; -import java.sql.SQLException; - /** * Service interface class for the HarvestedItem object. - * The implementation of this class is responsible for all business logic calls for the HarvestedItem object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the HarvestedItem object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -25,41 +26,32 @@ public interface HarvestedItemService { /** * Find the harvest parameters corresponding to the specified DSpace item * - * @param context - * The relevant DSpace Context. - * @param item - * target item + * @param context The relevant DSpace Context. + * @param item target item * @return a HarvestedItem object corresponding to this item, null if not found. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public HarvestedItem find(Context context, Item item) throws SQLException; /** * Retrieve a DSpace Item that corresponds to this particular combination of owning collection and OAI ID. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @param itemOaiID the string used by the OAI-PMH provider to identify the item * @param collection the local collection that the item should be found in * @return DSpace Item or null if no item was found - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public Item getItemByOAIId(Context context, String itemOaiID, Collection collection) throws SQLException; /** * Create a new harvested item row for a specified item id. * - * @param context - * The relevant DSpace Context. - * @param item - * target item - * @param itemOAIid - * the string used by the OAI-PMH provider to identify the item + * @param context The relevant DSpace Context. + * @param item target item + * @param itemOAIid the string used by the OAI-PMH provider to identify the item * @return a new HarvestedItem object - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public HarvestedItem create(Context context, Item item, String itemOAIid) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/health/Check.java b/dspace-api/src/main/java/org/dspace/health/Check.java index 66a2ca22b5..c18e09e817 100644 --- a/dspace-api/src/main/java/org/dspace/health/Check.java +++ b/dspace-api/src/main/java/org/dspace/health/Check.java @@ -11,6 +11,7 @@ import org.apache.log4j.Logger; /** * Abstract check interface. + * * @author LINDAT/CLARIN dev team */ @@ -22,28 +23,29 @@ public abstract class Check { private String errors_ = ""; // this method should be overridden - protected abstract String run( ReportInfo ri ); + protected abstract String run(ReportInfo ri); - public void report( ReportInfo ri ) { + public void report(ReportInfo ri) { took_ = System.currentTimeMillis(); try { String run_report = run(ri); report_ = errors_ + run_report; - }finally { + } finally { took_ = System.currentTimeMillis() - took_; } } - protected void error( Throwable e ) { + protected void error(Throwable e) { error(e, null); } - protected void error( Throwable e, String msg ) { + + protected void error(Throwable e, String msg) { errors_ += "====\nException occurred!\n"; - if ( null != e ) { + if (null != e) { errors_ += e.toString() + "\n"; log.error("Exception during healthcheck:", e); } - if ( null != msg ) { + if (null != msg) { errors_ += "Reason: " + msg + "\n"; } } diff --git a/dspace-api/src/main/java/org/dspace/health/ChecksumCheck.java b/dspace-api/src/main/java/org/dspace/health/ChecksumCheck.java index 67026a4972..80e19aef70 100644 --- a/dspace-api/src/main/java/org/dspace/health/ChecksumCheck.java +++ b/dspace-api/src/main/java/org/dspace/health/ChecksumCheck.java @@ -7,24 +7,28 @@ */ package org.dspace.health; -import org.dspace.checker.*; -import org.dspace.core.Context; - import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; +import org.dspace.checker.CheckerCommand; +import org.dspace.checker.ChecksumResultCode; +import org.dspace.checker.ChecksumResultsCollector; +import org.dspace.checker.MostRecentChecksum; +import org.dspace.checker.SimpleDispatcher; +import org.dspace.core.Context; + /** * @author LINDAT/CLARIN dev team */ public class ChecksumCheck extends Check { @Override - public String run( ReportInfo ri ) { + public String run(ReportInfo ri) { String ret = "No md5 checks made!"; - Context context = new Context(); + Context context = new Context(); CheckerCommand checker = new CheckerCommand(context); Date process_start = Calendar.getInstance().getTime(); checker.setProcessStartDate(process_start); @@ -48,17 +52,17 @@ public class ChecksumCheck extends Check { if (collector.arr.size() > 0) { ret = String.format("Checksum performed on [%d] items:\n", - collector.arr.size()); + collector.arr.size()); int ok_items = 0; for (MostRecentChecksum bi : collector.arr) { if (!ChecksumResultCode.CHECKSUM_MATCH.equals(bi - .getChecksumResult().getResultCode())) { + .getChecksumResult().getResultCode())) { ret += String .format("md5 checksum FAILED (%s): %s id: %s bitstream-id: %s\n was: %s\n is: %s\n", - bi.getChecksumResult(), bi.getBitstream().getName(), - bi.getBitstream().getInternalId(), bi.getBitstream().getID(), - bi.getExpectedChecksum(), - bi.getCurrentChecksum()); + bi.getChecksumResult(), bi.getBitstream().getName(), + bi.getBitstream().getInternalId(), bi.getBitstream().getID(), + bi.getExpectedChecksum(), + bi.getCurrentChecksum()); } else { ok_items++; } diff --git a/dspace-api/src/main/java/org/dspace/health/EmbargoCheck.java b/dspace-api/src/main/java/org/dspace/health/EmbargoCheck.java index ca840b24ed..5577f41e66 100644 --- a/dspace-api/src/main/java/org/dspace/health/EmbargoCheck.java +++ b/dspace-api/src/main/java/org/dspace/health/EmbargoCheck.java @@ -7,6 +7,8 @@ */ package org.dspace.health; +import java.sql.SQLException; +import java.util.Iterator; import org.dspace.content.DCDate; import org.dspace.content.Item; @@ -14,9 +16,6 @@ import org.dspace.core.Context; import org.dspace.embargo.factory.EmbargoServiceFactory; import org.dspace.embargo.service.EmbargoService; -import java.sql.SQLException; -import java.util.Iterator; - /** * @author LINDAT/CLARIN dev team */ @@ -25,7 +24,7 @@ public class EmbargoCheck extends Check { private static final EmbargoService embargoService = EmbargoServiceFactory.getInstance().getEmbargoService(); @Override - public String run( ReportInfo ri ) { + public String run(ReportInfo ri) { String ret = ""; Context context = null; try { @@ -35,8 +34,8 @@ public class EmbargoCheck extends Check { item_iter = embargoService.findItemsByLiftMetadata(context); } catch (IllegalArgumentException e) { error(e, "No embargoed items found"); - ret += "Note: This check is for pre-3.0 embargo functionality.\n"; - ret += "If you aren't using it, you can ignore this error.\n"; + ret += "Note: This check is for pre-3.0 embargo functionality.\n"; + ret += "If you aren't using it, you can ignore this error.\n"; } catch (Exception e) { error(e); } @@ -51,13 +50,13 @@ public class EmbargoCheck extends Check { error(e); } ret += String.format("%s embargoed till [%s]\n", handle, - date != null ? date.toString() : "null"); + date != null ? date.toString() : "null"); } context.complete(); } catch (SQLException e) { error(e); try { - if ( null != context ) { + if (null != context) { context.abort(); } } catch (Exception e1) { diff --git a/dspace-api/src/main/java/org/dspace/health/InfoCheck.java b/dspace-api/src/main/java/org/dspace/health/InfoCheck.java index 372b917a7a..ba6ba9b6c0 100644 --- a/dspace-api/src/main/java/org/dspace/health/InfoCheck.java +++ b/dspace-api/src/main/java/org/dspace/health/InfoCheck.java @@ -7,26 +7,26 @@ */ package org.dspace.health; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; + import org.apache.commons.io.FileUtils; import org.dspace.core.ConfigurationManager; import org.dspace.services.ConfigurationService; import org.dspace.storage.bitstore.DSBitStoreService; import org.dspace.utils.DSpace; -import java.io.File; -import java.text.SimpleDateFormat; -import java.util.Date; - /** * @author LINDAT/CLARIN dev team */ public class InfoCheck extends Check { @Override - public String run( ReportInfo ri ) { + public String run(ReportInfo ri) { StringBuilder sb = new StringBuilder(); ConfigurationService configurationService - = new DSpace().getConfigurationService(); + = new DSpace().getConfigurationService(); sb.append("Generated: ").append( new Date().toString() ).append("\n"); @@ -42,32 +42,31 @@ public class InfoCheck extends Check { ).append("\n"); sb.append("\n"); - DSBitStoreService localStore = new DSpace().getServiceManager().getServicesByType(DSBitStoreService.class).get(0); + DSBitStoreService localStore = new DSpace().getServiceManager().getServicesByType(DSBitStoreService.class) + .get(0); for (String[] ss : new String[][] { new String[] { localStore.getBaseDir().toString(), - "Assetstore size", }, + "Assetstore size",}, new String[] { - configurationService.getProperty("log.report.dir"), - "Log dir size", }, }) - { - if (ss[0] != null) { + configurationService.getProperty("log.report.dir"), + "Log dir size",},}) { + if (ss[0] != null) { try { File dir = new File(ss[0]); if (dir.exists()) { long dir_size = FileUtils.sizeOfDirectory(dir); sb.append(String.format("%-20s: %s\n", ss[1], - FileUtils.byteCountToDisplaySize(dir_size)) + FileUtils.byteCountToDisplaySize(dir_size)) ); } else { sb.append(String.format("Directory [%s] does not exist!\n", ss[0])); } - } catch(Exception e) { + } catch (Exception e) { error(e, "directory - " + ss[0]); } - } - else { // cannot read property for some reason - sb.append(String.format("Could not get information for %s!\n", ss[1])); + } else { // cannot read property for some reason + sb.append(String.format("Could not get information for %s!\n", ss[1])); } } diff --git a/dspace-api/src/main/java/org/dspace/health/ItemCheck.java b/dspace-api/src/main/java/org/dspace/health/ItemCheck.java index bdea65faae..4971b486da 100644 --- a/dspace-api/src/main/java/org/dspace/health/ItemCheck.java +++ b/dspace-api/src/main/java/org/dspace/health/ItemCheck.java @@ -7,13 +7,26 @@ */ package org.dspace.health; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.UUID; import org.apache.commons.io.FileUtils; import org.dspace.app.util.CollectionDropDown; -import org.dspace.content.*; +import org.dspace.content.Bitstream; import org.dspace.content.Collection; +import org.dspace.content.Community; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +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.content.service.MetadataValueService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; @@ -23,37 +36,34 @@ import org.dspace.handle.service.HandleService; import org.dspace.workflowbasic.factory.BasicWorkflowServiceFactory; import org.dspace.workflowbasic.service.BasicWorkflowItemService; -import java.sql.SQLException; -import java.util.*; - /** * @author LINDAT/CLARIN dev team */ public class ItemCheck extends Check { private BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - private BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); + private BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); private CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); private MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService(); private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); private WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); - private BasicWorkflowItemService basicWorkflowItemService = BasicWorkflowServiceFactory.getInstance().getBasicWorkflowItemService(); + private BasicWorkflowItemService basicWorkflowItemService = + BasicWorkflowServiceFactory.getInstance().getBasicWorkflowItemService(); private HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); private EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); private GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - @Override - public String run( ReportInfo ri ) { + public String run(ReportInfo ri) { String ret = ""; int tot_cnt = 0; Context context = new Context(); try { for (Map.Entry name_count : getCommunities(context)) { ret += String.format("Community [%s]: %d\n", - name_count.getKey(), name_count.getValue()); + name_count.getKey(), name_count.getValue()); tot_cnt += name_count.getValue(); } } catch (SQLException e) { @@ -78,8 +88,8 @@ public class ItemCheck extends Check { for (Map.Entry row : workspaceItemService.getStageReachedCounts(context)) { ret += String.format("\tIn Stage %s: %s\n", - row.getKey(), //"stage_reached" - row.getValue() //"cnt" + row.getKey(), //"stage_reached" + row.getValue() //"cnt" ); } @@ -101,36 +111,37 @@ public class ItemCheck extends Check { } - public String getObjectSizesInfo(Context context) throws SQLException { + public String getObjectSizesInfo(Context context) throws SQLException { StringBuilder sb = new StringBuilder(); sb.append(String.format("Count %-14s: %s\n", "Bitstream", - String.valueOf(bitstreamService.countTotal(context)))); + String.valueOf(bitstreamService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "Bundle", - String.valueOf(bundleService.countTotal(context)))); + String.valueOf(bundleService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "Collection", - String.valueOf(collectionService.countTotal(context)))); + String.valueOf(collectionService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "Community", - String.valueOf(communityService.countTotal(context)))); + String.valueOf(communityService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "MetadataValue", - String.valueOf(metadataValueService.countTotal(context)))); + String.valueOf(metadataValueService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "EPerson", - String.valueOf(ePersonService.countTotal(context)))); + String.valueOf(ePersonService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "Item", - String.valueOf(itemService.countTotal(context)))); + String.valueOf(itemService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "Handle", - String.valueOf(handleService.countTotal(context)))); + String.valueOf(handleService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "Group", - String.valueOf(groupService.countTotal(context)))); + String.valueOf(groupService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "BasicWorkflowItem", - String.valueOf(basicWorkflowItemService.countTotal(context)))); + String.valueOf(basicWorkflowItemService.countTotal(context)))); sb.append(String.format("Count %-14s: %s\n", "WorkspaceItem", - String.valueOf(workspaceItemService.countTotal(context)))); + String.valueOf(workspaceItemService.countTotal(context)))); return sb.toString(); } - public String getCollectionSizesInfo(final Context context) throws SQLException { + public String getCollectionSizesInfo(final Context context) throws SQLException { final StringBuffer ret = new StringBuffer(); - List> colBitSizes = collectionService.getCollectionsWithBitstreamSizesTotal(context); + List> colBitSizes = collectionService + .getCollectionsWithBitstreamSizesTotal(context); long total_size = 0; Collections.sort(colBitSizes, new Comparator>() { @@ -138,7 +149,7 @@ public class ItemCheck extends Check { public int compare(Map.Entry o1, Map.Entry o2) { try { return CollectionDropDown.collectionPath(context, o1.getKey()).compareTo( - CollectionDropDown.collectionPath(context, o2.getKey()) + CollectionDropDown.collectionPath(context, o2.getKey()) ); } catch (Exception e) { ret.append(e.getMessage()); @@ -151,37 +162,38 @@ public class ItemCheck extends Check { total_size += size; Collection col = row.getKey(); ret.append(String.format( - "\t%s: %s\n", CollectionDropDown.collectionPath(context, col), FileUtils.byteCountToDisplaySize((long) size))); + "\t%s: %s\n", CollectionDropDown.collectionPath(context, col), + FileUtils.byteCountToDisplaySize((long) size))); } ret.append(String.format( - "Total size: %s\n", FileUtils.byteCountToDisplaySize(total_size))); + "Total size: %s\n", FileUtils.byteCountToDisplaySize(total_size))); ret.append(String.format( - "Resource without policy: %d\n", bitstreamService.countBitstreamsWithoutPolicy(context))); + "Resource without policy: %d\n", bitstreamService.countBitstreamsWithoutPolicy(context))); ret.append(String.format( - "Deleted bitstreams: %d\n", bitstreamService.countDeletedBitstreams(context))); + "Deleted bitstreams: %d\n", bitstreamService.countDeletedBitstreams(context))); String list_str = ""; List bitstreamOrphans = bitstreamService.getNotReferencedBitstreams(context); for (Bitstream orphan : bitstreamOrphans) { UUID id = orphan.getID(); - list_str += String.format("%d, ", id); + list_str += String.format("%s, ", id); } ret.append(String.format( - "Orphan bitstreams: %d [%s]\n", bitstreamOrphans.size(), list_str)); + "Orphan bitstreams: %d [%s]\n", bitstreamOrphans.size(), list_str)); return ret.toString(); } - public List> getCommunities(Context context) - throws SQLException { + public List> getCommunities(Context context) + throws SQLException { List> cl = new java.util.ArrayList<>(); List top_communities = communityService.findAllTop(context); for (Community c : top_communities) { cl.add( - new java.util.AbstractMap.SimpleEntry<>(c.getName(), itemService.countItems(context, c)) + new java.util.AbstractMap.SimpleEntry<>(c.getName(), itemService.countItems(context, c)) ); } return cl; diff --git a/dspace-api/src/main/java/org/dspace/health/LogAnalyserCheck.java b/dspace-api/src/main/java/org/dspace/health/LogAnalyserCheck.java index aa45e60828..21e929121f 100644 --- a/dspace-api/src/main/java/org/dspace/health/LogAnalyserCheck.java +++ b/dspace-api/src/main/java/org/dspace/health/LogAnalyserCheck.java @@ -7,30 +7,29 @@ */ package org.dspace.health; - -import org.dspace.app.statistics.LogAnalyser; -import org.dspace.core.Context; - import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; +import org.dspace.app.statistics.LogAnalyser; +import org.dspace.core.Context; + /** * @author LINDAT/CLARIN dev team */ public class LogAnalyserCheck extends Check { final static private String[][] interesting_fields = new String[][] { - new String[] { "exceptions", "Exceptions" }, - new String[] { "warnings", "Warnings" }, - new String[] { "action.browse", "Archive browsed" }, - new String[] { "action.search", "Archive searched" }, - new String[] { "action.login", "Logged in" }, - new String[] { "action.oai_request", "OAI requests" }, + new String[] {"exceptions", "Exceptions"}, + new String[] {"warnings", "Warnings"}, + new String[] {"action.browse", "Archive browsed"}, + new String[] {"action.search", "Archive searched"}, + new String[] {"action.login", "Logged in"}, + new String[] {"action.oai_request", "OAI requests"}, }; @Override - public String run( ReportInfo ri ) { + public String run(ReportInfo ri) { StringBuilder sb = new StringBuilder(); Map info_map = new HashMap<>(); @@ -53,12 +52,12 @@ public class LogAnalyserCheck extends Check { } // create report - for (String[] info : interesting_fields ) { - sb.append( String.format("%-20s: %s\n", info[1], info_map.get(info[0])) ); + for (String[] info : interesting_fields) { + sb.append(String.format("%-20s: %s\n", info[1], info_map.get(info[0]))); } - sb.append( String.format("Items added since [%s] (db): %s\n", - new SimpleDateFormat("yyyy-MM-dd").format(ri.from().getTime()), - LogAnalyser.getNumItems(c))); + sb.append(String.format("Items added since [%s] (db): %s\n", + new SimpleDateFormat("yyyy-MM-dd").format(ri.from().getTime()), + LogAnalyser.getNumItems(c))); c.complete(); diff --git a/dspace-api/src/main/java/org/dspace/health/Report.java b/dspace-api/src/main/java/org/dspace/health/Report.java index 95ac3470a9..9285898220 100644 --- a/dspace-api/src/main/java/org/dspace/health/Report.java +++ b/dspace-api/src/main/java/org/dspace/health/Report.java @@ -7,15 +7,23 @@ */ package org.dspace.health; -import org.apache.commons.cli.*; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.StringTokenizer; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.log4j.Logger; import org.dspace.core.ConfigurationManager; import org.dspace.core.Email; - -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.Map.Entry; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.core.service.PluginService; import org.dspace.services.factory.DSpaceServicesFactory; @@ -43,14 +51,14 @@ public class Report { int pos = -1; for (Entry check_entry : checks().entrySet()) { ++pos; - if ( null != to_perform && !to_perform.contains(pos) ) { + if (null != to_perform && !to_perform.contains(pos)) { continue; } String check_name = check_entry.getKey(); Check check = check_entry.getValue(); log.info(String.format("#%d. Processing [%s] at [%s]", - pos, check_name, new SimpleDateFormat( + pos, check_name, new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))); try { @@ -58,7 +66,7 @@ public class Report { check.report(ri); store(check_name, check.took_, check.report_); - }catch( Exception e ) { + } catch (Exception e) { store( check_name, -1, @@ -71,16 +79,17 @@ public class Report { // create check list public static LinkedHashMap checks() { LinkedHashMap checks = new LinkedHashMap<>(); - String check_names[] = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("healthcheck.checks"); + String check_names[] = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("healthcheck.checks"); PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); - for ( String check_name : check_names ) { + for (String check_name : check_names) { Check check = (Check) pluginService.getNamedPlugin( Check.class, check_name); - if ( null != check ) { + if (null != check) { checks.put(check_name, check); - }else { - log.warn( String.format( - "Could not find implementation for [%s]", check_name) ); + } else { + log.warn(String.format( + "Could not find implementation for [%s]", check_name)); } } return checks; @@ -93,8 +102,8 @@ public class Report { // private void store(String name, long took, String report) { name += String.format(" [took: %ds] [# lines: %d]", - took / 1000, - new StringTokenizer(report, "\r\n").countTokens() + took / 1000, + new StringTokenizer(report, "\r\n").countTokens() ); String one_summary = String.format( @@ -124,15 +133,15 @@ public class Report { // command line options Options options = new Options(); options.addOption(option_help, "help", false, - "Show available checks and their index."); + "Show available checks and their index."); options.addOption(option_email, "email", true, - "Send report to this email address."); + "Send report to this email address."); options.addOption(option_check, "check", true, - "Perform only specific check (use index starting from 0)."); + "Perform only specific check (use index starting from 0)."); options.addOption(option_last_n, "for", true, - "For last N days."); + "For last N days."); options.addOption(option_verbose, "verbose", false, - "Verbose report."); + "Verbose report."); CommandLine cmdline = null; try { @@ -142,21 +151,21 @@ public class Report { System.exit(1); } - if ( cmdline.hasOption(option_help) ) { + if (cmdline.hasOption(option_help)) { String checks_summary = ""; int pos = 0; - for (String check_name: checks().keySet()) { - checks_summary += String.format( "%d. %s\n", pos++, check_name ); + for (String check_name : checks().keySet()) { + checks_summary += String.format("%d. %s\n", pos++, check_name); } HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("dspace healthcheck", options); - System.out.println( "\nAvailable checks:\n" + checks_summary ); + System.out.println("\nAvailable checks:\n" + checks_summary); return; } // what to perform List to_perform = null; - if ( null != cmdline.getOptionValues(option_check)) { + if (null != cmdline.getOptionValues(option_check)) { to_perform = new ArrayList<>(); for (String s : cmdline.getOptionValues('c')) { to_perform.add(Integer.valueOf(s)); @@ -168,13 +177,13 @@ public class Report { // last n days int for_last_n_days = ConfigurationManager.getIntProperty( "healthcheck", "last_n_days"); - if ( cmdline.hasOption(option_last_n) ) { + if (cmdline.hasOption(option_last_n)) { for_last_n_days = Integer.getInteger( cmdline.getOptionValue(option_last_n)); } - ReportInfo ri = new ReportInfo( for_last_n_days ); - if ( cmdline.hasOption(option_verbose) ) { - ri.verbose( true ); + ReportInfo ri = new ReportInfo(for_last_n_days); + if (cmdline.hasOption(option_verbose)) { + ri.verbose(true); } // run report @@ -185,13 +194,13 @@ public class Report { // send/output the report if (cmdline.hasOption(option_email)) { String to = cmdline.getOptionValue(option_email); - if ( !to.contains("@") ) { + if (!to.contains("@")) { to = ConfigurationManager.getProperty(to); } try { String dspace_dir = ConfigurationManager.getProperty("dspace.dir"); String email_path = dspace_dir.endsWith("/") ? dspace_dir - : dspace_dir + "/"; + : dspace_dir + "/"; email_path += Report.EMAIL_PATH; log.info(String.format( "Looking for email template at [%s]", email_path)); diff --git a/dspace-api/src/main/java/org/dspace/health/ReportInfo.java b/dspace-api/src/main/java/org/dspace/health/ReportInfo.java index 4a63d1989c..8a6947ef74 100644 --- a/dspace-api/src/main/java/org/dspace/health/ReportInfo.java +++ b/dspace-api/src/main/java/org/dspace/health/ReportInfo.java @@ -7,15 +7,16 @@ */ package org.dspace.health; -import java.util.Date; -import java.util.GregorianCalendar; - import static java.util.Calendar.DAY_OF_MONTH; import static java.util.Calendar.MONTH; import static java.util.Calendar.YEAR; +import java.util.Date; +import java.util.GregorianCalendar; + /** * Information about a report run accessible by each check. + * * @author LINDAT/CLARIN dev team */ public class ReportInfo { @@ -30,15 +31,16 @@ public class ReportInfo { cal.get(YEAR), cal.get(MONTH), cal.get(DAY_OF_MONTH) ); // get info from the last n days - from_ = (GregorianCalendar)till_.clone(); + from_ = (GregorianCalendar) till_.clone(); from_.add(DAY_OF_MONTH, -for_last_n_days); // filter output verbose_ = false; } - public void verbose( boolean verbose ) { + public void verbose(boolean verbose) { verbose_ = verbose; } + public boolean verbose() { return verbose_; } diff --git a/dspace-api/src/main/java/org/dspace/health/UserCheck.java b/dspace-api/src/main/java/org/dspace/health/UserCheck.java index fe8a994e83..19a2a9ced3 100644 --- a/dspace-api/src/main/java/org/dspace/health/UserCheck.java +++ b/dspace-api/src/main/java/org/dspace/health/UserCheck.java @@ -7,6 +7,10 @@ */ package org.dspace.health; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; @@ -19,11 +23,6 @@ import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * @author LINDAT/CLARIN dev team */ @@ -31,10 +30,11 @@ public class UserCheck extends Check { private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); private static final GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private static final CollectionService collectionService = ContentServiceFactory.getInstance() + .getCollectionService(); @Override - public String run( ReportInfo ri ) { + public String run(ReportInfo ri) { Context context = new Context(); String ret = ""; Map info = new HashMap(); @@ -50,21 +50,28 @@ public class UserCheck extends Check { info.put("Self registered", 0); for (EPerson e : epersons) { - if (e.getEmail() != null && e.getEmail().length() > 0) + if (e.getEmail() != null && e.getEmail().length() > 0) { info.put("Have email", info.get("Have email") + 1); - if (e.canLogIn()) + } + if (e.canLogIn()) { info.put("Can log in (password)", - info.get("Can log in (password)") + 1); - if (e.getFirstName() != null && e.getFirstName().length() > 0) + info.get("Can log in (password)") + 1); + } + if (e.getFirstName() != null && e.getFirstName().length() > 0) { info.put("Have 1st name", info.get("Have 1st name") + 1); - if (e.getLastName() != null && e.getLastName().length() > 0) + } + if (e.getLastName() != null && e.getLastName().length() > 0) { info.put("Have 2nd name", info.get("Have 2nd name") + 1); - if (e.getLanguage() != null && e.getLanguage().length() > 0) + } + if (e.getLanguage() != null && e.getLanguage().length() > 0) { info.put("Have lang", info.get("Have lang") + 1); - if (e.getNetid() != null && e.getNetid().length() > 0) + } + if (e.getNetid() != null && e.getNetid().length() > 0) { info.put("Have netid", info.get("Have netid") + 1); - if (e.getNetid() != null && e.getNetid().length() > 0) + } + if (e.getNetid() != null && e.getNetid().length() > 0) { info.put("Self registered", info.get("Self registered") + 1); + } } } catch (SQLException e) { @@ -78,7 +85,7 @@ public class UserCheck extends Check { for (Map.Entry e : info.entrySet()) { if (!e.getKey().equals("Count") && !e.getKey().equals("Have email")) { ret += String.format("%-21s: %s\n", e.getKey(), - String.valueOf(e.getValue())); + String.valueOf(e.getValue())); } } @@ -89,7 +96,7 @@ public class UserCheck extends Check { List emptyGroups = groupService.getEmptyGroups(context); ret += String.format("Empty groups: #%d\n ", emptyGroups.size()); for (Group group : emptyGroups) { - ret += String.format("id=%s;name=%s,\n ", group.getID(), group.getName() ); + ret += String.format("id=%s;name=%s,\n ", group.getID(), group.getName()); } //subscribers @@ -113,11 +120,10 @@ public class UserCheck extends Check { return ret; } - private String formatIds(List objects){ + private String formatIds(List objects) { StringBuilder ids = new StringBuilder(); - for(DSpaceObject o : objects){ - ids.append(o.getID()) - .append(", "); + for (DSpaceObject o : objects) { + ids.append(o.getID()).append(", "); } return ids.toString(); } diff --git a/dspace-api/src/main/java/org/dspace/identifier/DOI.java b/dspace-api/src/main/java/org/dspace/identifier/DOI.java index 8c8307abfa..b73fb2b155 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/DOI.java +++ b/dspace-api/src/main/java/org/dspace/identifier/DOI.java @@ -8,30 +8,38 @@ package org.dspace.identifier; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; -import javax.persistence.*; - /** * DOI identifiers. * * @author Pascal-Nicolas Becker */ @Entity -@Table(name = "Doi" ) +@Table(name = "doi") public class DOI - implements Identifier, ReloadableEntity -{ + implements Identifier, ReloadableEntity { public static final String SCHEME = "doi:"; public static final String RESOLVER = "http://dx.doi.org"; @Id - @Column(name="doi_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="doi_seq") - @SequenceGenerator(name="doi_seq", sequenceName="doi_seq", allocationSize = 1) + @Column(name = "doi_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "doi_seq") + @SequenceGenerator(name = "doi_seq", sequenceName = "doi_seq", allocationSize = 1) private Integer id; @Column(name = "doi", unique = true, length = 256) @@ -50,10 +58,8 @@ public class DOI /** * Protected constructor, create object using: * {@link org.dspace.identifier.service.DOIService#create(Context)} - * */ - protected DOI() - { + protected DOI() { } public Integer getID() { @@ -71,29 +77,29 @@ public class DOI public DSpaceObject getDSpaceObject() { return dSpaceObject; } - + public void setDSpaceObject(DSpaceObject dSpaceObject) { this.dSpaceObject = dSpaceObject; - + // set the Resource Type if the Object is not null // don't set object type null, we want to know to which resource type // the DOI was assigned to if the Object is deleted. - if (dSpaceObject != null) - { + if (dSpaceObject != null) { this.resourceTypeId = dSpaceObject.getType(); } } - + /** - * returns the resource type of the DSpaceObject the DOI is or was assigned - * to. The resource type is set automatically when a DOI is assigned to a + * returns the resource type of the DSpaceObject the DOI is or was assigned + * to. The resource type is set automatically when a DOI is assigned to a * DSpaceObject, using {@link #setDSpaceObject(org.dspace.content.DSpaceObject) }. + * * @return the integer constant of the DSO, see {@link org.dspace.core.Constants#Constants Constants} */ public Integer getResourceTypeId() { return this.resourceTypeId; } - + public Integer getStatus() { return status; } diff --git a/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java index 85cb4a2edc..31d9efa36e 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java @@ -15,9 +15,9 @@ import java.util.List; import org.apache.commons.lang.ObjectUtils; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.MetadataValue; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.Constants; @@ -32,20 +32,19 @@ import org.springframework.beans.factory.annotation.Required; /** * Provide service for DOIs using DataCite. - * + * *

    This class handles reservation, registration and deletion of DOIs using * the direct API from DataCite. * Please pay attention that some members of DataCite offer special services * and want their customers to use special APIs. If you are unsure ask your * registration agency.

    - * + * *

    Any identifier a method of this class returns is a string in the following format: doi:10.123/456.

    - * + * * @author Pascal-Nicolas Becker */ public class DOIIdentifierProvider - extends IdentifierProvider -{ + extends IdentifierProvider { private static final Logger log = LoggerFactory.getLogger(DOIIdentifierProvider.class); /** @@ -61,17 +60,17 @@ public class DOIIdentifierProvider * DSpace items. */ private DOIConnector connector; - + static final String CFG_PREFIX = "identifier.doi.prefix"; static final String CFG_NAMESPACE_SEPARATOR = "identifier.doi.namespaceseparator"; static final char SLASH = '/'; - + // Metadata field name elements // TODO: move these to MetadataSchema or some such? public static final String MD_SCHEMA = "dc"; public static final String DOI_ELEMENT = "identifier"; public static final String DOI_QUALIFIER = "uri"; - + public static final Integer TO_BE_REGISTERED = 1; public static final Integer TO_BE_RESERVED = 2; public static final Integer IS_REGISTERED = 3; @@ -96,7 +95,7 @@ public class DOIIdentifierProvider * Prefix of DOI namespace. Set in dspace.cfg. */ private String PREFIX; - + /** * Part of DOI to separate several applications that generate DOIs. * E.g. it could be 'dspace/' if DOIs generated by DSpace should have the form @@ -104,30 +103,24 @@ public class DOIIdentifierProvider * generate DOIs directly after the DOI Prefix. Set in dspace.cfg. */ private String NAMESPACE_SEPARATOR; - - protected String getPrefix() - { - if (null == this.PREFIX) - { + + protected String getPrefix() { + if (null == this.PREFIX) { this.PREFIX = this.configurationService.getProperty(CFG_PREFIX); - if (null == this.PREFIX) - { + if (null == this.PREFIX) { log.warn("Cannot find DOI prefix in configuration!"); throw new RuntimeException("Unable to load DOI prefix from " - + "configuration. Cannot find property " + - CFG_PREFIX + "."); + + "configuration. Cannot find property " + + CFG_PREFIX + "."); } } return this.PREFIX; } - - protected String getNamespaceSeparator() - { - if (null == this.NAMESPACE_SEPARATOR) - { + + protected String getNamespaceSeparator() { + if (null == this.NAMESPACE_SEPARATOR) { this.NAMESPACE_SEPARATOR = this.configurationService.getProperty(CFG_NAMESPACE_SEPARATOR); - if (null == this.NAMESPACE_SEPARATOR) - { + if (null == this.NAMESPACE_SEPARATOR) { this.NAMESPACE_SEPARATOR = ""; } } @@ -135,36 +128,35 @@ public class DOIIdentifierProvider } @Required - public void setDOIConnector(DOIConnector connector) - { + public void setDOIConnector(DOIConnector connector) { this.connector = connector; } - + /** * This identifier provider supports identifiers of type * {@link org.dspace.identifier.DOI}. + * * @param identifier to check if it will be supported by this provider. * @return boolean */ @Override - public boolean supports(Class identifier) - { + public boolean supports(Class identifier) { return DOI.class.isAssignableFrom(identifier); } - + /** * This identifier provider supports identifiers in the following format: *
      - *
    • doi:10.123/456
    • - *
    • 10.123/456
    • - *
    • http://dx.doi.org/10.123/456
    • + *
    • doi:10.123/456
    • + *
    • 10.123/456
    • + *
    • http://dx.doi.org/10.123/456
    • *
    + * * @param identifier to check if it is in a supported format. * @return boolean */ @Override - public boolean supports(String identifier) - { + public boolean supports(String identifier) { try { doiService.formatIdentifier(identifier); } catch (IdentifierException | IllegalArgumentException ex) { @@ -173,11 +165,10 @@ public class DOIIdentifierProvider return true; } - + @Override public String register(Context context, DSpaceObject dso) - throws IdentifierException - { + throws IdentifierException { String doi = mint(context, dso); // register tries to reserve doi if it's not already. // So we don't have to reserve it here. @@ -187,14 +178,12 @@ public class DOIIdentifierProvider @Override public void register(Context context, DSpaceObject dso, String identifier) - throws IdentifierException - { + throws IdentifierException { String doi = doiService.formatIdentifier(identifier); DOI doiRow = null; // search DOI in our db - try - { + try { doiRow = loadOrCreateDOI(context, dso, doi); } catch (SQLException ex) { log.error("Error in databse connection: " + ex.getMessage()); @@ -202,125 +191,105 @@ public class DOIIdentifierProvider } if (DELETED.equals(doiRow.getStatus()) || - TO_BE_DELETED.equals(doiRow.getStatus())) - { + TO_BE_DELETED.equals(doiRow.getStatus())) { throw new DOIIdentifierException("You tried to register a DOI that " - + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); + + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); } // Check status of DOI - if (IS_REGISTERED.equals(doiRow.getStatus())) - { + if (IS_REGISTERED.equals(doiRow.getStatus())) { return; } - + // change status of DOI doiRow.setStatus(TO_BE_REGISTERED); try { doiService.update(context, doiRow); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { log.warn("SQLException while changing status of DOI {} to be registered.", doi); throw new RuntimeException(sqle); } } /** - * @param context - * The relevant DSpace Context. - * @param dso DSpaceObject the DOI should be reserved for. Some metadata of - * this object will be send to the registration agency. + * @param context The relevant DSpace Context. + * @param dso DSpaceObject the DOI should be reserved for. Some metadata of + * this object will be send to the registration agency. * @param identifier DOI to register in a format that - * {@link org.dspace.identifier.service.DOIService#formatIdentifier(String)} accepts. - * @throws IdentifierException If the format of {@code identifier} was - * unrecognized or if it was impossible to - * reserve the DOI (registration agency denied - * for some reason, see logs). + * {@link org.dspace.identifier.service.DOIService#formatIdentifier(String)} accepts. + * @throws IdentifierException If the format of {@code identifier} was + * unrecognized or if it was impossible to + * reserve the DOI (registration agency denied + * for some reason, see logs). * @throws IllegalArgumentException If {@code identifier} is a DOI already - * registered for another DSpaceObject then {@code dso}. + * registered for another DSpaceObject then {@code dso}. * @see org.dspace.identifier.IdentifierProvider#reserve(Context, DSpaceObject, String) */ @Override public void reserve(Context context, DSpaceObject dso, String identifier) - throws IdentifierException, IllegalArgumentException - { + throws IdentifierException, IllegalArgumentException { String doi = doiService.formatIdentifier(identifier); DOI doiRow = null; - + try { // if the doi is in our db already loadOrCreateDOI just returns. // if it is not loadOrCreateDOI safes the doi. doiRow = loadOrCreateDOI(context, dso, doi); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { throw new RuntimeException(sqle); } if (doiRow.getStatus() != null) { return; - } - - doiRow.setStatus(TO_BE_RESERVED); - try - { - doiService.update(context, doiRow); } - catch (SQLException sqle) - { + + doiRow.setStatus(TO_BE_RESERVED); + try { + doiService.update(context, doiRow); + } catch (SQLException sqle) { throw new RuntimeException(sqle); } } public void reserveOnline(Context context, DSpaceObject dso, String identifier) - throws IdentifierException, IllegalArgumentException, SQLException - { + throws IdentifierException, IllegalArgumentException, SQLException { String doi = doiService.formatIdentifier(identifier); // get TableRow and ensure DOI belongs to dso regarding our db DOI doiRow = loadOrCreateDOI(context, dso, doi); - + if (DELETED.equals(doiRow.getStatus()) || - TO_BE_DELETED.equals(doiRow.getStatus())) - { + TO_BE_DELETED.equals(doiRow.getStatus())) { throw new DOIIdentifierException("You tried to reserve a DOI that " - + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); + + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); } - + connector.reserveDOI(context, dso, doi); - + doiRow.setStatus(IS_RESERVED); doiService.update(context, doiRow); } public void registerOnline(Context context, DSpaceObject dso, String identifier) - throws IdentifierException, IllegalArgumentException, SQLException - { + throws IdentifierException, IllegalArgumentException, SQLException { String doi = doiService.formatIdentifier(identifier); // get TableRow and ensure DOI belongs to dso regarding our db DOI doiRow = loadOrCreateDOI(context, dso, doi); - + if (DELETED.equals(doiRow.getStatus()) || - TO_BE_DELETED.equals(doiRow.getStatus())) - { + TO_BE_DELETED.equals(doiRow.getStatus())) { throw new DOIIdentifierException("You tried to register a DOI that " - + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); + + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); } - + // register DOI Online try { connector.registerDOI(context, dso, doi); - } - catch (DOIIdentifierException die) - { + } catch (DOIIdentifierException die) { // do we have to reserve DOI before we can register it? - if (die.getCode() == DOIIdentifierException.RESERVE_FIRST) - { + if (die.getCode() == DOIIdentifierException.RESERVE_FIRST) { this.reserveOnline(context, dso, identifier); connector.registerDOI(context, dso, doi); - } - else - { + } else { throw die; } } @@ -328,145 +297,116 @@ public class DOIIdentifierProvider // safe DOI as metadata of the item try { saveDOIToObject(context, dso, doi); - } - catch (AuthorizeException ae) - { + } catch (AuthorizeException ae) { throw new IdentifierException("Not authorized to save a DOI as metadata of an dso!", ae); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { throw new RuntimeException(sqle); } - + doiRow.setStatus(IS_REGISTERED); doiService.update(context, doiRow); } - + public void updateMetadata(Context context, DSpaceObject dso, String identifier) - throws IdentifierException, IllegalArgumentException, SQLException - { + throws IdentifierException, IllegalArgumentException, SQLException { String doi = doiService.formatIdentifier(identifier); DOI doiRow = loadOrCreateDOI(context, dso, doi); if (DELETED.equals(doiRow.getStatus()) || - TO_BE_DELETED.equals(doiRow.getStatus())) - { + TO_BE_DELETED.equals(doiRow.getStatus())) { throw new DOIIdentifierException("You tried to register a DOI that " - + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); + + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); } - if (IS_REGISTERED.equals(doiRow.getStatus())) - { + if (IS_REGISTERED.equals(doiRow.getStatus())) { doiRow.setStatus(UPDATE_REGISTERED); - } - else if (TO_BE_REGISTERED.equals(doiRow.getStatus())) - { + } else if (TO_BE_REGISTERED.equals(doiRow.getStatus())) { doiRow.setStatus(UPDATE_BEFORE_REGISTRATION); - } - else if (IS_RESERVED.equals(doiRow.getStatus())) - { + } else if (IS_RESERVED.equals(doiRow.getStatus())) { doiRow.setStatus(UPDATE_RESERVED); - } - else - { + } else { return; } doiService.update(context, doiRow); } - + public void updateMetadataOnline(Context context, DSpaceObject dso, String identifier) - throws IdentifierException, SQLException - { + throws IdentifierException, SQLException { String doi = doiService.formatIdentifier(identifier); // ensure DOI belongs to dso regarding our db DOI doiRow = null; - try - { + try { doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length())); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { log.warn("SQLException while searching a DOI in our db.", sqle); - throw new RuntimeException("Unable to retrieve information about "+ - "a DOI out of database.", sqle); + throw new RuntimeException("Unable to retrieve information about " + + "a DOI out of database.", sqle); } - if (null == doiRow) - { + if (null == doiRow) { log.error("Cannot update metadata for DOI {}: unable to find it in " - + "our db.", doi); + + "our db.", doi); throw new DOIIdentifierException("Unable to find DOI.", - DOIIdentifierException.DOI_DOES_NOT_EXIST); + DOIIdentifierException.DOI_DOES_NOT_EXIST); } - if (!ObjectUtils.equals(doiRow.getDSpaceObject(), dso)) - { + if (!ObjectUtils.equals(doiRow.getDSpaceObject(), dso)) { log.error("Refuse to update metadata of DOI {} with the metadata of " - + " an object ({}/{}) the DOI is not dedicated to.", - new String[] {doi, contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso), dso.getID().toString()}); + + " an object ({}/{}) the DOI is not dedicated to.", + new String[] {doi, contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso), dso + .getID().toString()}); throw new DOIIdentifierException("Cannot update DOI metadata: " - + "DOI and DSpaceObject does not match!", - DOIIdentifierException.MISMATCH); + + "DOI and DSpaceObject does not match!", + DOIIdentifierException.MISMATCH); } if (DELETED.equals(doiRow.getStatus()) || - TO_BE_DELETED.equals(doiRow.getStatus())) - { + TO_BE_DELETED.equals(doiRow.getStatus())) { throw new DOIIdentifierException("You tried to update the metadata" - + "of a DOI that is marked as DELETED.", - DOIIdentifierException.DOI_IS_DELETED); + + "of a DOI that is marked as DELETED.", + DOIIdentifierException.DOI_IS_DELETED); } - + connector.updateMetadata(context, dso, doi); - - if (UPDATE_REGISTERED.equals(doiRow.getStatus())) - { + + if (UPDATE_REGISTERED.equals(doiRow.getStatus())) { doiRow.setStatus(IS_REGISTERED); - } - else if (UPDATE_BEFORE_REGISTRATION.equals(doiRow.getStatus())) - { + } else if (UPDATE_BEFORE_REGISTRATION.equals(doiRow.getStatus())) { doiRow.setStatus(TO_BE_REGISTERED); - } - else if (UPDATE_RESERVED.equals(doiRow.getStatus())) - { + } else if (UPDATE_RESERVED.equals(doiRow.getStatus())) { doiRow.setStatus(IS_RESERVED); } - + doiService.update(context, doiRow); } - + @Override public String mint(Context context, DSpaceObject dso) - throws IdentifierException - { + throws IdentifierException { String doi = null; - try - { + try { doi = getDOIByObject(context, dso); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Error while attemping to retrieve information about a DOI for " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso.getID() + "."); + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso + .getID() + "."); throw new RuntimeException("Error while attempting to retrieve " + - "information about a DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + - " with ID " + dso.getID() + ".", e); + "information about a DOI for " + contentServiceFactory + .getDSpaceObjectService(dso).getTypeText(dso) + + " with ID " + dso.getID() + ".", e); } - if (null == doi) - { - try - { + if (null == doi) { + try { DOI doiRow = loadOrCreateDOI(context, dso, null); doi = DOI.SCHEME + doiRow.getDoi(); - - } - catch (SQLException e) - { + + } catch (SQLException e) { log.error("Error while creating new DOI for Object of " + - "ResourceType {} with id {}.", dso.getType(), dso.getID()); + "ResourceType {} with id {}.", dso.getType(), dso.getID()); throw new RuntimeException("Error while attempting to create a " + - "new DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + - dso.getID() + ".", e); + "new DOI for " + contentServiceFactory.getDSpaceObjectService(dso) + .getTypeText(dso) + " with ID " + + dso.getID() + ".", e); } } return doi; @@ -474,338 +414,287 @@ public class DOIIdentifierProvider @Override public DSpaceObject resolve(Context context, String identifier, String... attributes) - throws IdentifierNotFoundException, IdentifierNotResolvableException - { + throws IdentifierNotFoundException, IdentifierNotResolvableException { String doi = null; try { doi = doiService.formatIdentifier(identifier); } catch (IdentifierException e) { throw new IdentifierNotResolvableException(e); } - try - { + try { DSpaceObject dso = getObjectByDOI(context, doi); - if (null == dso) - { + if (null == dso) { throw new IdentifierNotFoundException(); } return dso; - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { log.error("SQLException while searching a DOI in our db.", sqle); - throw new RuntimeException("Unable to retrieve information about "+ - "a DOI out of database.", sqle); - } - catch (IdentifierException e) - { + throw new RuntimeException("Unable to retrieve information about " + + "a DOI out of database.", sqle); + } catch (IdentifierException e) { throw new IdentifierNotResolvableException(e); } } @Override public String lookup(Context context, DSpaceObject dso) - throws IdentifierNotFoundException, IdentifierNotResolvableException - { + throws IdentifierNotFoundException, IdentifierNotResolvableException { String doi = null; - try - { + try { doi = getDOIByObject(context, dso); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new RuntimeException("Error retrieving DOI out of database.", e); } - - if (null == doi) - { + + if (null == doi) { throw new IdentifierNotFoundException("No DOI for DSpaceObject of type " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso.getID() + " found."); + + contentServiceFactory.getDSpaceObjectService(dso) + .getTypeText(dso) + " with ID " + dso + .getID() + " found."); } - + return doi; } @Override public void delete(Context context, DSpaceObject dso) - throws IdentifierException - { + throws IdentifierException { // delete all DOIs for this Item from our database. - try - { + try { String doi = getDOIByObject(context, dso); - while (null != doi) - { + while (null != doi) { this.delete(context, dso, doi); doi = getDOIByObject(context, dso); } - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("Error while attemping to retrieve information about a DOI for " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso.getID() + ".", ex); + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso + .getID() + ".", ex); throw new RuntimeException("Error while attempting to retrieve " + - "information about a DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + - " with ID " + dso.getID() + ".", ex); + "information about a DOI for " + contentServiceFactory + .getDSpaceObjectService(dso).getTypeText(dso) + + " with ID " + dso.getID() + ".", ex); } - + // delete all DOIs of this item out of its metadata try { String doi = getDOIOutOfObject(dso); - - while (null != doi) - { + + while (null != doi) { this.removeDOIFromObject(context, dso, doi); doi = getDOIOutOfObject(dso); } - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Error while removing a DOI out of the metadata of an " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso.getID() + ".", ex); + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso + .getID() + ".", ex); throw new RuntimeException("Error while removing a DOI out of the " - + "metadata of an " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " - + dso.getID() + ".", ex); + + "metadata of an " + contentServiceFactory.getDSpaceObjectService(dso) + .getTypeText(dso) + " with ID " + + dso.getID() + ".", ex); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("Error while removing a DOI out of the metadata of an " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso.getID() + ".", ex); + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso + .getID() + ".", ex); throw new RuntimeException("Error while removing a DOI out of the " - + "metadata of an " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " - + dso.getID() + ".", ex); + + "metadata of an " + contentServiceFactory.getDSpaceObjectService(dso) + .getTypeText(dso) + " with ID " + + dso.getID() + ".", ex); } } @Override public void delete(Context context, DSpaceObject dso, String identifier) - throws IdentifierException - { + throws IdentifierException { String doi = doiService.formatIdentifier(identifier); DOI doiRow = null; - - try - { + + try { doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length())); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { throw new RuntimeException(sqle); } // check if DOI belongs to dso - if (null != doiRow) - { - if (!ObjectUtils.equals(dso, doiRow.getDSpaceObject())) - { + if (null != doiRow) { + if (!ObjectUtils.equals(dso, doiRow.getDSpaceObject())) { throw new DOIIdentifierException("Trying to delete a DOI out of " - + "an object that is not addressed by the DOI.", - DOIIdentifierException.MISMATCH); + + "an object that is not addressed by the DOI.", + DOIIdentifierException.MISMATCH); } } - + // remove DOI from metadata - try - { + try { removeDOIFromObject(context, dso, doi); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Not authorized to delete a DOI out of an Item.", ex); throw new DOIIdentifierException("Not authorized to delete DOI.", - ex, DOIIdentifierException.UNAUTHORIZED_METADATA_MANIPULATION); - } - catch (SQLException ex) - { + ex, DOIIdentifierException.UNAUTHORIZED_METADATA_MANIPULATION); + } catch (SQLException ex) { log.error("SQLException occurred while deleting a DOI out of an item: " - + ex.getMessage()); + + ex.getMessage()); throw new RuntimeException("Error while deleting a DOI out of the " + - "metadata of an Item " + dso.getID(), ex); + "metadata of an Item " + dso.getID(), ex); } - + // change doi status in db if necessary. - if (null != doiRow) - { + if (null != doiRow) { doiRow.setDSpaceObject(null); - if(doiRow.getStatus() == null) - { - doiRow.setStatus(DELETED); - } - else - { - doiRow.setStatus(TO_BE_DELETED); + if (doiRow.getStatus() == null) { + doiRow.setStatus(DELETED); + } else { + doiRow.setStatus(TO_BE_DELETED); } try { doiService.update(context, doiRow); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { log.warn("SQLException while changing status of DOI {} to be deleted.", doi); throw new RuntimeException(sqle); } - } + } // DOI is a permanent identifier. DataCite for example does not delete // DOIS. But it is possible to mark a DOI as "inactive". } - - public void deleteOnline(Context context, String identifier) - throws DOIIdentifierException - { + + public void deleteOnline(Context context, String identifier) + throws DOIIdentifierException { String doi = doiService.formatIdentifier(identifier); DOI doiRow = null; - - try - { + + try { doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length())); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { throw new RuntimeException(sqle); } - if(null == doiRow) - { + if (null == doiRow) { throw new DOIIdentifierException("This identifier: " + identifier - + " isn't in our database", - DOIIdentifierException.DOI_DOES_NOT_EXIST); + + " isn't in our database", + DOIIdentifierException.DOI_DOES_NOT_EXIST); } - if (!TO_BE_DELETED.equals(doiRow.getStatus())) - { + if (!TO_BE_DELETED.equals(doiRow.getStatus())) { log.error("This identifier: {} couldn't be deleted. " - + "Delete it first from metadata.", - DOI.SCHEME + doiRow.getDoi()); + + "Delete it first from metadata.", + DOI.SCHEME + doiRow.getDoi()); throw new IllegalArgumentException("Couldn't delete this identifier:" - + DOI.SCHEME + doiRow.getDoi() - + ". Delete it first from metadata."); + + DOI.SCHEME + doiRow.getDoi() + + ". Delete it first from metadata."); + } + connector.deleteDOI(context, doi); + + doiRow.setStatus(DELETED); + try { + doiService.update(context, doiRow); + } catch (SQLException sqle) { + log.warn("SQLException while changing status of DOI {} deleted.", doi); + throw new RuntimeException(sqle); } - connector.deleteDOI(context, doi); - - doiRow.setStatus(DELETED); - try { - doiService.update(context, doiRow); - } - catch (SQLException sqle) - { - log.warn("SQLException while changing status of DOI {} deleted.", doi); - throw new RuntimeException(sqle); - } } - + /** * Returns a DSpaceObject depending on its DOI. - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. * @param identifier The DOI in a format that is accepted by - * {@link org.dspace.identifier.service.DOIService#formatIdentifier(String)}. + * {@link org.dspace.identifier.service.DOIService#formatIdentifier(String)}. * @return Null if the DOI couldn't be found or the associated DSpaceObject. - * @throws SQLException if database error - * @throws DOIIdentifierException If {@code identifier} is null or an empty string. + * @throws SQLException if database error + * @throws DOIIdentifierException If {@code identifier} is null or an empty string. * @throws IllegalArgumentException If the identifier couldn't be recognized as DOI. */ public DSpaceObject getObjectByDOI(Context context, String identifier) - throws SQLException, DOIIdentifierException, IllegalArgumentException - { + throws SQLException, DOIIdentifierException, IllegalArgumentException { String doi = doiService.formatIdentifier(identifier); DOI doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length())); - - if (null == doiRow) - { + + if (null == doiRow) { return null; } - - if (doiRow.getDSpaceObject() == null) - { + + if (doiRow.getDSpaceObject() == null) { log.error("Found DOI " + doi + - " in database, but no assigned Object could be found."); + " in database, but no assigned Object could be found."); throw new IllegalStateException("Found DOI " + doi + - " in database, but no assigned Object could be found."); + " in database, but no assigned Object could be found."); } - + return doiRow.getDSpaceObject(); } - + /** * Search the database for a DOI, using the type and id of an DSpaceObject. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpaceObject to find doi for. DOIs with status TO_BE_DELETED will be - * ignored. + * @param context The relevant DSpace Context. + * @param dso DSpaceObject to find doi for. DOIs with status TO_BE_DELETED will be + * ignored. * @return The DOI as String or null if DOI was not found. * @throws SQLException if database error */ public String getDOIByObject(Context context, DSpaceObject dso) - throws SQLException - { + throws SQLException { // String sql = "SELECT * FROM Doi WHERE resource_type_id = ? " + // "AND resource_id = ? AND ((status != ? AND status != ?) OR status IS NULL)"; DOI doiRow = doiService.findDOIByDSpaceObject(context, dso, Arrays.asList(DELETED, TO_BE_DELETED)); - if (null == doiRow) - { + if (null == doiRow) { return null; } - if (doiRow.getDoi() == null) - { + if (doiRow.getDoi() == null) { log.error("A DOI with an empty doi column was found in the database. DSO-Type: " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", ID: " + dso.getID() + "."); + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", ID: " + dso + .getID() + "."); throw new IllegalStateException("A DOI with an empty doi column " + - "was found in the database. DSO-Type: " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + - ", ID: " + dso.getID() + "."); + "was found in the database. DSO-Type: " + contentServiceFactory + .getDSpaceObjectService(dso).getTypeText(dso) + + ", ID: " + dso.getID() + "."); } - + return DOI.SCHEME + doiRow.getDoi(); } - + /** * Load a DOI from the database or creates it if it does not exist. This * method can be used to ensure that a DOI exists in the database and to * load the appropriate TableRow. As protected method we don't check if the * DOI is in a decent format, use DOI.formatIdentifier(String) if necessary. - * - * @param context - * The relevant DSpace Context. - * @param dso The DSpaceObject the DOI should be loaded or created for. + * + * @param context The relevant DSpace Context. + * @param dso The DSpaceObject the DOI should be loaded or created for. * @param doiIdentifier A DOI or null if a DOI should be generated. The generated DOI - * can be found in the appropriate column for the TableRow. + * can be found in the appropriate column for the TableRow. * @return The database row of the object. - * @throws SQLException In case of an error using the database. + * @throws SQLException In case of an error using the database. * @throws DOIIdentifierException If {@code doi} is not part of our prefix or - * DOI is registered for another object already. + * DOI is registered for another object already. */ protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier) - throws SQLException, DOIIdentifierException - { + throws SQLException, DOIIdentifierException { DOI doi = null; - if (null != doiIdentifier) - { + if (null != doiIdentifier) { // we expect DOIs to have the DOI-Scheme except inside the doi table: doiIdentifier = doiIdentifier.substring(DOI.SCHEME.length()); - + // check if DOI is already in Database doi = doiService.findByDoi(context, doiIdentifier); - if (null != doi) - { - if (doi.getDSpaceObject() == null) - { + if (null != doi) { + if (doi.getDSpaceObject() == null) { // doi was deleted, check resource type if (doi.getResourceTypeId() != null - && doi.getResourceTypeId() != dso.getType()) - { + && doi.getResourceTypeId() != dso.getType()) { // doi was assigend to another resource type. Don't // reactivate it throw new DOIIdentifierException("Cannot reassing " - + "previously deleted DOI " + doiIdentifier - + " as the resource types of the object it was " - + "previously assigned to and the object it " - + "shall be assigned to now divert (was: " - + Constants.typeText[doi.getResourceTypeId()] - + ", trying to assign to " - + Constants.typeText[dso.getType()] + ").", - DOIIdentifierException.DOI_IS_DELETED); + + "previously deleted DOI " + doiIdentifier + + " as the resource types of the object it was " + + "previously assigned to and the object it " + + "shall be assigned to now divert (was: " + + Constants.typeText[doi.getResourceTypeId()] + + ", trying to assign to " + + Constants.typeText[dso.getType()] + ").", + DOIIdentifierException.DOI_IS_DELETED); } else { // reassign doi // nothing to do here, doi will br reassigned after this @@ -814,38 +703,31 @@ public class DOIIdentifierProvider } else { // doi is assigned to a DSO; is it assigned to our specific dso? // check if DOI already belongs to dso - if (dso.getID().equals(doi.getDSpaceObject().getID())) - { + if (dso.getID().equals(doi.getDSpaceObject().getID())) { return doi; - } - else - { + } else { throw new DOIIdentifierException("Trying to create a DOI " + - "that is already reserved for another object.", - DOIIdentifierException.DOI_ALREADY_EXISTS); + "that is already reserved for another object.", + DOIIdentifierException.DOI_ALREADY_EXISTS); } } } // check prefix - if (!doiIdentifier.startsWith(this.getPrefix() + "/")) - { + if (!doiIdentifier.startsWith(this.getPrefix() + "/")) { throw new DOIIdentifierException("Trying to create a DOI " + - "that's not part of our Namespace!", - DOIIdentifierException.FOREIGN_DOI); + "that's not part of our Namespace!", + DOIIdentifierException.FOREIGN_DOI); } - if (doi == null) - { + if (doi == null) { // prepare new doiRow doi = doiService.create(context); } - } - else - { + } else { // We need to generate a new DOI. doi = doiService.create(context); - doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() + - doi.getID(); + doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() + + doi.getID(); } // prepare new doiRow @@ -860,59 +742,57 @@ public class DOIIdentifierProvider return doi; } - + /** * Loads a DOI out of the metadata of an DSpaceObject. - * @param dso - * DSpace object to get DOI metadata from + * + * @param dso DSpace object to get DOI metadata from * @return The DOI or null if no DOI was found. * @throws DOIIdentifierException if identifier error */ public String getDOIOutOfObject(DSpaceObject dso) - throws DOIIdentifierException { + throws DOIIdentifierException { // FIXME - if (!(dso instanceof Item)) - { + if (!(dso instanceof Item)) { throw new IllegalArgumentException("We currently support DOIs for " - + "Items only, not for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + "."); + + "Items only, not for " + contentServiceFactory + .getDSpaceObjectService(dso).getTypeText(dso) + "."); } - Item item = (Item)dso; + Item item = (Item) dso; List metadata = itemService.getMetadata(item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null); - for (MetadataValue id : metadata) - { - if (id.getValue().startsWith(DOI.RESOLVER + String.valueOf(SLASH) + PREFIX + String.valueOf(SLASH) + NAMESPACE_SEPARATOR)) { + for (MetadataValue id : metadata) { + if (id.getValue().startsWith( + DOI.RESOLVER + String.valueOf(SLASH) + PREFIX + String.valueOf(SLASH) + NAMESPACE_SEPARATOR)) { return doiService.DOIFromExternalFormat(id.getValue()); } } return null; } - + /** * Adds a DOI to the metadata of an item. - * - * @param context - * The relevant DSpace Context. - * @param dso DSpaceObject the DOI should be added to. - * @param doi The DOI that should be added as metadata. - * @throws SQLException if database error - * @throws AuthorizeException if authorization error + * + * @param context The relevant DSpace Context. + * @param dso DSpaceObject the DOI should be added to. + * @param doi The DOI that should be added as metadata. + * @throws SQLException if database error + * @throws AuthorizeException if authorization error * @throws IdentifierException if identifier error */ protected void saveDOIToObject(Context context, DSpaceObject dso, String doi) - throws SQLException, AuthorizeException, IdentifierException - { + throws SQLException, AuthorizeException, IdentifierException { // FIXME - if (!(dso instanceof Item)) - { + if (!(dso instanceof Item)) { throw new IllegalArgumentException("We currently support DOIs for " - + "Items only, not for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + "."); + + "Items only, not for " + contentServiceFactory + .getDSpaceObjectService(dso).getTypeText(dso) + "."); } Item item = (Item) dso; - itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, doiService.DOIToExternalForm(doi)); - try - { + itemService + .addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, doiService.DOIToExternalForm(doi)); + try { itemService.update(context, item); } catch (SQLException ex) { throw ex; @@ -920,43 +800,39 @@ public class DOIIdentifierProvider throw ex; } } - + /** * Removes a DOI out of the metadata of a DSpaceObject. - * - * @param context - * The relevant DSpace Context. - * @param dso The DSpaceObject the DOI should be removed from. - * @param doi The DOI to remove out of the metadata. - * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * + * @param context The relevant DSpace Context. + * @param dso The DSpaceObject the DOI should be removed from. + * @param doi The DOI to remove out of the metadata. + * @throws AuthorizeException if authorization error + * @throws SQLException if database error * @throws IdentifierException if identifier error */ protected void removeDOIFromObject(Context context, DSpaceObject dso, String doi) - throws AuthorizeException, SQLException, IdentifierException - { + throws AuthorizeException, SQLException, IdentifierException { // FIXME - if (!(dso instanceof Item)) - { + if (!(dso instanceof Item)) { throw new IllegalArgumentException("We currently support DOIs for " - + "Items only, not for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + "."); + + "Items only, not for " + contentServiceFactory + .getDSpaceObjectService(dso).getTypeText(dso) + "."); } - Item item = (Item)dso; + Item item = (Item) dso; List metadata = itemService.getMetadata(item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null); List remainder = new ArrayList(); - for (MetadataValue id : metadata) - { - if (!id.getValue().equals(doiService.DOIToExternalForm(doi))) - { + for (MetadataValue id : metadata) { + if (!id.getValue().equals(doiService.DOIToExternalForm(doi))) { remainder.add(id.getValue()); } } itemService.clearMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null); itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, - remainder); + remainder); itemService.update(context, item); } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/DOIServiceImpl.java b/dspace-api/src/main/java/org/dspace/identifier/DOIServiceImpl.java index 3e69fac11a..aca933aab6 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/DOIServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/identifier/DOIServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.identifier; +import java.sql.SQLException; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.identifier.dao.DOIDAO; @@ -14,11 +19,6 @@ import org.dspace.identifier.doi.DOIIdentifierException; import org.dspace.identifier.service.DOIService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Service implementation for the DOI object. * This class is responsible for all business logic calls for the DOI object and is autowired by spring. @@ -31,8 +31,7 @@ public class DOIServiceImpl implements DOIService { @Autowired(required = true) protected DOIDAO doiDAO; - protected DOIServiceImpl() - { + protected DOIServiceImpl() { } @@ -57,23 +56,29 @@ public class DOIServiceImpl implements DOIService { } @Override - public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) throws SQLException { + public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) + throws SQLException { return doiDAO.findDOIByDSpaceObject(context, dso, statusToExclude); } @Override public String DOIToExternalForm(String identifier) throws IdentifierException { - if (null == identifier) + if (null == identifier) { throw new IllegalArgumentException("Identifier is null.", new NullPointerException()); - if (identifier.isEmpty()) + } + if (identifier.isEmpty()) { throw new IllegalArgumentException("Cannot format an empty identifier."); - if (identifier.startsWith(DOI.SCHEME)) + } + if (identifier.startsWith(DOI.SCHEME)) { return DOI.RESOLVER + "/" + identifier.substring(DOI.SCHEME.length()); - if (identifier.startsWith("10.") && identifier.contains("/")) + } + if (identifier.startsWith("10.") && identifier.contains("/")) { return DOI.RESOLVER + "/" + identifier; - if (identifier.startsWith(DOI.RESOLVER + "/10.")) + } + if (identifier.startsWith(DOI.RESOLVER + "/10.")) { return identifier; - + } + throw new IdentifierException(identifier + "does not seem to be a DOI."); } @@ -81,13 +86,12 @@ public class DOIServiceImpl implements DOIService { public String DOIFromExternalFormat(String identifier) throws DOIIdentifierException { Pattern pattern = Pattern.compile("^" + DOI.RESOLVER + "/+(10\\..*)$"); Matcher matcher = pattern.matcher(identifier); - if (matcher.find()) - { + if (matcher.find()) { return DOI.SCHEME + matcher.group(1); } throw new DOIIdentifierException("Cannot recognize DOI!", - DOIIdentifierException.UNRECOGNIZED); + DOIIdentifierException.UNRECOGNIZED); } @Override @@ -108,18 +112,18 @@ public class DOIServiceImpl implements DOIService { return DOI.SCHEME + identifier.substring(18); } throw new DOIIdentifierException(identifier + "does not seem to be a DOI.", - DOIIdentifierException.UNRECOGNIZED); + DOIIdentifierException.UNRECOGNIZED); } @Override - public List getDOIsByStatus(Context context, List statuses) throws SQLException{ + public List getDOIsByStatus(Context context, List statuses) throws SQLException { return doiDAO.findByStatus(context, statuses); } - + @Override - public List getSimilarDOIsNotInState(Context context, String doiPattern, List statuses, boolean dsoIsNotNull) - throws SQLException - { + public List getSimilarDOIsNotInState(Context context, String doiPattern, List statuses, + boolean dsoIsNotNull) + throws SQLException { return doiDAO.findSimilarNotInState(context, doiPattern, statuses, dsoIsNotNull); } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/DataCiteXMLCreator.java b/dspace-api/src/main/java/org/dspace/identifier/DataCiteXMLCreator.java index 2acfa6ff3f..0ea25ff3a4 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/DataCiteXMLCreator.java +++ b/dspace-api/src/main/java/org/dspace/identifier/DataCiteXMLCreator.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.crosswalk.CrosswalkException; @@ -33,9 +34,10 @@ import org.slf4j.LoggerFactory; * @author mohideen */ -public class DataCiteXMLCreator -{ - /** log4j category */ +public class DataCiteXMLCreator { + /** + * log4j category + */ private static final Logger LOG = LoggerFactory.getLogger(DataCiteXMLCreator.class); /** @@ -44,13 +46,13 @@ public class DataCiteXMLCreator protected String CROSSWALK_NAME = "DataCite"; private static final String CFG_PREFIX - = "identifier.doi.prefix"; + = "identifier.doi.prefix"; private static final String CFG_PUBLISHER - = "crosswalk.dissemination.DataCite.publisher"; + = "crosswalk.dissemination.DataCite.publisher"; private static final String CFG_DATAMANAGER - = "crosswalk.dissemination.DataCite.dataManager"; + = "crosswalk.dissemination.DataCite.dataManager"; private static final String CFG_HOSTINGINSTITUTION - = "crosswalk.dissemination.DataCite.hostingInstitution"; + = "crosswalk.dissemination.DataCite.hostingInstitution"; /** * DisseminationCrosswalk to map local metadata into DataCite metadata. The @@ -59,21 +61,18 @@ public class DataCiteXMLCreator */ protected ParameterizedDisseminationCrosswalk xwalk; - public String getXMLString(Context context, DSpaceObject dso) - { - if (dso == null) - { + public String getXMLString(Context context, DSpaceObject dso) { + if (dso == null) { LOG.info("Invalid object: {}", dso); return null; } this.prepareXwalk(); - if (!this.xwalk.canDisseminate(dso)) - { + if (!this.xwalk.canDisseminate(dso)) { LOG.error("Crosswalk " + this.CROSSWALK_NAME - + " cannot disseminate DSO with type " + dso.getType() - + " and ID " + dso.getID() + "."); + + " cannot disseminate DSO with type " + dso.getType() + + " and ID " + dso.getID() + "."); return null; } @@ -81,25 +80,26 @@ public class DataCiteXMLCreator // XXX Should the actual list be configurable? ConfigurationService cfg = new DSpace().getConfigurationService(); Map parameters = new HashMap<>(); - if (cfg.hasProperty(CFG_PREFIX)) + if (cfg.hasProperty(CFG_PREFIX)) { parameters.put("prefix", cfg.getProperty(CFG_PREFIX)); - if (cfg.hasProperty(CFG_PUBLISHER)) + } + if (cfg.hasProperty(CFG_PUBLISHER)) { parameters.put("publisher", cfg.getProperty(CFG_PUBLISHER)); - if (cfg.hasProperty(CFG_DATAMANAGER)) + } + if (cfg.hasProperty(CFG_DATAMANAGER)) { parameters.put("datamanager", cfg.getProperty(CFG_DATAMANAGER)); - if (cfg.hasProperty(CFG_HOSTINGINSTITUTION)) + } + if (cfg.hasProperty(CFG_HOSTINGINSTITUTION)) { parameters.put("hostinginstitution", cfg.getProperty(CFG_HOSTINGINSTITUTION)); + } // Transform the metadata Element root; - try - { + try { root = xwalk.disseminateElement(context, dso, parameters); - } - catch (CrosswalkException | IOException | SQLException | AuthorizeException e) - { + } catch (CrosswalkException | IOException | SQLException | AuthorizeException e) { LOG.error("Exception while crosswalking DSO with type " - + dso.getType() + " and ID " + dso.getID() + ".", e); + + dso.getType() + " and ID " + dso.getID() + ".", e); return null; } @@ -112,27 +112,24 @@ public class DataCiteXMLCreator * Set the name of the dissemination crosswalk used to convert the metadata * into DataCite Metadata Schema. Used by spring dependency injection. * - * @param CROSSWALK_NAME - * The name of the dissemination crosswalk to use. + * @param CROSSWALK_NAME The name of the dissemination crosswalk to use. */ - public void setDisseminationCrosswalkName(String CROSSWALK_NAME) - { + public void setDisseminationCrosswalkName(String CROSSWALK_NAME) { this.CROSSWALK_NAME = CROSSWALK_NAME; } - protected void prepareXwalk() - { - if (null != this.xwalk) + protected void prepareXwalk() { + if (null != this.xwalk) { return; + } this.xwalk = (ParameterizedDisseminationCrosswalk) CoreServiceFactory - .getInstance().getPluginService() - .getNamedPlugin(DisseminationCrosswalk.class, this.CROSSWALK_NAME); + .getInstance().getPluginService() + .getNamedPlugin(DisseminationCrosswalk.class, this.CROSSWALK_NAME); - if (this.xwalk == null) - { + if (this.xwalk == null) { throw new RuntimeException("Can't find crosswalk '" - + CROSSWALK_NAME + "'!"); + + CROSSWALK_NAME + "'!"); } } @@ -143,13 +140,12 @@ public class DataCiteXMLCreator * @throws Exception if error */ public static void main(String[] argv) - throws Exception - { + throws Exception { String handle = argv[0]; DataCiteXMLCreator instance = new DataCiteXMLCreator(); Context context = new Context(); DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService() - .resolveToObject(context, handle); + .resolveToObject(context, handle); System.out.println(instance.getXMLString(context, dso)); } diff --git a/dspace-api/src/main/java/org/dspace/identifier/EZIDIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/EZIDIdentifierProvider.java index c4ffefd85f..b34d10167c 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/EZIDIdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/EZIDIdentifierProvider.java @@ -9,14 +9,21 @@ package org.dspace.identifier; import java.io.IOException; -import java.net.*; +import java.net.HttpURLConnection; +import java.net.URISyntaxException; import java.sql.SQLException; -import java.util.*; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; + import org.dspace.authorize.AuthorizeException; -import org.dspace.content.MetadataValue; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.DSpaceObjectService; import org.dspace.content.service.ItemService; @@ -40,14 +47,14 @@ import org.springframework.beans.factory.annotation.Required; * [DSpace]/config**.

    * *
    - *
    identifier.doi.ezid.shoulder
    - *
    base of the site's DOIs. Example: 10.5072/FK2
    - *
    identifier.doi.ezid.user
    - *
    EZID username.
    - *
    identifier.doi.ezid.password
    - *
    EZID password.
    - *
    identifier.doi.ezid.publisher
    - *
    A default publisher, for Items not previously published. EZID requires a publisher.
    + *
    identifier.doi.ezid.shoulder
    + *
    base of the site's DOIs. Example: 10.5072/FK2
    + *
    identifier.doi.ezid.user
    + *
    EZID username.
    + *
    identifier.doi.ezid.password
    + *
    EZID password.
    + *
    identifier.doi.ezid.publisher
    + *
    A default publisher, for Items not previously published. EZID requires a publisher.
    *
    * *

    Then there are properties injected using Spring:

    @@ -57,17 +64,17 @@ import org.springframework.beans.factory.annotation.Required; * fully-qualified names of all metadata fields to be looked up on a DSpace * object and their values set on mapped fully-qualified names in the object's * DataCite metadata. - * + * *
  • A second map ("crosswalkTransform") provides Transform instances mapped * from EZID metadata field names. This allows the crosswalk to rewrite field * values where the form maintained by DSpace is not directly usable in EZID * metadata.
  • - * + * *
  • Optional: A boolean property ("generateDataciteXML") that controls the * creation and inclusion of DataCite xml schema during the metadata * crosswalking. The default "DataCite" dissemination plugin uses * DIM2DataCite.xsl for crosswalking. Default value: false.
  • - * + * *
  • Optional: A string property ("disseminationCrosswalkName") that can be * used to set the name of the dissemination crosswalk plugin for metadata * crosswalking. Default value: "DataCite".
  • @@ -76,8 +83,7 @@ import org.springframework.beans.factory.annotation.Required; * @author mwood */ public class EZIDIdentifierProvider - extends IdentifierProvider -{ + extends IdentifierProvider { private static final Logger log = LoggerFactory.getLogger(EZIDIdentifierProvider.class); // Configuration property names @@ -102,13 +108,19 @@ public class EZIDIdentifierProvider protected String DATACITE_XML_CROSSWALK = "DataCite"; - /** Map DataCite metadata into local metadata. */ + /** + * Map DataCite metadata into local metadata. + */ private Map crosswalk = new HashMap<>(); - /** Converters to be applied to specific fields. */ + /** + * Converters to be applied to specific fields. + */ private static Map transforms = new HashMap<>(); - /** Factory for EZID requests. */ + /** + * Factory for EZID requests. + */ private EZIDRequestFactory requestFactory; @Autowired(required = true) @@ -118,36 +130,28 @@ public class EZIDIdentifierProvider protected ItemService itemService; @Override - public boolean supports(Class identifier) - { + public boolean supports(Class identifier) { return DOI.class.isAssignableFrom(identifier); } @Override - public boolean supports(String identifier) - { - if (null == identifier) - { + public boolean supports(String identifier) { + if (null == identifier) { return false; - } - else - { + } else { return identifier.startsWith(DOI_SCHEME); } // XXX more thorough test? } @Override public String register(Context context, DSpaceObject dso) - throws IdentifierException - { + throws IdentifierException { log.debug("register {}", dso); DSpaceObjectService dsoService = contentServiceFactory.getDSpaceObjectService(dso); List identifiers = dsoService.getMetadata(dso, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null); - for (MetadataValue identifier : identifiers) - { - if ((null != identifier.getValue()) && (identifier.getValue().startsWith(DOI_SCHEME))) - { + for (MetadataValue identifier : identifiers) { + if ((null != identifier.getValue()) && (identifier.getValue().startsWith(DOI_SCHEME))) { return identifier.getValue(); } } @@ -164,50 +168,45 @@ public class EZIDIdentifierProvider } @Override - public void register(Context context, DSpaceObject object, String identifier) - { + public void register(Context context, DSpaceObject object, String identifier) { log.debug("register {} as {}", object, identifier); EZIDResponse response; try { EZIDRequest request = requestFactory.getInstance(loadAuthority(), - loadUser(), loadPassword()); + loadUser(), loadPassword()); response = request.create(identifier, crosswalkMetadata(context, object)); } catch (IdentifierException | IOException | URISyntaxException e) { log.error("Identifier '{}' not registered: {}", identifier, e.getMessage()); return; } - if (response.isSuccess()) - { + if (response.isSuccess()) { try { DSpaceObjectService dsoService = contentServiceFactory.getDSpaceObjectService(object); dsoService.addMetadata(context, object, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, - idToDOI(identifier)); + idToDOI(identifier)); dsoService.update(context, object); log.info("registered {}", identifier); } catch (SQLException | AuthorizeException | IdentifierException ex) { // TODO throw new IdentifierException("New identifier not stored", ex); log.error("New identifier not stored", ex); } - } - else - { + } else { log.error("Identifier '{}' not registered -- EZID returned: {}", - identifier, response.getEZIDStatusValue()); + identifier, response.getEZIDStatusValue()); } } @Override public void reserve(Context context, DSpaceObject dso, String identifier) - throws IdentifierException - { + throws IdentifierException { log.debug("reserve {}", identifier); EZIDResponse response; try { EZIDRequest request = requestFactory.getInstance(loadAuthority(), - loadUser(), loadPassword()); + loadUser(), loadPassword()); Map metadata = crosswalkMetadata(context, dso); metadata.put("_status", "reserved"); response = request.create(identifier, metadata); @@ -216,8 +215,7 @@ public class EZIDIdentifierProvider return; } - if (response.isSuccess()) - { + if (response.isSuccess()) { DSpaceObjectService dsoService = contentServiceFactory.getDSpaceObjectService(dso); try { dsoService.addMetadata(context, dso, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, idToDOI(identifier)); @@ -226,18 +224,15 @@ public class EZIDIdentifierProvider } catch (SQLException | AuthorizeException ex) { throw new IdentifierException("New identifier not stored", ex); } - } - else - { + } else { log.error("Identifier '{}' not registered -- EZID returned: {}", - identifier, response.getEZIDStatusValue()); + identifier, response.getEZIDStatusValue()); } } @Override public String mint(Context context, DSpaceObject dso) - throws IdentifierException - { + throws IdentifierException { log.debug("mint for {}", dso); // Compose the request @@ -251,8 +246,7 @@ public class EZIDIdentifierProvider // Send the request EZIDResponse response; - try - { + try { response = request.mint(crosswalkMetadata(context, dso)); } catch (IOException | URISyntaxException ex) { log.error("Failed to send EZID request: {}", ex.getMessage()); @@ -260,35 +254,30 @@ public class EZIDIdentifierProvider } // Good response? - if (HttpURLConnection.HTTP_CREATED != response.getHttpStatusCode()) - { - log.error("EZID server responded: {} {}: {}", - new String[] { - String.valueOf(response.getHttpStatusCode()), - response.getHttpReasonPhrase(), - response.getEZIDStatusValue() - }); - throw new IdentifierException("DOI not created: " - + response.getHttpReasonPhrase() - + ": " - + response.getEZIDStatusValue()); - } + if (HttpURLConnection.HTTP_CREATED != response.getHttpStatusCode()) { + log.error("EZID server responded: {} {}: {}", + new String[] { + String.valueOf(response.getHttpStatusCode()), + response.getHttpReasonPhrase(), + response.getEZIDStatusValue() + }); + throw new IdentifierException("DOI not created: " + + response.getHttpReasonPhrase() + + ": " + + response.getEZIDStatusValue()); + } - // Extract the DOI from the content blob - if (response.isSuccess()) - { + // Extract the DOI from the content blob + if (response.isSuccess()) { String value = response.getEZIDStatusValue(); int end = value.indexOf('|'); // Following pipe is "shadow ARK" - if (end < 0) - { + if (end < 0) { end = value.length(); } String doi = value.substring(0, end).trim(); log.info("Created {}", doi); return doi; - } - else - { + } else { log.error("EZID responded: {}", response.getEZIDStatusValue()); throw new IdentifierException("No DOI returned"); } @@ -296,27 +285,24 @@ public class EZIDIdentifierProvider @Override public DSpaceObject resolve(Context context, String identifier, - String... attributes) - throws IdentifierNotFoundException, IdentifierNotResolvableException - { + String... attributes) + throws IdentifierNotFoundException, IdentifierNotResolvableException { log.debug("resolve {}", identifier); Iterator found; try { found = itemService.findByMetadataField(context, - MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, - idToDOI(identifier)); + MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, + idToDOI(identifier)); } catch (IdentifierException | SQLException | AuthorizeException | IOException ex) { log.error(ex.getMessage()); throw new IdentifierNotResolvableException(ex); } - if (!found.hasNext()) - { + if (!found.hasNext()) { throw new IdentifierNotFoundException("No object bound to " + identifier); } Item found1 = found.next(); - if (found.hasNext()) - { + if (found.hasNext()) { log.error("More than one object bound to {}!", identifier); } log.debug("Resolved to {}", found1); @@ -325,36 +311,29 @@ public class EZIDIdentifierProvider @Override public String lookup(Context context, DSpaceObject object) - throws IdentifierNotFoundException, IdentifierNotResolvableException - { + throws IdentifierNotFoundException, IdentifierNotResolvableException { log.debug("lookup {}", object); MetadataValue found = null; DSpaceObjectService dsoService = contentServiceFactory.getDSpaceObjectService(object); - for (MetadataValue candidate : dsoService.getMetadata(object, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null)) - { - if (candidate.getValue().startsWith(DOI_SCHEME)) - { + for (MetadataValue candidate : dsoService.getMetadata(object, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null)) { + if (candidate.getValue().startsWith(DOI_SCHEME)) { found = candidate; break; } } - if (null != found) - { + if (null != found) { log.debug("Found {}", found.getValue()); return found.getValue(); - } - else - { + } else { throw new IdentifierNotFoundException(dsoService.getTypeText(object) + " " - + object.getID() + " has no DOI"); + + object.getID() + " has no DOI"); } } @Override public void delete(Context context, DSpaceObject dso) - throws IdentifierException - { + throws IdentifierException { log.debug("delete {}", dso); // delete from EZID @@ -362,10 +341,8 @@ public class EZIDIdentifierProvider List metadata = dsoService.getMetadata(dso, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null); List remainder = new ArrayList<>(); int skipped = 0; - for (MetadataValue id : metadata) - { - if (!id.getValue().startsWith(DOI_SCHEME)) - { + for (MetadataValue id : metadata) { + if (!id.getValue().startsWith(DOI_SCHEME)) { remainder.add(id.getValue()); continue; } @@ -373,7 +350,7 @@ public class EZIDIdentifierProvider EZIDResponse response; try { EZIDRequest request = requestFactory.getInstance(loadAuthority(), - loadUser(), loadPassword()); + loadUser(), loadPassword()); response = request.delete(DOIToId(id.getValue())); } catch (URISyntaxException e) { log.error("Bad URI in metadata value: {}", e.getMessage()); @@ -386,10 +363,9 @@ public class EZIDIdentifierProvider skipped++; continue; } - if (!response.isSuccess()) - { + if (!response.isSuccess()) { log.error("Unable to delete {} from DataCite: {}", id.getValue(), - response.getEZIDStatusValue()); + response.getEZIDStatusValue()); remainder.add(id.getValue()); skipped++; continue; @@ -406,26 +382,22 @@ public class EZIDIdentifierProvider log.error("Failed to re-add identifiers: {}", e.getMessage()); } - if (skipped > 0) - { + if (skipped > 0) { throw new IdentifierException(skipped + " identifiers could not be deleted."); } } @Override public void delete(Context context, DSpaceObject dso, String identifier) - throws IdentifierException - { + throws IdentifierException { log.debug("delete {} from {}", identifier, dso); DSpaceObjectService dsoService = contentServiceFactory.getDSpaceObjectService(dso); List metadata = dsoService.getMetadata(dso, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null); List remainder = new ArrayList<>(); int skipped = 0; - for (MetadataValue id : metadata) - { - if (!id.getValue().equals(idToDOI(identifier))) - { + for (MetadataValue id : metadata) { + if (!id.getValue().equals(idToDOI(identifier))) { remainder.add(id.getValue()); continue; } @@ -433,7 +405,7 @@ public class EZIDIdentifierProvider EZIDResponse response; try { EZIDRequest request = requestFactory.getInstance(loadAuthority(), - loadUser(), loadPassword()); + loadUser(), loadPassword()); response = request.delete(DOIToId(id.getValue())); } catch (URISyntaxException e) { log.error("Bad URI in metadata value {}: {}", id.getValue(), e.getMessage()); @@ -447,10 +419,9 @@ public class EZIDIdentifierProvider continue; } - if (!response.isSuccess()) - { + if (!response.isSuccess()) { log.error("Unable to delete {} from DataCite: {}", id.getValue(), - response.getEZIDStatusValue()); + response.getEZIDStatusValue()); remainder.add(id.getValue()); skipped++; continue; @@ -467,92 +438,78 @@ public class EZIDIdentifierProvider log.error("Failed to re-add identifiers: {}", e.getMessage()); } - if (skipped > 0) - { + if (skipped > 0) { throw new IdentifierException(identifier + " could not be deleted."); } } /** * Format a naked identifier as a DOI with our configured authority prefix. - * + * * @throws IdentifierException if authority prefix is not configured. */ String idToDOI(String id) - throws IdentifierException - { + throws IdentifierException { return "doi:" + loadAuthority() + id; } /** * Remove scheme and our configured authority prefix from a doi: URI string. + * * @return naked local identifier. * @throws IdentifierException if authority prefix is not configured. */ String DOIToId(String DOI) - throws IdentifierException - { + throws IdentifierException { String prefix = "doi:" + loadAuthority(); - if (DOI.startsWith(prefix)) - { + if (DOI.startsWith(prefix)) { return DOI.substring(prefix.length()); - } - else - { + } else { return DOI; } } /** * Get configured value of EZID username. + * * @throws IdentifierException if identifier error */ private String loadUser() - throws IdentifierException - { + throws IdentifierException { String user = configurationService.getProperty(CFG_USER); - if (null != user) - { + if (null != user) { return user; - } - else - { + } else { throw new IdentifierException("Unconfigured: define " + CFG_USER); } } /** * Get configured value of EZID password. + * * @throws IdentifierException if identifier error */ private String loadPassword() - throws IdentifierException - { + throws IdentifierException { String password = configurationService.getProperty(CFG_PASSWORD); - if (null != password) - { + if (null != password) { return password; - } - else - { + } else { throw new IdentifierException("Unconfigured: define " + CFG_PASSWORD); } } /** * Get configured value of EZID "shoulder". + * * @throws IdentifierException if identifier error */ private String loadAuthority() - throws IdentifierException - { + throws IdentifierException { String shoulder = configurationService.getProperty(CFG_SHOULDER); - if (null != shoulder) - { + if (null != shoulder) { return shoulder; - } - else - { + } else { throw new IdentifierException("Unconfigured: define " + CFG_SHOULDER); } } @@ -560,43 +517,35 @@ public class EZIDIdentifierProvider /** * Map selected DSpace metadata to fields recognized by DataCite. */ - Map crosswalkMetadata(Context context, DSpaceObject dso) - { - if ((null == dso) || !(dso instanceof Item)) - { + Map crosswalkMetadata(Context context, DSpaceObject dso) { + if ((null == dso) || !(dso instanceof Item)) { throw new IllegalArgumentException("Must be an Item"); } Item item = (Item) dso; // TODO generalize to DSO when all DSOs have metadata. Map mapped = new HashMap<>(); - for (Entry datum : crosswalk.entrySet()) - { + for (Entry datum : crosswalk.entrySet()) { List values = itemService.getMetadataByMetadataString(item, datum.getValue()); - if (null != values) - { - for (MetadataValue value : values) - { + if (null != values) { + for (MetadataValue value : values) { String key = datum.getKey(); String mappedValue; Transform xfrm = transforms.get(key); - if (null != xfrm) - { + if (null != xfrm) { try { mappedValue = xfrm.transform(value.getValue()); } catch (Exception ex) { log.error("Unable to transform '{}' from {} to {}: {}", - new String[] { - value.getValue(), - value.toString(), - key, - ex.getMessage() - }); + new String[] { + value.getValue(), + value.toString(), + key, + ex.getMessage() + }); continue; } - } - else - { + } else { mappedValue = value.getValue(); } mapped.put(key, mappedValue); @@ -604,8 +553,7 @@ public class EZIDIdentifierProvider } } - if (GENERATE_DATACITE_XML == true) - { + if (GENERATE_DATACITE_XML == true) { DataCiteXMLCreator xmlGen = new DataCiteXMLCreator(); xmlGen.setDisseminationCrosswalkName(DATACITE_XML_CROSSWALK); String xmlString = xmlGen.getXMLString(context, dso); @@ -615,8 +563,7 @@ public class EZIDIdentifierProvider // Supply a default publisher, if the Item has none. if (!mapped.containsKey(DATACITE_PUBLISHER) - && !mapped.containsKey("datacite")) - { + && !mapped.containsKey("datacite")) { String publisher = configurationService.getPropertyAsType(CFG_PUBLISHER, "unknown"); log.info("Supplying default publisher: {}", publisher); mapped.put(DATACITE_PUBLISHER, publisher); @@ -624,8 +571,7 @@ public class EZIDIdentifierProvider // Supply current year as year of publication, if the Item has none. if (!mapped.containsKey(DATACITE_PUBLICATION_YEAR) - && !mapped.containsKey("datacite")) - { + && !mapped.containsKey("datacite")) { String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR)); log.info("Supplying default publication year: {}", year); mapped.put(DATACITE_PUBLICATION_YEAR, year); @@ -633,15 +579,12 @@ public class EZIDIdentifierProvider // Supply _target link back to this object String handle = dso.getHandle(); - if (null == handle) - { + if (null == handle) { log.warn("{} #{} has no handle -- location not set.", - contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso), dso.getID()); - } - else - { + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso), dso.getID()); + } else { String url = configurationService.getProperty("dspace.url") - + "/handle/" + item.getHandle(); + + "/handle/" + item.getHandle(); log.info("Supplying location: {}", url); mapped.put("_target", url); } @@ -653,12 +596,10 @@ public class EZIDIdentifierProvider * Provide a map from DSO metadata keys to EZID keys. This will drive the * generation of EZID metadata for the minting of new identifiers. * - * @param aCrosswalk - * map of metadata fields to EZID keys + * @param aCrosswalk map of metadata fields to EZID keys */ @Required - public void setCrosswalk(Map aCrosswalk) - { + public void setCrosswalk(Map aCrosswalk) { crosswalk = aCrosswalk; } @@ -670,27 +611,22 @@ public class EZIDIdentifierProvider * Provide a map from DSO metadata keys to classes which can transform their * values to something acceptable to EZID. * - * @param transformMap - * map of metadata fields to EZID transformation classes + * @param transformMap map of metadata fields to EZID transformation classes */ - public void setCrosswalkTransform(Map transformMap) - { + public void setCrosswalkTransform(Map transformMap) { transforms = transformMap; } - public void setGenerateDataciteXML(boolean GENERATE_DATACITE_XML) - { + public void setGenerateDataciteXML(boolean GENERATE_DATACITE_XML) { this.GENERATE_DATACITE_XML = GENERATE_DATACITE_XML; } - public void setDisseminationCrosswalkName(String DATACITE_XML_CROSSWALK) - { + public void setDisseminationCrosswalkName(String DATACITE_XML_CROSSWALK) { this.DATACITE_XML_CROSSWALK = DATACITE_XML_CROSSWALK; } @Required - public void setRequestFactory(EZIDRequestFactory aRequestFactory) - { + public void setRequestFactory(EZIDRequestFactory aRequestFactory) { requestFactory = aRequestFactory; } @@ -700,9 +636,10 @@ public class EZIDIdentifierProvider /** * Method should never be used aside from the unit tests where we can cannot autowire this class. + * * @param itemService itemService instance */ - protected void setItemService(ItemService itemService){ + protected void setItemService(ItemService itemService) { this.itemService = itemService; } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/Handle.java b/dspace-api/src/main/java/org/dspace/identifier/Handle.java index e66b3806c6..56d43fd361 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/Handle.java +++ b/dspace-api/src/main/java/org/dspace/identifier/Handle.java @@ -8,8 +8,6 @@ package org.dspace.identifier; /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) diff --git a/dspace-api/src/main/java/org/dspace/identifier/HandleIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/HandleIdentifierProvider.java index fb6743e5e5..a91e6d06cd 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/HandleIdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/HandleIdentifierProvider.java @@ -7,9 +7,16 @@ */ package org.dspace.identifier; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; @@ -19,10 +26,6 @@ import org.dspace.services.factory.DSpaceServicesFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * The old DSpace handle identifier service, used to create handles or retrieve objects based on their handle * @@ -32,10 +35,14 @@ import java.util.List; */ @Component public class HandleIdentifierProvider extends IdentifierProvider { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(HandleIdentifierProvider.class); - /** Prefix registered to no one */ + /** + * Prefix registered to no one + */ protected static final String EXAMPLE_PREFIX = "123456789"; @Autowired(required = true) @@ -49,28 +56,27 @@ public class HandleIdentifierProvider extends IdentifierProvider { } @Override - public boolean supports(String identifier) - { + public boolean supports(String identifier) { String prefix = handleService.getPrefix(); - String canonicalPrefix = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("handle.canonical.prefix"); - if (identifier == null) - { + String canonicalPrefix = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("handle.canonical.prefix"); + if (identifier == null) { return false; } // return true if handle has valid starting pattern if (identifier.startsWith(prefix + "/") - || identifier.startsWith(canonicalPrefix) - || identifier.startsWith("hdl:") - || identifier.startsWith("info:hdl") - || identifier.matches("^https?://hdl\\.handle\\.net/.*") - || identifier.matches("^https?://.+/handle/.*")) - { + || identifier.startsWith(canonicalPrefix) + || identifier.startsWith("hdl:") + || identifier.startsWith("info:hdl") + || identifier.matches("^https?://hdl\\.handle\\.net/.*") + || identifier.matches("^https?://.+/handle/.*")) { return true; } - + //Check additional prefixes supported in the config file - String[] additionalPrefixes = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("handle.additional.prefixes"); - for(String additionalPrefix: additionalPrefixes) { + String[] additionalPrefixes = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("handle.additional.prefixes"); + for (String additionalPrefix : additionalPrefixes) { if (identifier.startsWith(additionalPrefix + "/")) { return true; } @@ -85,15 +91,15 @@ public class HandleIdentifierProvider extends IdentifierProvider { String id = mint(context, dso); // move canonical to point the latest version - if(dso instanceof Item) - { - Item item = (Item)dso; + if (dso instanceof Item) { + Item item = (Item) dso; populateHandleMetadata(context, item, id); } return id; } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID(), e); } } @@ -102,13 +108,13 @@ public class HandleIdentifierProvider extends IdentifierProvider { public void register(Context context, DSpaceObject dso, String identifier) { try { handleService.createHandle(context, dso, identifier); - if(dso instanceof Item) - { - Item item = (Item)dso; + if (dso instanceof Item) { + Item item = (Item) dso; populateHandleMetadata(context, item, identifier); } } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID(), e); } } @@ -119,7 +125,8 @@ public class HandleIdentifierProvider extends IdentifierProvider { try { handleService.createHandle(context, dso, identifier); } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID()); } } @@ -129,20 +136,20 @@ public class HandleIdentifierProvider extends IdentifierProvider { * Creates a new handle in the database. * * @param context DSpace context - * @param dso The DSpaceObject to create a handle for + * @param dso The DSpaceObject to create a handle for * @return The newly created handle */ @Override public String mint(Context context, DSpaceObject dso) { - if(dso.getHandle() != null) - { + if (dso.getHandle() != null) { return dso.getHandle(); } try { return handleService.createHandle(context, dso); } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID()); } } @@ -150,11 +157,11 @@ public class HandleIdentifierProvider extends IdentifierProvider { @Override public DSpaceObject resolve(Context context, String identifier, String... attributes) { // We can do nothing with this, return null - try - { + try { return handleService.resolveToObject(context, identifier); } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while resolving handle to item", "handle: " + identifier), e); + log.error(LogManager.getHeader(context, "Error while resolving handle to item", "handle: " + identifier), + e); } // throw new IllegalStateException("Unsupported Handle Type " // + Constants.typeText[handletypeid]); @@ -162,13 +169,13 @@ public class HandleIdentifierProvider extends IdentifierProvider { } @Override - public String lookup(Context context, DSpaceObject dso) throws IdentifierNotFoundException, IdentifierNotResolvableException { + public String lookup(Context context, DSpaceObject dso) + throws IdentifierNotFoundException, IdentifierNotResolvableException { - try - { + try { return handleService.findHandle(context, dso); } catch (SQLException sqe) { - throw new IdentifierNotResolvableException(sqe.getMessage(),sqe); + throw new IdentifierNotResolvableException(sqe.getMessage(), sqe); } } @@ -181,18 +188,16 @@ public class HandleIdentifierProvider extends IdentifierProvider { public void delete(Context context, DSpaceObject dso) throws IdentifierException { try { handleService.unbindHandle(context, dso); - } catch (SQLException sqe) - { - throw new IdentifierException(sqe.getMessage(),sqe); + } catch (SQLException sqe) { + throw new IdentifierException(sqe.getMessage(), sqe); } } public static String retrieveHandleOutOfUrl(String url) - throws SQLException { + throws SQLException { // We can do nothing with this, return null - if (!url.contains("/")) - { + if (!url.contains("/")) { return null; } @@ -203,13 +208,12 @@ public class HandleIdentifierProvider extends IdentifierProvider { /** * Get the configured Handle prefix string, or a default + * * @return configured prefix or "123456789" */ - public static String getPrefix() - { + public static String getPrefix() { String prefix = ConfigurationManager.getProperty("handle.prefix"); - if (null == prefix) - { + if (null == prefix) { prefix = EXAMPLE_PREFIX; // XXX no good way to exit cleanly log.error("handle.prefix is not configured; using " + prefix); } @@ -217,23 +221,20 @@ public class HandleIdentifierProvider extends IdentifierProvider { } protected void populateHandleMetadata(Context context, Item item, String handle) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { String handleref = handleService.getCanonicalForm(handle); // Add handle as identifier.uri DC value. // First check that identifier doesn't already exist. boolean identifierExists = false; - List identifiers = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); - for (MetadataValue identifier : identifiers) - { - if (handleref.equals(identifier.getValue())) - { + List identifiers = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); + for (MetadataValue identifier : identifiers) { + if (handleref.equals(identifier.getValue())) { identifierExists = true; } } - if (!identifierExists) - { + if (!identifierExists) { itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "uri", null, handleref); } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/Identifier.java b/dspace-api/src/main/java/org/dspace/identifier/Identifier.java index 273c7e2f17..2383998e03 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/Identifier.java +++ b/dspace-api/src/main/java/org/dspace/identifier/Identifier.java @@ -8,8 +8,6 @@ package org.dspace.identifier; /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) diff --git a/dspace-api/src/main/java/org/dspace/identifier/IdentifierException.java b/dspace-api/src/main/java/org/dspace/identifier/IdentifierException.java index 7d65790020..7bdbb34115 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/IdentifierException.java +++ b/dspace-api/src/main/java/org/dspace/identifier/IdentifierException.java @@ -8,12 +8,11 @@ package org.dspace.identifier; /** - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) */ -public class IdentifierException extends Exception{ +public class IdentifierException extends Exception { public IdentifierException() { super(); diff --git a/dspace-api/src/main/java/org/dspace/identifier/IdentifierNotFoundException.java b/dspace-api/src/main/java/org/dspace/identifier/IdentifierNotFoundException.java index 170090d1c4..7ec25f2f30 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/IdentifierNotFoundException.java +++ b/dspace-api/src/main/java/org/dspace/identifier/IdentifierNotFoundException.java @@ -8,8 +8,6 @@ package org.dspace.identifier; /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) diff --git a/dspace-api/src/main/java/org/dspace/identifier/IdentifierNotResolvableException.java b/dspace-api/src/main/java/org/dspace/identifier/IdentifierNotResolvableException.java index a69308dd25..1670dbc101 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/IdentifierNotResolvableException.java +++ b/dspace-api/src/main/java/org/dspace/identifier/IdentifierNotResolvableException.java @@ -8,8 +8,6 @@ package org.dspace.identifier; /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) diff --git a/dspace-api/src/main/java/org/dspace/identifier/IdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/IdentifierProvider.java index 830875a182..28d899f123 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/IdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/IdentifierProvider.java @@ -15,8 +15,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -39,7 +37,7 @@ public abstract class IdentifierProvider { /** * Can this provider provide identifiers of a given type? - * + * * @param identifier requested type. * @return true if the given type is assignable from this provider's type. */ @@ -47,7 +45,7 @@ public abstract class IdentifierProvider { /** * Can this provider provide identifiers of a given type? - * + * * @param identifier requested type. * @return true if this provider can provide the named type of identifier. */ @@ -55,10 +53,9 @@ public abstract class IdentifierProvider { /** * Create and apply an identifier to a DSpaceObject. - * - * @param context - * The relevant DSpace Context. - * @param item object to be named. + * + * @param context The relevant DSpace Context. + * @param item object to be named. * @return existing identifier of {@code item} if it has one, else a new identifier. * @throws IdentifierException if identifier error */ @@ -66,10 +63,9 @@ public abstract class IdentifierProvider { /** * Create an identifier for a DSpaceObject. - * - * @param context - * The relevant DSpace Context. - * @param dso object to be named. + * + * @param context The relevant DSpace Context. + * @param dso object to be named. * @return existing identifier of {@code dso} if it has one, else a new identifier. * @throws IdentifierException if identifier error */ @@ -77,45 +73,47 @@ public abstract class IdentifierProvider { /** * Find the object named by a given identifier. - * - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. * @param identifier to be resolved. * @param attributes additional information for resolving {@code identifier}. * @return the named object. - * @throws IdentifierNotFoundException if identifier not found - * @throws IdentifierNotResolvableException if identifier not resolvable + * @throws IdentifierNotFoundException if identifier not found + * @throws IdentifierNotResolvableException if identifier not resolvable */ - public abstract DSpaceObject resolve(Context context, String identifier, String... attributes) throws IdentifierNotFoundException, IdentifierNotResolvableException;; + public abstract DSpaceObject resolve(Context context, String identifier, String... attributes) + throws IdentifierNotFoundException, IdentifierNotResolvableException; + + ; /** * Return the identifier for a DSpaceObject. - * - * @param context - * The relevant DSpace Context. - * @param object The object to be looked up. + * + * @param context The relevant DSpace Context. + * @param object The object to be looked up. * @return identifier for {@code object}. - * @throws IdentifierNotFoundException if identifier not found - * @throws IdentifierNotResolvableException if identifier not resolvable + * @throws IdentifierNotFoundException if identifier not found + * @throws IdentifierNotResolvableException if identifier not resolvable */ - public abstract String lookup(Context context, DSpaceObject object) throws IdentifierNotFoundException, IdentifierNotResolvableException;; + public abstract String lookup(Context context, DSpaceObject object) + throws IdentifierNotFoundException, IdentifierNotResolvableException; + + ; /** * Unbind this type of identifier(s) from an object. - * - * @param context - * The relevant DSpace Context. - * @param dso object to lose its identity. + * + * @param context The relevant DSpace Context. + * @param dso object to lose its identity. * @throws IdentifierException if identifier error */ public abstract void delete(Context context, DSpaceObject dso) throws IdentifierException; /** * Unbind the given identifier from an object. - * - * @param context - * The relevant DSpace Context. - * @param dso object to be de-identified. + * + * @param context The relevant DSpace Context. + * @param dso object to be de-identified. * @param identifier to be removed. * @throws IdentifierException if identifier error */ @@ -123,10 +121,9 @@ public abstract class IdentifierProvider { /** * Set an object's identifier. - * - * @param context - * The relevant DSpace Context. - * @param dso object to be identified. + * + * @param context The relevant DSpace Context. + * @param dso object to be identified. * @param identifier to be set on the object. * @throws IdentifierException if identifier error */ @@ -134,13 +131,12 @@ public abstract class IdentifierProvider { /** * Create a specific identifier and apply it to an object. - * - * @param context - * The relevant DSpace Context. - * @param object to be identified. + * + * @param context The relevant DSpace Context. + * @param object to be identified. * @param identifier to be created. * @throws IdentifierException if identifier error */ public abstract void register(Context context, DSpaceObject object, String identifier) - throws IdentifierException; + throws IdentifierException; } diff --git a/dspace-api/src/main/java/org/dspace/identifier/IdentifierServiceImpl.java b/dspace-api/src/main/java/org/dspace/identifier/IdentifierServiceImpl.java index 65b97f4c75..4cfd365fc2 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/IdentifierServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/identifier/IdentifierServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.identifier; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; @@ -17,12 +22,6 @@ import org.dspace.identifier.service.IdentifierService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import org.apache.commons.lang.StringUtils; -import org.dspace.core.Constants; - /** * The main service class used to reserve, register and resolve identifiers * @@ -34,7 +33,9 @@ public class IdentifierServiceImpl implements IdentifierService { private List providers; - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(IdentifierServiceImpl.class); @Autowired(required = true) @@ -42,37 +43,32 @@ public class IdentifierServiceImpl implements IdentifierService { @Autowired(required = true) protected HandleService handleService; - protected IdentifierServiceImpl() - { + protected IdentifierServiceImpl() { } @Autowired @Required - public void setProviders(List providers) - { + public void setProviders(List providers) { this.providers = providers; - - for (IdentifierProvider p : providers) - { + + for (IdentifierProvider p : providers) { p.setParentService(this); } } /** * Reserves identifiers for the item + * * @param context dspace context - * @param dso dspace object + * @param dso dspace object */ @Override public void reserve(Context context, DSpaceObject dso) - throws AuthorizeException, SQLException, IdentifierException - { - for (IdentifierProvider service : providers) - { + throws AuthorizeException, SQLException, IdentifierException { + for (IdentifierProvider service : providers) { String identifier = service.mint(context, dso); - if (!StringUtils.isEmpty(identifier)) - { + if (!StringUtils.isEmpty(identifier)) { service.reserve(context, dso, identifier); } } @@ -82,13 +78,10 @@ public class IdentifierServiceImpl implements IdentifierService { @Override public void reserve(Context context, DSpaceObject dso, String identifier) - throws AuthorizeException, SQLException, IdentifierException - { + throws AuthorizeException, SQLException, IdentifierException { // Next resolve all other services - for (IdentifierProvider service : providers) - { - if (service.supports(identifier)) - { + for (IdentifierProvider service : providers) { + if (service.supports(identifier)) { service.reserve(context, dso, identifier); } } @@ -98,12 +91,10 @@ public class IdentifierServiceImpl implements IdentifierService { @Override public void register(Context context, DSpaceObject dso) - throws AuthorizeException, SQLException, IdentifierException - { + throws AuthorizeException, SQLException, IdentifierException { //We need to commit our context because one of the providers might require the handle created above // Next resolve all other services - for (IdentifierProvider service : providers) - { + for (IdentifierProvider service : providers) { service.register(context, dso); } //Update our item @@ -112,101 +103,82 @@ public class IdentifierServiceImpl implements IdentifierService { @Override public void register(Context context, DSpaceObject object, String identifier) - throws AuthorizeException, SQLException, IdentifierException - { + throws AuthorizeException, SQLException, IdentifierException { //We need to commit our context because one of the providers might require the handle created above // Next resolve all other services boolean registered = false; - for (IdentifierProvider service : providers) - { - if (service.supports(identifier)) - { + for (IdentifierProvider service : providers) { + if (service.supports(identifier)) { service.register(context, object, identifier); registered = true; } } - if (!registered) - { + if (!registered) { throw new IdentifierException("Cannot register identifier: Didn't " - + "find a provider that supports this identifier."); + + "find a provider that supports this identifier."); } //Update our item contentServiceFactory.getDSpaceObjectService(object).update(context, object); } @Override - public String lookup(Context context, DSpaceObject dso, Class identifier) - { - for (IdentifierProvider service : providers) - { - if (service.supports(identifier)) - { - try{ - String result = service.lookup(context, dso); - if (result != null){ - return result; - } - } - catch (IdentifierNotFoundException ex) - { - log.info(service.getClass().getName() + " doesn't find an " - + "Identifier for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", " - + dso.getID().toString() + "."); - log.debug(ex.getMessage(), ex); - } - catch (IdentifierException e) - { - log.error(e.getMessage(),e); - } + public String lookup(Context context, DSpaceObject dso, Class identifier) { + for (IdentifierProvider service : providers) { + if (service.supports(identifier)) { + try { + String result = service.lookup(context, dso); + if (result != null) { + return result; + } + } catch (IdentifierNotFoundException ex) { + log.info(service.getClass().getName() + " doesn't find an " + + "Identifier for " + contentServiceFactory.getDSpaceObjectService(dso) + .getTypeText(dso) + ", " + + dso.getID().toString() + "."); + log.debug(ex.getMessage(), ex); + } catch (IdentifierException e) { + log.error(e.getMessage(), e); + } } } return null; } - + @Override - public List lookup(Context context, DSpaceObject dso) - { + public List lookup(Context context, DSpaceObject dso) { List identifiers = new ArrayList<>(); - for (IdentifierProvider service : providers) - { + for (IdentifierProvider service : providers) { try { String result = service.lookup(context, dso); - if (!StringUtils.isEmpty(result)) - { - if (log.isDebugEnabled()) - { + if (!StringUtils.isEmpty(result)) { + if (log.isDebugEnabled()) { try { - log.debug("Got an identifier from " - + service.getClass().getCanonicalName() + "."); + log.debug("Got an identifier from " + + service.getClass().getCanonicalName() + "."); } catch (NullPointerException ex) { log.debug(ex.getMessage(), ex); } } - + identifiers.add(result); } - } - catch (IdentifierNotFoundException ex) - { + } catch (IdentifierNotFoundException ex) { log.info(service.getClass().getName() + " doesn't find an " - + "Identifier for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", " - + dso.getID().toString() + "."); + + "Identifier for " + contentServiceFactory.getDSpaceObjectService(dso) + .getTypeText(dso) + ", " + + dso.getID().toString() + "."); log.debug(ex.getMessage(), ex); - } - catch (IdentifierException ex) - { + } catch (IdentifierException ex) { log.error(ex.getMessage(), ex); } } - + try { String handle = dso.getHandle(); - if (!StringUtils.isEmpty(handle)) - { + if (!StringUtils.isEmpty(handle)) { if (!identifiers.contains(handle) - && !identifiers.contains("hdl:" + handle) - && !identifiers.contains(handleService.getCanonicalForm(handle))) - { + && !identifiers.contains("hdl:" + handle) + && !identifiers.contains(handleService.getCanonicalForm(handle))) { // The VerionedHandleIdentifierProvider gets loaded by default // it returns handles without any scheme (neither hdl: nor http:). // If the VersionedHandleIdentifierProvider is not loaded, @@ -214,46 +186,36 @@ public class IdentifierServiceImpl implements IdentifierService { // Generally it would be better if identifiers would be added // here in a way they could be recognized. log.info("Adding handle '" + handle + "' to the " - + "array of looked up identifiers."); + + "array of looked up identifiers."); identifiers.add(handle); } } - } - catch (Exception ex) - { + } catch (Exception ex) { // nothing is expected here, but if an exception is thrown it // should not stop everything running. log.error(ex.getMessage(), ex); } - + log.debug("Found identifiers: " + identifiers.toString()); return identifiers; } @Override public DSpaceObject resolve(Context context, String identifier) - throws IdentifierNotFoundException, IdentifierNotResolvableException - { - for (IdentifierProvider service : providers) - { - if (service.supports(identifier)) - { try - { + throws IdentifierNotFoundException, IdentifierNotResolvableException { + for (IdentifierProvider service : providers) { + if (service.supports(identifier)) { + try { DSpaceObject result = service.resolve(context, identifier); - if (result != null) - { + if (result != null) { return result; } - } - catch (IdentifierNotFoundException ex) - { + } catch (IdentifierNotFoundException ex) { log.info(service.getClass().getName() + " cannot resolve " - + "Identifier " + identifier + ": identifier not " - + "found."); + + "Identifier " + identifier + ": identifier not " + + "found."); log.debug(ex.getMessage(), ex); - } - catch (IdentifierException ex) - { + } catch (IdentifierException ex) { log.error(ex.getMessage(), ex); } } @@ -264,33 +226,26 @@ public class IdentifierServiceImpl implements IdentifierService { @Override public void delete(Context context, DSpaceObject dso) - throws AuthorizeException, SQLException, IdentifierException - { - for (IdentifierProvider service : providers) - { - try - { + throws AuthorizeException, SQLException, IdentifierException { + for (IdentifierProvider service : providers) { + try { service.delete(context, dso); } catch (IdentifierException e) { - log.error(e.getMessage(),e); + log.error(e.getMessage(), e); } } } @Override public void delete(Context context, DSpaceObject dso, String identifier) - throws AuthorizeException, SQLException, IdentifierException - { - for (IdentifierProvider service : providers) - { - try - { - if (service.supports(identifier)) - { + throws AuthorizeException, SQLException, IdentifierException { + for (IdentifierProvider service : providers) { + try { + if (service.supports(identifier)) { service.delete(context, dso, identifier); } } catch (IdentifierException e) { - log.error(e.getMessage(),e); + log.error(e.getMessage(), e); } } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/VersionedDOIIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/VersionedDOIIdentifierProvider.java index c8292b5d67..777fa4811f 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/VersionedDOIIdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/VersionedDOIIdentifierProvider.java @@ -7,6 +7,10 @@ */ package org.dspace.identifier; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; @@ -24,36 +28,30 @@ import org.dspace.versioning.service.VersioningService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /** - * * @author Marsa Haoua * @author Pascal-Nicolas Becker (dspace at pascal dash becker dot de) */ -public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider -{ - /** log4j category */ +public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider { + /** + * log4j category + */ private static Logger log = Logger.getLogger(VersionedDOIIdentifierProvider.class); - + protected DOIConnector connector; static final char DOT = '.'; - protected static final String pattern = "\\d+\\" + String.valueOf(DOT) +"\\d+"; - + protected static final String pattern = "\\d+\\" + String.valueOf(DOT) + "\\d+"; + @Autowired(required = true) protected VersioningService versioningService; @Autowired(required = true) protected VersionHistoryService versionHistoryService; - + @Override public String mint(Context context, DSpaceObject dso) - throws IdentifierException - { - if (!(dso instanceof Item)) - { + throws IdentifierException { + if (!(dso instanceof Item)) { throw new IdentifierException("Currently only Items are supported for DOIs."); } Item item = (Item) dso; @@ -66,29 +64,24 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider } String doi = null; - try - { + try { doi = getDOIByObject(context, dso); - if (doi != null) - { + if (doi != null) { return doi; } - } - catch (SQLException ex) - { - log.error("Error while attemping to retrieve information about a DOI for " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) - + " with ID " + dso.getID() + ".", ex); + } catch (SQLException ex) { + log.error("Error while attemping to retrieve information about a DOI for " + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + + " with ID " + dso.getID() + ".", ex); throw new RuntimeException("Error while attempting to retrieve " - + "information about a DOI for " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) - + " with ID " + dso.getID() + ".", ex); + + "information about a DOI for " + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + + " with ID " + dso.getID() + ".", ex); } - + // check whether we have a DOI in the metadata and if we have to remove it String metadataDOI = getDOIOutOfObject(dso); - if (metadataDOI != null) - { + if (metadataDOI != null) { // check whether doi and version number matches String bareDOI = getBareDOI(metadataDOI); int versionNumber; @@ -98,21 +91,20 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider throw new RuntimeException(ex); } String versionedDOI = bareDOI; - if (versionNumber > 1) - { + if (versionNumber > 1) { versionedDOI = bareDOI - .concat(String.valueOf(DOT)) - .concat(String.valueOf(versionNumber)); + .concat(String.valueOf(DOT)) + .concat(String.valueOf(versionNumber)); } - if (!metadataDOI.equalsIgnoreCase(versionedDOI)) - { - log.debug("Will remove DOI " + metadataDOI - + " from item metadata, as it should become " + versionedDOI + "."); + if (!metadataDOI.equalsIgnoreCase(versionedDOI)) { + log.debug("Will remove DOI " + metadataDOI + + " from item metadata, as it should become " + versionedDOI + "."); // remove old versioned DOIs try { removePreviousVersionDOIsOutOfObject(context, item, metadataDOI); } catch (AuthorizeException ex) { - throw new RuntimeException("Trying to remove an old DOI from a versioned item, but wasn't authorized to.", ex); + throw new RuntimeException( + "Trying to remove an old DOI from a versioned item, but wasn't authorized to.", ex); } } else { log.debug("DOI " + doi + " matches version number " + versionNumber + "."); @@ -121,23 +113,23 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider try { loadOrCreateDOI(context, dso, versionedDOI); } catch (SQLException ex) { - log.error("A problem with the database connection occurd while processing DOI " + versionedDOI + ".", ex); + log.error( + "A problem with the database connection occurd while processing DOI " + versionedDOI + ".", ex); throw new RuntimeException("A problem with the database connection occured.", ex); } return versionedDOI; } } - - try{ - if(history != null) - { + + try { + if (history != null) { // versioning is currently supported for items only // if we have a history, we have a item doi = makeIdentifierBasedOnHistory(context, dso, history); } else { doi = loadOrCreateDOI(context, dso, null).getDoi(); } - } catch(SQLException ex) { + } catch (SQLException ex) { log.error("SQLException while creating a new DOI: ", ex); throw new IdentifierException(ex); } catch (AuthorizeException ex) { @@ -146,28 +138,24 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider } return doi; } - + @Override - public void register(Context context, DSpaceObject dso, String identifier) - throws IdentifierException - { - if (!(dso instanceof Item)) - { + public void register(Context context, DSpaceObject dso, String identifier) + throws IdentifierException { + if (!(dso instanceof Item)) { throw new IdentifierException("Currently only Items are supported for DOIs."); } Item item = (Item) dso; - - if (StringUtils.isEmpty(identifier)) - { + + if (StringUtils.isEmpty(identifier)) { identifier = mint(context, dso); } String doiIdentifier = doiService.formatIdentifier(identifier); - + DOI doi = null; // search DOI in our db - try - { + try { doi = loadOrCreateDOI(context, dso, doiIdentifier); } catch (SQLException ex) { log.error("Error in databse connection: " + ex.getMessage(), ex); @@ -175,106 +163,96 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider } if (DELETED.equals(doi.getStatus()) || - TO_BE_DELETED.equals(doi.getStatus())) - { + TO_BE_DELETED.equals(doi.getStatus())) { throw new DOIIdentifierException("You tried to register a DOI that " - + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); + + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); } // Check status of DOI - if (IS_REGISTERED.equals(doi.getStatus())) - { + if (IS_REGISTERED.equals(doi.getStatus())) { return; } - + String metadataDOI = getDOIOutOfObject(dso); if (!StringUtils.isEmpty(metadataDOI) - && !metadataDOI.equalsIgnoreCase(doiIdentifier)) - { + && !metadataDOI.equalsIgnoreCase(doiIdentifier)) { // remove doi of older version from the metadata - try { - removePreviousVersionDOIsOutOfObject(context, item, metadataDOI); - } catch (AuthorizeException ex) { - throw new RuntimeException("Trying to remove an old DOI from a versioned item, but wasn't authorized to.", ex); - } + try { + removePreviousVersionDOIsOutOfObject(context, item, metadataDOI); + } catch (AuthorizeException ex) { + throw new RuntimeException( + "Trying to remove an old DOI from a versioned item, but wasn't authorized to.", ex); + } } - + // change status of DOI doi.setStatus(TO_BE_REGISTERED); try { doiService.update(context, doi); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.warn("SQLException while changing status of DOI {} to be registered.", ex); throw new RuntimeException(ex); } } - + protected String getBareDOI(String identifier) - throws DOIIdentifierException - { + throws DOIIdentifierException { doiService.formatIdentifier(identifier); String doiPrefix = DOI.SCHEME.concat(getPrefix()) .concat(String.valueOf(SLASH)) .concat(getNamespaceSeparator()); String doiPostfix = identifier.substring(doiPrefix.length()); - if (doiPostfix.matches(pattern) && doiPostfix.lastIndexOf(DOT) != -1) - { + if (doiPostfix.matches(pattern) && doiPostfix.lastIndexOf(DOT) != -1) { return doiPrefix.concat(doiPostfix.substring(0, doiPostfix.lastIndexOf(DOT))); } // if the pattern does not match, we are already working on a bare handle. return identifier; } - - protected String getDOIPostfix(String identifier) - throws DOIIdentifierException{ - + + protected String getDOIPostfix(String identifier) + throws DOIIdentifierException { + String doiPrefix = DOI.SCHEME.concat(getPrefix()).concat(String.valueOf(SLASH)).concat(getNamespaceSeparator()); String doiPostfix = null; - if(null != identifier){ + if (null != identifier) { doiPostfix = identifier.substring(doiPrefix.length()); } return doiPostfix; } - + // Should never return null! - protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history) - throws AuthorizeException, SQLException, DOIIdentifierException - { + protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history) + throws AuthorizeException, SQLException, DOIIdentifierException { // Mint foreach new version an identifier like: 12345/100.versionNumber // use the bare handle (g.e. 12345/100) for the first version. // currently versioning is supported for items only - if (!(dso instanceof Item)) - { - throw new IllegalArgumentException("Cannot create versioned handle for objects other then item: Currently versioning supports items only."); + if (!(dso instanceof Item)) { + throw new IllegalArgumentException( + "Cannot create versioned handle for objects other then item: Currently versioning supports items only" + + "."); } - Item item = (Item)dso; + Item item = (Item) dso; Version version = versionHistoryService.getVersion(context, history, item); String previousVersionDOI = null; - for (Version v : versioningService.getVersionsByHistory(context, history)) - { + for (Version v : versioningService.getVersionsByHistory(context, history)) { previousVersionDOI = getDOIByObject(context, v.getItem()); - if (null != previousVersionDOI) - { + if (null != previousVersionDOI) { break; } } - if (previousVersionDOI == null) - { + if (previousVersionDOI == null) { // We need to generate a new DOI. DOI doi = doiService.create(context); - + // as we reuse the DOI ID, we do not have to check whether the DOI exists already. String identifier = this.getPrefix() + "/" + this.getNamespaceSeparator() + - doi.getID().toString(); + doi.getID().toString(); - if (version.getVersionNumber() > 1) - { - identifier.concat(String.valueOf(DOT).concat(String.valueOf(version.getVersionNumber()))); + if (version.getVersionNumber() > 1) { + identifier = identifier.concat(String.valueOf(DOT).concat(String.valueOf(version.getVersionNumber()))); } doi.setDoi(identifier); @@ -283,52 +261,47 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider doiService.update(context, doi); return doi.getDoi(); } - assert(previousVersionDOI != null); + assert (previousVersionDOI != null); String identifier = getBareDOI(previousVersionDOI); - if (version.getVersionNumber() > 1) - { - identifier = identifier.concat(String.valueOf(DOT)).concat(String.valueOf(versionHistoryService.getVersion(context, history, item).getVersionNumber())); + if (version.getVersionNumber() > 1) { + identifier = identifier.concat(String.valueOf(DOT)).concat( + String.valueOf(versionHistoryService.getVersion(context, history, item).getVersionNumber())); } loadOrCreateDOI(context, dso, identifier); return identifier; } - + void removePreviousVersionDOIsOutOfObject(Context c, Item item, String oldDoi) - throws IdentifierException, AuthorizeException - { - if (StringUtils.isEmpty(oldDoi)) - { + throws IdentifierException, AuthorizeException { + if (StringUtils.isEmpty(oldDoi)) { throw new IllegalArgumentException("Old DOI must be neither empty nor null!"); } - + String bareDoi = getBareDOI(doiService.formatIdentifier(oldDoi)); - String bareDoiRef = doiService.DOIToExternalForm(bareDoi); - - List identifiers = itemService.getMetadata(item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, Item.ANY); + String bareDoiRef = doiService.DOIToExternalForm(bareDoi); + + List identifiers = itemService + .getMetadata(item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, Item.ANY); // We have to remove all DOIs referencing previous versions. To do that, - // we store all identifiers we do not know in an array list, clear + // we store all identifiers we do not know in an array list, clear // dc.identifier.uri and add the safed identifiers. // The list of identifiers to safe won't get larger then the number of // existing identifiers. ArrayList newIdentifiers = new ArrayList(identifiers.size()); boolean changed = false; - for (MetadataValue identifier : identifiers) - { - if (!StringUtils.startsWithIgnoreCase(identifier.getValue(), bareDoiRef)) - { + for (MetadataValue identifier : identifiers) { + if (!StringUtils.startsWithIgnoreCase(identifier.getValue(), bareDoiRef)) { newIdentifiers.add(identifier.getValue()); } else { changed = true; } } // reset the metadata if neccessary. - if (changed) - { - try - { + if (changed) { + try { itemService.clearMetadata(c, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, Item.ANY); itemService.addMetadata(c, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, newIdentifiers); itemService.update(c, item); @@ -339,12 +312,11 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider } @Required - public void setDOIConnector(DOIConnector connector) - { + public void setDOIConnector(DOIConnector connector) { super.setDOIConnector(connector); this.connector = connector; } - + @Required public void setConfigurationService(ConfigurationService configurationService) { super.setConfigurationService(configurationService); diff --git a/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProvider.java index c23c6e19e9..da7f1d7882 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProvider.java @@ -7,9 +7,20 @@ */ package org.dspace.identifier; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; @@ -17,24 +28,14 @@ import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.handle.service.HandleService; import org.dspace.services.factory.DSpaceServicesFactory; -import org.dspace.versioning.*; +import org.dspace.versioning.Version; +import org.dspace.versioning.VersionHistory; import org.dspace.versioning.service.VersionHistoryService; import org.dspace.versioning.service.VersioningService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.apache.commons.lang3.StringUtils; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -42,10 +43,14 @@ import org.apache.commons.lang3.StringUtils; */ @Component public class VersionedHandleIdentifierProvider extends IdentifierProvider { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(VersionedHandleIdentifierProvider.class); - /** Prefix registered to no one */ + /** + * Prefix registered to no one + */ static final String EXAMPLE_PREFIX = "123456789"; private static final char DOT = '.'; @@ -63,34 +68,32 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { private ItemService itemService; @Override - public boolean supports(Class identifier) - { + public boolean supports(Class identifier) { return Handle.class.isAssignableFrom(identifier); } @Override - public boolean supports(String identifier) - { - String prefix = handleService.getPrefix(); - String canonicalPrefix = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("handle.canonical.prefix"); - if (identifier == null) - { + public boolean supports(String identifier) { + String prefix = handleService.getPrefix(); + String canonicalPrefix = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("handle.canonical.prefix"); + if (identifier == null) { return false; } // return true if handle has valid starting pattern if (identifier.startsWith(prefix + "/") - || identifier.startsWith(canonicalPrefix) - || identifier.startsWith("hdl:") - || identifier.startsWith("info:hdl") - || identifier.matches("^https?://hdl\\.handle\\.net/.*") - || identifier.matches("^https?://.+/handle/.*")) - { + || identifier.startsWith(canonicalPrefix) + || identifier.startsWith("hdl:") + || identifier.startsWith("info:hdl") + || identifier.matches("^https?://hdl\\.handle\\.net/.*") + || identifier.matches("^https?://.+/handle/.*")) { return true; } //Check additional prefixes supported in the config file - String[] additionalPrefixes = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("handle.additional.prefixes"); - for(String additionalPrefix: additionalPrefixes) { + String[] additionalPrefixes = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("handle.additional.prefixes"); + for (String additionalPrefix : additionalPrefixes) { if (identifier.startsWith(additionalPrefix + "/")) { return true; } @@ -101,38 +104,34 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { } @Override - public String register(Context context, DSpaceObject dso) - { + public String register(Context context, DSpaceObject dso) { String id = mint(context, dso); - try - { - if (dso instanceof Item) - { + try { + if (dso instanceof Item) { populateHandleMetadata(context, (Item) dso, id); } - }catch (Exception e){ - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + (dso != null ? dso.getID() : "")), e); - throw new RuntimeException("Error while attempting to create identifier for Item id: " + (dso != null ? dso.getID() : "")); + } catch (Exception e) { + log.error(LogManager.getHeader(context, "Error while attempting to create handle", + "Item id: " + (dso != null ? dso.getID() : "")), e); + throw new RuntimeException( + "Error while attempting to create identifier for Item id: " + (dso != null ? dso.getID() : "")); } return id; } @Override public void register(Context context, DSpaceObject dso, String identifier) - throws IdentifierException - { - if (dso instanceof Item && identifier != null) - { + throws IdentifierException { + if (dso instanceof Item && identifier != null) { Item item = (Item) dso; - // if identifier == 1234.5/100.4 reinstate the version 4 in the + // if identifier == 1234.5/100.4 reinstate the version 4 in the // version table if absent - - + + Matcher versionHandleMatcher = Pattern.compile("^.*/.*\\.(\\d+)$").matcher(identifier); // do we have to register a versioned handle? - if(versionHandleMatcher.matches()) - { + if (versionHandleMatcher.matches()) { // parse the version number from the handle int versionNumber = -1; try { @@ -140,21 +139,20 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { } catch (NumberFormatException ex) { throw new IllegalStateException("Cannot detect the interger value of a digit.", ex); } - + // get history VersionHistory history = null; try { history = versionHistoryService.findByItem(context, item); } catch (SQLException ex) { - throw new RuntimeException("Unable to create handle '" - + identifier + "' for " - + Constants.typeText[dso.getType()] + " " + dso.getID() - + " in cause of a problem with the database: ", ex); + throw new RuntimeException("Unable to create handle '" + + identifier + "' for " + + Constants.typeText[dso.getType()] + " " + dso.getID() + + " in cause of a problem with the database: ", ex); } - + // do we have a version history? - if (history != null) - { + if (history != null) { // get the version Version version = null; try { @@ -162,16 +160,15 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { } catch (SQLException ex) { throw new RuntimeException("Problem with the database connection occurd.", ex); } - + // did we found a version? - if (version != null) - { + if (version != null) { // do the version's number and the handle versionnumber match? - if (version.getVersionNumber() != versionNumber) - { - throw new IdentifierException("Trying to register a handle without matching its item's version number."); + if (version.getVersionNumber() != versionNumber) { + throw new IdentifierException( + "Trying to register a handle without matching its item's version number."); } - + // create the handle try { handleService.createHandle(context, dso, identifier); @@ -179,14 +176,14 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { return; } catch (AuthorizeException ex) { throw new IdentifierException("Current user does not " - + "have the privileges to add the handle " - + identifier + " to the item's (" - + dso.getID() + ") metadata.", ex); + + "have the privileges to add the handle " + + identifier + " to the item's (" + + dso.getID() + ") metadata.", ex); } catch (SQLException | IOException ex) { throw new RuntimeException("Unable to create handle '" - + identifier + "' for " - + Constants.typeText[dso.getType()] + " " + dso.getID() - + ".", ex); + + identifier + "' for " + + Constants.typeText[dso.getType()] + " " + dso.getID() + + ".", ex); } } } else { @@ -196,12 +193,12 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { restoreItAsVersion(context, item, identifier, versionNumber); } catch (SQLException | IOException ex) { throw new RuntimeException("Unable to restore a versioned " - + "handle as there was a problem in creating a " - + "neccessary item version: ", ex); + + "handle as there was a problem in creating a " + + "neccessary item version: ", ex); } catch (AuthorizeException ex) { throw new RuntimeException("Unable to restore a versioned " - + "handle as the current user was not allowed to " - + "create a neccessary item version: ", ex); + + "handle as the current user was not allowed to " + + "create a neccessary item version: ", ex); } return; } @@ -213,30 +210,30 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { // just register it. createNewIdentifier(context, dso, identifier); if (dso instanceof Item) { - populateHandleMetadata(context, (Item) dso, identifier); + populateHandleMetadata(context, (Item) dso, identifier); } } catch (SQLException ex) { - throw new RuntimeException("Unable to create handle '" - + identifier + "' for " - + Constants.typeText[dso.getType()] + " " + dso.getID() - + " in cause of a problem with the database: ", ex); + throw new RuntimeException("Unable to create handle '" + + identifier + "' for " + + Constants.typeText[dso.getType()] + " " + dso.getID() + + " in cause of a problem with the database: ", ex); } catch (AuthorizeException ex) { - throw new IdentifierException("Current user does not " - + "have the privileges to add the handle " - + identifier + " to the item's (" - + dso.getID() + ") metadata.", ex); + throw new IdentifierException("Current user does not " + + "have the privileges to add the handle " + + identifier + " to the item's (" + + dso.getID() + ") metadata.", ex); } catch (IOException ex) { throw new RuntimeException("Unable add the handle '" - + identifier + "' for " - + Constants.typeText[dso.getType()] + " " + dso.getID() - + " in the object's metadata.", ex); + + identifier + "' for " + + Constants.typeText[dso.getType()] + " " + dso.getID() + + " in the object's metadata.", ex); } } // get VersionHistory by handle protected VersionHistory getHistory(Context context, String identifier) throws SQLException { DSpaceObject item = this.resolve(context, identifier); - if(item!=null){ + if (item != null) { VersionHistory history = versionHistoryService.findByItem(context, (Item) item); return history; } @@ -244,31 +241,29 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { } protected void restoreItAsVersion(Context context, Item item, String identifier, int versionNumber) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { createNewIdentifier(context, item, identifier); populateHandleMetadata(context, item, identifier); - + VersionHistory vh = versionHistoryService.findByItem(context, item); - if (vh == null) - { + if (vh == null) { vh = versionHistoryService.create(context); } Version version = versionHistoryService.getVersion(context, vh, item); - if (version == null) - { - version = versionService.createNewVersion(context, vh, item, "Restoring from AIP Service", new Date(), versionNumber); + if (version == null) { + version = versionService + .createNewVersion(context, vh, item, "Restoring from AIP Service", new Date(), versionNumber); } versionHistoryService.update(context, vh); } @Override - public void reserve(Context context, DSpaceObject dso, String identifier) - { - try{ + public void reserve(Context context, DSpaceObject dso, String identifier) { + try { handleService.createHandle(context, dso, identifier); - }catch(Exception e){ - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + } catch (Exception e) { + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID()); } } @@ -278,58 +273,55 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { * Creates a new handle in the database. * * @param context DSpace context - * @param dso The DSpaceObject to create a handle for + * @param dso The DSpaceObject to create a handle for * @return The newly created handle */ @Override - public String mint(Context context, DSpaceObject dso) - { - if(dso.getHandle() != null) - { + public String mint(Context context, DSpaceObject dso) { + if (dso.getHandle() != null) { return dso.getHandle(); } - try{ + try { String handleId = null; VersionHistory history = null; - if(dso instanceof Item) - { + if (dso instanceof Item) { history = versionHistoryService.findByItem(context, (Item) dso); } - if(history!=null) - { + if (history != null) { handleId = makeIdentifierBasedOnHistory(context, dso, history); - }else{ + } else { handleId = createNewIdentifier(context, dso, null); } return handleId; - }catch (Exception e){ - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + } catch (Exception e) { + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID()); } } @Override - public DSpaceObject resolve(Context context, String identifier, String... attributes) - { + public DSpaceObject resolve(Context context, String identifier, String... attributes) { // We can do nothing with this, return null - try{ + try { return handleService.resolveToObject(context, identifier); - }catch (Exception e){ - log.error(LogManager.getHeader(context, "Error while resolving handle to item", "handle: " + identifier), e); + } catch (Exception e) { + log.error(LogManager.getHeader(context, "Error while resolving handle to item", "handle: " + identifier), + e); } return null; } @Override - public String lookup(Context context, DSpaceObject dso) throws IdentifierNotFoundException, IdentifierNotResolvableException { + public String lookup(Context context, DSpaceObject dso) + throws IdentifierNotFoundException, IdentifierNotResolvableException { - try - { + try { return handleService.findHandle(context, dso); - }catch(SQLException sqe){ - throw new IdentifierNotResolvableException(sqe.getMessage(),sqe); + } catch (SQLException sqe) { + throw new IdentifierNotResolvableException(sqe.getMessage(), sqe); } } @@ -340,17 +332,18 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { @Override public void delete(Context context, DSpaceObject dso) throws IdentifierException { - try{ + try { handleService.unbindHandle(context, dso); - } catch(SQLException sqe) { - throw new RuntimeException(sqe.getMessage(),sqe); + } catch (SQLException sqe) { + throw new RuntimeException(sqe.getMessage(), sqe); } } - public static String retrieveHandleOutOfUrl(String url) throws SQLException - { + public static String retrieveHandleOutOfUrl(String url) throws SQLException { // We can do nothing with this, return null - if (!url.contains("/")) return null; + if (!url.contains("/")) { + return null; + } String[] splitUrl = url.split("/"); @@ -359,63 +352,44 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { /** * Get the configured Handle prefix string, or a default + * * @return configured prefix or "123456789" */ - public static String getPrefix() - { + public static String getPrefix() { String prefix = ConfigurationManager.getProperty("handle.prefix"); - if (null == prefix) - { + if (null == prefix) { prefix = EXAMPLE_PREFIX; // XXX no good way to exit cleanly log.error("handle.prefix is not configured; using " + prefix); } return prefix; } - protected static String getCanonicalForm(String handle) - { - - // Let the admin define a new prefix, if not then we'll use the - // CNRI default. This allows the admin to use "hdl:" if they want to or - // use a locally branded prefix handle.myuni.edu. - String handlePrefix = ConfigurationManager.getProperty("handle.canonical.prefix"); - if (handlePrefix == null || handlePrefix.length() == 0) - { - handlePrefix = "http://hdl.handle.net/"; - } - - return handlePrefix + handle; - } - protected String createNewIdentifier(Context context, DSpaceObject dso, String handleId) throws SQLException { - if(handleId == null) - { + if (handleId == null) { return handleService.createHandle(context, dso); - }else{ - return handleService.createHandle(context, dso, handleId); + } else { + return handleService.createHandle(context, dso, handleId); } } - protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history) throws AuthorizeException, SQLException - { - if (!(dso instanceof Item)) - { + protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history) + throws AuthorizeException, SQLException { + if (!(dso instanceof Item)) { throw new IllegalStateException("Cannot create versioned handle for " - + "objects other then item: Currently versioning supports " - + "items only."); + + "objects other then item: Currently versioning supports " + + "items only."); } - Item item = (Item)dso; - + Item item = (Item) dso; + // The first version will have a handle like 12345/100 to be backward compatible // to DSpace installation that started without versioning. // Mint foreach new VERSION an identifier like: 12345/100.versionNumber. - + Version version = versionService.getVersion(context, item); Version firstVersion = versionHistoryService.getFirstVersion(context, history); String bareHandle = firstVersion.getItem().getHandle(); - if(bareHandle.matches(".*/.*\\.\\d+")) - { + if (bareHandle.matches(".*/.*\\.\\d+")) { bareHandle = bareHandle.substring(0, bareHandle.lastIndexOf(DOT)); } @@ -423,55 +397,48 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { int versionNumber = version.getVersionNumber(); String identifier = bareHandle; - if (versionNumber > 1) - { + if (versionNumber > 1) { identifier = identifier.concat(String.valueOf(DOT)).concat(String.valueOf(versionNumber)); } // Ensure this handle does not exist already. - if (handleService.resolveToObject(context, identifier) == null) - { - handleService.createHandle(context, dso, identifier); - } - else - { + if (handleService.resolveToObject(context, identifier) == null) { + handleService.createHandle(context, dso, identifier); + } else { throw new IllegalStateException("A versioned handle is used for another version already!"); } return identifier; } - + protected void populateHandleMetadata(Context context, Item item, String handle) - throws SQLException, IOException, AuthorizeException - { - String handleref = getCanonicalForm(handle); - // we want to remove the old handle and insert the new. To do so, we - // load all identifiers, clear the metadata field, re add all + throws SQLException, IOException, AuthorizeException { + String handleref = handleService.getCanonicalForm(handle); + // we want to remove the old handle and insert the new. To do so, we + // load all identifiers, clear the metadata field, re add all // identifiers which are not from type handle and add the new handle. - List identifiers = itemService.getMetadata(item, - MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); - itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, - "identifier", "uri", Item.ANY); - for (MetadataValue identifier : identifiers) - { - if (this.supports(identifier.getValue())) - { + List identifiers = itemService.getMetadata(item, + MetadataSchema.DC_SCHEMA, "identifier", "uri", + Item.ANY); + itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, + "identifier", "uri", Item.ANY); + for (MetadataValue identifier : identifiers) { + if (this.supports(identifier.getValue())) { // ignore handles log.debug("Removing identifier " + identifier.getValue()); continue; } log.debug("Preserving identifier " + identifier.getValue()); - itemService.addMetadata(context, - item, - identifier.getMetadataField(), - identifier.getLanguage(), - identifier.getValue(), - identifier.getAuthority(), - identifier.getConfidence()); + itemService.addMetadata(context, + item, + identifier.getMetadataField(), + identifier.getLanguage(), + identifier.getValue(), + identifier.getAuthority(), + identifier.getConfidence()); } - + // Add handle as identifier.uri DC value. - if (StringUtils.isNotBlank(handleref)) - { + if (StringUtils.isNotBlank(handleref)) { itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "uri", null, handleref); } itemService.update(context, item); diff --git a/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProviderWithCanonicalHandles.java b/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProviderWithCanonicalHandles.java index 1e912a80b7..72cbf7d4e7 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProviderWithCanonicalHandles.java +++ b/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProviderWithCanonicalHandles.java @@ -7,9 +7,18 @@ */ package org.dspace.identifier; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; @@ -17,31 +26,28 @@ import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.handle.service.HandleService; import org.dspace.services.factory.DSpaceServicesFactory; -import org.dspace.versioning.*; +import org.dspace.versioning.Version; +import org.dspace.versioning.VersionHistory; import org.dspace.versioning.service.VersionHistoryService; import org.dspace.versioning.service.VersioningService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; -import org.apache.commons.lang.StringUtils; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) */ @Component public class VersionedHandleIdentifierProviderWithCanonicalHandles extends IdentifierProvider { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger.getLogger(VersionedHandleIdentifierProviderWithCanonicalHandles.class); - /** Prefix registered to no one */ + /** + * Prefix registered to no one + */ static final String EXAMPLE_PREFIX = "123456789"; private static final char DOT = '.'; @@ -59,34 +65,32 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident private ItemService itemService; @Override - public boolean supports(Class identifier) - { + public boolean supports(Class identifier) { return Handle.class.isAssignableFrom(identifier); } @Override - public boolean supports(String identifier) - { + public boolean supports(String identifier) { String prefix = handleService.getPrefix(); - String canonicalPrefix = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("handle.canonical.prefix"); - if (identifier == null) - { + String canonicalPrefix = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("handle.canonical.prefix"); + if (identifier == null) { return false; } // return true if handle has valid starting pattern if (identifier.startsWith(prefix + "/") - || identifier.startsWith(canonicalPrefix) - || identifier.startsWith("hdl:") - || identifier.startsWith("info:hdl") - || identifier.matches("^https?://hdl\\.handle\\.net/.*") - || identifier.matches("^https?://.+/handle/.*")) - { + || identifier.startsWith(canonicalPrefix) + || identifier.startsWith("hdl:") + || identifier.startsWith("info:hdl") + || identifier.matches("^https?://hdl\\.handle\\.net/.*") + || identifier.matches("^https?://.+/handle/.*")) { return true; } //Check additional prefixes supported in the config file - String[] additionalPrefixes = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("handle.additional.prefixes"); - for (String additionalPrefix: additionalPrefixes) { + String[] additionalPrefixes = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("handle.additional.prefixes"); + for (String additionalPrefix : additionalPrefixes) { if (identifier.startsWith(additionalPrefix + "/")) { return true; } @@ -97,31 +101,28 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident } @Override - public String register(Context context, DSpaceObject dso) - { + public String register(Context context, DSpaceObject dso) { String id = mint(context, dso); // move canonical to point the latest version - if (dso != null && dso.getType() == Constants.ITEM) - { - Item item = (Item)dso; + if (dso != null && dso.getType() == Constants.ITEM) { + Item item = (Item) dso; VersionHistory history = null; try { history = versionHistoryService.findByItem(context, (Item) dso); } catch (SQLException ex) { throw new RuntimeException("A problem with the database connection occured.", ex); } - if (history!=null) - { + if (history != null) { String canonical = getCanonical(context, item); - + // Modify Canonical: 12345/100 will point to the new item try { handleService.modifyHandleDSpaceObject(context, canonical, item); } catch (SQLException ex) { throw new RuntimeException("A problem with the database connection occured.", ex); } - + Version version; Version previous; boolean previousIsFirstVersion = false; @@ -129,8 +130,7 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident try { version = versionService.getVersion(context, item); previous = versionHistoryService.getPrevious(context, history, version); - if (previous != null) - { + if (previous != null) { previousIsFirstVersion = versionHistoryService.isFirstVersion(context, history, previous); previousItemHandle = handleService.findHandle(context, previous.getItem()); } @@ -140,8 +140,7 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident // we have to ensure the previous item still has a handle // check if we have a previous item - if (previous != null) - { + if (previous != null) { try { // If we have a reviewer he/she might not have the // rights to edit the metadata of thes previous item. @@ -149,14 +148,12 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident context.turnOffAuthorisationSystem(); // Check if our previous item hasn't got a handle anymore. - // This only occurs when a switch has been made from - // the default handle identifier provider to the + // This only occurs when a switch has been made from + // the default handle identifier provider to the // versioned one. In this case no "versioned handle" is // reserved so we need to create one. - if (previousItemHandle == null) - { - if (previousIsFirstVersion) - { + if (previousItemHandle == null) { + if (previousIsFirstVersion) { previousItemHandle = getCanonical(id) + DOT + previous.getVersionNumber(); handleService.createHandle(context, previous.getItem(), previousItemHandle); } else { @@ -170,8 +167,8 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident } catch (AuthorizeException ex) { // cannot occure, as the authorization system is turned of throw new IllegalStateException("Caught an " - + "AuthorizeException while the " - + "authorization system was turned off!", ex); + + "AuthorizeException while the " + + "authorization system was turned off!", ex); } finally { context.restoreAuthSystemState(); } @@ -191,10 +188,8 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident } @Override - public void register(Context context, DSpaceObject dso, String identifier) - { - try - { + public void register(Context context, DSpaceObject dso, String identifier) { + try { Item item = (Item) dso; @@ -203,67 +198,63 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident // trying to restore the latest version the identifier in input doesn't have the for 1234/123.latestVersion // it is the canonical 1234/123 VersionHistory itemHistory = getHistory(context, identifier); - if (!identifier.matches(".*/.*\\.\\d+") && itemHistory!=null) { + if (!identifier.matches(".*/.*\\.\\d+") && itemHistory != null) { - int newVersionNumber = versionHistoryService.getLatestVersion(context, itemHistory).getVersionNumber()+1; + int newVersionNumber = versionHistoryService.getLatestVersion(context, itemHistory) + .getVersionNumber() + 1; String canonical = identifier; identifier = identifier.concat(".").concat("" + newVersionNumber); restoreItAsVersion(context, dso, identifier, item, canonical, itemHistory); - } - // if identifier == 1234.5/100.4 reinstate the version 4 in the version table if absent - else if (identifier.matches(".*/.*\\.\\d+")) - { + } else if (identifier.matches(".*/.*\\.\\d+")) { + // if identifier == 1234.5/100.4 reinstate the version 4 in the version table if absent + // if it is a version of an item is needed to put back the record // in the versionitem table String canonical = getCanonical(identifier); DSpaceObject canonicalItem = this.resolve(context, canonical); - if (canonicalItem==null) { + if (canonicalItem == null) { restoreItAsCanonical(context, dso, identifier, item, canonical); - } - else { + } else { VersionHistory history = versionHistoryService.findByItem(context, (Item) canonicalItem); - if (history==null) { + if (history == null) { restoreItAsCanonical(context, dso, identifier, item, canonical); - } - else - { + } else { restoreItAsVersion(context, dso, identifier, item, canonical, history); } } - } - else - { + } else { //A regular handle createNewIdentifier(context, dso, identifier); - if (dso instanceof Item) - { + if (dso instanceof Item) { modifyHandleMetadata(context, item, getCanonical(identifier)); } } } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID(), e); } } protected VersionHistory getHistory(Context context, String identifier) throws SQLException { DSpaceObject item = this.resolve(context, identifier); - if (item!=null) { + if (item != null) { VersionHistory history = versionHistoryService.findByItem(context, (Item) item); return history; } return null; } - protected void restoreItAsVersion(Context context, DSpaceObject dso, String identifier, Item item, String canonical, VersionHistory history) - throws SQLException, IOException, AuthorizeException - { + protected void restoreItAsVersion(Context context, DSpaceObject dso, String identifier, Item item, String canonical, + VersionHistory history) + throws SQLException, IOException, AuthorizeException { createNewIdentifier(context, dso, identifier); modifyHandleMetadata(context, item, getCanonical(identifier)); int versionNumber = Integer.parseInt(identifier.substring(identifier.lastIndexOf(".") + 1)); - versionService.createNewVersion(context, history, item, "Restoring from AIP Service", new Date(), versionNumber); + versionService + .createNewVersion(context, history, item, "Restoring from AIP Service", new Date(), versionNumber); Version latest = versionHistoryService.getLatestVersion(context, history); @@ -273,14 +264,15 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident } } - protected void restoreItAsCanonical(Context context, DSpaceObject dso, String identifier, Item item, String canonical) throws SQLException, IOException, AuthorizeException - { + protected void restoreItAsCanonical(Context context, DSpaceObject dso, String identifier, Item item, + String canonical) throws SQLException, IOException, AuthorizeException { createNewIdentifier(context, dso, identifier); modifyHandleMetadata(context, item, getCanonical(identifier)); - int versionNumber = Integer.parseInt(identifier.substring(identifier.lastIndexOf(".")+1)); - VersionHistory history=versionHistoryService.create(context); - versionService.createNewVersion(context, history, item, "Restoring from AIP Service", new Date(), versionNumber); + int versionNumber = Integer.parseInt(identifier.substring(identifier.lastIndexOf(".") + 1)); + VersionHistory history = versionHistoryService.create(context); + versionService + .createNewVersion(context, history, item, "Restoring from AIP Service", new Date(), versionNumber); handleService.modifyHandleDSpaceObject(context, canonical, dso); @@ -288,12 +280,12 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident @Override - public void reserve(Context context, DSpaceObject dso, String identifier) - { - try{ + public void reserve(Context context, DSpaceObject dso, String identifier) { + try { handleService.createHandle(context, dso, identifier); - } catch(Exception e) { - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + } catch (Exception e) { + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID()); } } @@ -303,58 +295,55 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident * Creates a new handle in the database. * * @param context DSpace context - * @param dso The DSpaceObject to create a handle for + * @param dso The DSpaceObject to create a handle for * @return The newly created handle */ @Override - public String mint(Context context, DSpaceObject dso) - { - if (dso.getHandle() != null) - { + public String mint(Context context, DSpaceObject dso) { + if (dso.getHandle() != null) { return dso.getHandle(); } try { String handleId = null; VersionHistory history = null; - if (dso instanceof Item) - { + if (dso instanceof Item) { history = versionHistoryService.findByItem(context, (Item) dso); } - if (history!=null) - { + if (history != null) { handleId = makeIdentifierBasedOnHistory(context, dso, history); } else { handleId = createNewIdentifier(context, dso, null); } return handleId; } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); + log.error( + LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e); throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID()); } } @Override - public DSpaceObject resolve(Context context, String identifier, String... attributes) - { + public DSpaceObject resolve(Context context, String identifier, String... attributes) { // We can do nothing with this, return null try { return handleService.resolveToObject(context, identifier); } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while resolving handle to item", "handle: " + identifier), e); + log.error(LogManager.getHeader(context, "Error while resolving handle to item", "handle: " + identifier), + e); } return null; } @Override - public String lookup(Context context, DSpaceObject dso) throws IdentifierNotFoundException, IdentifierNotResolvableException { + public String lookup(Context context, DSpaceObject dso) + throws IdentifierNotFoundException, IdentifierNotResolvableException { - try - { + try { return handleService.findHandle(context, dso); - } catch(SQLException sqe) { - throw new IdentifierNotResolvableException(sqe.getMessage(),sqe); + } catch (SQLException sqe) { + throw new IdentifierNotResolvableException(sqe.getMessage(), sqe); } } @@ -367,18 +356,18 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident public void delete(Context context, DSpaceObject dso) throws IdentifierException { try { - if (dso instanceof Item) - { + if (dso instanceof Item) { Item item = (Item) dso; // If it is the most current version occurs to move the canonical to the previous version VersionHistory history = versionHistoryService.findByItem(context, item); - if (history!=null && versionHistoryService.getLatestVersion(context, history).getItem().equals(item) - && versionService.getVersionsByHistory(context, history).size() > 1) - { + if (history != null && versionHistoryService.getLatestVersion(context, history).getItem().equals(item) + && versionService.getVersionsByHistory(context, history).size() > 1) { Item previous; try { - previous = versionHistoryService.getPrevious(context, history, versionHistoryService.getLatestVersion(context, history)).getItem(); + previous = versionHistoryService + .getPrevious(context, history, versionHistoryService.getLatestVersion(context, history)) + .getItem(); } catch (SQLException ex) { throw new RuntimeException("A problem with our database connection occured.", ex); } @@ -389,17 +378,19 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident } } } catch (Exception e) { - log.error(LogManager.getHeader(context, "Error while attempting to register doi", "Item id: " + dso.getID()), e); + log.error( + LogManager.getHeader(context, "Error while attempting to register doi", "Item id: " + dso.getID()), e); throw new IdentifierException("Error while moving doi identifier", e); } } - public static String retrieveHandleOutOfUrl(String url) - { + public static String retrieveHandleOutOfUrl(String url) { // We can do nothing with this, return null - if (!url.contains("/")) return null; + if (!url.contains("/")) { + return null; + } String[] splitUrl = url.split("/"); @@ -408,49 +399,32 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident /** * Get the configured Handle prefix string, or a default + * * @return configured prefix or "123456789" */ - public static String getPrefix() - { + public static String getPrefix() { String prefix = ConfigurationManager.getProperty("handle.prefix"); - if (null == prefix) - { + if (null == prefix) { prefix = EXAMPLE_PREFIX; // XXX no good way to exit cleanly log.error("handle.prefix is not configured; using " + prefix); } return prefix; } - protected static String getCanonicalForm(String handle) - { - - // Let the admin define a new prefix, if not then we'll use the - // CNRI default. This allows the admin to use "hdl:" if they want to or - // use a locally branded prefix handle.myuni.edu. - String handlePrefix = ConfigurationManager.getProperty("handle.canonical.prefix"); - if (handlePrefix == null || handlePrefix.length() == 0) - { - handlePrefix = "http://hdl.handle.net/"; - } - - return handlePrefix + handle; - } - protected String createNewIdentifier(Context context, DSpaceObject dso, String handleId) throws SQLException { - if (handleId == null) - { + if (handleId == null) { return handleService.createHandle(context, dso); } else { - return handleService.createHandle(context, dso, handleId); + return handleService.createHandle(context, dso, handleId); } } protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history) - throws AuthorizeException, SQLException - { - Item item = (Item)dso; + throws AuthorizeException, SQLException { + Item item = (Item) dso; - // FIRST time a VERSION is created 2 identifiers will be minted and the canonical will be updated to point to the newer URL: + // FIRST time a VERSION is created 2 identifiers will be minted and the canonical will be updated to point + // to the newer URL: // - id.1-->old URL // - id.2-->new URL Version version = versionService.getVersion(context, item); @@ -462,13 +436,11 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident } String canonical = getCanonical(context, previous.getItem()); - if (versionHistoryService.isFirstVersion(context, history, previous)) - { + if (versionHistoryService.isFirstVersion(context, history, previous)) { // add a new Identifier for previous item: 12345/100.1 - String identifierPreviousItem=canonical + DOT + previous.getVersionNumber(); + String identifierPreviousItem = canonical + DOT + previous.getVersionNumber(); //Make sure that this hasn't happened already - if (handleService.resolveToObject(context, identifierPreviousItem) == null) - { + if (handleService.resolveToObject(context, identifierPreviousItem) == null) { handleService.createHandle(context, previous.getItem(), identifierPreviousItem, true); } } @@ -476,8 +448,7 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident // add a new Identifier for this item: 12345/100.x String idNew = canonical + DOT + version.getVersionNumber(); //Make sure we don't have an old handle hanging around (if our previous version was deleted in the workspace) - if (handleService.resolveToObject(context, idNew) == null) - { + if (handleService.resolveToObject(context, idNew) == null) { handleService.createHandle(context, dso, idNew); } else { handleService.modifyHandleDSpaceObject(context, idNew, dso); @@ -489,20 +460,17 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident protected String getCanonical(Context context, Item item) { String canonical = item.getHandle(); - if ( canonical.matches(".*/.*\\.\\d+") && canonical.lastIndexOf(DOT)!=-1) - { - canonical = canonical.substring(0, canonical.lastIndexOf(DOT)); + if (canonical.matches(".*/.*\\.\\d+") && canonical.lastIndexOf(DOT) != -1) { + canonical = canonical.substring(0, canonical.lastIndexOf(DOT)); } return canonical; } - protected String getCanonical(String identifier) - { + protected String getCanonical(String identifier) { String canonical = identifier; - if ( canonical.matches(".*/.*\\.\\d+") && canonical.lastIndexOf(DOT)!=-1) - { - canonical = canonical.substring(0, canonical.lastIndexOf(DOT)); + if (canonical.matches(".*/.*\\.\\d+") && canonical.lastIndexOf(DOT) != -1) { + canonical = canonical.substring(0, canonical.lastIndexOf(DOT)); } return canonical; @@ -511,41 +479,35 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident /** * Remove all handles from an item's metadata and add the supplied handle instead. * - * @param context - * The relevant DSpace Context. - * @param item - * which item to modify - * @param handle - * which handle to add - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param item which item to modify + * @param handle which handle to add + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ protected void modifyHandleMetadata(Context context, Item item, String handle) - throws SQLException, AuthorizeException - { - // we want to exchange the old handle against the new one. To do so, we - // load all identifiers, clear the metadata field, re add all + throws SQLException, AuthorizeException { + // we want to exchange the old handle against the new one. To do so, we + // load all identifiers, clear the metadata field, re add all // identifiers which are not from type handle and add the new handle. - String handleref = getCanonicalForm(handle); - List identifiers = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); + String handleref = handleService.getCanonicalForm(handle); + List identifiers = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); - for (MetadataValue identifier : identifiers) - { - if (this.supports(identifier.getValue())) - { + for (MetadataValue identifier : identifiers) { + if (this.supports(identifier.getValue())) { // ignore handles continue; } - itemService.addMetadata(context, - item, - identifier.getMetadataField(), - identifier.getLanguage(), - identifier.getValue(), - identifier.getAuthority(), - identifier.getConfidence()); + itemService.addMetadata(context, + item, + identifier.getMetadataField(), + identifier.getLanguage(), + identifier.getValue(), + identifier.getAuthority(), + identifier.getConfidence()); } - if (!StringUtils.isEmpty(handleref)) - { + if (!StringUtils.isEmpty(handleref)) { itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "uri", null, handleref); } itemService.update(context, item); diff --git a/dspace-api/src/main/java/org/dspace/identifier/dao/DOIDAO.java b/dspace-api/src/main/java/org/dspace/identifier/dao/DOIDAO.java index 5ade8a4b84..8085c6599b 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/dao/DOIDAO.java +++ b/dspace-api/src/main/java/org/dspace/identifier/dao/DOIDAO.java @@ -7,14 +7,14 @@ */ package org.dspace.identifier.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.identifier.DOI; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the DOI object. * The implementation of this class is responsible for all database calls for the DOI object and is autowired by spring @@ -22,14 +22,14 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public interface DOIDAO extends GenericDAO -{ +public interface DOIDAO extends GenericDAO { public DOI findByDoi(Context context, String doi) throws SQLException; - public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) throws SQLException; - + public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) + throws SQLException; + public List findSimilarNotInState(Context context, String doi, List statuses, boolean dsoNotNull) - throws SQLException; + throws SQLException; public List findByStatus(Context context, List statuses) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/identifier/dao/impl/DOIDAOImpl.java b/dspace-api/src/main/java/org/dspace/identifier/dao/impl/DOIDAOImpl.java index e4c588168b..019e89c129 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/dao/impl/DOIDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/identifier/dao/impl/DOIDAOImpl.java @@ -7,18 +7,20 @@ */ package org.dspace.identifier.dao.impl; -import org.dspace.content.DSpaceObject; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.identifier.DOI; -import org.dspace.identifier.dao.DOIDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Conjunction; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.dspace.content.DSpaceObject; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.identifier.DOI; +import org.dspace.identifier.DOI_; +import org.dspace.identifier.dao.DOIDAO; /** * Hibernate implementation of the Database Access Object interface class for the DOI object. @@ -27,81 +29,95 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class DOIDAOImpl extends AbstractHibernateDAO implements DOIDAO -{ - protected DOIDAOImpl() - { +public class DOIDAOImpl extends AbstractHibernateDAO implements DOIDAO { + protected DOIDAOImpl() { super(); } @Override public DOI findByDoi(Context context, String doi) throws SQLException { - Criteria criteria = createCriteria(context, DOI.class); - criteria.add(Restrictions.eq("doi", doi)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); + criteriaQuery.where(criteriaBuilder.equal(doiRoot.get(DOI_.doi), doi)); + return uniqueResult(context, criteriaQuery, false, DOI.class, -1, -1); } @Override - public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) throws SQLException { - //SELECT * FROM Doi WHERE resource_type_id = ? AND resource_id = ? AND resource_id = ? AND ((status != ? AND status != ?) OR status IS NULL) - Criteria criteria = createCriteria(context, DOI.class); - Disjunction statusQuery = Restrictions.or(); - Conjunction statusConjunctionAnd = Restrictions.and(); - for (Integer status : statusToExclude) { - statusConjunctionAnd.add(Restrictions.not(Restrictions.eq("status", status))); - } - statusQuery.add(statusConjunctionAnd); - statusQuery.add(Restrictions.isNull("status")); - criteria.add( - Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - statusQuery + public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); - ) + List listToIncludeInOrPredicate = new LinkedList<>(); + + for (Integer status : statusToExclude) { + listToIncludeInOrPredicate.add(criteriaBuilder.notEqual(doiRoot.get(DOI_.status), status)); + } + listToIncludeInOrPredicate.add(criteriaBuilder.isNull(doiRoot.get(DOI_.status))); + + Predicate orPredicate = criteriaBuilder.or(listToIncludeInOrPredicate.toArray(new Predicate[] {})); + + criteriaQuery.where(criteriaBuilder.and(orPredicate, + criteriaBuilder.equal(doiRoot.get(DOI_.dSpaceObject), dso) + ) ); - return singleResult(criteria); + + return singleResult(context, criteriaQuery); } @Override public List findByStatus(Context context, List statuses) throws SQLException { - Criteria criteria = createCriteria(context, DOI.class); - Disjunction statusQuery = Restrictions.or(); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); + List orPredicates = new LinkedList<>(); for (Integer status : statuses) { - statusQuery.add(Restrictions.eq("status", status)); + orPredicates.add(criteriaBuilder.equal(doiRoot.get(DOI_.status), status)); } - criteria.add(statusQuery); - return list(criteria); + criteriaQuery.where(criteriaBuilder.or(orPredicates.toArray(new Predicate[] {}))); + return list(context, criteriaQuery, false, DOI.class, -1, -1); } - + @Override - public List findSimilarNotInState(Context context, String doi, List excludedStatuses, boolean dsoNotNull) - throws SQLException - { - // SELECT * FROM Doi WHERE doi LIKE ? AND resource_type_id = ? AND resource_id IS NOT NULL AND status != ? AND status != ? - Criteria criteria = createCriteria(context, DOI.class); - Conjunction conjunctionAnd = Restrictions.and(); - Disjunction statusQuery = Restrictions.or(); + public List findSimilarNotInState(Context context, String doi, List excludedStatuses, + boolean dsoNotNull) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); + + List listToIncludeInOrPredicate = new LinkedList<>(); + for (Integer status : excludedStatuses) { - statusQuery.add(Restrictions.ne("status", status)); + listToIncludeInOrPredicate.add(criteriaBuilder.notEqual(doiRoot.get(DOI_.status), status)); } - conjunctionAnd.add(Restrictions.like("doi", doi)); - conjunctionAnd.add(statusQuery); - if (dsoNotNull) - { - conjunctionAnd.add(Restrictions.isNotNull("dSpaceObject")); + + List listToIncludeInAndPredicate = new LinkedList<>(); + + listToIncludeInAndPredicate.add(criteriaBuilder.like(doiRoot.get(DOI_.doi), doi)); + listToIncludeInAndPredicate.add(criteriaBuilder.or(listToIncludeInOrPredicate.toArray(new Predicate[] {}))); + if (dsoNotNull) { + listToIncludeInAndPredicate.add(criteriaBuilder.isNotNull(doiRoot.get(DOI_.dSpaceObject))); } - criteria.add(conjunctionAnd); - return list(criteria); + criteriaQuery.where(listToIncludeInAndPredicate.toArray(new Predicate[] {})); + return list(context, criteriaQuery, false, DOI.class, -1, -1); + + } @Override public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso) throws SQLException { - Criteria criteria = createCriteria(context, DOI.class); - criteria.add( - Restrictions.and( - Restrictions.eq("dSpaceObject", dso) - ) - ); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); + criteriaQuery.where(criteriaBuilder.equal(doiRoot.get(DOI_.dSpaceObject), dso)); + return singleResult(context, criteriaQuery); } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/doi/DOIConnector.java b/dspace-api/src/main/java/org/dspace/identifier/doi/DOIConnector.java index b2d9fa97b2..9239563d9e 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/doi/DOIConnector.java +++ b/dspace-api/src/main/java/org/dspace/identifier/doi/DOIConnector.java @@ -13,7 +13,7 @@ import org.dspace.core.Context; /** * A DOIConnector handles all calls to the API of your DOI registry. - * + * * A DOIConnector should care about rules of the registration agency. For * example, if the registration agency wants us to reserve a DOI before we can * register it, the DOIConnector should check if a DOI is reserved. Use a @@ -26,83 +26,73 @@ import org.dspace.core.Context; */ public interface DOIConnector { public boolean isDOIReserved(Context context, String doi) - throws DOIIdentifierException; - + throws DOIIdentifierException; + public boolean isDOIRegistered(Context context, String doi) - throws DOIIdentifierException; - + throws DOIIdentifierException; + /** * Sends the DELETE-Request to the DOI registry. - * + * *

    This method sends a request to "delete" a DOI. As DOIs are persistent * identifiers they should never be deleted. For example, if you send a HTTP * DELETE request to the DataCite Metadata API directly, it will set the DOI * to inactive.

    - * - * @param context - * The relevant DSpace Context. - * @param doi - * DOI string to "delete" + * + * @param context The relevant DSpace Context. + * @param doi DOI string to "delete" * @throws DOIIdentifierException if DOI error */ public void deleteDOI(Context context, String doi) - throws DOIIdentifierException; - + throws DOIIdentifierException; + /** * Sends a request to the DOI registry to reserve a DOI. - * + * * The DOIConnector should check weather this DOI is reserved for another - * object already. In this case it should throw an + * object already. In this case it should throw an * {@link org.dspace.identifier.doi.DOIIdentifierException#DOIIdentifierException DOIIdentifierException}. - * DOIIdentifierException} and set the error code to {@code + * DOIIdentifierException} and set the error code to {@code * DOIIdentifierException.DOI_ALREADY_EXISTS}. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to associate to the DOI - * @param doi - * DOI string to reserve + * @param context The relevant DSpace Context. + * @param dso DSpace object to associate to the DOI + * @param doi DOI string to reserve * @throws DOIIdentifierException if DOI error */ public void reserveDOI(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException; + throws DOIIdentifierException; + /** * Sends a request to the DOI registry to register a DOI. - * + * * The DOIConnector ensures compliance with the workflow of the registration * agency. For example, if a DOI has to be reserved before it can be * registered the DOIConnector has to check if it is reserved. In this case - * you can throw an + * you can throw an * {@link org.dspace.identifier.doi.DOIIdentifierException#DOIIdentifierException DOIIdentifierException}. - * and set the error code to + * and set the error code to * {@code DOIIdentifierException.RESERVE_FIRST}. - * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to associate to the DOI - * @param doi - * DOI string to register + * + * @param context The relevant DSpace Context. + * @param dso DSpace object to associate to the DOI + * @param doi DOI string to register * @throws DOIIdentifierException if DOI error */ public void registerDOI(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException; - + throws DOIIdentifierException; + /** * Sends a request to the DOI registry to update metadata for a DOI. - * - * The DOIConnector should check weather the DOI is reserved or registered + * + * The DOIConnector should check weather the DOI is reserved or registered * for the specified DSpace Object before it sends the metadata update. - * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object associated to the DOI - * @param doi - * DOI string to update (metadata) + * + * @param context The relevant DSpace Context. + * @param dso DSpace object associated to the DOI + * @param doi DOI string to update (metadata) * @throws DOIIdentifierException if DOI error */ public void updateMetadata(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException; + throws DOIIdentifierException; } diff --git a/dspace-api/src/main/java/org/dspace/identifier/doi/DOIConsumer.java b/dspace-api/src/main/java/org/dspace/identifier/doi/DOIConsumer.java index 969fd95874..8ad93e6e56 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/doi/DOIConsumer.java +++ b/dspace-api/src/main/java/org/dspace/identifier/doi/DOIConsumer.java @@ -22,12 +22,12 @@ import org.dspace.utils.DSpace; import org.dspace.workflow.factory.WorkflowServiceFactory; /** - * * @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de) */ -public class DOIConsumer implements Consumer -{ - /** log4j logger */ +public class DOIConsumer implements Consumer { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(DOIConsumer.class); @Override @@ -36,76 +36,64 @@ public class DOIConsumer implements Consumer // we can ask spring to give as a properly setuped instance of // DOIIdentifierProvider. Doing so we don't have to configure it and // can load it in consume method as this is not very expensive. - + } - + // as we use asynchronous metadata update, our updates are not very expensive. // so we can do everything in the consume method. @Override public void consume(Context ctx, Event event) throws Exception { - if (event.getSubjectType() != Constants.ITEM) - { + if (event.getSubjectType() != Constants.ITEM) { log.warn("DOIConsumer should not have been given this kind of " - + "subject in an event, skipping: " + event.toString()); + + "subject in an event, skipping: " + event.toString()); return; } - if (Event.MODIFY_METADATA != event.getEventType()) - { + if (Event.MODIFY_METADATA != event.getEventType()) { log.warn("DOIConsumer should not have been given this kind of " - + "event type, skipping: " + event.toString()); + + "event type, skipping: " + event.toString()); return; } - + DSpaceObject dso = event.getSubject(ctx); //FIXME - if (!(dso instanceof Item)) - { + if (!(dso instanceof Item)) { log.debug("DOIConsumer got an event whose subject was not an item, " - + "skipping: " + event.toString()); + + "skipping: " + event.toString()); return; } Item item = (Item) dso; - + if (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item) != null - || WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) - { + || WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) { // ignore workflow and workspace items, DOI will be minted when item is installed return; } - + DOIIdentifierProvider provider = new DSpace().getSingletonService( - DOIIdentifierProvider.class); - + DOIIdentifierProvider.class); + String doi = null; try { doi = provider.lookup(ctx, dso); - } - catch (IdentifierNotFoundException ex) - { + } catch (IdentifierNotFoundException ex) { // nothing to do here, next if clause will stop us from processing // items without dois. } - if (doi == null) - { + if (doi == null) { log.debug("DOIConsumer cannot handles items without DOIs, skipping: " - + event.toString()); + + event.toString()); return; } - try - { + try { provider.updateMetadata(ctx, dso, doi); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { // should not happen, as we got the DOI from the DOIProvider log.warn("DOIConsumer caught an IdentifierException.", ex); - } - catch (IdentifierException ex) - { + } catch (IdentifierException ex) { log.warn("DOIConsumer cannot update metadata for Item with ID " - + item.getID() + " and DOI " + doi + ".", ex); + + item.getID() + " and DOI " + doi + ".", ex); } - } + } @Override public void end(Context ctx) throws Exception { @@ -117,5 +105,5 @@ public class DOIConsumer implements Consumer public void finish(Context ctx) throws Exception { // nothing to do } - + } diff --git a/dspace-api/src/main/java/org/dspace/identifier/doi/DOIIdentifierException.java b/dspace-api/src/main/java/org/dspace/identifier/doi/DOIIdentifierException.java index 3639a244a6..61f738d7cb 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/doi/DOIIdentifierException.java +++ b/dspace-api/src/main/java/org/dspace/identifier/doi/DOIIdentifierException.java @@ -10,7 +10,6 @@ package org.dspace.identifier.doi; import org.dspace.identifier.IdentifierException; /** - * * @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de) */ public class DOIIdentifierException extends IdentifierException { @@ -45,7 +44,7 @@ public class DOIIdentifierException extends IdentifierException { */ public static final int BAD_REQUEST = 5; /** - * Some registration agencies request that a DOI gets reserved before it can + * Some registration agencies request that a DOI gets reserved before it can * be registered. This error code signals that a unreserved DOI should be * registered and that the registration agency denied it. */ @@ -55,7 +54,7 @@ public class DOIIdentifierException extends IdentifierException { */ public static final int AUTHENTICATION_ERROR = 7; /** - * A internal error occurred either in the registration agency or in the + * A internal error occurred either in the registration agency or in the * DOIConnector. */ public static final int INTERNAL_ERROR = 8; @@ -81,7 +80,7 @@ public class DOIIdentifierException extends IdentifierException { * You tried to reserve or register a DOI that is marked as DELETED. */ public static final int DOI_IS_DELETED = 13; - + private int code; // FOR DEBUGGING @@ -157,18 +156,15 @@ public class DOIIdentifierException extends IdentifierException { super(cause); this.code = code; } - - public int getCode() - { + + public int getCode() { return this.code; } @Override - public String getMessage() - { + public String getMessage() { String message = super.getMessage(); - if ((message == null || message.isEmpty()) && code != CODE_NOT_SET) - { + if ((message == null || message.isEmpty()) && code != CODE_NOT_SET) { return codeToString(code); } return message; diff --git a/dspace-api/src/main/java/org/dspace/identifier/doi/DOIOrganiser.java b/dspace-api/src/main/java/org/dspace/identifier/doi/DOIOrganiser.java index ef352796f6..ed59eb3cdf 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/doi/DOIOrganiser.java +++ b/dspace-api/src/main/java/org/dspace/identifier/doi/DOIOrganiser.java @@ -8,12 +8,33 @@ package org.dspace.identifier.doi; -import org.apache.commons.cli.*; +import java.io.IOException; +import java.io.PrintStream; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +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.content.DSpaceObject; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; -import org.dspace.core.*; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; import org.dspace.identifier.DOI; @@ -23,14 +44,8 @@ import org.dspace.identifier.factory.IdentifierServiceFactory; import org.dspace.identifier.service.DOIService; import org.dspace.utils.DSpace; -import java.io.IOException; -import java.io.PrintStream; -import java.sql.SQLException; -import java.util.*; - /** - * * @author Marsa Haoua * @author Pascal-Nicolas Becker */ @@ -45,8 +60,7 @@ public class DOIOrganiser { protected ItemService itemService; protected DOIService doiService; - public DOIOrganiser(Context context, DOIIdentifierProvider provider) - { + public DOIOrganiser(Context context, DOIIdentifierProvider provider) { this.context = context; this.provider = provider; this.quiet = false; @@ -55,8 +69,7 @@ public class DOIOrganiser { this.doiService = IdentifierServiceFactory.getInstance().getDOIService(); } - public static void main(String[] args) - { + public static void main(String[] args) { LOG.debug("Starting DOI organiser "); // setup Context @@ -65,90 +78,87 @@ public class DOIOrganiser { // Started from commandline, don't use the authentication system. context.turnOffAuthorisationSystem(); - DOIOrganiser organiser = new DOIOrganiser(context, new DSpace().getSingletonService(DOIIdentifierProvider.class)); - + DOIOrganiser organiser = new DOIOrganiser(context, + new DSpace().getSingletonService(DOIIdentifierProvider.class)); + // run command line interface runCLI(context, organiser, args); - - try - { + + try { context.complete(); - } - catch (SQLException sqle) - { + } catch (SQLException sqle) { System.err.println("Cannot save changes to database: " + sqle.getMessage()); System.exit(-1); } } - public static void runCLI(Context context, DOIOrganiser organiser, String[] args) - { + public static void runCLI(Context context, DOIOrganiser organiser, String[] args) { // initlize options Options options = new Options(); options.addOption("h", "help", false, "Help"); options.addOption("l", "list", false, - "List all objects to be reserved, registered, deleted of updated "); + "List all objects to be reserved, registered, deleted of updated "); options.addOption("r", "register-all", false, - "Perform online registration for all identifiers queued for registration."); + "Perform online registration for all identifiers queued for registration."); options.addOption("s", "reserve-all", false, - "Perform online reservation for all identifiers queued for reservation."); + "Perform online reservation for all identifiers queued for reservation."); options.addOption("u", "update-all", false, - "Perform online metadata update for all identifiers queued for metadata update."); + "Perform online metadata update for all identifiers queued for metadata update."); options.addOption("d", "delete-all", false, - "Perform online deletion for all identifiers queued for deletion."); - + "Perform online deletion for all identifiers queued for deletion."); + options.addOption("q", "quiet", false, - "Turn the command line output off."); - + "Turn the command line output off."); + Option registerDoi = OptionBuilder.withArgName("DOI|ItemID|handle") - .withLongOpt("register-doi") - .hasArgs(1) - .withDescription("Register a specified identifier. " - + "You can specify the identifier by ItemID, Handle or DOI.") - .create(); - + .withLongOpt("register-doi") + .hasArgs(1) + .withDescription("Register a specified identifier. " + + "You can specify the identifier by ItemID, Handle or" + + " DOI.") + .create(); + options.addOption(registerDoi); - + Option reserveDoi = OptionBuilder.withArgName("DOI|ItemID|handle") - .withLongOpt("reserve-doi") - .hasArgs(1) - .withDescription("Reserve a specified identifier online. " - + "You can specify the identifier by ItemID, Handle or DOI.") - .create(); + .withLongOpt("reserve-doi") + .hasArgs(1) + .withDescription("Reserve a specified identifier online. " + + "You can specify the identifier by ItemID, Handle or " + + "DOI.") + .create(); options.addOption(reserveDoi); Option update = OptionBuilder.withArgName("DOI|ItemID|handle") - .hasArgs(1) - .withDescription("Update online an object for a given DOI identifier" - + " or ItemID or Handle. A DOI identifier or an ItemID or a Handle is needed.\n") - .withLongOpt("update-doi") - .create(); + .hasArgs(1) + .withDescription("Update online an object for a given DOI identifier" + + " or ItemID or Handle. A DOI identifier or an ItemID or a" + + " Handle is needed.\n") + .withLongOpt("update-doi") + .create(); options.addOption(update); - + Option delete = OptionBuilder.withArgName("DOI identifier") - .withLongOpt("delete-doi") - .hasArgs(1) - .withDescription("Delete a specified identifier.") - .create(); + .withLongOpt("delete-doi") + .hasArgs(1) + .withDescription("Delete a specified identifier.") + .create(); options.addOption(delete); - + // initialize parser CommandLineParser parser = new PosixParser(); CommandLine line = null; HelpFormatter helpformater = new HelpFormatter(); - try - { + try { line = parser.parse(options, args); - } - catch (ParseException ex) - { + } catch (ParseException ex) { LOG.fatal(ex); System.exit(1); } @@ -156,38 +166,34 @@ public class DOIOrganiser { // process options // user asks for help - if (line.hasOption('h') || 0 == line.getOptions().length) - { + if (line.hasOption('h') || 0 == line.getOptions().length) { helpformater.printHelp("\nDOI organiser\n", options); } - - if (line.hasOption('q')) - { + + if (line.hasOption('q')) { organiser.setQuiet(); } - - if (line.hasOption('l')) - { + + if (line.hasOption('l')) { organiser.list("reservation", null, null, DOIIdentifierProvider.TO_BE_RESERVED); organiser.list("registration", null, null, DOIIdentifierProvider.TO_BE_REGISTERED); organiser.list("update", null, null, - DOIIdentifierProvider.UPDATE_BEFORE_REGISTRATION, - DOIIdentifierProvider.UPDATE_REGISTERED, - DOIIdentifierProvider.UPDATE_RESERVED); + DOIIdentifierProvider.UPDATE_BEFORE_REGISTRATION, + DOIIdentifierProvider.UPDATE_REGISTERED, + DOIIdentifierProvider.UPDATE_RESERVED); organiser.list("deletion", null, null, DOIIdentifierProvider.TO_BE_DELETED); } DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService(); - if (line.hasOption('s')) - { + if (line.hasOption('s')) { try { - List dois = doiService.getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_RESERVED)); - if (0 == dois.size()) - { + List dois = doiService + .getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_RESERVED)); + if (0 == dois.size()) { System.err.println("There are no objects in the database " - + "that could be reserved."); + + "that could be reserved."); } for (DOI doi : dois) { @@ -200,18 +206,16 @@ public class DOIOrganiser { } } - if (line.hasOption('r')) - { + if (line.hasOption('r')) { try { - List dois = doiService.getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_REGISTERED)); - if (0 == dois.size()) - { + List dois = doiService + .getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_REGISTERED)); + if (0 == dois.size()) { System.err.println("There are no objects in the database " - + "that could be registered."); + + "that could be registered."); } - for (DOI doi : dois) - { + for (DOI doi : dois) { organiser.register(doi); context.uncacheEntity(doi); } @@ -220,23 +224,20 @@ public class DOIOrganiser { ex.printStackTrace(System.err); } } - - if (line.hasOption('u')) - { + + if (line.hasOption('u')) { try { List dois = doiService.getDOIsByStatus(context, Arrays.asList( - DOIIdentifierProvider.UPDATE_BEFORE_REGISTRATION, - DOIIdentifierProvider.UPDATE_RESERVED, - DOIIdentifierProvider.UPDATE_REGISTERED)); - if (0 == dois.size()) - { + DOIIdentifierProvider.UPDATE_BEFORE_REGISTRATION, + DOIIdentifierProvider.UPDATE_RESERVED, + DOIIdentifierProvider.UPDATE_REGISTERED)); + if (0 == dois.size()) { System.err.println("There are no objects in the database " - + "whose metadata needs an update."); + + "whose metadata needs an update."); } - - for (DOI doi : dois) - { + + for (DOI doi : dois) { organiser.update(doi); context.uncacheEntity(doi); } @@ -246,15 +247,14 @@ public class DOIOrganiser { } } - if (line.hasOption('d')) - { + if (line.hasOption('d')) { try { - List dois = doiService.getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_DELETED)); - if (0 == dois.size()) - { + List dois = doiService + .getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_DELETED)); + if (0 == dois.size()) { System.err.println("There are no objects in the database " - + "that could be deleted."); + + "that could be deleted."); } Iterator iterator = dois.iterator(); @@ -270,48 +270,34 @@ public class DOIOrganiser { } } - - if(line.hasOption("reserve-doi")) - { + + if (line.hasOption("reserve-doi")) { String identifier = line.getOptionValue("reserve-doi"); - - if(null == identifier) - { + + if (null == identifier) { helpformater.printHelp("\nDOI organiser\n", options); - } - else - { + } else { try { DOI doiRow = organiser.resolveToDOI(identifier); organiser.reserve(doiRow); - } - catch (SQLException ex) - { + } catch (SQLException ex) { LOG.error(ex); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { LOG.error(ex); - } - catch (IllegalStateException ex) - { + } catch (IllegalStateException ex) { LOG.error(ex); } catch (IdentifierException ex) { LOG.error(ex); } } } - - if(line.hasOption("register-doi")) - { + + if (line.hasOption("register-doi")) { String identifier = line.getOptionValue("register-doi"); - - if(null == identifier) - { + + if (null == identifier) { helpformater.printHelp("\nDOI organiser\n", options); - } - else - { + } else { try { DOI doiRow = organiser.resolveToDOI(identifier); organiser.register(doiRow); @@ -326,17 +312,13 @@ public class DOIOrganiser { } } } - - if(line.hasOption("update-doi")) - { + + if (line.hasOption("update-doi")) { String identifier = line.getOptionValue("update-doi"); - - if(null == identifier) - { + + if (null == identifier) { helpformater.printHelp("\nDOI organiser\n", options); - } - else - { + } else { try { DOI doiRow = organiser.resolveToDOI(identifier); organiser.update(doiRow); @@ -351,16 +333,13 @@ public class DOIOrganiser { } } } - - if(line.hasOption("delete-doi")) - { + + if (line.hasOption("delete-doi")) { String identifier = line.getOptionValue("delete-doi"); - if (null == identifier) - { + if (null == identifier) { helpformater.printHelp("\nDOI organiser\n", options); - } - else { + } else { try { organiser.delete(identifier); } catch (SQLException ex) { @@ -373,31 +352,23 @@ public class DOIOrganiser { } - public void list(String processName, PrintStream out, PrintStream err, Integer ... status) - { + public void list(String processName, PrintStream out, PrintStream err, Integer... status) { String indent = " "; - if (null == out) - { + if (null == out) { out = System.out; } - if (null == err) - { + if (null == err) { err = System.err; } - try - { + try { List doiList = doiService.getDOIsByStatus(context, Arrays.asList(status)); - if (0 < doiList.size()) - { + if (0 < doiList.size()) { out.println("DOIs queued for " + processName + ": "); - } - else - { + } else { out.println("There are no DOIs queued for " + processName + "."); } - for (DOI doiRow : doiList) - { + for (DOI doiRow : doiList) { out.print(indent + DOI.SCHEME + doiRow.getDoi()); DSpaceObject dso = doiRow.getDSpaceObject(); if (null != dso) { @@ -407,381 +378,311 @@ public class DOIOrganiser { } } out.println(""); - } - catch (SQLException ex) - { + } catch (SQLException ex) { err.println("Error in database Connection: " + ex.getMessage()); ex.printStackTrace(err); } } - public void register(DOI doiRow) throws SQLException - { + public void register(DOI doiRow) throws SQLException { DSpaceObject dso = doiRow.getDSpaceObject(); - if (Constants.ITEM != dso.getType()) - { + if (Constants.ITEM != dso.getType()) { throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only."); } - + try { provider.registerOnline(context, dso, - DOI.SCHEME + doiRow.getDoi()); - - if(!quiet) - { - System.out.println("This identifier: " - + DOI.SCHEME + doiRow.getDoi() - + " is successfully registered."); + DOI.SCHEME + doiRow.getDoi()); + + if (!quiet) { + System.out.println("This identifier: " + + DOI.SCHEME + doiRow.getDoi() + + " is successfully registered."); } - } - catch (IdentifierException ex) - { - if (!(ex instanceof DOIIdentifierException)) - { - LOG.error("It wasn't possible to register this identifier: " - + DOI.SCHEME + doiRow.getDoi() - + " online. ", ex); + } catch (IdentifierException ex) { + if (!(ex instanceof DOIIdentifierException)) { + LOG.error("It wasn't possible to register this identifier: " + + DOI.SCHEME + doiRow.getDoi() + + " online. ", ex); } DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex; - - try - { + + try { sendAlertMail("Register", dso, DOI.SCHEME + doiRow.getDoi(), doiIdentifierException.codeToString(doiIdentifierException - .getCode())); - } - catch (IOException ioe) - { + .getCode())); + } catch (IOException ioe) { LOG.error("Couldn't send mail", ioe); } - LOG.error("It wasn't possible to register this identifier : " - + DOI.SCHEME + doiRow.getDoi() - + " online. Exceptions code: " - + doiIdentifierException - .codeToString(doiIdentifierException.getCode()), ex); - - if(!quiet) - { - System.err.println("It wasn't possible to register this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + LOG.error("It wasn't possible to register this identifier : " + + DOI.SCHEME + doiRow.getDoi() + + " online. Exceptions code: " + + doiIdentifierException + .codeToString(doiIdentifierException.getCode()), ex); + + if (!quiet) { + System.err.println("It wasn't possible to register this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } - - } - catch (IllegalArgumentException ex) - { + + } catch (IllegalArgumentException ex) { LOG.error("Database table DOI contains a DOI that is not valid: " - + DOI.SCHEME + doiRow.getDoi() + "!", ex); - - if(!quiet) - { - System.err.println("It wasn't possible to register this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + + DOI.SCHEME + doiRow.getDoi() + "!", ex); + + if (!quiet) { + System.err.println("It wasn't possible to register this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } - + throw new IllegalStateException("Database table DOI contains a DOI " - + " that is not valid: " - + DOI.SCHEME + doiRow.getDoi() + "!", ex); - } - catch (SQLException ex) - { + + " that is not valid: " + + DOI.SCHEME + doiRow.getDoi() + "!", ex); + } catch (SQLException ex) { LOG.error("Error while trying to get data from database", ex); - - if(!quiet) - { - System.err.println("It wasn't possible to register this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + + if (!quiet) { + System.err.println("It wasn't possible to register this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } throw new RuntimeException("Error while trying to get data from database", ex); } } - - public void reserve(DOI doiRow) throws SQLException - { + + public void reserve(DOI doiRow) throws SQLException { DSpaceObject dso = doiRow.getDSpaceObject(); - if (Constants.ITEM != dso.getType()) - { + if (Constants.ITEM != dso.getType()) { throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only."); } - - try - { - provider.reserveOnline(context, dso, - DOI.SCHEME + doiRow.getDoi()); - - if(!quiet) - { - System.out.println("This identifier : " - + DOI.SCHEME + doiRow.getDoi() - + " is successfully reserved."); + + try { + provider.reserveOnline(context, dso, + DOI.SCHEME + doiRow.getDoi()); + + if (!quiet) { + System.out.println("This identifier : " + + DOI.SCHEME + doiRow.getDoi() + + " is successfully reserved."); } - } - catch (IdentifierException ex) - { - if (!(ex instanceof DOIIdentifierException)) - { - LOG.error("It wasn't possible to register this identifier : " - + DOI.SCHEME + doiRow.getDoi() - + " online. ",ex); + } catch (IdentifierException ex) { + if (!(ex instanceof DOIIdentifierException)) { + LOG.error("It wasn't possible to register this identifier : " + + DOI.SCHEME + doiRow.getDoi() + + " online. ", ex); } - + DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex; - - try - { + + try { sendAlertMail("Reserve", dso, DOI.SCHEME + doiRow.getDoi(), DOIIdentifierException.codeToString( - doiIdentifierException.getCode())); - } - catch (IOException ioe) - { + doiIdentifierException.getCode())); + } catch (IOException ioe) { LOG.error("Couldn't send mail", ioe); } LOG.error("It wasn't possible to reserve the identifier online. " - + " Exceptions code: " - + DOIIdentifierException - .codeToString(doiIdentifierException.getCode()), ex); - - if(!quiet) - { - System.err.println("It wasn't possible to reserve this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + + " Exceptions code: " + + DOIIdentifierException + .codeToString(doiIdentifierException.getCode()), ex); + + if (!quiet) { + System.err.println("It wasn't possible to reserve this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { LOG.error("Database table DOI contains a DOI that is not valid: " - + DOI.SCHEME + doiRow.getDoi() + "!", ex); - - if(!quiet) - { - System.err.println("It wasn't possible to reserve this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + + DOI.SCHEME + doiRow.getDoi() + "!", ex); + + if (!quiet) { + System.err.println("It wasn't possible to reserve this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } throw new IllegalStateException("Database table DOI contains a DOI " - + " that is not valid: " - + DOI.SCHEME + doiRow.getDoi() + "!", ex); - } - catch (SQLException ex) - { + + " that is not valid: " + + DOI.SCHEME + doiRow.getDoi() + "!", ex); + } catch (SQLException ex) { LOG.error("Error while trying to get data from database", ex); - - if(!quiet) - { - System.err.println("It wasn't possible to reserve this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + + if (!quiet) { + System.err.println("It wasn't possible to reserve this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } throw new RuntimeException("Error while trying to get data from database", ex); } } - - public void update(DOI doiRow) - { + + public void update(DOI doiRow) { DSpaceObject dso = doiRow.getDSpaceObject(); - if (Constants.ITEM != dso.getType()) - { + if (Constants.ITEM != dso.getType()) { throw new IllegalArgumentException("Currenty DSpace supports DOIs " - + "for Items only."); + + "for Items only."); } - - try - { + + try { provider.updateMetadataOnline(context, dso, - DOI.SCHEME + doiRow.getDoi()); - - if(!quiet) - { + DOI.SCHEME + doiRow.getDoi()); + + if (!quiet) { System.out.println("Successfully updated metadata of DOI " + DOI.SCHEME - + doiRow.getDoi() + "."); + + doiRow.getDoi() + "."); } - } - catch (IdentifierException ex) - { - if (!(ex instanceof DOIIdentifierException)) - { - LOG.error("It wasn't possible to register the identifier online. ",ex); + } catch (IdentifierException ex) { + if (!(ex instanceof DOIIdentifierException)) { + LOG.error("It wasn't possible to register the identifier online. ", ex); } - + DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex; - - try - { + + try { sendAlertMail("Update", dso, DOI.SCHEME + doiRow.getDoi(), doiIdentifierException.codeToString(doiIdentifierException - .getCode())); - } - catch (IOException ioe) - { + .getCode())); + } catch (IOException ioe) { LOG.error("Couldn't send mail", ioe); } LOG.error("It wasn't possible to update this identifier: " - + DOI.SCHEME + doiRow.getDoi() - + " Exceptions code: " - + doiIdentifierException - .codeToString(doiIdentifierException.getCode()), ex); - - if(!quiet) - { - System.err.println("It wasn't possible to update this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + + DOI.SCHEME + doiRow.getDoi() + + " Exceptions code: " + + doiIdentifierException + .codeToString(doiIdentifierException.getCode()), ex); + + if (!quiet) { + System.err.println("It wasn't possible to update this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } - - } - catch (IllegalArgumentException ex) - { + + } catch (IllegalArgumentException ex) { LOG.error("Database table DOI contains a DOI that is not valid: " - + DOI.SCHEME + doiRow.getDoi() + "!", ex); - - if(!quiet) - { - System.err.println("It wasn't possible to update this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + + DOI.SCHEME + doiRow.getDoi() + "!", ex); + + if (!quiet) { + System.err.println("It wasn't possible to update this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } - + throw new IllegalStateException("Database table DOI contains a DOI " - + " that is not valid: " - + DOI.SCHEME + doiRow.getDoi() + "!", ex); - } - catch (SQLException ex) - { + + " that is not valid: " + + DOI.SCHEME + doiRow.getDoi() + "!", ex); + } catch (SQLException ex) { LOG.error("It wasn't possible to connect to the Database!", ex); } } - - public void delete(String identifier) - throws SQLException - { + + public void delete(String identifier) + throws SQLException { String doi = null; DOI doiRow = null; - - try - { + + try { doi = doiService.formatIdentifier(identifier); - + // If there's no exception: we found a valid DOI. :) doiRow = doiService.findByDoi(context, - doi.substring(DOI.SCHEME.length())); - - if (null == doiRow) - { + doi.substring(DOI.SCHEME.length())); + + if (null == doiRow) { throw new IllegalStateException("You specified a valid DOI," - + " that is not stored in our database."); + + " that is not stored in our database."); } provider.deleteOnline(context, doi); - - if (!quiet) - { + + if (!quiet) { System.err.println("It was possible to delete this identifier: " - + DOI.SCHEME + doiRow.getDoi() - + " online."); + + DOI.SCHEME + doiRow.getDoi() + + " online."); } - } - catch (DOIIdentifierException ex) - { + } catch (DOIIdentifierException ex) { // Identifier was not recognized as DOI. LOG.error("It wasn't possible to detect this identifier: " - + identifier - + " Exceptions code: " - + ex.codeToString(ex.getCode()), ex); + + identifier + + " Exceptions code: " + + ex.codeToString(ex.getCode()), ex); - if (!quiet) - { + if (!quiet) { System.err.println("It wasn't possible to detect this identifier: " - + identifier); + + identifier); } - } - catch (IllegalArgumentException ex) - { - if (!quiet) - { + } catch (IllegalArgumentException ex) { + if (!quiet) { System.err.println("It wasn't possible to delete this identifier: " - + DOI.SCHEME + doiRow.getDoi() - + " online. Take a look in log file."); + + DOI.SCHEME + doiRow.getDoi() + + " online. Take a look in log file."); } } } - + /** * Finds the TableRow in the Doi table that belongs to the specified * DspaceObject. * * @param identifier Either an ItemID, a DOI or a handle. If the identifier - * contains digits only we treat it as ItemID, if not we try to find a - * matching doi or a handle (in this order). + * contains digits only we treat it as ItemID, if not we try to find a + * matching doi or a handle (in this order). * @return The TableRow or null if the Object does not have a DOI. - * @throws SQLException if database error + * @throws SQLException if database error * @throws IllegalArgumentException If the identifier is null, an empty - * String or specifies an DSpaceObject that is not an item. We currently - * support DOIs for items only, but this may change once... - * @throws IllegalStateException If the identifier was a valid DOI that is - * not stored in our database or if it is a handle that is not bound to an - * DSpaceObject. - * @throws IdentifierException if identifier error + * String or specifies an DSpaceObject that is not an item. We currently + * support DOIs for items only, but this may change once... + * @throws IllegalStateException If the identifier was a valid DOI that is + * not stored in our database or if it is a handle that is not bound to an + * DSpaceObject. + * @throws IdentifierException if identifier error */ public DOI resolveToDOI(String identifier) - throws SQLException, IllegalArgumentException, IllegalStateException, IdentifierException - { - if (null == identifier || identifier.isEmpty()) - { + throws SQLException, IllegalArgumentException, IllegalStateException, IdentifierException { + if (null == identifier || identifier.isEmpty()) { throw new IllegalArgumentException("Identifier is null or empty."); } DOI doiRow = null; String doi = null; - + // detect it identifer is ItemID, handle or DOI. // try to detect ItemID - if (identifier.matches("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[34][0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}")) - { + if (identifier + .matches("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[34][0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}")) { DSpaceObject dso = itemService.find(context, UUID.fromString(identifier)); - if (null != dso) - { + if (null != dso) { doiRow = doiService.findDOIByDSpaceObject(context, dso); - + //Check if this Item has an Identifier, mint one if it doesn't - if (null == doiRow) - { + if (null == doiRow) { doi = provider.mint(context, dso); doiRow = doiService.findByDoi(context, - doi.substring(DOI.SCHEME.length())); + doi.substring(DOI.SCHEME.length())); return doiRow; } return doiRow; - } - else - { + } else { throw new IllegalStateException("You specified an ItemID, " - + "that is not stored in our database."); + + "that is not stored in our database."); } } // detect handle DSpaceObject dso = handleService.resolveToObject(context, identifier); - if (null != dso) - { - if (dso.getType() != Constants.ITEM) - { + if (null != dso) { + if (dso.getType() != Constants.ITEM) { throw new IllegalArgumentException( - "Currently DSpace supports DOIs for Items only. " + "Currently DSpace supports DOIs for Items only. " + "Cannot process specified handle as it does not identify an Item."); } - + doiRow = doiService.findDOIByDSpaceObject(context, dso); - if (null == doiRow) - { + if (null == doiRow) { doi = provider.mint(context, dso); doiRow = doiService.findByDoi(context, - doi.substring(DOI.SCHEME.length())); + doi.substring(DOI.SCHEME.length())); } return doiRow; } @@ -790,42 +691,35 @@ public class DOIOrganiser { doi = doiService.formatIdentifier(identifier); // If there's no exception: we found a valid DOI. :) doiRow = doiService.findByDoi(context, - doi.substring(DOI.SCHEME.length())); - if (null == doiRow) - { + doi.substring(DOI.SCHEME.length())); + if (null == doiRow) { throw new IllegalStateException("You specified a valid DOI," - + " that is not stored in our database."); + + " that is not stored in our database."); } - } - catch (DOIIdentifierException ex) - { + } catch (DOIIdentifierException ex) { // Identifier was not recognized as DOI. - LOG.error("It wasn't possible to detect this identifier: " - + identifier - + " Exceptions code: " - + ex.codeToString(ex.getCode()), ex); - - if(!quiet) - { - System.err.println("It wasn't possible to detect this identifier: " - + DOI.SCHEME + doiRow.getDoi()); + LOG.error("It wasn't possible to detect this identifier: " + + identifier + + " Exceptions code: " + + ex.codeToString(ex.getCode()), ex); + + if (!quiet) { + System.err.println("It wasn't possible to detect this identifier: " + + DOI.SCHEME + doiRow.getDoi()); } } return doiRow; } - private void sendAlertMail(String action, DSpaceObject dso, String doi, String reason) - throws IOException - { + private void sendAlertMail(String action, DSpaceObject dso, String doi, String reason) + throws IOException { String recipient = ConfigurationManager.getProperty("alert.recipient"); - try - { - if (recipient != null) - { + try { + if (recipient != null) { Email email = Email.getEmail( - I18nUtil.getEmailFilename(Locale.getDefault(), "doi_maintenance_error")); + I18nUtil.getEmailFilename(Locale.getDefault(), "doi_maintenance_error")); email.addRecipient(recipient); email.addArgument(action); email.addArgument(new Date()); @@ -834,25 +728,21 @@ public class DOIOrganiser { email.addArgument(doi); email.addArgument(reason); email.send(); - - if (!quiet) - { + + if (!quiet) { System.err.println("Email alert is sent."); } } - } - catch (Exception e) { + } catch (Exception e) { LOG.warn("Unable to send email alert", e); - if (!quiet) - { + if (!quiet) { System.err.println("Unable to send email alert."); } } } - private void setQuiet() - { + private void setQuiet() { this.quiet = true; } - + } diff --git a/dspace-api/src/main/java/org/dspace/identifier/doi/DataCiteConnector.java b/dspace-api/src/main/java/org/dspace/identifier/doi/DataCiteConnector.java index 44202437f5..fc094d767d 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/doi/DataCiteConnector.java +++ b/dspace-api/src/main/java/org/dspace/identifier/doi/DataCiteConnector.java @@ -14,6 +14,7 @@ import java.sql.SQLException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; + import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; @@ -53,28 +54,26 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; /** - * * @author Pascal-Nicolas Becker */ public class DataCiteConnector -implements DOIConnector -{ + implements DOIConnector { private static final Logger log = LoggerFactory.getLogger(DataCiteConnector.class); - + // Configuration property names static final String CFG_USER = "identifier.doi.user"; static final String CFG_PASSWORD = "identifier.doi.password"; static final String CFG_PREFIX - = "identifier.doi.prefix"; + = "identifier.doi.prefix"; static final String CFG_PUBLISHER - = "crosswalk.dissemination.DataCite.publisher"; + = "crosswalk.dissemination.DataCite.publisher"; static final String CFG_DATAMANAGER - = "crosswalk.dissemination.DataCite.dataManager"; + = "crosswalk.dissemination.DataCite.dataManager"; static final String CFG_HOSTINGINSTITUTION - = "crosswalk.dissemination.DataCite.hostingInstitution"; + = "crosswalk.dissemination.DataCite.hostingInstitution"; static final String CFG_NAMESPACE - = "crosswalk.dissemination.DataCite.namespace"; + = "crosswalk.dissemination.DataCite.namespace"; /** * Stores the scheme used to connect to the DataCite server. It will be set @@ -86,7 +85,7 @@ implements DOIConnector * injection. */ protected String HOST; - + /** * Path on the DataCite server used to generate DOIs. Set by spring * dependency injection. @@ -98,105 +97,100 @@ implements DOIConnector */ protected String METADATA_PATH; /** - * Name of crosswalk to convert metadata into DataCite Metadata Scheme. Set + * Name of crosswalk to convert metadata into DataCite Metadata Scheme. Set * by spring dependency injection. */ protected String CROSSWALK_NAME; - /** + /** * DisseminationCrosswalk to map local metadata into DataCite metadata. * The name of the crosswalk is set by spring dependency injection using * {@link #setDisseminationCrosswalkName(String) setDisseminationCrosswalkName} which * instantiates the crosswalk. */ protected ParameterizedDisseminationCrosswalk xwalk; - + protected ConfigurationService configurationService; - + protected String USERNAME; protected String PASSWORD; @Autowired protected HandleService handleService; - - public DataCiteConnector() - { + + public DataCiteConnector() { this.xwalk = null; this.USERNAME = null; this.PASSWORD = null; } - + /** * Used to set the scheme to connect the DataCite server. Used by spring * dependency injection. + * * @param DATACITE_SCHEME Probably https or http. */ @Required - public void setDATACITE_SCHEME(String DATACITE_SCHEME) - { + public void setDATACITE_SCHEME(String DATACITE_SCHEME) { this.SCHEME = DATACITE_SCHEME; } /** * Set the hostname of the DataCite server. Used by spring dependency * injection. + * * @param DATACITE_HOST Hostname to connect to register DOIs (f.e. test.datacite.org). */ @Required - public void setDATACITE_HOST(String DATACITE_HOST) - { + public void setDATACITE_HOST(String DATACITE_HOST) { this.HOST = DATACITE_HOST; } - + /** * Set the path on the DataCite server to register DOIs. Used by spring * dependency injection. + * * @param DATACITE_DOI_PATH Path to register DOIs, f.e. /doi. */ @Required - public void setDATACITE_DOI_PATH(String DATACITE_DOI_PATH) - { - if (!DATACITE_DOI_PATH.startsWith("/")) - { + public void setDATACITE_DOI_PATH(String DATACITE_DOI_PATH) { + if (!DATACITE_DOI_PATH.startsWith("/")) { DATACITE_DOI_PATH = "/" + DATACITE_DOI_PATH; } - if (!DATACITE_DOI_PATH.endsWith("/")) - { + if (!DATACITE_DOI_PATH.endsWith("/")) { DATACITE_DOI_PATH = DATACITE_DOI_PATH + "/"; } - + this.DOI_PATH = DATACITE_DOI_PATH; } - + /** * Set the path to register metadata on DataCite server. Used by spring * dependency injection. + * * @param DATACITE_METADATA_PATH Path to register metadata, f.e. /mds. */ @Required - public void setDATACITE_METADATA_PATH(String DATACITE_METADATA_PATH) - { - if (!DATACITE_METADATA_PATH.startsWith("/")) - { + public void setDATACITE_METADATA_PATH(String DATACITE_METADATA_PATH) { + if (!DATACITE_METADATA_PATH.startsWith("/")) { DATACITE_METADATA_PATH = "/" + DATACITE_METADATA_PATH; } - if (!DATACITE_METADATA_PATH.endsWith("/")) - { + if (!DATACITE_METADATA_PATH.endsWith("/")) { DATACITE_METADATA_PATH = DATACITE_METADATA_PATH + "/"; } - + this.METADATA_PATH = DATACITE_METADATA_PATH; } - - + + @Autowired @Required - public void setConfigurationService(ConfigurationService configurationService) - { + public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } - + /** * Set the name of the dissemination crosswalk used to convert the metadata * into DataCite Metadata Schema. Used by spring dependency injection. + * * @param CROSSWALK_NAME The name of the dissemination crosswalk to use. This * crosswalk must be configured in dspace.cfg. */ @@ -204,578 +198,509 @@ implements DOIConnector public void setDisseminationCrosswalkName(String CROSSWALK_NAME) { this.CROSSWALK_NAME = CROSSWALK_NAME; } - - protected void prepareXwalk() - { - if (null != this.xwalk) + + protected void prepareXwalk() { + if (null != this.xwalk) { return; - - this.xwalk = (ParameterizedDisseminationCrosswalk) CoreServiceFactory.getInstance().getPluginService().getNamedPlugin( - DisseminationCrosswalk.class, this.CROSSWALK_NAME); - - if (this.xwalk == null) - { + } + + this.xwalk = (ParameterizedDisseminationCrosswalk) CoreServiceFactory.getInstance().getPluginService() + .getNamedPlugin( + DisseminationCrosswalk.class, + this.CROSSWALK_NAME); + + if (this.xwalk == null) { throw new RuntimeException("Can't find crosswalk '" - + CROSSWALK_NAME + "'!"); + + CROSSWALK_NAME + "'!"); } } - - protected String getUsername() - { - if (null == this.USERNAME) - { + + protected String getUsername() { + if (null == this.USERNAME) { this.USERNAME = this.configurationService.getProperty(CFG_USER); - if (null == this.USERNAME) - { + if (null == this.USERNAME) { throw new RuntimeException("Unable to load username from " - + "configuration. Cannot find property " + - CFG_USER + "."); + + "configuration. Cannot find property " + + CFG_USER + "."); } } return this.USERNAME; } - - protected String getPassword() - { - if (null == this.PASSWORD) - { + + protected String getPassword() { + if (null == this.PASSWORD) { this.PASSWORD = this.configurationService.getProperty(CFG_PASSWORD); - if (null == this.PASSWORD) - { + if (null == this.PASSWORD) { throw new RuntimeException("Unable to load password from " - + "configuration. Cannot find property " + - CFG_PASSWORD + "."); + + "configuration. Cannot find property " + + CFG_PASSWORD + "."); } } return this.PASSWORD; } - + @Override public boolean isDOIReserved(Context context, String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { // get mds/metadata/ DataCiteResponse resp = this.sendMetadataGetRequest(doi); - - switch (resp.getStatusCode()) - { + + switch (resp.getStatusCode()) { // 200 -> reserved // if (200 && dso != null) -> compare url (out of response-content) with dso - case (200) : - { + case (200): { return true; } - + // 404 "Not Found" means DOI is neither reserved nor registered. - case (404) : - { + case (404): { return false; } - + // 410 GONE -> DOI is set inactive // that means metadata has been deleted // it is unclear if the doi has been registered before or only reserved. // it is unclear for which item it has been reserved // we will handle this as if it reserved for an unknown object. - case (410) : - { + case (410): { return true; } - + // Catch all other http status code in case we forgot one. - default : - { + default: { log.warn("While checking if the DOI {} is registered, we got a " - + "http status code {} and the message \"{}\".", - new String[] - { - doi, Integer.toString(resp.statusCode), - resp.getContent() - }); + + "http status code {} and the message \"{}\".", + new String[] { + doi, Integer.toString(resp.statusCode), + resp.getContent() + }); throw new DOIIdentifierException("Unable to parse an answer from " - + "DataCite API. Please have a look into DSpace logs.", - DOIIdentifierException.BAD_ANSWER); + + "DataCite API. Please have a look into DSpace logs.", + DOIIdentifierException.BAD_ANSWER); } } } - + @Override public boolean isDOIRegistered(Context context, String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { DataCiteResponse response = sendDOIGetRequest(doi); - - switch (response.getStatusCode()) - { + + switch (response.getStatusCode()) { // status code 200 means the doi is reserved and registered - case (200) : - { + case (200): { return true; } // Status Code 204 "No Content" stands for a known DOI without URL. // A DOI that is known but does not have any associated URL is // reserved but not registered yet. - case (204) : - { + case (204): { // we know it is reserved, but we do not know for which object. return false; } // 404 "Not Found" means DOI is neither reserved nor registered. - case (404) : - { + case (404): { return false; } // Catch all other http status code in case we forgot one. - default : - { + default: { log.warn("While checking if the DOI {} is registered, we got a " - + "http status code {} and the message \"{}\".", - new String[] {doi, Integer.toString(response.statusCode), response.getContent()}); + + "http status code {} and the message \"{}\".", + new String[] {doi, Integer.toString(response.statusCode), response.getContent()}); throw new DOIIdentifierException("Unable to parse an answer from " - + "DataCite API. Please have a look into DSpace logs.", - DOIIdentifierException.BAD_ANSWER); + + "DataCite API. Please have a look into DSpace logs.", + DOIIdentifierException.BAD_ANSWER); } } } - + @Override public void deleteDOI(Context context, String doi) - throws DOIIdentifierException - { - if (!isDOIReserved(context, doi)) + throws DOIIdentifierException { + if (!isDOIReserved(context, doi)) { return; - + } + // delete mds/metadata/ DataCiteResponse resp = this.sendMetadataDeleteRequest(doi); - switch(resp.getStatusCode()) - { + switch (resp.getStatusCode()) { //ok - case (200) : - { + case (200): { return; } // 404 "Not Found" means DOI is neither reserved nor registered. - case (404) : - { + case (404): { log.error("DOI {} is at least reserved, but a delete request " - + "told us that it is unknown!", doi); + + "told us that it is unknown!", doi); return; } // Catch all other http status code in case we forgot one. - default : - { + default: { log.warn("While deleting metadata of DOI {}, we got a " - + "http status code {} and the message \"{}\".", - new String[] {doi, Integer.toString(resp.statusCode), resp.getContent()}); + + "http status code {} and the message \"{}\".", + new String[] {doi, Integer.toString(resp.statusCode), resp.getContent()}); throw new DOIIdentifierException("Unable to parse an answer from " - + "DataCite API. Please have a look into DSpace logs.", - DOIIdentifierException.BAD_ANSWER); + + "DataCite API. Please have a look into DSpace logs.", + DOIIdentifierException.BAD_ANSWER); } } } @Override public void reserveDOI(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { this.prepareXwalk(); - DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService(dso); + DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance() + .getDSpaceObjectService(dso); - if (!this.xwalk.canDisseminate(dso)) - { - log.error("Crosswalk " + this.CROSSWALK_NAME - + " cannot disseminate DSO with type " + dso.getType() - + " and ID " + dso.getID() + ". Giving up reserving the DOI " - + doi + "."); + if (!this.xwalk.canDisseminate(dso)) { + log.error("Crosswalk " + this.CROSSWALK_NAME + + " cannot disseminate DSO with type " + dso.getType() + + " and ID " + dso.getID() + ". Giving up reserving the DOI " + + doi + "."); throw new DOIIdentifierException("Cannot disseminate " - + dSpaceObjectService.getTypeText(dso) + "/" + dso.getID() - + " using crosswalk " + this.CROSSWALK_NAME + ".", - DOIIdentifierException.CONVERSION_ERROR); + + dSpaceObjectService.getTypeText(dso) + "/" + dso.getID() + + " using crosswalk " + this.CROSSWALK_NAME + ".", + DOIIdentifierException.CONVERSION_ERROR); } // Set the transform's parameters. // XXX Should the actual list be configurable? Map parameters = new HashMap<>(); - if (configurationService.hasProperty(CFG_PREFIX)) + if (configurationService.hasProperty(CFG_PREFIX)) { parameters.put("prefix", - configurationService.getProperty(CFG_PREFIX)); - if (configurationService.hasProperty(CFG_PUBLISHER)) + configurationService.getProperty(CFG_PREFIX)); + } + if (configurationService.hasProperty(CFG_PUBLISHER)) { parameters.put("publisher", - configurationService.getProperty(CFG_PUBLISHER)); - if (configurationService.hasProperty(CFG_DATAMANAGER)) + configurationService.getProperty(CFG_PUBLISHER)); + } + if (configurationService.hasProperty(CFG_DATAMANAGER)) { parameters.put("datamanager", - configurationService.getProperty(CFG_DATAMANAGER)); - if (configurationService.hasProperty(CFG_HOSTINGINSTITUTION)) + configurationService.getProperty(CFG_DATAMANAGER)); + } + if (configurationService.hasProperty(CFG_HOSTINGINSTITUTION)) { parameters.put("hostinginstitution", - configurationService.getProperty(CFG_HOSTINGINSTITUTION)); + configurationService.getProperty(CFG_HOSTINGINSTITUTION)); + } Element root = null; - try - { + try { root = xwalk.disseminateElement(context, dso, parameters); - } - catch (AuthorizeException ae) - { + } catch (AuthorizeException ae) { log.error("Caught an AuthorizeException while disseminating DSO " - + "with type " + dso.getType() + " and ID " + dso.getID() - + ". Giving up to reserve DOI " + doi + ".", ae); + + "with type " + dso.getType() + " and ID " + dso.getID() + + ". Giving up to reserve DOI " + doi + ".", ae); throw new DOIIdentifierException("AuthorizeException occured while " - + "converting " + dSpaceObjectService.getTypeText(dso) + "/" + dso.getID() - + " using crosswalk " + this.CROSSWALK_NAME + ".", ae, - DOIIdentifierException.CONVERSION_ERROR); - } - catch (CrosswalkException ce) - { + + "converting " + dSpaceObjectService.getTypeText(dso) + "/" + dso + .getID() + + " using crosswalk " + this.CROSSWALK_NAME + ".", ae, + DOIIdentifierException.CONVERSION_ERROR); + } catch (CrosswalkException ce) { log.error("Caught an CrosswalkException while reserving a DOI (" - + doi + ") for DSO with type " + dso.getType() + " and ID " - + dso.getID() + ". Won't reserve the doi.", ce); + + doi + ") for DSO with type " + dso.getType() + " and ID " + + dso.getID() + ". Won't reserve the doi.", ce); throw new DOIIdentifierException("CrosswalkException occured while " - + "converting " + dSpaceObjectService.getTypeText(dso) + "/" + dso.getID() - + " using crosswalk " + this.CROSSWALK_NAME + ".", ce, - DOIIdentifierException.CONVERSION_ERROR); - } - catch (IOException | SQLException ex) - { + + "converting " + dSpaceObjectService.getTypeText(dso) + "/" + dso + .getID() + + " using crosswalk " + this.CROSSWALK_NAME + ".", ce, + DOIIdentifierException.CONVERSION_ERROR); + } catch (IOException | SQLException ex) { throw new RuntimeException(ex); } - + String metadataDOI = extractDOI(root); - if (null == metadataDOI) - { + if (null == metadataDOI) { // The DOI will be saved as metadata of dso after successful // registration. To register a doi it has to be part of the metadata // sent to DataCite. So we add it to the XML we'll send to DataCite // and we'll add it to the DSO after successful registration. root = addDOI(doi, root); - } - else if (!metadataDOI.equals(doi.substring(DOI.SCHEME.length()))) - { + } else if (!metadataDOI.equals(doi.substring(DOI.SCHEME.length()))) { log.error("While reserving a DOI, the " - + "crosswalk to generate the metadata used another DOI than " - + "the DOI we're reserving. Cannot reserve DOI " + doi - + " for " + dSpaceObjectService.getTypeText(dso) + " " - + dso.getID() + "."); + + "crosswalk to generate the metadata used another DOI than " + + "the DOI we're reserving. Cannot reserve DOI " + doi + + " for " + dSpaceObjectService.getTypeText(dso) + " " + + dso.getID() + "."); throw new IllegalStateException("An internal error occured while " - + "generating the metadata. Unable to reserve doi, see logs " - + "for further information."); + + "generating the metadata. Unable to reserve doi, see logs " + + "for further information."); } - + // send metadata as post to mds/metadata DataCiteResponse resp = this.sendMetadataPostRequest(doi, root); - - switch (resp.getStatusCode()) - { + + switch (resp.getStatusCode()) { // 201 -> created / ok - case (201) : - { + case (201): { return; } // 400 -> invalid XML - case (400) : - { + case (400): { log.warn("DataCite was unable to understand the XML we send."); log.warn("DataCite Metadata API returned a http status code " - +"400: " + resp.getContent()); + + "400: " + resp.getContent()); Format format = Format.getCompactFormat(); format.setEncoding("UTF-8"); XMLOutputter xout = new XMLOutputter(format); log.info("We send the following XML:\n" + xout.outputString(root)); - throw new DOIIdentifierException("Unable to reserve DOI " + doi - + ". Please inform your administrator or take a look " - +" into the log files.", DOIIdentifierException.BAD_REQUEST); + throw new DOIIdentifierException("Unable to reserve DOI " + doi + + ". Please inform your administrator or take a look " + + " into the log files.", DOIIdentifierException.BAD_REQUEST); } // Catch all other http status code in case we forgot one. - default : - { + default: { log.warn("While reserving the DOI {}, we got a http status code " - + "{} and the message \"{}\".", new String[] - {doi, Integer.toString(resp.statusCode), resp.getContent()}); + + "{} and the message \"{}\".", new String[] + {doi, Integer.toString(resp.statusCode), resp.getContent()}); throw new DOIIdentifierException("Unable to parse an answer from " - + "DataCite API. Please have a look into DSpace logs.", - DOIIdentifierException.BAD_ANSWER); + + "DataCite API. Please have a look into DSpace logs.", + DOIIdentifierException.BAD_ANSWER); } } } - + @Override public void registerDOI(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { // DataCite wants us to reserve a DOI before we can register it - if (!this.isDOIReserved(context, doi)) - { + if (!this.isDOIReserved(context, doi)) { // the DOIIdentifierProvider should catch and handle this throw new DOIIdentifierException("You need to reserve a DOI " - + "before you can register it.", - DOIIdentifierException.RESERVE_FIRST); + + "before you can register it.", + DOIIdentifierException.RESERVE_FIRST); } // send doi=\nurl= to mds/doi DataCiteResponse resp = null; - try - { - resp = this.sendDOIPostRequest(doi, - handleService.resolveToURL(context, dso.getHandle())); - } - catch (SQLException e) - { + try { + resp = this.sendDOIPostRequest(doi, + handleService.resolveToURL(context, dso.getHandle())); + } catch (SQLException e) { log.error("Caught SQL-Exception while resolving handle to URL: " - + e.getMessage()); + + e.getMessage()); throw new RuntimeException(e); } - - switch(resp.statusCode) - { + + switch (resp.statusCode) { // 201 -> created/updated -> okay - case (201) : - { + case (201): { return; } // 400 -> wrong domain, wrong prefix, wrong request body - case (400) : - { + case (400): { log.warn("We send an irregular request to DataCite. While " - + "registering a DOI they told us: " + resp.getContent()); + + "registering a DOI they told us: " + resp.getContent()); throw new DOIIdentifierException("Currently we cannot register " - + "DOIs. Please inform the administrator or take a look " - + " in the DSpace log file.", - DOIIdentifierException.BAD_REQUEST); + + "DOIs. Please inform the administrator or take a look " + + " in the DSpace log file.", + DOIIdentifierException.BAD_REQUEST); } // 412 Precondition failed: DOI was not reserved before registration! - case (412) : - { + case (412): { log.error("We tried to register a DOI {} that has not been reserved " - + "before! The registration agency told us: {}.", doi, - resp.getContent()); + + "before! The registration agency told us: {}.", doi, + resp.getContent()); throw new DOIIdentifierException("There was an error in handling " - + "of DOIs. The DOI we wanted to register had not been " - + "reserved in advance. Please contact the administrator " - + "or take a look in DSpace log file.", - DOIIdentifierException.RESERVE_FIRST); + + "of DOIs. The DOI we wanted to register had not been " + + "reserved in advance. Please contact the administrator " + + "or take a look in DSpace log file.", + DOIIdentifierException.RESERVE_FIRST); } // Catch all other http status code in case we forgot one. - default : - { + default: { log.warn("While registration of DOI {}, we got a http status code " - + "{} and the message \"{}\".", new String[] - {doi, Integer.toString(resp.statusCode), resp.getContent()}); + + "{} and the message \"{}\".", new String[] + {doi, Integer.toString(resp.statusCode), resp.getContent()}); throw new DOIIdentifierException("Unable to parse an answer from " - + "DataCite API. Please have a look into DSpace logs.", - DOIIdentifierException.BAD_ANSWER); + + "DataCite API. Please have a look into DSpace logs.", + DOIIdentifierException.BAD_ANSWER); } } } - + @Override - public void updateMetadata(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException - { + public void updateMetadata(Context context, DSpaceObject dso, String doi) + throws DOIIdentifierException { // We can use reserveDOI to update metadata. DataCite API uses the same // request for reservation as for updating metadata. this.reserveDOI(context, dso, doi); } - + protected DataCiteResponse sendDOIPostRequest(String doi, String url) - throws DOIIdentifierException - { + throws DOIIdentifierException { // post mds/doi/ // body must contaion "doi=\nurl=}n" URIBuilder uribuilder = new URIBuilder(); uribuilder.setScheme(SCHEME).setHost(HOST).setPath(DOI_PATH); - + HttpPost httppost = null; - try - { + try { httppost = new HttpPost(uribuilder.build()); - } - catch (URISyntaxException e) - { + } catch (URISyntaxException e) { log.error("The URL we constructed to check a DOI " - + "produced a URISyntaxException. Please check the configuration parameters!"); + + "produced a URISyntaxException. Please check the configuration parameters!"); log.error("The URL was {}.", SCHEME + "://" + HOST + - DOI_PATH + "/" + doi.substring(DOI.SCHEME.length())); + DOI_PATH + "/" + doi.substring(DOI.SCHEME.length())); throw new RuntimeException("The URL we constructed to check a DOI " - + "produced a URISyntaxException. Please check the configuration parameters!", e); + + "produced a URISyntaxException. Please check the configuration " + + "parameters!", + e); } - + // assemble request content: HttpEntity reqEntity = null; - try - { + try { String req = "doi=" + doi.substring(DOI.SCHEME.length()) + "\n" + "url=" + url + "\n"; ContentType contentType = ContentType.create("text/plain", "UTF-8"); reqEntity = new StringEntity(req, contentType); httppost.setEntity(reqEntity); - + return sendHttpRequest(httppost, doi); - } - finally - { + } finally { // release resources - try - { + try { EntityUtils.consume(reqEntity); - } - catch (IOException ioe) - { - log.info("Caught an IOException while releasing a HTTPEntity:" - + ioe.getMessage()); + } catch (IOException ioe) { + log.info("Caught an IOException while releasing a HTTPEntity:" + + ioe.getMessage()); } } } - - + + protected DataCiteResponse sendMetadataDeleteRequest(String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { // delete mds/metadata/ URIBuilder uribuilder = new URIBuilder(); uribuilder.setScheme(SCHEME).setHost(HOST).setPath(METADATA_PATH - + doi.substring(DOI.SCHEME.length())); - + + doi.substring(DOI.SCHEME.length())); + HttpDelete httpdelete = null; - try - { + try { httpdelete = new HttpDelete(uribuilder.build()); - } - catch (URISyntaxException e) - { + } catch (URISyntaxException e) { log.error("The URL we constructed to check a DOI " - + "produced a URISyntaxException. Please check the configuration parameters!"); + + "produced a URISyntaxException. Please check the configuration parameters!"); log.error("The URL was {}.", SCHEME + "://" + HOST + - DOI_PATH + "/" + doi.substring(DOI.SCHEME.length())); + DOI_PATH + "/" + doi.substring(DOI.SCHEME.length())); throw new RuntimeException("The URL we constructed to check a DOI " - + "produced a URISyntaxException. Please check the configuration parameters!", e); + + "produced a URISyntaxException. Please check the configuration " + + "parameters!", + e); } return sendHttpRequest(httpdelete, doi); } - + protected DataCiteResponse sendDOIGetRequest(String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { return sendGetRequest(doi, DOI_PATH); } - + protected DataCiteResponse sendMetadataGetRequest(String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { return sendGetRequest(doi, METADATA_PATH); } - + protected DataCiteResponse sendGetRequest(String doi, String path) - throws DOIIdentifierException - { + throws DOIIdentifierException { URIBuilder uribuilder = new URIBuilder(); uribuilder.setScheme(SCHEME).setHost(HOST).setPath(path - + doi.substring(DOI.SCHEME.length())); - + + doi.substring(DOI.SCHEME.length())); + HttpGet httpget = null; - try - { + try { httpget = new HttpGet(uribuilder.build()); - } - catch (URISyntaxException e) - { + } catch (URISyntaxException e) { log.error("The URL we constructed to check a DOI " - + "produced a URISyntaxException. Please check the configuration parameters!"); + + "produced a URISyntaxException. Please check the configuration parameters!"); log.error("The URL was {}.", SCHEME + "://" + HOST + - DOI_PATH + "/" + doi.substring(DOI.SCHEME.length())); + DOI_PATH + "/" + doi.substring(DOI.SCHEME.length())); throw new RuntimeException("The URL we constructed to check a DOI " - + "produced a URISyntaxException. Please check the configuration parameters!", e); + + "produced a URISyntaxException. Please check the configuration " + + "parameters!", + e); } return sendHttpRequest(httpget, doi); } - + protected DataCiteResponse sendMetadataPostRequest(String doi, Element metadataRoot) - throws DOIIdentifierException - { + throws DOIIdentifierException { Format format = Format.getCompactFormat(); format.setEncoding("UTF-8"); XMLOutputter xout = new XMLOutputter(format); return sendMetadataPostRequest(doi, xout.outputString(new Document(metadataRoot))); } - + protected DataCiteResponse sendMetadataPostRequest(String doi, String metadata) - throws DOIIdentifierException - { + throws DOIIdentifierException { // post mds/metadata/ // body must contain metadata in DataCite-XML. URIBuilder uribuilder = new URIBuilder(); uribuilder.setScheme(SCHEME).setHost(HOST).setPath(METADATA_PATH); - + HttpPost httppost = null; - try - { + try { httppost = new HttpPost(uribuilder.build()); - } - catch (URISyntaxException e) - { + } catch (URISyntaxException e) { log.error("The URL we constructed to check a DOI " - + "produced a URISyntaxException. Please check the configuration parameters!"); + + "produced a URISyntaxException. Please check the configuration parameters!"); log.error("The URL was {}.", SCHEME + "://" + HOST + - DOI_PATH + "/" + doi.substring(DOI.SCHEME.length())); + DOI_PATH + "/" + doi.substring(DOI.SCHEME.length())); throw new RuntimeException("The URL we constructed to check a DOI " - + "produced a URISyntaxException. Please check the configuration parameters!", e); + + "produced a URISyntaxException. Please check the configuration " + + "parameters!", + e); } - + // assemble request content: HttpEntity reqEntity = null; - try - { + try { ContentType contentType = ContentType.create("application/xml", "UTF-8"); reqEntity = new StringEntity(metadata, contentType); httppost.setEntity(reqEntity); - + return sendHttpRequest(httppost, doi); - } - finally - { + } finally { // release resources - try - { + try { EntityUtils.consume(reqEntity); - } - catch (IOException ioe) - { - log.info("Caught an IOException while releasing an HTTPEntity:" - + ioe.getMessage()); + } catch (IOException ioe) { + log.info("Caught an IOException while releasing an HTTPEntity:" + + ioe.getMessage()); } } } - + /** * Internal method to send requests prepared by the caller to DataCite. - * - * @param req - * Extended version of the HttpRequest interface that provides convenience methods to access request properties such as request URI and method type. - * @param doi - * DOI string to operate on + * + * @param req Extended version of the HttpRequest interface that provides convenience methods to access request + * properties such as request URI and method type. + * @param doi DOI string to operate on * @return response from DataCite * @throws DOIIdentifierException if DOI error */ protected DataCiteResponse sendHttpRequest(HttpUriRequest req, String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { DefaultHttpClient httpclient = new DefaultHttpClient(); httpclient.getCredentialsProvider().setCredentials( - new AuthScope(HOST, 443), - new UsernamePasswordCredentials(this.getUsername(), this.getPassword())); - + new AuthScope(HOST, 443), + new UsernamePasswordCredentials(this.getUsername(), this.getPassword())); + HttpEntity entity = null; - try - { + try { HttpResponse response = httpclient.execute(req); - + StatusLine status = response.getStatusLine(); int statusCode = status.getStatusCode(); - + String content = null; entity = response.getEntity(); - if (null != entity) - { + if (null != entity) { content = EntityUtils.toString(entity, "UTF-8"); } @@ -799,7 +724,7 @@ implements DOIConnector * } * log.info("----"); * } catch (IOException ex) { - * + * * } * } * } else { @@ -812,68 +737,58 @@ implements DOIConnector * } else { * log.debug("DataCite says: {}", content); * } - * + * */ // We can handle some status codes here, others have to be handled above - switch (statusCode) - { + switch (statusCode) { // we get a 401 if we forgot to send credentials or if the username // and password did not match. - case (401) : - { + case (401): { log.info("We were unable to authenticate against the DOI registry agency."); log.info("The response was: {}", content); throw new DOIIdentifierException("Cannot authenticate at the " - + "DOI registry agency. Please check if username " - + "and password are set correctly.", - DOIIdentifierException.AUTHENTICATION_ERROR); + + "DOI registry agency. Please check if username " + + "and password are set correctly.", + DOIIdentifierException.AUTHENTICATION_ERROR); } // We get a 403 Forbidden if we are managing a DOI that belongs to // another party or if there is a login problem. - case (403) : - { + case (403): { log.info("Managing a DOI ({}) was prohibited by the DOI " - + "registration agency: {}", doi, content); + + "registration agency: {}", doi, content); throw new DOIIdentifierException("We can check, register or " - + "reserve DOIs that belong to us only.", - DOIIdentifierException.FOREIGN_DOI); + + "reserve DOIs that belong to us only.", + DOIIdentifierException.FOREIGN_DOI); } // 500 is documented and signals an internal server error - case (500) : - { + case (500): { log.warn("Caught an http status code 500 while managing DOI " - +"{}. Message was: " + content); + + "{}. Message was: " + content); throw new DOIIdentifierException("DataCite API has an internal error. " - + "It is temporarily impossible to manage DOIs. " - + "Further information can be found in DSpace log file.", - DOIIdentifierException.INTERNAL_ERROR); + + "It is temporarily impossible to manage DOIs. " + + "Further information can be found in DSpace log file.", + DOIIdentifierException.INTERNAL_ERROR); } + default: + break; } - + return new DataCiteResponse(statusCode, content); - } - catch (IOException e) - { + } catch (IOException e) { log.warn("Caught an IOException: " + e.getMessage()); throw new RuntimeException(e); - } - finally - { - try - { + } finally { + try { // Release any resources used by HTTP-Request. - if (null != entity) - { + if (null != entity) { EntityUtils.consume(entity); } - } - catch (IOException e) - { + } catch (IOException e) { log.warn("Can't release HTTP-Entity: " + e.getMessage()); } } @@ -881,87 +796,71 @@ implements DOIConnector // returns null or handle protected String extractAlternateIdentifier(Context context, String content) - throws SQLException, DOIIdentifierException - { - if (content == null) - { + throws SQLException, DOIIdentifierException { + if (content == null) { return null; } - + // parse the XML SAXBuilder saxBuilder = new SAXBuilder(); Document doc = null; - try - { + try { doc = saxBuilder.build(new ByteArrayInputStream(content.getBytes("UTF-8"))); - } - catch (IOException ioe) - { + } catch (IOException ioe) { throw new RuntimeException("Got an IOException while reading from a string?!", ioe); - } - catch (JDOMException jde) - { + } catch (JDOMException jde) { throw new DOIIdentifierException("Got a JDOMException while parsing " - + "a response from the DataCite API.", jde, - DOIIdentifierException.BAD_ANSWER); + + "a response from the DataCite API.", jde, + DOIIdentifierException.BAD_ANSWER); } - + String handle = null; - + Iterator it = doc.getDescendants(new ElementFilter("alternateIdentifier")); - while (handle == null && it.hasNext()) - { + while (handle == null && it.hasNext()) { Element alternateIdentifier = it.next(); - try - { + try { handle = handleService.resolveUrlToHandle(context, - alternateIdentifier.getText()); - } - catch (SQLException e) - { + alternateIdentifier.getText()); + } catch (SQLException e) { throw e; } } return handle; } - + protected String extractDOI(Element root) { Element doi = root.getChild("identifier", root.getNamespace()); return (null == doi) ? null : doi.getTextTrim(); } protected Element addDOI(String doi, Element root) { - if (null != extractDOI(root)) - { + if (null != extractDOI(root)) { return root; } Element identifier = new Element("identifier", - configurationService.getProperty(CFG_NAMESPACE, - "http://datacite.org/schema/kernel-3")); + configurationService.getProperty(CFG_NAMESPACE, + "http://datacite.org/schema/kernel-3")); identifier.setAttribute("identifierType", "DOI"); identifier.addContent(doi.substring(DOI.SCHEME.length())); return root.addContent(0, identifier); } - protected class DataCiteResponse - { + protected class DataCiteResponse { private final int statusCode; private final String content; - protected DataCiteResponse(int statusCode, String content) - { + protected DataCiteResponse(int statusCode, String content) { this.statusCode = statusCode; this.content = content; } - - protected int getStatusCode() - { + + protected int getStatusCode() { return this.statusCode; } - - protected String getContent() - { + + protected String getContent() { return this.content; } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/ezid/DateToYear.java b/dspace-api/src/main/java/org/dspace/identifier/ezid/DateToYear.java index ac21379fce..d1bc796b36 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/ezid/DateToYear.java +++ b/dspace-api/src/main/java/org/dspace/identifier/ezid/DateToYear.java @@ -20,15 +20,13 @@ import java.util.GregorianCalendar; * @author mwood */ public class DateToYear - implements Transform -{ + implements Transform { private static final SimpleDateFormat parser - = new SimpleDateFormat("yyyy'-'MM'-'dd"); + = new SimpleDateFormat("yyyy'-'MM'-'dd"); @Override public synchronized String transform(String from) - throws ParseException - { + throws ParseException { Date when = parser.parse(from); Calendar calendar = new GregorianCalendar(); calendar.setTime(when); diff --git a/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequest.java b/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequest.java index ce6cbb4f1b..485424e6b6 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequest.java +++ b/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequest.java @@ -13,6 +13,7 @@ import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; + import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -33,8 +34,7 @@ import org.slf4j.LoggerFactory; * * @author Mark H. Wood */ -public class EZIDRequest -{ +public class EZIDRequest { private static final Logger log = LoggerFactory.getLogger(EZIDRequest.class); private static final String ID_PATH = "/id/" + DOI.SCHEME; @@ -59,40 +59,35 @@ public class EZIDRequest * Prepare a context for requests concerning a specific identifier or * authority prefix. * - * @param scheme URL scheme for access to the EZID service. - * @param host Host name for access to the EZID service. + * @param scheme URL scheme for access to the EZID service. + * @param host Host name for access to the EZID service. * @param authority DOI authority prefix, e.g. "10.5072/FK2". - * @param username an EZID user identity. - * @param password user's password, or {@code null} for none. + * @param username an EZID user identity. + * @param password user's password, or {@code null} for none. * @throws URISyntaxException if host or authority is bad. * @deprecated since 4.1 */ @Deprecated EZIDRequest(String scheme, String host, String authority, String username, String password) - throws URISyntaxException - { + throws URISyntaxException { this.scheme = scheme; this.host = host; this.path = "ezid"; - if (authority.charAt(authority.length()-1) == '/') - { - this.authority = authority.substring(0, authority.length()-1); - } - else - { + if (authority.charAt(authority.length() - 1) == '/') { + this.authority = authority.substring(0, authority.length() - 1); + } else { this.authority = authority; } client = new DefaultHttpClient(); - if (null != username) - { + if (null != username) { URI uri = new URI(scheme, host, path, null); client.getCredentialsProvider().setCredentials( - new AuthScope(uri.getHost(), uri.getPort()), - new UsernamePasswordCredentials(username, password)); + new AuthScope(uri.getHost(), uri.getPort()), + new UsernamePasswordCredentials(username, password)); } } @@ -100,56 +95,49 @@ public class EZIDRequest * Prepare a context for requests concerning a specific identifier or * authority prefix. * - * @param scheme URL scheme for access to the EZID service. - * @param host Host name for access to the EZID service. - * @param path Local-path to the EZID service. + * @param scheme URL scheme for access to the EZID service. + * @param host Host name for access to the EZID service. + * @param path Local-path to the EZID service. * @param authority DOI authority prefix, e.g. "10.5072/FK2". - * @param username an EZID user identity. - * @param password user's password, or {@code null} for none. + * @param username an EZID user identity. + * @param password user's password, or {@code null} for none. * @throws URISyntaxException if host or authority is bad. */ EZIDRequest(String scheme, String host, String path, - String authority, String username, String password) - throws URISyntaxException - { + String authority, String username, String password) + throws URISyntaxException { this.scheme = scheme; this.host = host; this.path = path; - if (authority.charAt(authority.length()-1) == '/') - { - this.authority = authority.substring(0, authority.length()-1); - } - else - { + if (authority.charAt(authority.length() - 1) == '/') { + this.authority = authority.substring(0, authority.length() - 1); + } else { this.authority = authority; } client = new DefaultHttpClient(); - if (null != username) - { + if (null != username) { URI uri = new URI(scheme, host, path, null); client.getCredentialsProvider().setCredentials( - new AuthScope(uri.getHost(), uri.getPort()), - new UsernamePasswordCredentials(username, password)); + new AuthScope(uri.getHost(), uri.getPort()), + new UsernamePasswordCredentials(username, password)); } } /** * Fetch the metadata bound to an identifier. * - * @param name - * identifier name + * @param name identifier name * @return Decoded response data evoked by a request made to EZID. * @throws IdentifierException if the response is error or body malformed. - * @throws IOException if the HTTP request fails. - * @throws URISyntaxException if host or authority is bad. + * @throws IOException if the HTTP request fails. + * @throws URISyntaxException if host or authority is bad. */ public EZIDResponse lookup(String name) - throws IdentifierException, IOException, URISyntaxException - { + throws IdentifierException, IOException, URISyntaxException { // GET path HttpGet request; URI uri = new URI(scheme, host, path + ID_PATH + authority + name, null); @@ -164,24 +152,21 @@ public class EZIDRequest * request path. Note: to "reserve" a given identifier, include "_status = * reserved" in {@code metadata}. * - * @param name - * identifier name + * @param name identifier name * @param metadata ANVL-encoded key/value pairs. * @return Decoded response data evoked by a request made to EZID. * @throws IdentifierException if the response is error or body malformed. - * @throws IOException if the HTTP request fails. - * @throws URISyntaxException if host or authority is bad. + * @throws IOException if the HTTP request fails. + * @throws URISyntaxException if host or authority is bad. */ public EZIDResponse create(String name, Map metadata) - throws IOException, IdentifierException, URISyntaxException - { + throws IOException, IdentifierException, URISyntaxException { // PUT path [+metadata] HttpPut request; URI uri = new URI(scheme, host, path + ID_PATH + authority + '/' + name, null); log.debug("EZID create {}", uri.toASCIIString()); request = new HttpPut(uri); - if (null != metadata) - { + if (null != metadata) { request.setEntity(new StringEntity(formatMetadata(metadata), UTF_8)); } HttpResponse response = client.execute(request); @@ -195,19 +180,17 @@ public class EZIDRequest * @param metadata ANVL-encoded key/value pairs. * @return Decoded response data evoked by a request made to EZID. * @throws IdentifierException if the response is error or body malformed. - * @throws IOException if the HTTP request fails. - * @throws URISyntaxException if host or authority is bad. + * @throws IOException if the HTTP request fails. + * @throws URISyntaxException if host or authority is bad. */ public EZIDResponse mint(Map metadata) - throws IOException, IdentifierException, URISyntaxException - { + throws IOException, IdentifierException, URISyntaxException { // POST path [+metadata] HttpPost request; URI uri = new URI(scheme, host, path + SHOULDER_PATH + authority, null); log.debug("EZID mint {}", uri.toASCIIString()); request = new HttpPost(uri); - if (null != metadata) - { + if (null != metadata) { request.setEntity(new StringEntity(formatMetadata(metadata), UTF_8)); } HttpResponse response = client.execute(request); @@ -218,21 +201,17 @@ public class EZIDRequest /** * Alter the metadata bound to an identifier. * - * @param name - * identifier name - * @param metadata - * metadata fields to be altered. Leave the value of a field's empty - * to delete the field. + * @param name identifier name + * @param metadata metadata fields to be altered. Leave the value of a field's empty + * to delete the field. * @return Decoded response data evoked by a request made to EZID. * @throws IdentifierException if the response is error or body malformed. - * @throws IOException if the HTTP request fails. - * @throws URISyntaxException if host or authority is bad. + * @throws IOException if the HTTP request fails. + * @throws URISyntaxException if host or authority is bad. */ public EZIDResponse modify(String name, Map metadata) - throws IOException, IdentifierException, URISyntaxException - { - if (null == metadata) - { + throws IOException, IdentifierException, URISyntaxException { + if (null == metadata) { throw new IllegalArgumentException("metadata must not be null"); } // POST path +metadata @@ -248,16 +227,14 @@ public class EZIDRequest /** * Destroy a reserved identifier. Fails if ID was ever public. * - * @param name - * identifier name + * @param name identifier name * @return Decoded response data evoked by a request made to EZID. * @throws IdentifierException if the response is error or body malformed. - * @throws IOException if the HTTP request fails. - * @throws URISyntaxException if host or authority is bad. + * @throws IOException if the HTTP request fails. + * @throws URISyntaxException if host or authority is bad. */ public EZIDResponse delete(String name) - throws IOException, IdentifierException, URISyntaxException - { + throws IOException, IdentifierException, URISyntaxException { // DELETE path HttpDelete request; URI uri = new URI(scheme, host, path + ID_PATH + authority + name, null); @@ -270,16 +247,14 @@ public class EZIDRequest /** * Remove a public identifier from view. * - * @param name - * identifier name + * @param name identifier name * @return Decoded response data evoked by a request made to EZID. * @throws IdentifierException if the response is error or body malformed. - * @throws IOException if the HTTP request fails. - * @throws URISyntaxException if host or authority is bad. + * @throws IOException if the HTTP request fails. + * @throws URISyntaxException if host or authority is bad. */ public EZIDResponse withdraw(String name) - throws IOException, IdentifierException, URISyntaxException - { + throws IOException, IdentifierException, URISyntaxException { Map metadata = new HashMap(); metadata.put(MD_KEY_STATUS, "unavailable"); return modify(name, metadata); @@ -288,18 +263,15 @@ public class EZIDRequest /** * Remove a public identifier from view, with a reason. * - * @param name - * identifier name - * @param reason - * annotation for the item's unavailability. + * @param name identifier name + * @param reason annotation for the item's unavailability. * @return Decoded response data evoked by a request made to EZID. * @throws IdentifierException if the response is error or body malformed. - * @throws IOException if the HTTP request fails. - * @throws URISyntaxException if host or authority is bad. + * @throws IOException if the HTTP request fails. + * @throws URISyntaxException if host or authority is bad. */ public EZIDResponse withdraw(String name, String reason) - throws IOException, IdentifierException, URISyntaxException - { + throws IOException, IdentifierException, URISyntaxException { Map metadata = new HashMap(); metadata.put(MD_KEY_STATUS, "unavailable | " + escape(reason)); return modify(name, metadata); @@ -309,17 +281,14 @@ public class EZIDRequest * Create ANVL-formatted name/value pairs from a Map. * * @param raw - * */ - private static String formatMetadata(Map raw) - { + private static String formatMetadata(Map raw) { StringBuilder formatted = new StringBuilder(); - for (Entry entry : raw.entrySet()) - { + for (Entry entry : raw.entrySet()) { formatted.append(escape(entry.getKey())) - .append(": ") - .append(escape(entry.getValue())) - .append('\n'); + .append(": ") + .append(escape(entry.getValue())) + .append('\n'); } return formatted.toString(); @@ -330,9 +299,10 @@ public class EZIDRequest * * @return null for null input. */ - private static String escape(String s) - { - if (null == s) { return s; } + private static String escape(String s) { + if (null == s) { + return s; + } return s.replace("%", "%25") .replace("\n", "%0A") diff --git a/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequestFactory.java b/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequestFactory.java index 58e1701344..043df8be8a 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequestFactory.java +++ b/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequestFactory.java @@ -9,6 +9,7 @@ package org.dspace.identifier.ezid; import java.net.URISyntaxException; + import org.springframework.beans.factory.annotation.Required; /** @@ -17,18 +18,17 @@ import org.springframework.beans.factory.annotation.Required; *

    Common EZID constant properties are:

    * *
    - *
    EZID_SCHEME
    - *
    URL scheme (e.g. "https")
    - *
    EZID_HOST
    - *
    Name of the EZID API host
    - *
    EZID_PATH
    - *
    Path to the API endpoints
    + *
    EZID_SCHEME
    + *
    URL scheme (e.g. "https")
    + *
    EZID_HOST
    + *
    Name of the EZID API host
    + *
    EZID_PATH
    + *
    Path to the API endpoints
    *
    * * @author mwood */ -public class EZIDRequestFactory -{ +public class EZIDRequestFactory { private String EZID_SCHEME; private String EZID_HOST; private String EZID_PATH; @@ -37,24 +37,22 @@ public class EZIDRequestFactory * Configure an EZID request. * * @param authority our DOI authority number. - * @param username EZID user name. - * @param password {@code username}'s password. + * @param username EZID user name. + * @param password {@code username}'s password. * @return a new EZID request with the given parameters * @throws URISyntaxException if host or authority is bad. */ public EZIDRequest getInstance(String authority, String username, String password) - throws URISyntaxException - { + throws URISyntaxException { return new EZIDRequest(EZID_SCHEME, EZID_HOST, EZID_PATH, - authority, username, password); + authority, username, password); } /** * @param aEZID_SCHEME the EZID URL scheme to set. */ @Required - public void setEZID_SCHEME(String aEZID_SCHEME) - { + public void setEZID_SCHEME(String aEZID_SCHEME) { EZID_SCHEME = aEZID_SCHEME; } @@ -62,8 +60,7 @@ public class EZIDRequestFactory * @param aEZID_HOST the EZID host to set. */ @Required - public void setEZID_HOST(String aEZID_HOST) - { + public void setEZID_HOST(String aEZID_HOST) { EZID_HOST = aEZID_HOST; } @@ -71,8 +68,7 @@ public class EZIDRequestFactory * @param aEZID_PATH the local path to the EZID API. */ @Required - public void setEZID_PATH(String aEZID_PATH) - { + public void setEZID_PATH(String aEZID_PATH) { EZID_PATH = aEZID_PATH; } diff --git a/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDResponse.java b/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDResponse.java index 1c1e37ea54..9c5ad90484 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDResponse.java +++ b/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDResponse.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; + import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.ParseException; @@ -25,8 +26,7 @@ import org.slf4j.LoggerFactory; /** * Decoded response data evoked by a request made to EZID. */ -public class EZIDResponse -{ +public class EZIDResponse { private static final Logger log = LoggerFactory.getLogger(EZIDResponse.class); private static final String UTF_8 = "UTF-8"; @@ -40,27 +40,23 @@ public class EZIDResponse private final HttpResponse response; public EZIDResponse(HttpResponse response) - throws IdentifierException - { + throws IdentifierException { this.response = response; HttpEntity responseBody = response.getEntity(); // Collect the content of the percent-encoded response. String body; - try - { + try { body = EntityUtils.toString(responseBody, UTF_8); - } catch (IOException ex) - { + } catch (IOException ex) { log.error(ex.getMessage()); throw new IdentifierException("EZID response not understood: " - + ex.getMessage()); - } catch (ParseException ex) - { + + ex.getMessage()); + } catch (ParseException ex) { log.error(ex.getMessage()); throw new IdentifierException("EZID response not understood: " - + ex.getMessage()); + + ex.getMessage()); } String[] parts; @@ -70,28 +66,22 @@ public class EZIDResponse // First line is request status and message or value parts = lines[0].split(":", 2); status = parts[0].trim(); - if (parts.length > 1) - { + if (parts.length > 1) { statusValue = parts[1].trim(); - } - else - { + } else { statusValue = null; } // Remaining lines are key: value pairs - for (int i = 1; i < lines.length; i++) - { + for (int i = 1; i < lines.length; i++) { parts = lines[i].split(":", 2); - String key = null, value = null; + String key = null; + String value = null; try { key = URLDecoder.decode(parts[0], UTF_8).trim(); - if (parts.length > 1) - { + if (parts.length > 1) { value = URLDecoder.decode(parts[1], UTF_8).trim(); - } - else - { + } else { value = null; } } catch (UnsupportedEncodingException e) { @@ -106,8 +96,7 @@ public class EZIDResponse * * @return returned status was success. */ - public boolean isSuccess() - { + public boolean isSuccess() { return status.equalsIgnoreCase("success"); } @@ -116,8 +105,7 @@ public class EZIDResponse * * @return should be "success" or "error". */ - public String getEZIDStatus() - { + public String getEZIDStatus() { return status; } @@ -126,8 +114,7 @@ public class EZIDResponse * * @return EZID status value */ - public String getEZIDStatusValue() - { + public String getEZIDStatusValue() { return statusValue; } @@ -136,11 +123,9 @@ public class EZIDResponse * * @return all keys found in the response. */ - public List getKeys() - { + public List getKeys() { List keys = new ArrayList(); - for (String key : attributes.keySet()) - { + for (String key : attributes.keySet()) { keys.add(key); } return keys; @@ -152,24 +137,21 @@ public class EZIDResponse * @param key the datum to look up. * @return the value of {@code key}, or null if {@code key} is undefined. */ - public String get(String key) - { + public String get(String key) { return attributes.get(key); } /** * @return status of the HTTP request. */ - public int getHttpStatusCode() - { + public int getHttpStatusCode() { return response.getStatusLine().getStatusCode(); } /** * @return reason for status of the HTTP request. */ - public String getHttpReasonPhrase() - { + public String getHttpReasonPhrase() { return response.getStatusLine().getReasonPhrase(); } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/ezid/Transform.java b/dspace-api/src/main/java/org/dspace/identifier/ezid/Transform.java index 6970523825..7df2cee8a9 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/ezid/Transform.java +++ b/dspace-api/src/main/java/org/dspace/identifier/ezid/Transform.java @@ -13,16 +13,14 @@ package org.dspace.identifier.ezid; * * @author mwood */ -public interface Transform -{ +public interface Transform { /** * Convert the input form to the desired output form. - * @param from - * input form to transform from + * + * @param from input form to transform from * @return transformed output form - * @throws Exception - * A general exception + * @throws Exception A general exception */ public String transform(String from) - throws Exception; + throws Exception; } diff --git a/dspace-api/src/main/java/org/dspace/identifier/factory/IdentifierServiceFactory.java b/dspace-api/src/main/java/org/dspace/identifier/factory/IdentifierServiceFactory.java index 1aa24067f2..1155062f34 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/factory/IdentifierServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/identifier/factory/IdentifierServiceFactory.java @@ -12,7 +12,8 @@ import org.dspace.identifier.service.IdentifierService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the identifier package, use IdentifierServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the identifier package, use IdentifierServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -22,7 +23,8 @@ public abstract class IdentifierServiceFactory { public abstract DOIService getDOIService(); - public static IdentifierServiceFactory getInstance(){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("identifierServiceFactory", IdentifierServiceFactory.class); + public static IdentifierServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("identifierServiceFactory", IdentifierServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/factory/IdentifierServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/identifier/factory/IdentifierServiceFactoryImpl.java index c037535972..f586bdbba0 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/factory/IdentifierServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/identifier/factory/IdentifierServiceFactoryImpl.java @@ -12,7 +12,8 @@ import org.dspace.identifier.service.IdentifierService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the identifier package, use IdentifierServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the identifier package, use IdentifierServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/identifier/service/DOIService.java b/dspace-api/src/main/java/org/dspace/identifier/service/DOIService.java index 4e87c7a246..9af1fd8a0a 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/service/DOIService.java +++ b/dspace-api/src/main/java/org/dspace/identifier/service/DOIService.java @@ -7,18 +7,19 @@ */ package org.dspace.identifier.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.identifier.DOI; import org.dspace.identifier.IdentifierException; import org.dspace.identifier.doi.DOIIdentifierException; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the DOI object. - * The implementation of this class is responsible for all business logic calls for the DOI object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the DOI object and is autowired + * by spring * * @author kevinvandevelde at atmire.com */ @@ -32,7 +33,8 @@ public interface DOIService { public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso) throws SQLException; - public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) throws SQLException; + public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) + throws SQLException; /** @@ -40,44 +42,47 @@ public interface DOIService { * the following formats and returns it as URL (f.e. * http://dx.doi.org/10.123/456). Allowed formats are: *
      - *
    • doi:10.123/456
    • - *
    • 10.123/456
    • - *
    • http://dx.doi.org/10.123/456
    • + *
    • doi:10.123/456
    • + *
    • 10.123/456
    • + *
    • http://dx.doi.org/10.123/456
    • *
    * - * @param identifier A DOI that should be returned in external form. + * @param identifier A DOI that should be returned in external form. * @return A String containing a URL to the official DOI resolver. - * @throws IllegalArgumentException If identifier is null or an empty String. + * @throws IllegalArgumentException If identifier is null or an empty String. * @throws org.dspace.identifier.IdentifierException If identifier could not be recognized as valid DOI. */ public String DOIToExternalForm(String identifier) - throws IdentifierException; + throws IdentifierException; public String DOIFromExternalFormat(String identifier) - throws DOIIdentifierException; + throws DOIIdentifierException; /** * Recognize format of DOI and return it with leading doi-Scheme. + * * @param identifier Identifier to format, following format are accepted: * f.e. 10.123/456, doi:10.123/456, http://dx.doi.org/10.123/456. * @return Given Identifier with DOI-Scheme, f.e. doi:10.123/456. - * @throws IllegalArgumentException If identifier is empty or null. + * @throws IllegalArgumentException If identifier is empty or null. * @throws org.dspace.identifier.doi.DOIIdentifierException If DOI could not be recognized. */ public String formatIdentifier(String identifier) - throws DOIIdentifierException; + throws DOIIdentifierException; public List getDOIsByStatus(Context context, List statuses) throws SQLException; - + /** * Find all DOIs that are similar to the specified pattern ant not in the specified states. - * @param context DSpace context - * @param doiPattern The pattern, e.g. "10.5072/123.%" - * @param statuses The statuses the DOI should not be in, @{link DOIIdentifierProvider.DELETED}. + * + * @param context DSpace context + * @param doiPattern The pattern, e.g. "10.5072/123.%" + * @param statuses The statuses the DOI should not be in, @{link DOIIdentifierProvider.DELETED}. * @param dsoIsNotNull Boolean whether all DOIs should be excluded where the DSpaceObject is NULL. * @return null or a list of DOIs * @throws SQLException if database error */ - public List getSimilarDOIsNotInState(Context context, String doiPattern, List statuses, boolean dsoIsNotNull) - throws SQLException; + public List getSimilarDOIsNotInState(Context context, String doiPattern, List statuses, + boolean dsoIsNotNull) + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/identifier/service/IdentifierService.java b/dspace-api/src/main/java/org/dspace/identifier/service/IdentifierService.java index 97b83f788b..74219fc71c 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/service/IdentifierService.java +++ b/dspace-api/src/main/java/org/dspace/identifier/service/IdentifierService.java @@ -7,6 +7,9 @@ */ package org.dspace.identifier.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; @@ -15,12 +18,7 @@ import org.dspace.identifier.IdentifierException; import org.dspace.identifier.IdentifierNotFoundException; import org.dspace.identifier.IdentifierNotResolvableException; -import java.sql.SQLException; -import java.util.List; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -31,29 +29,26 @@ public interface IdentifierService { * Get an identifier for a given object which is assignment-compatible * with a given Identifier type. * - * @param context - * The relevant DSpace Context. - * @param dso the object to be identified. + * @param context The relevant DSpace Context. + * @param dso the object to be identified. * @param identifier instance of an Identifier of the required type. * @return the matching identifier, or the site identifier if the object - * is a Site, or null if no matching identifier is found. + * is a Site, or null if no matching identifier is found. */ String lookup(Context context, DSpaceObject dso, Class identifier); - + /** - * Gets the identifiers all registered IdentifierProvider returns if asked + * Gets the identifiers all registered IdentifierProvider returns if asked * to lookup the provided DSpaceObject. * - * @param context - * The relevant DSpace Context. - * @param dso the object to be identified. + * @param context The relevant DSpace Context. + * @param dso the object to be identified. * @return the matching identifiers, or the site identifier if the object - * is a Site, or an empty array if no matching identifier is found. + * is a Site, or an empty array if no matching identifier is found. */ List lookup(Context context, DSpaceObject dso); /** - * * This will resolve a DSpaceObject based on a provided Identifier. * The Service will interrogate the providers in no particular order * and return the first successful result discovered. If no resolution @@ -61,89 +56,74 @@ public interface IdentifierService { * * TODO: Verify null is returned. * - * @param context - * The relevant DSpace Context. - * @param identifier - * instance of an Identifier of the required type. + * @param context The relevant DSpace Context. + * @param identifier instance of an Identifier of the required type. * @return the DSpace object associated with the identifier - * @throws IdentifierNotFoundException if identifier not found + * @throws IdentifierNotFoundException if identifier not found * @throws IdentifierNotResolvableException if identifier not resolvable */ - DSpaceObject resolve(Context context, String identifier) throws IdentifierNotFoundException, IdentifierNotResolvableException; + DSpaceObject resolve(Context context, String identifier) + throws IdentifierNotFoundException, IdentifierNotResolvableException; /** - * * Reserves any identifiers necessary based on the capabilities of all providers in the service. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to be reserved - * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param dso DSpace object to be reserved + * @throws AuthorizeException if authorization error + * @throws SQLException if database error * @throws IdentifierException if identifier error */ void reserve(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException; /** - * * Used to Reserve a Specific Identifier (for example a Handle, hdl:1234.5/6) The provider is responsible for * Detecting and Processing the appropriate identifier, all Providers are interrogated, multiple providers * can process the same identifier. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to be reserved - * @param identifier - * instance of an Identifier of the required type. - * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param dso DSpace object to be reserved + * @param identifier instance of an Identifier of the required type. + * @throws AuthorizeException if authorization error + * @throws SQLException if database error * @throws IdentifierException if identifier error */ - void reserve(Context context, DSpaceObject dso, String identifier) throws AuthorizeException, SQLException, IdentifierException; + void reserve(Context context, DSpaceObject dso, String identifier) + throws AuthorizeException, SQLException, IdentifierException; /** - * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to be registered - * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param dso DSpace object to be registered + * @throws AuthorizeException if authorization error + * @throws SQLException if database error * @throws IdentifierException if identifier error */ void register(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException; /** - * * Used to Register a specific Identifier (for example a Handle, hdl:1234.5/6) * The provider is responsible for detecting and processing the appropriate * identifier. All Providers are interrogated. Multiple providers * can process the same identifier. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to be registered - * @param identifier - * instance of an Identifier of the required type. - * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param dso DSpace object to be registered + * @param identifier instance of an Identifier of the required type. + * @throws AuthorizeException if authorization error + * @throws SQLException if database error * @throws IdentifierException if identifier error */ - void register(Context context, DSpaceObject dso, String identifier) throws AuthorizeException, SQLException, IdentifierException; + void register(Context context, DSpaceObject dso, String identifier) + throws AuthorizeException, SQLException, IdentifierException; /** * Delete (Unbind) all identifiers registered for a specific DSpace item. Identifiers are "unbound" across * all providers in no particular order. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to be deleted - * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param dso DSpace object to be deleted + * @throws AuthorizeException if authorization error + * @throws SQLException if database error * @throws IdentifierException if identifier error */ void delete(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException; @@ -153,16 +133,14 @@ public interface IdentifierService { * Detecting and Processing the appropriate identifier, all Providers are interrogated, multiple providers * can process the same identifier. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to be deleted - * @param identifier - * instance of an Identifier of the required type. - * @throws AuthorizeException if authorization error - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param dso DSpace object to be deleted + * @param identifier instance of an Identifier of the required type. + * @throws AuthorizeException if authorization error + * @throws SQLException if database error * @throws IdentifierException if identifier error */ - void delete(Context context, DSpaceObject dso, String identifier) throws AuthorizeException, SQLException, IdentifierException; + void delete(Context context, DSpaceObject dso, String identifier) + throws AuthorizeException, SQLException, IdentifierException; } diff --git a/dspace-api/src/main/java/org/dspace/importer/external/datamodel/ImportRecord.java b/dspace-api/src/main/java/org/dspace/importer/external/datamodel/ImportRecord.java index e20c8b47e5..f5d3a6f722 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/datamodel/ImportRecord.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/datamodel/ImportRecord.java @@ -7,13 +7,13 @@ */ package org.dspace.importer.external.datamodel; -import org.dspace.importer.external.metadatamapping.MetadatumDTO; - import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import org.dspace.importer.external.metadatamapping.MetadatumDTO; + /** * This class contains all MetadatumDTO objects from an imported item * @@ -34,8 +34,7 @@ public class ImportRecord { /** * Create an ImportRecord instance initialized with a List of MetadatumDTO objects * - * @param valueList - * list of metadata values + * @param valueList list of metadata values */ public ImportRecord(List valueList) { //don't want to alter the original list. Also now I can control the type of list @@ -54,7 +53,7 @@ public class ImportRecord { final StringBuilder sb = new StringBuilder(); sb.append("Record"); sb.append("{valueList="); - for (MetadatumDTO val:valueList) { + for (MetadatumDTO val : valueList) { sb.append("{"); sb.append(val.getSchema()); sb.append("; "); @@ -75,19 +74,20 @@ public class ImportRecord { /** * Return the MetadatumDTO's that are related to a given schema/element/qualifier pair/triplet - * @param schema metadata field schema - * @param element metadata field element + * + * @param schema metadata field schema + * @param element metadata field element * @param qualifier metadata field qualifier * @return the MetadatumDTO's that are related to a given schema/element/qualifier pair/triplet */ public Collection getValue(String schema, String element, String qualifier) { List values = new LinkedList(); - for (MetadatumDTO value:valueList) { - if (value.getSchema().equals(schema)&&value.getElement().equals(element)) { - if (qualifier==null && value.getQualifier() == null) { - values.add(value); - } else if (value.getQualifier() != null && value.getQualifier().equals(qualifier)) { - values.add(value); + for (MetadatumDTO value : valueList) { + if (value.getSchema().equals(schema) && value.getElement().equals(element)) { + if (qualifier == null && value.getQualifier() == null) { + values.add(value); + } else if (value.getQualifier() != null && value.getQualifier().equals(qualifier)) { + values.add(value); } } } @@ -96,6 +96,7 @@ public class ImportRecord { /** * Add a value to the valueList + * * @param value The MetadatumDTO to add to the valueList */ public void addValue(MetadatumDTO value) { diff --git a/dspace-api/src/main/java/org/dspace/importer/external/datamodel/Query.java b/dspace-api/src/main/java/org/dspace/importer/external/datamodel/Query.java index b5f242d8da..8c5e1b394a 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/datamodel/Query.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/datamodel/Query.java @@ -8,16 +8,19 @@ package org.dspace.importer.external.datamodel; -import org.apache.commons.collections.map.MultiValueMap; - import java.util.Collection; -/** Represents a query to a source. Subclasses may enforce stricter typing or more verbose setting of parameters. +import org.apache.commons.collections4.map.MultiValueMap; + +/** + * Represents a query to a source. Subclasses may enforce stricter typing or more verbose setting of parameters. + * * @author Roeland Dillen (roeland at atmire dot com) */ public class Query { private MultiValueMap parameters = new MultiValueMap(); + /** * Retrieve the parameters set to this Query object * @@ -33,8 +36,8 @@ public class Query { * Unlike a normal Map the previous value is not replaced. * Instead the new value is added to the collection stored against the key. * - * @param key the key to store against - * @param value the value to add to the collection at the key + * @param key the key to store against + * @param value the value to add to the collection at the key */ public void addParameter(String key, Object value) { parameters.put(key, value); @@ -46,8 +49,8 @@ public class Query { * Unlike {@link #addParameter(String, Object)} the previous value is overridden. * First, any existing values are removed, then the new value is added to the collection at the specified key * - * @param key the key to store against - * @param value the value to add to the collection at the key + * @param key the key to store against + * @param value the value to add to the collection at the key */ protected void addSingletonParameter(String key, Object value) { parameters.remove(key); @@ -56,14 +59,15 @@ public class Query { /** * Retrieve a parameter as a certain given class - * @param the type of parameter returned. - * @param key the key to retrieve the parameter from + * + * @param the type of parameter returned. + * @param key the key to retrieve the parameter from * @param clazz the type to retrieve. (If no parameter with that class is found, a null value is returned.) * @return the selected parameter, or null. */ public T getParameterAsClass(String key, Class clazz) { - Collection c=parameters.getCollection(key); - if (c==null || c.isEmpty()) { + Collection c = parameters.getCollection(key); + if (c == null || c.isEmpty()) { return null; } else { Object o = c.iterator().next(); @@ -74,11 +78,12 @@ public class Query { } } } + /** * Gets the collection mapped to the specified key. * This method is a convenience method to typecast the result of get(key). * - * @param key the key used to retrieve the collection + * @param key the key used to retrieve the collection * @return the collection mapped to the key, null if no mapping */ public Collection getParameter(String key) { @@ -88,6 +93,7 @@ public class Query { /** * Set the parameters of this query object based on a given {@link org.apache.commons.collections.map.MultiValueMap} + * * @param parameters a {@link org.apache.commons.collections.map.MultiValueMap} to set to this Query object */ public void setParameters(MultiValueMap parameters) { diff --git a/dspace-api/src/main/java/org/dspace/importer/external/exception/MetadataSourceException.java b/dspace-api/src/main/java/org/dspace/importer/external/exception/MetadataSourceException.java index 968dbebaa9..f8dc2b6a52 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/exception/MetadataSourceException.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/exception/MetadataSourceException.java @@ -8,7 +8,9 @@ package org.dspace.importer.external.exception; -/** Represents a problem with the input source: e.g. cannot connect to the source. +/** + * Represents a problem with the input source: e.g. cannot connect to the source. + * * @author Roeland Dillen (roeland at atmire dot com) */ public class MetadataSourceException extends Exception { @@ -27,8 +29,8 @@ public class MetadataSourceException extends Exception { * cause is not initialized, and may subsequently be initialized by * a call to {@link #initCause}. * - * @param message the detail message. The detail message is saved for - * later retrieval by the {@link #getMessage()} method. + * @param message the detail message. The detail message is saved for + * later retrieval by the {@link #getMessage()} method. */ public MetadataSourceException(String message) { super(message); @@ -40,12 +42,12 @@ public class MetadataSourceException extends Exception { * {@code cause} is not automatically incorporated in * this exception's detail message. * - * @param message the detail message (which is saved for later retrieval - * by the {@link #getMessage()} method). - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method). (A null value is - * permitted, and indicates that the cause is nonexistent or - * unknown.) + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) */ public MetadataSourceException(String message, Throwable cause) { super(message, cause); @@ -59,10 +61,10 @@ public class MetadataSourceException extends Exception { * wrappers for other throwables (for example, {@link * java.security.PrivilegedActionException}). * - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method). (A null value is - * permitted, and indicates that the cause is nonexistent or - * unknown.) + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) */ public MetadataSourceException(Throwable cause) { super(cause); diff --git a/dspace-api/src/main/java/org/dspace/importer/external/exception/SourceExceptionHandler.java b/dspace-api/src/main/java/org/dspace/importer/external/exception/SourceExceptionHandler.java index 55ed247f6e..25f3e06a1c 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/exception/SourceExceptionHandler.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/exception/SourceExceptionHandler.java @@ -12,6 +12,7 @@ import org.dspace.importer.external.service.components.AbstractRemoteMetadataSou /** * Represent a handler that forces implementations to define their own behaviour for exceptions originating from + * * @author Antoine Snyers (antoine at atmire dot com) */ public abstract interface SourceExceptionHandler { @@ -19,7 +20,8 @@ public abstract interface SourceExceptionHandler implements MetadataFieldMapping> { +public abstract class AbstractMetadataFieldMapping + implements MetadataFieldMapping> { private Map> metadataFieldMap; @@ -38,25 +38,25 @@ public abstract class AbstractMetadataFieldMapping implements Metada private Map metadataProcessorMap; /** - * Set a map of metadataprocessors. This map is used to process metadata to make it more compliant for certain metadata fields + * Set a map of metadataprocessors. This map is used to process metadata to make it more compliant for certain + * metadata fields + * * @param metadataProcessorMap the new map. */ - public void setMetadataProcessorMap(Map metadataProcessorMap) - { + public void setMetadataProcessorMap(Map metadataProcessorMap) { this.metadataProcessorMap = metadataProcessorMap; } /** * Return the metadataProcessor used to update values to make them more compliant for certain goals + * * @param metadataField to retrieve processor for * @return metadataProcessor */ - public MetadataProcessorService getMetadataProcessor(MetadataFieldConfig metadataField) - { - if(metadataProcessorMap != null) - { + public MetadataProcessorService getMetadataProcessor(MetadataFieldConfig metadataField) { + if (metadataProcessorMap != null) { return metadataProcessorMap.get(metadataField); - }else{ + } else { return null; } } @@ -69,10 +69,11 @@ public abstract class AbstractMetadataFieldMapping implements Metada public MetadatumDTO toDCValue(MetadataFieldConfig field, String value) { MetadatumDTO dcValue = new MetadatumDTO(); - if (field == null) return null; + if (field == null) { + return null; + } MetadataProcessorService metadataProcessor = getMetadataProcessor(field); - if(metadataProcessor != null) - { + if (metadataProcessor != null) { value = metadataProcessor.processMetadataValue(value); } dcValue.setValue(value); @@ -84,35 +85,40 @@ public abstract class AbstractMetadataFieldMapping implements Metada /** * Retrieve the metadataFieldMap set to this class + * * @return a map representing the metadataFieldMap */ public Map> getMetadataFieldMap() { return metadataFieldMap; } - /** Defines which metadatum is mapped on which metadatum. Note that while the key must be unique it + /** + * Defines which metadatum is mapped on which metadatum. Note that while the key must be unique it * only matters here for postprocessing of the value. The mapped MetadatumContributor has full control over * what metadatafield is generated. - * @param metadataFieldMap The map containing the link between retrieve metadata and metadata that will be set to the item. + * + * @param metadataFieldMap The map containing the link between retrieve metadata and metadata that will be set to + * the item. */ public void setMetadataFieldMap(Map> metadataFieldMap) { this.metadataFieldMap = metadataFieldMap; - for(MetadataContributor mc:metadataFieldMap.values()){ + for (MetadataContributor mc : metadataFieldMap.values()) { mc.setMetadataFieldMapping(this); } } /** * Loop over the MetadataContributors and return their concatenated retrieved metadatumDTO objects + * * @param record Used to retrieve the MetadatumDTO * @return Lit of metadatumDTO */ @Override public Collection resultToDCValueMapping(RecordType record) { - List values=new LinkedList(); + List values = new LinkedList(); - for(MetadataContributor query:getMetadataFieldMap().values()){ + for (MetadataContributor query : getMetadataFieldMap().values()) { try { values.addAll(query.contributeMetadata(record)); } catch (Exception e) { diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadataFieldConfig.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadataFieldConfig.java index 39a153fa8a..d19939248c 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadataFieldConfig.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadataFieldConfig.java @@ -21,26 +21,38 @@ public class MetadataFieldConfig { /** * Indicates whether some other object is "equal to" this one. + * * @param o the reference object with which to compare. - * @return {@code true} if this object is the same as the obj - * argument; {@code false} otherwise. + * @return {@code true} if this object is the same as the obj + * argument; {@code false} otherwise. */ @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } MetadataFieldConfig that = (MetadataFieldConfig) o; - if (!element.equals(that.element)) return false; - if (qualifier != null ? !qualifier.equals(that.qualifier) : that.qualifier != null) return false; - if (!schema.equals(that.schema)) return false; + if (!element.equals(that.element)) { + return false; + } + if (qualifier != null ? !qualifier.equals(that.qualifier) : that.qualifier != null) { + return false; + } + if (!schema.equals(that.schema)) { + return false; + } return true; } /** * Create the String representation of the MetadataFieldConfig + * * @return a string representation of the MetadataFieldConfig */ @Override @@ -58,7 +70,8 @@ public class MetadataFieldConfig { * Returns a hash code value for the object. This method is * supported for the benefit of hash tables such as those provided by * {@link java.util.HashMap}. - * @return a hash code value for this object. + * + * @return a hash code value for this object. */ @Override public int hashCode() { @@ -72,6 +85,7 @@ public class MetadataFieldConfig { /** * Create a MetadataFieldConfig based on a given MetadatumDTO * This MetadatumDTO object contains the schema, element and qualifier needed to initialize the MetadataFieldConfig + * * @param value the DTO. */ public MetadataFieldConfig(MetadatumDTO value) { @@ -88,8 +102,9 @@ public class MetadataFieldConfig { /** * Create a MetadataFieldConfig using a schema,element and qualifier - * @param schema The schema to set to this object - * @param element The element to set to this object + * + * @param schema The schema to set to this object + * @param element The element to set to this object * @param qualifier The qualifier to set to this object */ public MetadataFieldConfig(String schema, String element, String qualifier) { @@ -101,24 +116,27 @@ public class MetadataFieldConfig { /** * Create a MetadataFieldConfig using a single value. * This value is split up into schema, element and qualifier, based on a dot(.) + * * @param full A string representing the schema.element.qualifier triplet */ public MetadataFieldConfig(String full) { - String elements[]=full.split("\\."); - if(elements.length==2){ + String elements[] = full.split("\\."); + if (elements.length == 2) { this.schema = elements[0]; - this.element =elements[1]; - } else if(elements.length==3){ + this.element = elements[1]; + } else if (elements.length == 3) { this.schema = elements[0]; - this.element =elements[1]; + this.element = elements[1]; this.qualifier = elements[2]; } } + /** * Create a MetadataFieldConfig using a schema and element * qualifier will be set to null - * @param schema The schema to set to this object + * + * @param schema The schema to set to this object * @param element The element to set to this object */ public MetadataFieldConfig(String schema, String element) { @@ -129,6 +147,7 @@ public class MetadataFieldConfig { /** * Set the schema to this MetadataFieldConfig + * * @param schema The schema to set to this object */ public void setSchema(String schema) { @@ -139,6 +158,7 @@ public class MetadataFieldConfig { /** * Return the schema set to this object. * null if nothing is set + * * @return The schema of this object */ public String getSchema() { @@ -148,15 +168,17 @@ public class MetadataFieldConfig { /** * Return a string representing the field of this object + * * @return The field that is set to this object, in the form of schema.element.qualifier */ public String getField() { - return schema + "." + element + (qualifier==null?"":("." + qualifier)); + return schema + "." + element + (qualifier == null ? "" : ("." + qualifier)); } /** * Return the qualifier set to this object. * null if nothing is set + * * @return The qualifier of this object */ public String getElement() { @@ -165,6 +187,7 @@ public class MetadataFieldConfig { /** * Set the element to this MetadataFieldConfig + * * @param element The element to set to this object */ public void setElement(String element) { @@ -174,6 +197,7 @@ public class MetadataFieldConfig { /** * Return the qualifier set to this object. * null if nothing is set + * * @return The qualifier of this object */ public String getQualifier() { @@ -182,6 +206,7 @@ public class MetadataFieldConfig { /** * Set the qualifier to this MetadataFieldConfig + * * @param qualifier The qualifier to set to this object */ public void setQualifier(String qualifier) { diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadataFieldMapping.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadataFieldMapping.java index 7037a07e48..afa4334045 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadataFieldMapping.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadataFieldMapping.java @@ -15,7 +15,7 @@ import java.util.Collection; * @author Roeland Dillen (roeland at atmire dot com) */ -public interface MetadataFieldMapping { +public interface MetadataFieldMapping { /** * @param field MetadataFieldConfig representing what to map the value to @@ -27,11 +27,11 @@ public interface MetadataFieldMapping { /** * Create a collection of MetadatumDTO retrieved from a given RecordType + * * @param record Used to retrieve the MetadatumDTO * @return Collection of MetadatumDTO */ public Collection resultToDCValueMapping(RecordType record); - } diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadatumDTO.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadatumDTO.java index 2e95c5740e..265dd55eb9 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadatumDTO.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/MetadatumDTO.java @@ -9,12 +9,13 @@ package org.dspace.importer.external.metadatamapping; /** * This class is used to cary data between processes. - * Using this class, we have a uniform, generalised single Object type containing the information used by different classes. - * This Data Transfer Object contains all data for a call pertaining metadata, resulting in the possibility to return a larger quantity of information. + * Using this class, we have a uniform, generalised single Object type containing the information used by different + * classes. + * This Data Transfer Object contains all data for a call pertaining metadata, resulting in the possibility to return + * a larger quantity of information. * As this is a generalised class, we can use this across the external imports implementations * - * @author Philip Vissenaekens (philip at atmire dot com) - * + * @author Philip Vissenaekens (philip at atmire dot com) */ public class MetadatumDTO { @@ -32,6 +33,7 @@ public class MetadatumDTO { /** * Retrieve the schema set to this MetadatumDTO. * Returns null of no schema is set + * * @return metadata field schema */ public String getSchema() { @@ -40,6 +42,7 @@ public class MetadatumDTO { /** * Set the schema to this MetadatumDTO + * * @param schema metadata field schema */ public void setSchema(String schema) { @@ -49,6 +52,7 @@ public class MetadatumDTO { /** * Retrieve the element set to this MetadatumDTO. * Returns null of no element is set + * * @return metadata field element */ public String getElement() { @@ -57,6 +61,7 @@ public class MetadatumDTO { /** * Set the element to this MetadatumDTO + * * @param element metadata field element */ public void setElement(String element) { @@ -66,6 +71,7 @@ public class MetadatumDTO { /** * Retrieve the qualifier set to this MetadatumDTO. * Returns null of no qualifier is set + * * @return metadata field qualifier */ public String getQualifier() { @@ -74,6 +80,7 @@ public class MetadatumDTO { /** * Set the qualifier to this MetadatumDTO + * * @param qualifier metadata field qualifier */ public void setQualifier(String qualifier) { @@ -83,6 +90,7 @@ public class MetadatumDTO { /** * Retrieve the value set to this MetadatumDTO. * Returns null of no value is set + * * @return metadata field value */ public String getValue() { @@ -91,6 +99,7 @@ public class MetadatumDTO { /** * Set the MetadatumDTO to this value. + * * @param value metadata field value */ public void setValue(String value) { diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/CombinedMetadatumContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/CombinedMetadatumContributor.java index 026e9453f6..4b3811db69 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/CombinedMetadatumContributor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/CombinedMetadatumContributor.java @@ -7,16 +7,17 @@ */ package org.dspace.importer.external.metadatamapping.contributor; -import org.dspace.importer.external.metadatamapping.MetadataFieldConfig; -import org.dspace.importer.external.metadatamapping.MetadataFieldMapping; -import org.dspace.importer.external.metadatamapping.MetadatumDTO; - import java.util.Collection; import java.util.LinkedList; import java.util.List; +import org.dspace.importer.external.metadatamapping.MetadataFieldConfig; +import org.dspace.importer.external.metadatamapping.MetadataFieldMapping; +import org.dspace.importer.external.metadatamapping.MetadatumDTO; + /** * Wrapper class used to accommodate for the possibility of correlations between multiple MetadatumContributor objects + * * @author Philip Vissenaekens (philip at atmire dot com) */ public class CombinedMetadatumContributor implements MetadataContributor { @@ -26,7 +27,7 @@ public class CombinedMetadatumContributor implements MetadataContributor { private String separator; - private MetadataFieldMapping> metadataFieldMapping; + private MetadataFieldMapping> metadataFieldMapping; /** * Initialize an empty CombinedMetadatumContributor object @@ -35,13 +36,13 @@ public class CombinedMetadatumContributor implements MetadataContributor { } /** - * - * - * @param field {@link org.dspace.importer.external.metadatamapping.MetadataFieldConfig} used in mapping + * @param field {@link org.dspace.importer.external.metadatamapping.MetadataFieldConfig} used in + * mapping * @param metadatumContributors A list of MetadataContributor - * @param separator A separator used to differentiate between different values + * @param separator A separator used to differentiate between different values */ - public CombinedMetadatumContributor(MetadataFieldConfig field, List metadatumContributors, String separator) { + public CombinedMetadatumContributor(MetadataFieldConfig field, List metadatumContributors, + String separator) { this.field = field; this.metadatumContributors = (LinkedList) metadatumContributors; this.separator = separator; @@ -71,7 +72,7 @@ public class CombinedMetadatumContributor implements MetadataContributor { */ @Override public Collection contributeMetadata(T t) { - List values=new LinkedList<>(); + List values = new LinkedList<>(); LinkedList> metadatumLists = new LinkedList<>(); @@ -80,7 +81,7 @@ public class CombinedMetadatumContributor implements MetadataContributor { metadatumLists.add(metadatums); } - for (int i = 0; i implements MetadataContributor { /** * Set the separator used to differentiate between distinct values * - * @param separator - * separator used to differentiate between distinct values + * @param separator separator used to differentiate between distinct values */ public void setSeparator(String separator) { this.separator = separator; diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/MetadataContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/MetadataContributor.java index 34e09de96e..82992cc737 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/MetadataContributor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/MetadataContributor.java @@ -7,11 +7,11 @@ */ package org.dspace.importer.external.metadatamapping.contributor; +import java.util.Collection; + import org.dspace.importer.external.metadatamapping.MetadataFieldMapping; import org.dspace.importer.external.metadatamapping.MetadatumDTO; -import java.util.Collection; - /** * @author Roeland Dillen (roeland at atmire dot com) */ @@ -19,6 +19,7 @@ public interface MetadataContributor { /** * Set the metadataFieldMapping + * * @param rt the MetadataFieldMapping object to set to the MetadataContributor */ public void setMetadataFieldMapping(MetadataFieldMapping> rt); @@ -26,6 +27,7 @@ public interface MetadataContributor { /** * Implementations have the responsibility to process/map their own type of metadata based on a given record * and return a collection of the generalised MetadatumDTO objects + * * @param t The recordType object to retrieve metadata from * @return A collection of MetadatumDTO objects, retrieve from the recordtype */ diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleXpathMetadatumContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleXpathMetadatumContributor.java index 335ed4b075..ba5afceb5f 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleXpathMetadatumContributor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleXpathMetadatumContributor.java @@ -7,6 +7,12 @@ */ package org.dspace.importer.external.metadatamapping.contributor; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.annotation.Resource; + import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMText; @@ -17,14 +23,9 @@ import org.dspace.importer.external.metadatamapping.MetadatumDTO; import org.jaxen.JaxenException; import org.springframework.beans.factory.annotation.Required; -import javax.annotation.Resource; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - /** * Metadata contributor that takes an axiom OMElement and turns it into a metadatum + * * @author Roeland Dillen (roeland at atmire dot com) */ public class SimpleXpathMetadatumContributor implements MetadataContributor { @@ -32,51 +33,56 @@ public class SimpleXpathMetadatumContributor implements MetadataContributor getPrefixToNamespaceMapping() { return prefixToNamespaceMapping; } - private MetadataFieldMapping> metadataFieldMapping; + private MetadataFieldMapping> metadataFieldMapping; /** * Return metadataFieldMapping + * * @return MetadataFieldMapping */ - public MetadataFieldMapping> getMetadataFieldMapping() { + public MetadataFieldMapping> getMetadataFieldMapping() { return metadataFieldMapping; } /** * Set the metadataFieldMapping of this SimpleXpathMetadatumContributor + * * @param metadataFieldMapping the new mapping. */ - public void setMetadataFieldMapping(MetadataFieldMapping> metadataFieldMapping) { + public void setMetadataFieldMapping( + MetadataFieldMapping> metadataFieldMapping) { this.metadataFieldMapping = metadataFieldMapping; } /** * Set the prefixToNamespaceMapping for this object, + * * @param prefixToNamespaceMapping the new mapping. */ - @Resource(name="isiFullprefixMapping") + @Resource(name = "isiFullprefixMapping") public void setPrefixToNamespaceMapping(Map prefixToNamespaceMapping) { this.prefixToNamespaceMapping = prefixToNamespaceMapping; } - private Map prefixToNamespaceMapping; + private Map prefixToNamespaceMapping; /** * Initialize SimpleXpathMetadatumContributor with a query, prefixToNamespaceMapping and MetadataFieldConfig - * @param query - * query string - * @param prefixToNamespaceMapping - * metadata prefix to namespace mapping + * + * @param query query string + * @param prefixToNamespaceMapping metadata prefix to namespace mapping * @param field - * MetadataFieldConfig + * MetadataFieldConfig */ - public SimpleXpathMetadatumContributor(String query, Map prefixToNamespaceMapping, MetadataFieldConfig field) { + public SimpleXpathMetadatumContributor(String query, Map prefixToNamespaceMapping, + MetadataFieldConfig field) { this.query = query; this.prefixToNamespaceMapping = prefixToNamespaceMapping; this.field = field; @@ -93,6 +99,7 @@ public class SimpleXpathMetadatumContributor implements MetadataContributor contributeMetadata(OMElement t) { - List values=new LinkedList<>(); + List values = new LinkedList<>(); try { - AXIOMXPath xpath=new AXIOMXPath(query); - for(String ns:prefixToNamespaceMapping.keySet()){ - xpath.addNamespace(prefixToNamespaceMapping.get(ns),ns); + AXIOMXPath xpath = new AXIOMXPath(query); + for (String ns : prefixToNamespaceMapping.keySet()) { + xpath.addNamespace(prefixToNamespaceMapping.get(ns), ns); } - List nodes=xpath.selectNodes(t); - for(Object el:nodes) - if(el instanceof OMElement) + List nodes = xpath.selectNodes(t); + for (Object el : nodes) { + if (el instanceof OMElement) { values.add(metadataFieldMapping.toDCValue(field, ((OMElement) el).getText())); - else if(el instanceof OMAttribute){ + } else if (el instanceof OMAttribute) { values.add(metadataFieldMapping.toDCValue(field, ((OMAttribute) el).getAttributeValue())); - } else if(el instanceof String){ + } else if (el instanceof String) { values.add(metadataFieldMapping.toDCValue(field, (String) el)); - } else if(el instanceof OMText) + } else if (el instanceof OMText) { values.add(metadataFieldMapping.toDCValue(field, ((OMText) el).getText())); - else - { - System.err.println("node of type: "+el.getClass()); + } else { + System.err.println("node of type: " + el.getClass()); } + } return values; } catch (JaxenException e) { System.err.println(query); diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/package-info.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/package-info.java index 4be1bd19a6..8f73bafba3 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/package-info.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/package-info.java @@ -7,10 +7,12 @@ */ /** - * Contains the classes used to map between retrieved records and actual usable {@link org.dspace.importer.external.metadatamapping.MetadatumDTO} - * Classes are used in the spring config of implementations of {@link org.dspace.importer.external.metadatamapping.AbstractMetadataFieldMapping} + * Contains the classes used to map between retrieved records and actual usable + * {@link org.dspace.importer.external.metadatamapping.MetadatumDTO} + * Classes are used in the spring config of implementations of + * {@link org.dspace.importer.external.metadatamapping.AbstractMetadataFieldMapping} * which query to an element in the retrieved record and map it to a metadatafield. * @author Roeland Dillen (roeland at atmire dot com) * @author Jonas Van Goolen (jonas at atmire dot com) */ -package org.dspace.importer.external.metadatamapping.contributor; \ No newline at end of file +package org.dspace.importer.external.metadatamapping.contributor; diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/transform/AuthorMetadataProcessorService.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/transform/AuthorMetadataProcessorService.java index af649a6901..948075d9dc 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/transform/AuthorMetadataProcessorService.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/transform/AuthorMetadataProcessorService.java @@ -18,14 +18,15 @@ public class AuthorMetadataProcessorService implements MetadataProcessorService /** * Strip a given value of its last dot (.) + * * @param value the value to run the processing over * @return The initial param with its ending dot stripped */ @Override public String processMetadataValue(String value) { - String ret=value; - ret= StringUtils.strip(ret); - ret= StringUtils.stripEnd(ret, "."); + String ret = value; + ret = StringUtils.strip(ret); + ret = StringUtils.stripEnd(ret, "."); return ret; } diff --git a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/PubmedFieldMapping.java b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/PubmedFieldMapping.java index 89d57bbd19..2d31537766 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/PubmedFieldMapping.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/PubmedFieldMapping.java @@ -8,10 +8,10 @@ package org.dspace.importer.external.pubmed.metadatamapping; -import org.dspace.importer.external.metadatamapping.AbstractMetadataFieldMapping; - -import javax.annotation.Resource; import java.util.Map; +import javax.annotation.Resource; + +import org.dspace.importer.external.metadatamapping.AbstractMetadataFieldMapping; /** * An implementation of {@link AbstractMetadataFieldMapping} @@ -21,13 +21,16 @@ import java.util.Map; */ public class PubmedFieldMapping extends AbstractMetadataFieldMapping { - /** Defines which metadatum is mapped on which metadatum. Note that while the key must be unique it + /** + * Defines which metadatum is mapped on which metadatum. Note that while the key must be unique it * only matters here for postprocessing of the value. The mapped MetadatumContributor has full control over * what metadatafield is generated. - * @param metadataFieldMap The map containing the link between retrieve metadata and metadata that will be set to the item. + * + * @param metadataFieldMap The map containing the link between retrieve metadata and metadata that will be set to + * the item. */ @Override - @Resource (name = "pubmedMetadataFieldMap") + @Resource(name = "pubmedMetadataFieldMap") public void setMetadataFieldMap(Map metadataFieldMap) { super.setMetadataFieldMap(metadataFieldMap); } diff --git a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/contributor/PubmedDateMetadatumContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/contributor/PubmedDateMetadatumContributor.java index 2a50dcd832..dea509f470 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/contributor/PubmedDateMetadatumContributor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/contributor/PubmedDateMetadatumContributor.java @@ -8,6 +8,13 @@ package org.dspace.importer.external.pubmed.metadatamapping.contributor; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.content.DCDate; import org.dspace.importer.external.metadatamapping.MetadataFieldConfig; @@ -16,13 +23,6 @@ import org.dspace.importer.external.metadatamapping.MetadatumDTO; import org.dspace.importer.external.metadatamapping.contributor.MetadataContributor; import org.springframework.beans.factory.annotation.Required; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Collection; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - /** * Pubmed specific implementation of {@link MetadataContributor} * Responsible for generating a set of Date metadata from the retrieved document. @@ -55,6 +55,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Set the metadatafieldMapping used in the transforming of a record to actual metadata. + * * @param metadataFieldMapping the new mapping. */ @Override @@ -64,6 +65,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor month.setMetadataFieldMapping(metadataFieldMapping); year.setMetadataFieldMapping(metadataFieldMapping); } + /** * Initialize an empty PubmedDateMetadatumContributor object */ @@ -71,13 +73,13 @@ public class PubmedDateMetadatumContributor implements MetadataContributor } /** - * * @param field {@link org.dspace.importer.external.metadatamapping.MetadataFieldConfig} used in mapping - * @param day a MetadataContributor, representing a day + * @param day a MetadataContributor, representing a day * @param month a {@link MetadataContributor}, representing a month - * @param year a {@link MetadataContributor}, representing a year + * @param year a {@link MetadataContributor}, representing a year */ - public PubmedDateMetadatumContributor(MetadataFieldConfig field, MetadataContributor day, MetadataContributor month, MetadataContributor year) { + public PubmedDateMetadatumContributor(MetadataFieldConfig field, MetadataContributor day, MetadataContributor month, + MetadataContributor year) { this.field = field; this.day = day; this.month = month; @@ -86,8 +88,11 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Retrieve the metadata associated with the given object. - * The code will loop over the different dates and attempt to format them using the configured dateFormats to attempt. - * For each date, once a format is successful, this result is used. Make sure that dateFormatsToAttempt is configured from most restrictive to most lenient to try and get the most precise result + * The code will loop over the different dates and attempt to format them using the configured dateFormats to + * attempt. + * For each date, once a format is successful, this result is used. Make sure that dateFormatsToAttempt is + * configured from most restrictive to most lenient to try and get the most precise result + * * @param t A class to retrieve metadata from. * @return a collection of import records. Only the identifier of the found records may be put in the record. */ @@ -106,24 +111,28 @@ public class PubmedDateMetadatumContributor implements MetadataContributor String dateString = ""; if (monthList.size() > i && dayList.size() > i) { - dateString = yearList.get(i).getValue() + "-" + monthList.get(i).getValue() + "-" + dayList.get(i).getValue(); + dateString = yearList.get(i).getValue() + "-" + monthList.get(i).getValue() + + "-" + dayList.get(i).getValue(); } else if (monthList.size() > i) { dateString = yearList.get(i).getValue() + "-" + monthList.get(i).getValue(); } else { dateString = yearList.get(i).getValue(); } - int j = 0 ; + int j = 0; // Use the first dcDate that has been formatted (Config should go from most specific to most lenient) - while (j implements MetadataContributor /** * Return the MetadataFieldConfig used while retrieving MetadatumDTO + * * @return MetadataFieldConfig */ public MetadataFieldConfig getField() { @@ -148,6 +158,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Setting the MetadataFieldConfig + * * @param field MetadataFieldConfig used while retrieving MetadatumDTO */ public void setField(MetadataFieldConfig field) { @@ -156,6 +167,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Retrieve the day from the object + * * @return {@link MetadataContributor}, representing a day */ public MetadataContributor getDay() { @@ -164,6 +176,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Set a day ({@link MetadataContributor}) to this object + * * @param day a {@link MetadataContributor}, representing a day */ public void setDay(MetadataContributor day) { @@ -172,6 +185,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Retrieve the month from the object + * * @return {@link MetadataContributor}, representing a month */ public MetadataContributor getMonth() { @@ -180,6 +194,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Set a month ({@link MetadataContributor}) to this object + * * @param month a {@link MetadataContributor}, representing a month */ public void setMonth(MetadataContributor month) { @@ -188,6 +203,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Retrieve the year from the object + * * @return {@link MetadataContributor}, representing a year */ public MetadataContributor getYear() { @@ -196,6 +212,7 @@ public class PubmedDateMetadatumContributor implements MetadataContributor /** * Set a year ({@link MetadataContributor}) to this object + * * @param year a {@link MetadataContributor}, representing a year */ public void setYear(MetadataContributor year) { diff --git a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/contributor/PubmedLanguageMetadatumContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/contributor/PubmedLanguageMetadatumContributor.java index 1163e85842..82da062036 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/contributor/PubmedLanguageMetadatumContributor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/contributor/PubmedLanguageMetadatumContributor.java @@ -7,14 +7,19 @@ */ package org.dspace.importer.external.pubmed.metadatamapping.contributor; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + import org.apache.log4j.Logger; import org.dspace.importer.external.metadatamapping.MetadataFieldConfig; import org.dspace.importer.external.metadatamapping.MetadataFieldMapping; import org.dspace.importer.external.metadatamapping.MetadatumDTO; import org.dspace.importer.external.metadatamapping.contributor.MetadataContributor; -import java.util.*; - /** * Pubmed specific implementation of {@link MetadataContributor} * Responsible for generating a set of Language metadata from the retrieved document. @@ -24,27 +29,30 @@ import java.util.*; public class PubmedLanguageMetadatumContributor implements MetadataContributor { Logger log = Logger.getLogger(PubmedDateMetadatumContributor.class); - private MetadataFieldMapping> metadataFieldMapping; - private HashMap iso3toIso2; + private MetadataFieldMapping> metadataFieldMapping; + private HashMap iso3toIso2; private MetadataFieldConfig field; private MetadataContributor language; /** - * Initialize PubmedLanguageMetadatumContributor and create the iso3toiso2 mapping used in the transforming of language codes + * Initialize PubmedLanguageMetadatumContributor and create the iso3toiso2 mapping used in the transforming of + * language codes */ public PubmedLanguageMetadatumContributor() { iso3toIso2 = new HashMap<>(); // Populate the languageMap with the mapping between iso3 and iso2 language codes for (Locale locale : Locale.getAvailableLocales()) { - iso3toIso2.put(locale.getISO3Language(),locale.getLanguage()); + iso3toIso2.put(locale.getISO3Language(), locale.getLanguage()); } } /** - * Initialize the PubmedLanguageMetadatumContributor class using a {@link org.dspace.importer.external.metadatamapping.MetadataFieldConfig} and a language -{@link org.dspace.importer.external.metadatamapping.contributor.MetadataContributor} + * Initialize the PubmedLanguageMetadatumContributor class using a + * {@link org.dspace.importer.external.metadatamapping.MetadataFieldConfig} and a language + * -{@link org.dspace.importer.external.metadatamapping.contributor.MetadataContributor} * - * @param field {@link org.dspace.importer.external.metadatamapping.MetadataFieldConfig} used in mapping + * @param field {@link org.dspace.importer.external.metadatamapping.MetadataFieldConfig} used in mapping * @param language the language. */ public PubmedLanguageMetadatumContributor(MetadataFieldConfig field, MetadataContributor language) { @@ -65,8 +73,6 @@ public class PubmedLanguageMetadatumContributor implements MetadataContributo } /** - * - * * @param t A class to retrieve metadata from. * @return a collection of import records. Only the identifier of the found records may be put in the record. */ diff --git a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/transform/GeneratePubmedQueryService.java b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/transform/GeneratePubmedQueryService.java index c35aa15ab5..eb7211fbdf 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/transform/GeneratePubmedQueryService.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/metadatamapping/transform/GeneratePubmedQueryService.java @@ -8,16 +8,16 @@ package org.dspace.importer.external.pubmed.metadatamapping.transform; +import java.util.List; + import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; -import org.dspace.importer.external.exception.MetadataSourceException; import org.dspace.importer.external.datamodel.Query; +import org.dspace.importer.external.exception.MetadataSourceException; import org.dspace.importer.external.metadatamapping.transform.GenerateQueryService; -import java.util.List; - /** * This class is an implementation of {@link GenerateQueryService} * Represents a service that generates the pubmed query which is used to retrieve the records. @@ -33,6 +33,7 @@ public class GeneratePubmedQueryService implements GenerateQueryService { * If the item has at least 1 value for dc.identifier.doi, the first one will be used. * If no DOI is found, the title will be used. * When no DOI or title is found, an null object is returned instead. + * * @param item the Item to create a Query from */ @Override @@ -43,17 +44,17 @@ public class GeneratePubmedQueryService implements GenerateQueryService { ItemService itemService = ContentServiceFactory.getInstance().getItemService(); List doi = itemService.getMetadata(item, "dc", "identifier", "doi", Item.ANY); - if(doi.size()>0){ + if (doi.size() > 0) { query.addParameter("term", doi.get(0).getValue()); - query.addParameter("field","ELocationID"); + query.addParameter("field", "ELocationID"); return query; } List title = itemService.getMetadata(item, "dc", "title", null, Item.ANY); - if(title.size()>0) { + if (title.size() > 0) { query.addParameter("term", title.get(0).getValue()); - query.addParameter("field","title"); + query.addParameter("field", "title"); return query; } return null; diff --git a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/service/PubmedImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/service/PubmedImportMetadataSourceServiceImpl.java index 8311096d10..bcb5034301 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/pubmed/service/PubmedImportMetadataSourceServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/pubmed/service/PubmedImportMetadataSourceServiceImpl.java @@ -8,28 +8,28 @@ package org.dspace.importer.external.pubmed.service; -import org.apache.axiom.om.OMElement; -import org.apache.axiom.om.OMXMLBuilderFactory; -import org.apache.axiom.om.OMXMLParserWrapper; -import org.apache.axiom.om.xpath.AXIOMXPath; -import org.dspace.content.Item; -import org.dspace.importer.external.exception.MetadataSourceException; -import org.dspace.importer.external.datamodel.Query; -import org.dspace.importer.external.datamodel.ImportRecord; -import org.dspace.importer.external.service.AbstractImportMetadataSourceService; -import org.jaxen.JaxenException; - +import java.io.StringReader; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Callable; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.io.StringReader; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Callable; + +import org.apache.axiom.om.OMElement; +import org.apache.axiom.om.OMXMLBuilderFactory; +import org.apache.axiom.om.OMXMLParserWrapper; +import org.apache.axiom.om.xpath.AXIOMXPath; +import org.dspace.content.Item; +import org.dspace.importer.external.datamodel.ImportRecord; +import org.dspace.importer.external.datamodel.Query; +import org.dspace.importer.external.exception.MetadataSourceException; +import org.dspace.importer.external.service.AbstractImportMetadataSourceService; +import org.jaxen.JaxenException; /** * Implements a data source for querying PubMed Central @@ -66,7 +66,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat } /** - * Find the number of records matching a string query. Supports pagination + * Find the number of records matching a string query. Supports pagination * * @param query a query string to base the search on. * @param start offset to start at @@ -122,7 +122,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat */ @Override public String getImportSource() { - return "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/"; + return "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/"; } /** @@ -139,7 +139,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat /** * Finds records based on query object. - * Delegates to one or more MetadataSource implementations based on the uri. Results will be aggregated. + * Delegates to one or more MetadataSource implementations based on the uri. Results will be aggregated. * * @param query a query object to base the search on. * @return a collection of import records. Only the identifier of the found records may be put in the record. @@ -184,7 +184,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat private GetNbRecords(String queryString) { query = new Query(); - query.addParameter("query",queryString); + query.addParameter("query", queryString); } private Query query; @@ -195,7 +195,8 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat @Override public Integer call() throws Exception { - WebTarget getRecordIdsTarget = pubmedWebTarget.queryParam("term", query.getParameterAsClass("query", String.class)); + WebTarget getRecordIdsTarget = pubmedWebTarget + .queryParam("term", query.getParameterAsClass("query", String.class)); getRecordIdsTarget = getRecordIdsTarget.path("esearch.fcgi"); @@ -212,7 +213,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat } - private String getSingleElementValue(String src, String elementName){ + private String getSingleElementValue(String src, String elementName) { OMXMLParserWrapper records = OMXMLBuilderFactory.createOMBuilder(new StringReader(src)); OMElement element = records.getDocumentElement(); AXIOMXPath xpath = null; @@ -220,7 +221,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat try { xpath = new AXIOMXPath("//" + elementName); List recordsList = xpath.selectNodes(element); - if(!recordsList.isEmpty()) { + if (!recordsList.isEmpty()) { value = recordsList.get(0).getText(); } } catch (JaxenException e) { @@ -235,9 +236,9 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat private GetRecords(String queryString, int start, int count) { query = new Query(); - query.addParameter("query",queryString); - query.addParameter("start",start); - query.addParameter("count",count); + query.addParameter("query", queryString); + query.addParameter("start", start); + query.addParameter("count", count); } private GetRecords(Query q) { @@ -246,15 +247,15 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat @Override public Collection call() throws Exception { - String queryString = query.getParameterAsClass("query",String.class); - Integer start = query.getParameterAsClass("start",Integer.class); - Integer count = query.getParameterAsClass("count",Integer.class); + String queryString = query.getParameterAsClass("query", String.class); + Integer start = query.getParameterAsClass("start", Integer.class); + Integer count = query.getParameterAsClass("count", Integer.class); - if(count==null || count < 0){ + if (count == null || count < 0) { count = 10; } - if(start==null || start < 0){ + if (start == null || start < 0) { start = 0; } @@ -313,7 +314,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat private GetRecord(String id) { query = new Query(); - query.addParameter("id",id); + query.addParameter("id", id); } public GetRecord(Query q) { @@ -334,7 +335,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat List omElements = splitToRecords(response.readEntity(String.class)); - if(omElements.size()==0) { + if (omElements.size() == 0) { return null; } @@ -346,7 +347,7 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat private Query query; - private FindMatchingRecords(Item item) throws MetadataSourceException { + private FindMatchingRecords(Item item) throws MetadataSourceException { query = getGenerateQueryForItem().generateQueryForItem(item); } @@ -358,8 +359,10 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat public Collection call() throws Exception { List records = new LinkedList(); - WebTarget getRecordIdsTarget = pubmedWebTarget.queryParam("term", query.getParameterAsClass("term", String.class)); - getRecordIdsTarget = getRecordIdsTarget.queryParam("field", query.getParameterAsClass("field",String.class)); + WebTarget getRecordIdsTarget = pubmedWebTarget + .queryParam("term", query.getParameterAsClass("term", String.class)); + getRecordIdsTarget = getRecordIdsTarget + .queryParam("field", query.getParameterAsClass("field", String.class)); getRecordIdsTarget = getRecordIdsTarget.queryParam("usehistory", "y"); getRecordIdsTarget = getRecordIdsTarget.path("esearch.fcgi"); diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/AbstractImportMetadataSourceService.java b/dspace-api/src/main/java/org/dspace/importer/external/service/AbstractImportMetadataSourceService.java index cc876b8d87..a803958a9d 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/AbstractImportMetadataSourceService.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/AbstractImportMetadataSourceService.java @@ -8,36 +8,39 @@ package org.dspace.importer.external.service; +import java.util.LinkedList; + import org.dspace.importer.external.datamodel.ImportRecord; import org.dspace.importer.external.metadatamapping.MetadataFieldMapping; import org.dspace.importer.external.metadatamapping.contributor.MetadataContributor; -import org.dspace.importer.external.service.components.MetadataSource; -import org.dspace.importer.external.service.components.AbstractRemoteMetadataSource; import org.dspace.importer.external.metadatamapping.transform.GenerateQueryService; +import org.dspace.importer.external.service.components.AbstractRemoteMetadataSource; +import org.dspace.importer.external.service.components.MetadataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; -import java.util.LinkedList; - /** - * This class is a partial implementation of {@link MetadataSource}. It provides assistance with mapping metadata from source format to DSpace format. + * This class is a partial implementation of {@link MetadataSource}. It provides assistance with mapping metadata + * from source format to DSpace format. * AbstractImportSourceService has a generic type set 'RecordType'. - * In the importer implementation this type set should be the class of the records received from the remote source's response. + * In the importer implementation this type set should be the class of the records received from the remote source's + * response. * * @author Roeland Dillen (roeland at atmire dot com) - * */ -public abstract class AbstractImportMetadataSourceService extends AbstractRemoteMetadataSource implements MetadataSource { - private GenerateQueryService generateQueryForItem = null; - private MetadataFieldMapping> metadataFieldMapping; +public abstract class AbstractImportMetadataSourceService extends AbstractRemoteMetadataSource + implements MetadataSource { + private GenerateQueryService generateQueryForItem = null; + private MetadataFieldMapping> metadataFieldMapping; /** * Retrieve the {@link GenerateQueryService} + * * @return A GenerateForQueryService object set to this class */ - public GenerateQueryService getGenerateQueryForItem() { - return generateQueryForItem; - } + public GenerateQueryService getGenerateQueryForItem() { + return generateQueryForItem; + } /** * Set the {@link GenerateQueryService} used to create a @@ -47,34 +50,37 @@ public abstract class AbstractImportMetadataSourceService extends Ab * @param generateQueryForItem the query generator to be used. */ @Autowired - public void setGenerateQueryForItem(GenerateQueryService generateQueryForItem) { - this.generateQueryForItem = generateQueryForItem; - } + public void setGenerateQueryForItem(GenerateQueryService generateQueryForItem) { + this.generateQueryForItem = generateQueryForItem; + } /** * Retrieve the MetadataFieldMapping containing the mapping between RecordType and Metadata + * * @return The configured MetadataFieldMapping */ - public MetadataFieldMapping> getMetadataFieldMapping() { - return metadataFieldMapping; - } + public MetadataFieldMapping> getMetadataFieldMapping() { + return metadataFieldMapping; + } /** * Sets the MetadataFieldMapping to base the mapping of RecordType and + * * @param metadataFieldMapping the map to be used. */ - @Required - public void setMetadataFieldMapping( - MetadataFieldMapping> metadataFieldMapping) { - this.metadataFieldMapping = metadataFieldMapping; - } + @Required + public void setMetadataFieldMapping( + MetadataFieldMapping> metadataFieldMapping) { + this.metadataFieldMapping = metadataFieldMapping; + } /** - * Return an ImportRecord constructed from the results in a RecordType + * Return an ImportRecord constructed from the results in a RecordType + * * @param recordType The record type to retrieve the DCValueMapping from * @return An {@link ImportRecord}, This is based on the results retrieved from the recordTypeMapping */ - public ImportRecord transformSourceRecords(RecordType recordType){ - return new ImportRecord(new LinkedList<>(getMetadataFieldMapping().resultToDCValueMapping(recordType))); - } + public ImportRecord transformSourceRecords(RecordType recordType) { + return new ImportRecord(new LinkedList<>(getMetadataFieldMapping().resultToDCValueMapping(recordType))); + } } diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/ImportService.java b/dspace-api/src/main/java/org/dspace/importer/external/service/ImportService.java index 7047c80d4f..74f6b26a77 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/ImportService.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/ImportService.java @@ -8,21 +8,29 @@ package org.dspace.importer.external.service; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + import org.apache.log4j.Logger; import org.dspace.content.Item; -import org.dspace.importer.external.exception.MetadataSourceException; -import org.dspace.importer.external.datamodel.Query; import org.dspace.importer.external.datamodel.ImportRecord; +import org.dspace.importer.external.datamodel.Query; +import org.dspace.importer.external.exception.MetadataSourceException; import org.dspace.importer.external.service.components.Destroyable; import org.dspace.importer.external.service.components.MetadataSource; import org.springframework.beans.factory.annotation.Autowired; -import java.util.*; - -/** Main entry point for the import framework. +/** + * Main entry point for the import framework. * Instead of calling the different importer implementations, the ImportService should be called instead. * This class contains the same methods as the other implementations, but has an extra parameter URL. - * This URL should be the same identifier that is returned by the "getImportSource" method that is defined in the importer implementation you want to use. + * This URL should be the same identifier that is returned by the "getImportSource" method that is defined in the + * importer implementation you want to use. + * * @author Roeland Dillen (roeland at atmire dot com) */ public class ImportService implements Destroyable { @@ -41,6 +49,7 @@ public class ImportService implements Destroyable { /** * Sets the importsources that will be used to delegate the retrieving and matching of records to + * * @param importSources A list of {@link MetadataSource} to set to this service * @throws MetadataSourceException if the underlying methods throw any exception. */ @@ -55,7 +64,8 @@ public class ImportService implements Destroyable { /** * Retrieve the importSources set to this class. - * @return An unmodifiableMap of importSources + * + * @return An unmodifiableMap of importSources */ protected Map getImportSources() { return Collections.unmodifiableMap(importSources); @@ -63,6 +73,7 @@ public class ImportService implements Destroyable { /** * Utility method to find what import implementations match the imports uri. + * * @param uri the identifier of the import implementation or * for all * @return matching MetadataSource implementations */ @@ -70,16 +81,19 @@ public class ImportService implements Destroyable { if (ANY.equals(uri)) { return importSources.values(); } else { - if(importSources.containsKey(uri)) + if (importSources.containsKey(uri)) { return Collections.singletonList(importSources.get(uri)); - else + } else { return Collections.emptyList(); + } } } - /** Finds records based on an item + /** + * Finds records based on an item * Delegates to one or more MetadataSource implementations based on the uri. Results will be aggregated. - * @param uri the identifier of the import implementation or * for all + * + * @param uri the identifier of the import implementation or * for all * @param item an item to base the search on * @return a collection of import records. Only the identifier of the found records may be put in the record. * @throws MetadataSourceException if the underlying methods throw any exception. @@ -98,9 +112,11 @@ public class ImportService implements Destroyable { } } - /** Finds records based on query object. - * Delegates to one or more MetadataSource implementations based on the uri. Results will be aggregated. - * @param uri the identifier of the import implementation or * for all + /** + * Finds records based on query object. + * Delegates to one or more MetadataSource implementations based on the uri. Results will be aggregated. + * + * @param uri the identifier of the import implementation or * for all * @param query a query object to base the search on. The implementation decides how the query is interpreted. * @return a collection of import records. Only the identifier of the found records may be put in the record. * @throws MetadataSourceException if the underlying methods throw any exception. @@ -118,9 +134,10 @@ public class ImportService implements Destroyable { } } - /** Find the number of records matching a string query; + /** + * Find the number of records matching a string query; * - * @param uri the identifier of the import implementation or * for all + * @param uri the identifier of the import implementation or * for all * @param query a query to base the search on * @return the sum of the matching records over all import sources * @throws MetadataSourceException if the underlying methods throw any exception. @@ -136,9 +153,11 @@ public class ImportService implements Destroyable { throw new MetadataSourceException(e); } } - /** Find the number of records matching a query; + + /** + * Find the number of records matching a query; * - * @param uri the identifier of the import implementation or * for all + * @param uri the identifier of the import implementation or * for all * @param query a query object to base the search on The implementation decides how the query is interpreted. * @return the sum of the matching records over all import sources * @throws MetadataSourceException if the underlying methods throw any exception. @@ -155,16 +174,18 @@ public class ImportService implements Destroyable { } } - /** Find the number of records matching a string query. Supports pagination + /** + * Find the number of records matching a string query. Supports pagination * - * @param uri the identifier of the import implementation or * for all + * @param uri the identifier of the import implementation or * for all * @param query a query object to base the search on. The implementation decides how the query is interpreted. * @param start offset to start at * @param count number of records to retrieve. * @return a set of records. Fully transformed. * @throws MetadataSourceException if the underlying methods throw any exception. */ - public Collection getRecords(String uri, String query, int start, int count) throws MetadataSourceException { + public Collection getRecords(String uri, String query, int start, int count) + throws MetadataSourceException { try { List recordList = new LinkedList<>(); for (MetadataSource metadataSource : matchingImports(uri)) { @@ -176,9 +197,10 @@ public class ImportService implements Destroyable { } } - /** Find the number of records matching a object query. + /** + * Find the number of records matching a object query. * - * @param uri the identifier of the import implementation or * for all + * @param uri the identifier of the import implementation or * for all * @param query a query object to base the search on. The implementation decides how the query is interpreted. * @return a set of records. Fully transformed. * @throws MetadataSourceException if the underlying methods throw any exception. @@ -195,27 +217,34 @@ public class ImportService implements Destroyable { } } - /** Get a single record from a source. + /** + * Get a single record from a source. * The first match will be returned + * * @param uri uri the identifier of the import implementation or * for all - * @param id identifier for the record + * @param id identifier for the record * @return a matching record * @throws MetadataSourceException if the underlying methods throw any exception. */ public ImportRecord getRecord(String uri, String id) throws MetadataSourceException { try { for (MetadataSource metadataSource : matchingImports(uri)) { - if (metadataSource.getRecord(id) != null) return metadataSource.getRecord(id); - + if (metadataSource.getRecord(id) != null) { + return metadataSource.getRecord(id); + } + } return null; } catch (Exception e) { throw new MetadataSourceException(e); } } - /** Get a single record from the source. + + /** + * Get a single record from the source. * The first match will be returned - * @param uri uri the identifier of the import implementation or * for all + * + * @param uri uri the identifier of the import implementation or * for all * @param query a query matching a single record * @return a matching record * @throws MetadataSourceException if the underlying methods throw any exception. @@ -223,8 +252,10 @@ public class ImportService implements Destroyable { public ImportRecord getRecord(String uri, Query query) throws MetadataSourceException { try { for (MetadataSource metadataSource : matchingImports(uri)) { - if (metadataSource.getRecord(query) != null) return metadataSource.getRecord(query); - + if (metadataSource.getRecord(query) != null) { + return metadataSource.getRecord(query); + } + } return null; } catch (Exception e) { @@ -232,19 +263,24 @@ public class ImportService implements Destroyable { } } - /** Retrieve the importUrls that are set on the importSources . - * @return a Collection of string, representing the configured importUrls + /** + * Retrieve the importUrls that are set on the importSources . + * + * @return a Collection of string, representing the configured importUrls */ public Collection getImportUrls() { return importSources.keySet(); } - /** Call destroy on all {@link Destroyable} {@link MetadataSource} objects set in this ImportService + /** + * Call destroy on all {@link Destroyable} {@link MetadataSource} objects set in this ImportService */ @Override public void destroy() throws Exception { for (MetadataSource metadataSource : importSources.values()) { - if (metadataSource instanceof Destroyable) ((Destroyable) metadataSource).destroy(); + if (metadataSource instanceof Destroyable) { + ((Destroyable) metadataSource).destroy(); + } } } } diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/components/AbstractRemoteMetadataSource.java b/dspace-api/src/main/java/org/dspace/importer/external/service/components/AbstractRemoteMetadataSource.java index b683255579..a0340236c5 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/components/AbstractRemoteMetadataSource.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/components/AbstractRemoteMetadataSource.java @@ -8,23 +8,24 @@ package org.dspace.importer.external.service.components; -import org.apache.log4j.Logger; -import org.dspace.importer.external.exception.MetadataSourceException; -import org.dspace.importer.external.exception.SourceExceptionHandler; - -import javax.annotation.Resource; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.locks.ReentrantLock; +import javax.annotation.Resource; + +import org.apache.log4j.Logger; +import org.dspace.importer.external.exception.MetadataSourceException; +import org.dspace.importer.external.exception.SourceExceptionHandler; /** * This class contains primitives to handle request timeouts and to retry requests. * This is achieved by classifying exceptions as fatal or as non fatal/retryable. * Evidently only subclasses can make the proper determination of what is retryable and what isn't. * This is useful in case the service employs throttling and to deal with general network issues. + * * @author Roeland Dillen (roeland at atmire dot com) * @author Antoine Snyers (antoine at atmire dot com) */ @@ -51,7 +52,7 @@ public abstract class AbstractRemoteMetadataSource { } /** - * initialize the exceptionHandlersMap with an empty {@link java.util.LinkedHashMap} + * initialize the exceptionHandlersMap with an empty {@link java.util.LinkedHashMap} */ protected void initExceptionHandlers() { exceptionHandlersMap = new LinkedHashMap<>(); @@ -71,8 +72,7 @@ public abstract class AbstractRemoteMetadataSource { /** * Set the warning message used for logging * - * @param warning - * warning message + * @param warning warning message */ public void setWarning(String warning) { this.warning = warning; @@ -86,6 +86,7 @@ public abstract class AbstractRemoteMetadataSource { public int getRetry() { return retry; } + /** * Return the number of max retries that can be undertaken before separate functionality kicks in * @@ -98,10 +99,9 @@ public abstract class AbstractRemoteMetadataSource { /** * Set the number of maximum retries before throwing on the exception * - * @param maxRetry - * maximum number of retries + * @param maxRetry maximum number of retries */ - @Resource(name="maxRetry") + @Resource(name = "maxRetry") public void setMaxRetry(int maxRetry) { this.maxRetry = maxRetry; } @@ -147,7 +147,8 @@ public abstract class AbstractRemoteMetadataSource { * the public methods of this class. * @param return type. Generics for type safety. * @return The result of the call - * @throws org.dspace.importer.external.exception.MetadataSourceException if something unrecoverable happens (e.g. network failures) + * @throws org.dspace.importer.external.exception.MetadataSourceException if something unrecoverable happens (e.g + * . network failures) */ protected T retry(Callable callable) throws MetadataSourceException { @@ -185,7 +186,7 @@ public abstract class AbstractRemoteMetadataSource { lock.unlock(); } - try{ + try { Thread.sleep(1000L); } catch (InterruptedException e) { throwSourceException(retry, e, operationId); @@ -196,10 +197,11 @@ public abstract class AbstractRemoteMetadataSource { } /** - * Handles a given exception or throws on a {@link org.dspace.importer.external.exception.MetadataSourceException} if no ExceptionHandler is set + * Handles a given exception or throws on a + * {@link org.dspace.importer.external.exception.MetadataSourceException} if no ExceptionHandler is set * - * @param retry The number of retries before the exception was thrown on - * @param exception The exception to handle + * @param retry The number of retries before the exception was thrown on + * @param exception The exception to handle * @param operationId The id of the operation that threw the exception * @throws MetadataSourceException if no ExceptionHandler is configured for the given exception */ @@ -218,7 +220,8 @@ public abstract class AbstractRemoteMetadataSource { /** * Retrieve a list of SourceExceptionHandler objects that have an instanceof the exception configured to them. * - * @param exception The exception to base the retrieval of {@link org.dspace.importer.external.exception.SourceExceptionHandler} on + * @param exception The exception to base the retrieval of + * {@link org.dspace.importer.external.exception.SourceExceptionHandler} on * @return a list of {@link org.dspace.importer.external.exception.SourceExceptionHandler} objects */ protected List getExceptionHandler(Exception exception) { @@ -233,14 +236,15 @@ public abstract class AbstractRemoteMetadataSource { /** * Throw a {@link MetadataSourceException} * - * @param retry The number of retries before the exception was thrown on - * @param exception The exception to throw + * @param retry The number of retries before the exception was thrown on + * @param exception The exception to throw * @param operationId The id of the operation that threw the exception * @throws MetadataSourceException if no ExceptionHandler is configured for the given exception */ - protected void throwSourceException(int retry, Exception exception, String operationId) throws MetadataSourceException { + protected void throwSourceException(int retry, Exception exception, String operationId) + throws MetadataSourceException { throwSourceExceptionHook(); - log.error("Source exception " + exception.getMessage(),exception); + log.error("Source exception " + exception.getMessage(), exception); throw new MetadataSourceException("At retry of operation " + operationId + " " + retry, exception); } diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/components/MetadataSource.java b/dspace-api/src/main/java/org/dspace/importer/external/service/components/MetadataSource.java index 813cc1e043..79bdcfa903 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/components/MetadataSource.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/components/MetadataSource.java @@ -8,26 +8,31 @@ package org.dspace.importer.external.service.components; -import org.dspace.content.Item; -import org.dspace.importer.external.exception.MetadataSourceException; -import org.dspace.importer.external.datamodel.Query; -import org.dspace.importer.external.datamodel.ImportRecord; - import java.util.Collection; -/** Common interface for all import implementations. +import org.dspace.content.Item; +import org.dspace.importer.external.datamodel.ImportRecord; +import org.dspace.importer.external.datamodel.Query; +import org.dspace.importer.external.exception.MetadataSourceException; + +/** + * Common interface for all import implementations. + * * @author Roeland Dillen (roeland at atmire dot com) */ public interface MetadataSource { /** * Gets the number of records matching a query + * * @param query the query in string format * @return the number of records matching the query * @throws MetadataSourceException if the underlying methods throw any exception. */ public int getNbRecords(String query) throws MetadataSourceException; + /** * Gets the number of records matching a query + * * @param query the query object * @return the number of records matching the query * @throws MetadataSourceException if the underlying methods throw any exception. @@ -36,54 +41,65 @@ public interface MetadataSource { /** * Gets a set of records matching a query. Supports pagination + * * @param query the query. The query will generally be posted 'as is' to the source * @param start offset * @param count page size * @return a collection of fully transformed id's * @throws MetadataSourceException if the underlying methods throw any exception. */ - public Collection getRecords(String query, int start, int count)throws MetadataSourceException; + public Collection getRecords(String query, int start, int count) throws MetadataSourceException; - /** Find records based on a object query. + /** + * Find records based on a object query. * * @param query a query object to base the search on. * @return a set of records. Fully transformed. * @throws MetadataSourceException if the underlying methods throw any exception. */ - public Collection getRecords(Query query)throws MetadataSourceException; + public Collection getRecords(Query query) throws MetadataSourceException; - /** Get a single record from the source. + /** + * Get a single record from the source. * The first match will be returned + * * @param id identifier for the record * @return a matching record * @throws MetadataSourceException if the underlying methods throw any exception. */ - public ImportRecord getRecord(String id)throws MetadataSourceException; + public ImportRecord getRecord(String id) throws MetadataSourceException; - /** Get a single record from the source. + /** + * Get a single record from the source. * The first match will be returned + * * @param query a query matching a single record * @return a matching record * @throws MetadataSourceException if the underlying methods throw any exception. */ - public ImportRecord getRecord(Query query)throws MetadataSourceException; + public ImportRecord getRecord(Query query) throws MetadataSourceException; - /** + /** * The string that identifies this import implementation. Preferable a URI + * * @return the identifying uri */ public String getImportSource(); - /** Finds records based on an item + /** + * Finds records based on an item * Delegates to one or more MetadataSource implementations based on the uri. Results will be aggregated. + * * @param item an item to base the search on * @return a collection of import records. Only the identifier of the found records may be put in the record. * @throws MetadataSourceException if the underlying methods throw any exception. */ public Collection findMatchingRecords(Item item) throws MetadataSourceException; - /** Finds records based on query object. - * Delegates to one or more MetadataSource implementations based on the uri. Results will be aggregated. + /** + * Finds records based on query object. + * Delegates to one or more MetadataSource implementations based on the uri. Results will be aggregated. + * * @param query a query object to base the search on. * @return a collection of import records. Only the identifier of the found records may be put in the record. * @throws MetadataSourceException passed through. diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/components/package-info.java b/dspace-api/src/main/java/org/dspace/importer/external/service/components/package-info.java index f36c6cb29e..03a4530a03 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/service/components/package-info.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/service/components/package-info.java @@ -6,7 +6,9 @@ * http://www.dspace.org/license/ */ /** - * Service components that are aggregated/used in the {@link org.dspace.importer.external.service.AbstractImportMetadataSourceService} and {@link org.dspace.importer.external.service.ImportService} + * Service components that are aggregated/used in the + * {@link org.dspace.importer.external.service.AbstractImportMetadataSourceService} and + * {@link org.dspace.importer.external.service.ImportService} * @author Roeland Dillen (roeland at atmire dot com) */ -package org.dspace.importer.external.service.components; \ No newline at end of file +package org.dspace.importer.external.service.components; diff --git a/dspace-api/src/main/java/org/dspace/license/CCLicense.java b/dspace-api/src/main/java/org/dspace/license/CCLicense.java index 9aa10f3d70..b015e3a9d3 100644 --- a/dspace-api/src/main/java/org/dspace/license/CCLicense.java +++ b/dspace-api/src/main/java/org/dspace/license/CCLicense.java @@ -10,48 +10,47 @@ package org.dspace.license; /** * @author wbossons - * */ public class CCLicense { - private String licenseName; - private String licenseId; - private int order = 0; + private String licenseName; + private String licenseId; + private int order = 0; - public CCLicense() { - super(); - } + public CCLicense() { + super(); + } - public CCLicense(String licenseId, String licenseName, int order) { - super(); - this.licenseId = licenseId; - this.licenseName = licenseName; - this.order = order; - } + public CCLicense(String licenseId, String licenseName, int order) { + super(); + this.licenseId = licenseId; + this.licenseName = licenseName; + this.order = order; + } - public String getLicenseName() { - return licenseName; - } + public String getLicenseName() { + return licenseName; + } - public void setLicenseName(String licenseName) { - this.licenseName = licenseName; - } + public void setLicenseName(String licenseName) { + this.licenseName = licenseName; + } - public String getLicenseId() { - return licenseId; - } + public String getLicenseId() { + return licenseId; + } - public void setLicenseId(String licenseId) { - this.licenseId = licenseId; - } + public void setLicenseId(String licenseId) { + this.licenseId = licenseId; + } - public int getOrder() { - return this.order; - } + public int getOrder() { + return this.order; + } - public void setOrder(int order) { - this.order = order; - } + public void setOrder(int order) { + this.order = order; + } } diff --git a/dspace-api/src/main/java/org/dspace/license/CCLicenseField.java b/dspace-api/src/main/java/org/dspace/license/CCLicenseField.java index 9a1e00c74f..6360249f65 100644 --- a/dspace-api/src/main/java/org/dspace/license/CCLicenseField.java +++ b/dspace-api/src/main/java/org/dspace/license/CCLicenseField.java @@ -5,7 +5,7 @@ * * http://www.dspace.org/license/ */ -package org.dspace.license; +package org.dspace.license; import java.util.HashMap; import java.util.Map; @@ -14,91 +14,90 @@ import java.util.Map; * Wrapper class for representation of a license field declaration. * A license field is a single "question" which must be answered to * successfully generate a license. - * */ public class CCLicenseField { - private String id = ""; - private String label = ""; - private String description = ""; - private String type = ""; + private String id = ""; + private String label = ""; + private String description = ""; + private String type = ""; - private HashMap fieldEnum = null; + private HashMap fieldEnum = null; - /** - * Construct a new LicenseField class. Note that after construction, - * at least the type should be set. - * - * @param id The unique identifier for this field; this value will be used in constructing the answers XML. - * @param label The label to use when generating the user interface. - */ - public CCLicenseField(String id, String label) { - super(); + /** + * Construct a new LicenseField class. Note that after construction, + * at least the type should be set. + * + * @param id The unique identifier for this field; this value will be used in constructing the answers XML. + * @param label The label to use when generating the user interface. + */ + public CCLicenseField(String id, String label) { + super(); - this.fieldEnum = new HashMap(); + this.fieldEnum = new HashMap(); - this.id = id; - this.label = label; - } + this.id = id; + this.label = label; + } - /** - * - * @return Returns the identifier for this field. - */ - public String getId() { - return this.id; - } + /** + * @return Returns the identifier for this field. + */ + public String getId() { + return this.id; + } - /** - * @return Returns the description of the field. - */ - public String getDescription() { - return description; - } - /** - * @param description The new description; this is often used as a tooltip when generating user interfaces. - */ - public void setDescription(String description) { - this.description = description; - } - /** - * @return Returns the label. - */ - public String getLabel() { - return label; - } + /** + * @return Returns the description of the field. + */ + public String getDescription() { + return description; + } - /** - * @param label The label to set. - */ - public void setLabel(String label) { - this.label = label; - } + /** + * @param description The new description; this is often used as a tooltip when generating user interfaces. + */ + public void setDescription(String description) { + this.description = description; + } - /** - * @return Returns the type. - */ - public String getType() { - return type; - } - /** - * @param type The type to set. - */ - public void setType(String type) { - this.type = type; - } + /** + * @return Returns the label. + */ + public String getLabel() { + return label; + } - /** - * - * @return Returns an instance implementing the Map interface; - * the instance contains a mapping from identifiers to - * labels for the enumeration values. - * - * @see Map - */ - public Map getEnum() { - return this.fieldEnum; - } + /** + * @param label The label to set. + */ + public void setLabel(String label) { + this.label = label; + } + + /** + * @return Returns the type. + */ + public String getType() { + return type; + } + + /** + * @param type The type to set. + */ + public void setType(String type) { + this.type = type; + } + + /** + * @return Returns an instance implementing the Map interface; + * the instance contains a mapping from identifiers to + * labels for the enumeration values. + * @see Map + */ + public Map getEnum() { + return this.fieldEnum; + } } diff --git a/dspace-api/src/main/java/org/dspace/license/CCLookup.java b/dspace-api/src/main/java/org/dspace/license/CCLookup.java index be24e8844a..6ddd31a77d 100644 --- a/dspace-api/src/main/java/org/dspace/license/CCLookup.java +++ b/dspace-api/src/main/java/org/dspace/license/CCLookup.java @@ -5,7 +5,7 @@ * * http://www.dspace.org/license/ */ -package org.dspace.license; +package org.dspace.license; import java.io.IOException; import java.io.OutputStreamWriter; @@ -42,41 +42,43 @@ import org.jdom.input.SAXBuilder; */ public class CCLookup { - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(CCLookup.class); private String cc_root; - private String jurisdiction; + private String jurisdiction; private List lcFilter = new ArrayList(); - - private Document license_doc = null; - private String rdfString = null; - private String errorMessage = null; - private boolean success = false; - private SAXBuilder parser = new SAXBuilder(); - private List licenses = new ArrayList(); + private Document license_doc = null; + private String rdfString = null; + private String errorMessage = null; + private boolean success = false; + + private SAXBuilder parser = new SAXBuilder(); + private List licenses = new ArrayList(); private List licenseFields = new ArrayList(); - - protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance().getCreativeCommonsService(); - + + protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance() + .getCreativeCommonsService(); + /** * Constructs a new instance with the default web services root. - * */ public CCLookup() { super(); - + ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - + cc_root = configurationService.getProperty("cc.api.rooturl"); - + String jurisProp = configurationService.getProperty("cc.license.jurisdiction"); jurisdiction = (jurisProp != null) ? jurisProp : ""; - + String[] filters = configurationService.getArrayProperty("cc.license.classfilter"); if (filters != null) { - for (String name: filters) { + for (String name : filters) { lcFilter.add(name.trim()); } } @@ -88,15 +90,13 @@ public class CCLookup { * * @param class_label The CCLicense label to find. * @return Returns a String containing the License class ID if the label - * is found; if not found, returns an empty string. - * + * is found; if not found, returns an empty string. * @see CCLicense - * */ - public String getLicenseId (String class_label) { + public String getLicenseId(String class_label) { for (int i = 0; i < this.licenses.size(); i++) { - if ( ((CCLicense)this.licenses.get(i)).getLicenseName().equals(class_label)) { - return ( (CCLicense)this.licenses.get(i) ).getLicenseId(); + if (((CCLicense) this.licenses.get(i)).getLicenseName().equals(class_label)) { + return ((CCLicense) this.licenses.get(i)).getLicenseId(); } } @@ -108,10 +108,8 @@ public class CCLookup { * * @param language The language to request labels and description strings in. * @return Returns a Map of CCLicense objects. - * * @see Map * @see CCLicense - * */ public Collection getLicenses(String language) { @@ -128,8 +126,8 @@ public class CCLookup { for (int i = 0; i < results.size(); i++) { Element license = results.get(i); // add if not filtered - String liD = ((Attribute)xp_LicenseID.selectSingleNode(license)).getValue(); - if (! lcFilter.contains(liD)) { + String liD = ((Attribute) xp_LicenseID.selectSingleNode(license)).getValue(); + if (!lcFilter.contains(liD)) { this.licenses.add(new CCLicense(liD, license.getText(), i)); } } @@ -142,7 +140,7 @@ public class CCLookup { } catch (Exception e) { // do nothing... but we should return null; - } + } return licenses; } @@ -151,15 +149,11 @@ public class CCLookup { /** * Queries the web service for a set of licenseFields for a particular license class. * - * @param license - * A String specifying the CCLicense identifier to - * retrieve fields for. - * @param language - * the locale string + * @param license A String specifying the CCLicense identifier to + * retrieve fields for. + * @param language the locale string * @return A Collection of LicenseField objects. - * * @see CCLicense - * */ public Collection getLicenseFields(String license, String language) { @@ -216,25 +210,26 @@ public class CCLookup { return null; } - for (int i=0; i < results.size(); i++) { - Element field = (Element)results.get(i); + for (int i = 0; i < results.size(); i++) { + Element field = (Element) results.get(i); try { // create the field object - CCLicenseField cclicensefield = new CCLicenseField(((Attribute)xp_LicenseID.selectSingleNode(field)).getValue(), - ((Element)xp_Label.selectSingleNode(field)).getText() ); + CCLicenseField cclicensefield = new CCLicenseField( + ((Attribute) xp_LicenseID.selectSingleNode(field)).getValue(), + ((Element) xp_Label.selectSingleNode(field)).getText()); // extract additional properties - cclicensefield.setDescription( ((Element)xp_Description.selectSingleNode(field)).getText() ); - cclicensefield.setType( ((Element)xp_FieldType.selectSingleNode(field)).getText() ); + cclicensefield.setDescription(((Element) xp_Description.selectSingleNode(field)).getText()); + cclicensefield.setType(((Element) xp_FieldType.selectSingleNode(field)).getText()); enumOptions = xp_Enum.selectNodes(field); for (int j = 0; j < enumOptions.size(); j++) { - String id = ((Attribute)xp_LicenseID.selectSingleNode(enumOptions.get(j))).getValue(); - String label =((Element)xp_Label.selectSingleNode(enumOptions.get(j))).getText(); + String id = ((Attribute) xp_LicenseID.selectSingleNode(enumOptions.get(j))).getValue(); + String label = ((Element) xp_Label.selectSingleNode(enumOptions.get(j))).getText(); - cclicensefield.getEnum().put( id, label); + cclicensefield.getEnum().put(id, label); } // for each enum option @@ -251,18 +246,16 @@ public class CCLookup { * Passes a set of "answers" to the web service and retrieves a license. * * @param licenseId The identifier of the license class being requested. - * @param answers A Map containing the answers to the license fields; - * each key is the identifier of a LicenseField, with the value - * containing the user-supplied answer. - * @param lang The language to request localized elements in. - * + * @param answers A Map containing the answers to the license fields; + * each key is the identifier of a LicenseField, with the value + * containing the user-supplied answer. + * @param lang The language to request localized elements in. * @throws IOException if IO error - * * @see CCLicense * @see Map */ public void issue(String licenseId, Map answers, String lang) - throws IOException{ + throws IOException { // Determine the issue URL String issueUrl = this.cc_root + "/license/" + licenseId + "/issue"; @@ -271,11 +264,11 @@ public class CCLookup { Iterator keys = answers.keySet().iterator(); try { - String current = (String)keys.next(); + String current = (String) keys.next(); while (true) { - answer_doc += "<" + current + ">" + (String)answers.get(current) + "\n"; - current = (String)keys.next(); + answer_doc += "<" + current + ">" + (String) answers.get(current) + "\n"; + current = (String) keys.next(); } @@ -284,7 +277,7 @@ public class CCLookup { // entire collection; just swallow and continue } // answer_doc += "\n"; FAILS with jurisdiction argument - answer_doc += "\n\n"; + answer_doc += "\n\n"; String post_data; try { @@ -311,7 +304,7 @@ public class CCLookup { java.io.InputStream stream = connection.getInputStream(); this.license_doc = this.parser.build(stream); } catch (JDOMException jde) { - log.warn(jde.getMessage()); + log.warn(jde.getMessage()); } catch (Exception e) { log.warn(e.getCause()); } @@ -323,15 +316,13 @@ public class CCLookup { * * @param licenseURI The uri of the license. * - * Note: does not support localization in 1.5 -- not yet - * + * Note: does not support localization in 1.5 -- not yet * @throws IOException if IO error - * * @see CCLicense * @see Map */ public void issue(String licenseURI) - throws IOException{ + throws IOException { // Determine the issue URL // Example: http://api.creativecommons.org/rest/1.5/details? @@ -352,7 +343,7 @@ public class CCLookup { java.io.InputStream stream = connection.getInputStream(); license_doc = this.parser.build(stream); } catch (JDOMException jde) { - log.warn( jde.getMessage()); + log.warn(jde.getMessage()); } catch (Exception e) { log.warn(e.getCause()); } @@ -368,15 +359,12 @@ public class CCLookup { String text = null; try { JDOMXPath xp_LicenseName = new JDOMXPath("//result/license-uri"); - text = ((Element)xp_LicenseName.selectSingleNode(this.license_doc)).getText(); - } - catch (Exception e) { + text = ((Element) xp_LicenseName.selectSingleNode(this.license_doc)).getText(); + } catch (Exception e) { log.warn(e.getMessage()); setSuccess(false); text = "An error occurred getting the license - uri."; - } - finally - { + } finally { return text; } } // getLicenseUrl @@ -390,15 +378,12 @@ public class CCLookup { String text = null; try { JDOMXPath xp_LicenseName = new JDOMXPath("//result/license-name"); - text = ((Element)xp_LicenseName.selectSingleNode(this.license_doc)).getText(); - } - catch (Exception e) { + text = ((Element) xp_LicenseName.selectSingleNode(this.license_doc)).getText(); + } catch (Exception e) { log.warn(e.getMessage()); setSuccess(false); text = "An error occurred on the license name."; - } - finally - { + } finally { return text; } } // getLicenseName @@ -410,13 +395,13 @@ public class CCLookup { public String getRdf() throws IOException { - String result = ""; + String result = ""; try { result = creativeCommonsService.fetchLicenseRDF(license_doc); } catch (Exception e) { - log.warn("An error occurred getting the rdf . . ." + e.getMessage() ); + log.warn("An error occurred getting the rdf . . ." + e.getMessage()); setSuccess(false); - } + } return result; } @@ -426,10 +411,9 @@ public class CCLookup { String text = null; try { xp_Success = new JDOMXPath("//message"); - text = ((Element)xp_Success.selectSingleNode(this.license_doc)).getText(); + text = ((Element) xp_Success.selectSingleNode(this.license_doc)).getText(); setErrorMessage(text); - } - catch (Exception e) { + } catch (Exception e) { log.warn("There was an issue . . . " + text); setSuccess(true); } diff --git a/dspace-api/src/main/java/org/dspace/license/CreativeCommonsServiceImpl.java b/dspace-api/src/main/java/org/dspace/license/CreativeCommonsServiceImpl.java index 1eb258e492..c88c7d8b4b 100644 --- a/dspace-api/src/main/java/org/dspace/license/CreativeCommonsServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/license/CreativeCommonsServiceImpl.java @@ -14,7 +14,6 @@ import java.io.InputStream; import java.io.StringWriter; import java.sql.SQLException; import java.util.List; - import javax.xml.transform.Templates; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; @@ -33,7 +32,6 @@ import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; import org.dspace.content.service.ItemService; -import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.core.Utils; import org.dspace.license.service.CreativeCommonsService; @@ -44,9 +42,10 @@ import org.jdom.transform.JDOMSource; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -public class CreativeCommonsServiceImpl implements CreativeCommonsService, InitializingBean -{ - /** log4j category */ +public class CreativeCommonsServiceImpl implements CreativeCommonsService, InitializingBean { + /** + * log4j category + */ private static Logger log = Logger.getLogger(CreativeCommonsServiceImpl.class); /** @@ -57,14 +56,16 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi /** * Some BitStream Names (BSN) - * - * @deprecated use the metadata retrieved at {@link CreativeCommonsService#getCCField(String)} (see https://jira.duraspace.org/browse/DS-2604) + * + * @deprecated use the metadata retrieved at {@link CreativeCommonsService#getCCField(String)} (see https://jira + * .duraspace.org/browse/DS-2604) */ @Deprecated protected static final String BSN_LICENSE_URL = "license_url"; /** - * @deprecated to make uniform JSPUI and XMLUI approach the bitstream with the license in the textual format it is no longer stored (see https://jira.duraspace.org/browse/DS-2604) + * @deprecated to make uniform JSPUI and XMLUI approach the bitstream with the license in the textual format it + * is no longer stored (see https://jira.duraspace.org/browse/DS-2604) */ @Deprecated protected static final String BSN_LICENSE_TEXT = "license_text"; @@ -81,57 +82,48 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi protected BundleService bundleService; @Autowired(required = true) protected ItemService itemService; - + protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - - protected CreativeCommonsServiceImpl() - { - + + protected CreativeCommonsServiceImpl() { + } @Override - public void afterPropertiesSet() throws Exception - { + public void afterPropertiesSet() throws Exception { // if defined, set a proxy server for http requests to Creative // Commons site String proxyHost = configurationService.getProperty("http.proxy.host"); String proxyPort = configurationService.getProperty("http.proxy.port"); - if (StringUtils.isNotBlank(proxyHost) && StringUtils.isNotBlank(proxyPort)) - { + if (StringUtils.isNotBlank(proxyHost) && StringUtils.isNotBlank(proxyPort)) { System.setProperty("http.proxyHost", proxyHost); System.setProperty("http.proxyPort", proxyPort); } - - try - { + + try { templates = TransformerFactory.newInstance().newTemplates( - new StreamSource(CreativeCommonsServiceImpl.class - .getResourceAsStream("CreativeCommons.xsl"))); + new StreamSource(CreativeCommonsServiceImpl.class + .getResourceAsStream("CreativeCommons.xsl"))); + } catch (TransformerConfigurationException e) { + throw new RuntimeException(e.getMessage(), e); } - catch (TransformerConfigurationException e) - { - throw new RuntimeException(e.getMessage(),e); - } - - + + } @Override - public boolean isEnabled() - { + public boolean isEnabled() { return true; } - // create the CC bundle if it doesn't exist - // If it does, remove it and create a new one. + // create the CC bundle if it doesn't exist + // If it does, remove it and create a new one. protected Bundle getCcBundle(Context context, Item item) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { List bundles = itemService.getBundles(item, CC_BUNDLE_NAME); - if ((bundles.size() > 0) && (bundles.get(0) != null)) - { + if ((bundles.size() > 0) && (bundles.get(0) != null)) { itemService.removeBundle(context, item, bundles.get(0)); } return bundleService.create(context, item, CC_BUNDLE_NAME); @@ -140,27 +132,24 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi @Override public void setLicenseRDF(Context context, Item item, String licenseRdf) throws SQLException, IOException, - AuthorizeException - { + AuthorizeException { Bundle bundle = getCcBundle(context, item); // set the format BitstreamFormat bs_rdf_format = bitstreamFormatService.findByShortDescription(context, "RDF XML"); // set the RDF bitstream setBitstreamFromBytes(context, item, bundle, BSN_LICENSE_RDF, bs_rdf_format, licenseRdf.getBytes()); } - + @Override public void setLicense(Context context, Item item, - InputStream licenseStm, String mimeType) - throws SQLException, IOException, AuthorizeException - { + InputStream licenseStm, String mimeType) + throws SQLException, IOException, AuthorizeException { Bundle bundle = getCcBundle(context, item); - // set the format + // set the format BitstreamFormat bs_format; - if (mimeType.equalsIgnoreCase("text/xml")) - { + if (mimeType.equalsIgnoreCase("text/xml")) { bs_format = bitstreamFormatService.findByShortDescription(context, "CC License"); } else if (mimeType.equalsIgnoreCase("text/rdf")) { bs_format = bitstreamFormatService.findByShortDescription(context, "RDF XML"); @@ -171,9 +160,9 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi Bitstream bs = bitstreamService.create(context, bundle, licenseStm); bs.setSource(context, CC_BS_SOURCE); bs.setName(context, (mimeType != null && - (mimeType.equalsIgnoreCase("text/xml") || - mimeType.equalsIgnoreCase("text/rdf"))) ? - BSN_LICENSE_RDF : BSN_LICENSE_TEXT); + (mimeType.equalsIgnoreCase("text/xml") || + mimeType.equalsIgnoreCase("text/rdf"))) ? + BSN_LICENSE_RDF : BSN_LICENSE_TEXT); bs.setFormat(context, bs_format); bitstreamService.update(context, bs); } @@ -181,39 +170,31 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi @Override public void removeLicense(Context context, Item item) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { // remove CC license bundle if one exists List bundles = itemService.getBundles(item, CC_BUNDLE_NAME); - if ((bundles.size() > 0) && (bundles.get(0) != null)) - { + if ((bundles.size() > 0) && (bundles.get(0) != null)) { itemService.removeBundle(context, item, bundles.get(0)); } } @Override public boolean hasLicense(Context context, Item item) - throws SQLException, IOException - { + throws SQLException, IOException { // try to find CC license bundle List bundles = itemService.getBundles(item, CC_BUNDLE_NAME); - if (bundles.size() == 0) - { + if (bundles.size() == 0) { return false; } // verify it has correct contents - try - { - if ((getLicenseURL(context, item) == null)) - { + try { + if ((getLicenseURL(context, item) == null)) { return false; } - } - catch (AuthorizeException ae) - { + } catch (AuthorizeException ae) { return false; } @@ -222,23 +203,20 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi @Override public String getLicenseRDF(Context context, Item item) throws SQLException, - IOException, AuthorizeException - { + IOException, AuthorizeException { return getStringFromBitstream(context, item, BSN_LICENSE_RDF); } @Override public Bitstream getLicenseRdfBitstream(Item item) throws SQLException, - IOException, AuthorizeException - { + IOException, AuthorizeException { return getBitstream(item, BSN_LICENSE_RDF); } @Deprecated @Override public Bitstream getLicenseTextBitstream(Item item) throws SQLException, - IOException, AuthorizeException - { + IOException, AuthorizeException { return getBitstream(item, BSN_LICENSE_TEXT); } @@ -248,26 +226,22 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi if (StringUtils.isNotBlank(licenseUri)) { return licenseUri; } - + // JSPUI backward compatibility see https://jira.duraspace.org/browse/DS-2604 return getStringFromBitstream(context, item, BSN_LICENSE_URL); } @Override - public String fetchLicenseRDF(Document license) - { + public String fetchLicenseRDF(Document license) { StringWriter result = new StringWriter(); - - try - { + + try { templates.newTransformer().transform( - new JDOMSource(license), - new StreamResult(result) - ); - } - catch (TransformerException e) - { - throw new IllegalStateException(e.getMessage(),e); + new JDOMSource(license), + new StreamResult(result) + ); + } catch (TransformerException e) { + throw new IllegalStateException(e.getMessage(), e); } return result.getBuffer().toString(); @@ -280,30 +254,20 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi * Note: This helper method assumes that the CC * bitstreams are short and easily expressed as byte arrays in RAM * - * @param context - * The relevant DSpace Context. - * @param item - * parent item - * @param bundle - * parent bundle - * @param bitstream_name - * bitstream name to set - * @param format - * bitstream format - * @param bytes - * bitstream data - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param item parent item + * @param bundle parent bundle + * @param bitstream_name bitstream name to set + * @param format bitstream format + * @param bytes bitstream data + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ protected void setBitstreamFromBytes(Context context, Item item, Bundle bundle, - String bitstream_name, BitstreamFormat format, byte[] bytes) - throws SQLException, IOException, AuthorizeException - { + String bitstream_name, BitstreamFormat format, byte[] bytes) + throws SQLException, IOException, AuthorizeException { ByteArrayInputStream bais = new ByteArrayInputStream(bytes); Bitstream bs = bitstreamService.create(context, bundle, bais); @@ -322,29 +286,21 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi * Note: This helper method assumes that the CC * bitstreams are short and easily expressed as byte arrays in RAM * - * @param context - * The relevant DSpace Context. - * @param item - * parent item - * @param bitstream_name - * bitstream name to set + * @param context The relevant DSpace Context. + * @param item parent item + * @param bitstream_name bitstream name to set * @return the bitstream as string - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ protected String getStringFromBitstream(Context context, Item item, - String bitstream_name) throws SQLException, IOException, - AuthorizeException - { + String bitstream_name) throws SQLException, IOException, + AuthorizeException { byte[] bytes = getBytesFromBitstream(context, item, bitstream_name); - if (bytes == null) - { + if (bytes == null) { return null; } @@ -355,40 +311,28 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi * This helper method retrieves the bytes of a bitstream for an item under * the CC bundle, with the given bitstream name * - * @param item - * parent item - * @param bitstream_name - * bitstream name to set + * @param item parent item + * @param bitstream_name bitstream name to set * @return the bitstream - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ protected Bitstream getBitstream(Item item, String bitstream_name) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { Bundle cc_bundle = null; // look for the CC bundle - try - { + try { List bundles = itemService.getBundles(item, CC_BUNDLE_NAME); - if ((bundles != null) && (bundles.size() > 0)) - { + if ((bundles != null) && (bundles.size() > 0)) { cc_bundle = bundles.get(0); - } - else - { + } else { return null; } - } - catch (Exception exc) - { + } catch (Exception exc) { // this exception catching is a bit generic, // but basically it happens if there is no CC bundle return null; @@ -398,13 +342,11 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi } protected byte[] getBytesFromBitstream(Context context, Item item, String bitstream_name) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { Bitstream bs = getBitstream(item, bitstream_name); // no such bitstream - if (bs == null) - { + if (bs == null) { return null; } @@ -419,27 +361,23 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi * Returns a metadata field handle for given field Id */ @Override - public LicenseMetadataValue getCCField(String fieldId) - { + public LicenseMetadataValue getCCField(String fieldId) { return new LicenseMetadataValue(configurationService.getProperty("cc.license." + fieldId)); } - + @Override public void removeLicense(Context context, LicenseMetadataValue uriField, - LicenseMetadataValue nameField, Item item) - throws AuthorizeException, IOException, SQLException - { + LicenseMetadataValue nameField, Item item) + throws AuthorizeException, IOException, SQLException { // only remove any previous licenses String licenseUri = uriField.ccItemValue(item); if (licenseUri != null) { uriField.removeItemValue(context, item, licenseUri); - if (configurationService.getBooleanProperty("cc.submit.setname")) - { + if (configurationService.getBooleanProperty("cc.submit.setname")) { String licenseName = nameField.keyedItemValue(item, licenseUri); nameField.removeItemValue(context, item, licenseName); } - if (configurationService.getBooleanProperty("cc.submit.addbitstream")) - { + if (configurationService.getBooleanProperty("cc.submit.addbitstream")) { removeLicense(context, item); } } diff --git a/dspace-api/src/main/java/org/dspace/license/LicenseCleanup.java b/dspace-api/src/main/java/org/dspace/license/LicenseCleanup.java index ffbd6f7872..30d7147079 100644 --- a/dspace-api/src/main/java/org/dspace/license/LicenseCleanup.java +++ b/dspace-api/src/main/java/org/dspace/license/LicenseCleanup.java @@ -19,7 +19,6 @@ import java.sql.SQLException; import java.util.Iterator; import java.util.List; import java.util.Properties; - import javax.xml.transform.Templates; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; @@ -40,44 +39,44 @@ import org.dspace.core.Context; /** * Cleanup class for CC Licenses, corrects XML formating errors by replacing the license_rdf bitstream. - * + * * @author mdiggory */ -public class LicenseCleanup -{ +public class LicenseCleanup { private static final Logger log = Logger.getLogger(LicenseCleanup.class); protected static final Templates templates; - protected static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); + protected static final BitstreamService bitstreamService = ContentServiceFactory.getInstance() + .getBitstreamService(); protected static final BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - static - { - try - { + static { + try { templates = TransformerFactory.newInstance().newTemplates( new StreamSource(CreativeCommonsServiceImpl.class - .getResourceAsStream("LicenseCleanup.xsl"))); - } - catch (TransformerConfigurationException e) - { + .getResourceAsStream("LicenseCleanup.xsl"))); + } catch (TransformerConfigurationException e) { log.error(e.getMessage(), e); throw new IllegalStateException(e.getMessage(), e); } } + /** + * Default constructor + */ + private LicenseCleanup() { } + /** * @param args the command line arguments given - * @throws SQLException if database error - * @throws IOException if IO error + * @throws SQLException if database error + * @throws IOException if IO error * @throws AuthorizeException if authorization error */ public static void main(String[] args) throws SQLException, - AuthorizeException, IOException - { + AuthorizeException, IOException { Context ctx = new Context(); ctx.turnOffAuthorisationSystem(); @@ -87,28 +86,23 @@ public class LicenseCleanup File processed = new File("license.processed"); - if (processed.exists()) - { + if (processed.exists()) { props.load(new FileInputStream(processed)); } int i = 0; - try - { - while (iter.hasNext()) - { - if (i == 100) - { + try { + while (iter.hasNext()) { + if (i == 100) { props.store(new FileOutputStream(processed), - "processed license files, remove to restart processing from scratch"); + "processed license files, remove to restart processing from scratch"); i = 0; } Item item = (Item) iter.next(); log.info("checking: " + item.getID()); - if (!props.containsKey("I" + item.getID())) - { + if (!props.containsKey("I" + item.getID())) { handleItem(ctx, item); log.info("processed: " + item.getID()); } @@ -116,33 +110,27 @@ public class LicenseCleanup props.put("I" + item.getID(), "done"); i++; } - } - finally - { + } finally { props - .store(new FileOutputStream(processed), - "processed license files, remove to restart processing from scratch"); + .store(new FileOutputStream(processed), + "processed license files, remove to restart processing from scratch"); } } /** * Process Item, correcting CC-License if encountered. * - * @param context - * The relevant DSpace Context. - * @param item - * The item to process - * @throws SQLException if database error + * @param context The relevant DSpace Context. + * @param item The item to process + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ protected static void handleItem(Context context, Item item) throws SQLException, - AuthorizeException, IOException - { + AuthorizeException, IOException { List bundles = itemService.getBundles(item, "CC-LICENSE"); - if (bundles == null || bundles.size() == 0) - { + if (bundles == null || bundles.size() == 0) { return; } @@ -158,29 +146,26 @@ public class LicenseCleanup StringWriter result = new StringWriter(); - try - { + try { templates.newTransformer().transform( new StreamSource(new ByteArrayInputStream(license_rdf.getBytes())), new StreamResult(result)); - } - catch (TransformerException e) - { + } catch (TransformerException e) { throw new IllegalStateException(e.getMessage(), e); } StringBuffer buffer = result.getBuffer(); Bitstream newBitstream = bitstreamService - .create(context, bundle, new ByteArrayInputStream(buffer.toString() - .getBytes())); + .create(context, bundle, new ByteArrayInputStream(buffer.toString() + .getBytes())); newBitstream.setName(context, bitstream.getName()); newBitstream.setDescription(context, bitstream.getDescription()); newBitstream.setFormat(context, bitstream.getFormat(context)); newBitstream.setSource(context, bitstream.getSource()); newBitstream.setUserFormatDescription(context, bitstream - .getUserFormatDescription()); + .getUserFormatDescription()); bitstreamService.update(context, newBitstream); bundleService.removeBitstream(context, bundle, bitstream); @@ -194,45 +179,35 @@ public class LicenseCleanup /** * Fast stream copy routine - * - * @param context - * The relevant DSpace Context. - * @param b the Bitstream to be copied. + * + * @param context The relevant DSpace Context. + * @param b the Bitstream to be copied. * @return copy of the content of {@code b}. - * @throws IOException if IO error - * @throws SQLException if database error + * @throws IOException if IO error + * @throws SQLException if database error * @throws AuthorizeException if authorization error */ public static byte[] copy(Context context, Bitstream b) - throws IOException, SQLException, AuthorizeException - { + throws IOException, SQLException, AuthorizeException { InputStream in = null; ByteArrayOutputStream out = null; - try - { + try { in = bitstreamService.retrieve(context, b); out = new ByteArrayOutputStream(); - while (true) - { - synchronized (buffer) - { + while (true) { + synchronized (buffer) { int amountRead = in.read(buffer); - if (amountRead == -1) - { + if (amountRead == -1) { break; } out.write(buffer, 0, amountRead); } } - } - finally - { - if (in != null) - { + } finally { + if (in != null) { in.close(); } - if (out != null) - { + if (out != null) { out.close(); } } diff --git a/dspace-api/src/main/java/org/dspace/license/LicenseMetadataValue.java b/dspace-api/src/main/java/org/dspace/license/LicenseMetadataValue.java index afc3793aee..ec5c9e447b 100644 --- a/dspace-api/src/main/java/org/dspace/license/LicenseMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/license/LicenseMetadataValue.java @@ -7,6 +7,11 @@ */ package org.dspace.license; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; import org.dspace.content.MetadataValue; @@ -14,11 +19,6 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.Context; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /** * Helper class for using CC-related Metadata fields * @@ -32,19 +32,16 @@ public class LicenseMetadataValue { private String[] params = new String[4]; - public LicenseMetadataValue(String fieldName) - { - if (fieldName != null && fieldName.length() > 0) - { - String[] fParams = fieldName.split("\\."); - for (int i = 0; i < fParams.length; i++) - { - params[i] = fParams[i]; - } - params[3] = Item.ANY; + public LicenseMetadataValue(String fieldName) { + if (fieldName != null && fieldName.length() > 0) { + String[] fParams = fieldName.split("\\."); + for (int i = 0; i < fParams.length; i++) { + params[i] = fParams[i]; } - itemService = ContentServiceFactory.getInstance().getItemService(); + params[3] = Item.ANY; } + itemService = ContentServiceFactory.getInstance().getItemService(); + } /** * Returns first value that matches Creative Commons 'shibboleth', @@ -54,13 +51,10 @@ public class LicenseMetadataValue { * @param item - the item to read * @return value - the first CC-matched value, or null if no such value */ - public String ccItemValue(Item item) - { + public String ccItemValue(Item item) { List dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]); - for (MetadataValue dcvalue : dcvalues) - { - if ((dcvalue.getValue()).indexOf(ccShib) != -1) - { + for (MetadataValue dcvalue : dcvalues) { + if ((dcvalue.getValue()).indexOf(ccShib) != -1) { // return first value that matches the shib return dcvalue.getValue(); } @@ -73,59 +67,45 @@ public class LicenseMetadataValue { * NB: this only delivers a license name (if present in field) given a license URI * * @param item - the item to read - * @param key - the key for desired value + * @param key - the key for desired value * @return value - the value associated with key or null if no such value - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public String keyedItemValue(Item item, String key) - throws AuthorizeException, IOException, SQLException - { - CCLookup ccLookup = new CCLookup(); - ccLookup.issue(key); - String matchValue = ccLookup.getLicenseName(); - List dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]); - for (MetadataValue dcvalue : dcvalues) - { - if (dcvalue.getValue().equals(matchValue)) - { - return dcvalue.getValue(); - } - } + throws AuthorizeException, IOException, SQLException { + CCLookup ccLookup = new CCLookup(); + ccLookup.issue(key); + String matchValue = ccLookup.getLicenseName(); + List dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]); + for (MetadataValue dcvalue : dcvalues) { + if (dcvalue.getValue().equals(matchValue)) { + return dcvalue.getValue(); + } + } return null; } /** * Removes the passed value from the set of values for the field in passed item. * - * @param context - * The relevant DSpace Context. - * @param item - the item to update - * @param value - the value to remove - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param item - the item to update + * @param value - the value to remove + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void removeItemValue(Context context, Item item, String value) - throws AuthorizeException, IOException, SQLException - { - if (value != null) - { + throws AuthorizeException, IOException, SQLException { + if (value != null) { List dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]); ArrayList arrayList = new ArrayList(); - for (MetadataValue dcvalue : dcvalues) - { - if (!dcvalue.getValue().equals(value)) - { + for (MetadataValue dcvalue : dcvalues) { + if (!dcvalue.getValue().equals(value)) { arrayList.add(dcvalue.getValue()); } } @@ -137,12 +117,10 @@ public class LicenseMetadataValue { /** * Adds passed value to the set of values for the field in passed item. * - * @param context - * The relevant DSpace Context. - * @param item - the item to update - * @param value - the value to add in this field - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param context The relevant DSpace Context. + * @param item - the item to update + * @param value - the value to add in this field + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void addItemValue(Context context, Item item, String value) throws SQLException { itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], value); diff --git a/dspace-api/src/main/java/org/dspace/license/factory/LicenseServiceFactory.java b/dspace-api/src/main/java/org/dspace/license/factory/LicenseServiceFactory.java index b0a8027c63..6e5cc38894 100644 --- a/dspace-api/src/main/java/org/dspace/license/factory/LicenseServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/license/factory/LicenseServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.license.service.CreativeCommonsService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract factory to get services for the license package, use LicenseServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the license package, use LicenseServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class LicenseServiceFactory { public abstract CreativeCommonsService getCreativeCommonsService(); - public static LicenseServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("licenseServiceFactory", LicenseServiceFactory.class); + public static LicenseServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("licenseServiceFactory", LicenseServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/license/factory/LicenseServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/license/factory/LicenseServiceFactoryImpl.java index 1566d0a42f..27c438ce13 100644 --- a/dspace-api/src/main/java/org/dspace/license/factory/LicenseServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/license/factory/LicenseServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.license.service.CreativeCommonsService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the license package, use LicenseServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the license package, use LicenseServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/license/service/CreativeCommonsService.java b/dspace-api/src/main/java/org/dspace/license/service/CreativeCommonsService.java index 752201ff01..c99c38a127 100644 --- a/dspace-api/src/main/java/org/dspace/license/service/CreativeCommonsService.java +++ b/dspace-api/src/main/java/org/dspace/license/service/CreativeCommonsService.java @@ -7,6 +7,10 @@ */ package org.dspace.license.service; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.Item; @@ -14,13 +18,10 @@ import org.dspace.core.Context; import org.dspace.license.LicenseMetadataValue; import org.jdom.Document; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; - /** * Service interface class for the Creative commons licensing. - * The implementation of this class is responsible for all business logic calls for the Creative commons licensing and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the Creative commons licensing + * and is autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -35,23 +36,18 @@ public interface CreativeCommonsService { */ public boolean isEnabled(); - /** setLicenseRDF + /** + * setLicenseRDF * * CC Web Service method for setting the RDF bitstream * - * @param context - * The relevant DSpace Context. - * @param item - * The item to set license on. - * @param licenseRdf - * license RDF string - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param item The item to set license on. + * @param licenseRdf license RDF string + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void setLicenseRDF(Context context, Item item, String licenseRdf) throws SQLException, IOException, AuthorizeException; @@ -60,23 +56,19 @@ public interface CreativeCommonsService { /** * Used by DSpaceMetsIngester * - * @param context - * The relevant DSpace Context. - * @param item - * The item to set license on. - * @param licenseStm - * InputStream with the license text. - * @param mimeType - * License text file MIME type ("text/xml", "text/rdf" or generic) - * @throws SQLException if database error - * An exception that provides information on a database access error or other errors. - * @throws IOException if IO error - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param context The relevant DSpace Context. + * @param item The item to set license on. + * @param licenseStm InputStream with the license text. + * @param mimeType License text file MIME type ("text/xml", "text/rdf" or generic) + * @throws SQLException if database error + * An exception that provides information on a database access error or other errors. + * @throws IOException if IO error + * A general class of exceptions produced by failed or interrupted I/O operations. * @throws AuthorizeException if authorization error - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * Exception indicating the current user of the context does not have permission + * to perform a particular action. * - * * // PATCHED 12/01 FROM JIRA re: mimetypes for CCLicense and License RDF wjb + * * // PATCHED 12/01 FROM JIRA re: mimetypes for CCLicense and License RDF wjb */ public void setLicense(Context context, Item item, InputStream licenseStm, String mimeType) @@ -97,34 +89,27 @@ public interface CreativeCommonsService { /** * Get Creative Commons license RDF, returning Bitstream object. * - * @param item - * bitstream's parent item + * @param item bitstream's parent item * @return bitstream or null. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public Bitstream getLicenseRdfBitstream(Item item) throws SQLException, IOException, AuthorizeException; /** * Get Creative Commons license Text, returning Bitstream object. - * - * @param item - * bitstream's parent item + * + * @param item bitstream's parent item * @return bitstream or null. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @deprecated to make uniform JSPUI and XMLUI approach the bitstream with the license in the textual format it is no longer stored (see https://jira.duraspace.org/browse/DS-2604) + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @deprecated to make uniform JSPUI and XMLUI approach the bitstream with the license in the textual format it + * is no longer stored (see https://jira.duraspace.org/browse/DS-2604) */ public Bitstream getLicenseTextBitstream(Item item) throws SQLException, IOException, AuthorizeException; @@ -137,39 +122,31 @@ public interface CreativeCommonsService { * @return its value. */ public LicenseMetadataValue getCCField(String fieldId); - + /** * Apply same transformation on the document to retrieve only the most * relevant part of the document passed as parameter. If no transformation * is needed then take in consideration to empty the CreativeCommons.xml - * - * @param license - * - an element that could be contains as part of your content - * the license rdf + * + * @param license - an element that could be contains as part of your content + * the license rdf * @return the document license in textual format after the transformation */ public String fetchLicenseRDF(Document license); - + /** * Remove license information, delete also the bitstream - * - * @param context - * - DSpace Context - * @param uriField - * - the metadata field for license uri - * @param nameField - * - the metadata field for license name - * @param item - * - the item - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * + * @param context - DSpace Context + * @param uriField - the metadata field for license uri + * @param nameField - the metadata field for license name + * @param item - the item + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void removeLicense(Context context, LicenseMetadataValue uriField, - LicenseMetadataValue nameField, Item item) + LicenseMetadataValue nameField, Item item) throws AuthorizeException, IOException, SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/plugin/CollectionHomeProcessor.java b/dspace-api/src/main/java/org/dspace/plugin/CollectionHomeProcessor.java index 1d9c15972e..408198fca0 100644 --- a/dspace-api/src/main/java/org/dspace/plugin/CollectionHomeProcessor.java +++ b/dspace-api/src/main/java/org/dspace/plugin/CollectionHomeProcessor.java @@ -20,25 +20,22 @@ import org.dspace.core.Context; * implement the process method and appear in the configuration will be run * before the at the start of preparing the collection home page has any chance * to continue its execution - * + * * @author Richard Jones - * */ -public interface CollectionHomeProcessor -{ - /** - * execute the process - * - * @param context the DSpace context - * @param request the HTTP request - * @param response the HTTP response - * @param collection the collection object whose home page we are on - * - * @throws PluginException any particular problem with the plugin execution - * @throws AuthorizeException Authorisation errors during plugin execution - */ - void process(Context context, HttpServletRequest request, - HttpServletResponse response, Collection collection) - throws PluginException, AuthorizeException; - -} \ No newline at end of file +public interface CollectionHomeProcessor { + /** + * execute the process + * + * @param context the DSpace context + * @param request the HTTP request + * @param response the HTTP response + * @param collection the collection object whose home page we are on + * @throws PluginException any particular problem with the plugin execution + * @throws AuthorizeException Authorisation errors during plugin execution + */ + void process(Context context, HttpServletRequest request, + HttpServletResponse response, Collection collection) + throws PluginException, AuthorizeException; + +} diff --git a/dspace-api/src/main/java/org/dspace/plugin/CommunityHomeProcessor.java b/dspace-api/src/main/java/org/dspace/plugin/CommunityHomeProcessor.java index 651757411b..704789f800 100644 --- a/dspace-api/src/main/java/org/dspace/plugin/CommunityHomeProcessor.java +++ b/dspace-api/src/main/java/org/dspace/plugin/CommunityHomeProcessor.java @@ -15,29 +15,26 @@ import org.dspace.content.Community; import org.dspace.core.Context; /** - * Interface that must be implemented by any plugin wanting to be called at + * Interface that must be implemented by any plugin wanting to be called at * the inception of the Community home page (in HandleServlet). Classes that implement the process method * and appear in the configuration will be run before the at the start of preparing the community home page has any * chance to continue its execution - * - * @author Richard Jones * + * @author Richard Jones */ -public interface CommunityHomeProcessor -{ - /** - * execute the process - * - * @param context the DSpace context - * @param request the HTTP request - * @param response the HTTP response - * @param community The community object whose home page we are on - * - * @throws PluginException any particular problem with the plugin execution - * @throws AuthorizeException Authorisation errors during plugin execution - */ - void process(Context context, HttpServletRequest request, - HttpServletResponse response, Community community) - throws PluginException, AuthorizeException; - -} \ No newline at end of file +public interface CommunityHomeProcessor { + /** + * execute the process + * + * @param context the DSpace context + * @param request the HTTP request + * @param response the HTTP response + * @param community The community object whose home page we are on + * @throws PluginException any particular problem with the plugin execution + * @throws AuthorizeException Authorisation errors during plugin execution + */ + void process(Context context, HttpServletRequest request, + HttpServletResponse response, Community community) + throws PluginException, AuthorizeException; + +} diff --git a/dspace-api/src/main/java/org/dspace/plugin/ItemHomeProcessor.java b/dspace-api/src/main/java/org/dspace/plugin/ItemHomeProcessor.java index e2549462ce..a0ef4168fd 100644 --- a/dspace-api/src/main/java/org/dspace/plugin/ItemHomeProcessor.java +++ b/dspace-api/src/main/java/org/dspace/plugin/ItemHomeProcessor.java @@ -19,27 +19,24 @@ import org.dspace.core.Context; * inception of the Item page (in HandleServlet). Classes that * implement the process method and appear in the configuration will be run * before the at the start of preparing the item home page has any chance - * to continue its execution. Note that the plugin is executed also before + * to continue its execution. Note that the plugin is executed also before * than the READ permission on the item is checked - * + * * @author Andrea Bollini - * */ -public interface ItemHomeProcessor -{ - /** - * execute the process - * - * @param context the DSpace context - * @param request the HTTP request - * @param response the HTTP response - * @param item the item object whose home page we are on - * - * @throws PluginException any particular problem with the plugin execution - * @throws AuthorizeException Authorisation errors during plugin execution - */ - void process(Context context, HttpServletRequest request, - HttpServletResponse response, Item item) - throws PluginException, AuthorizeException; - -} \ No newline at end of file +public interface ItemHomeProcessor { + /** + * execute the process + * + * @param context the DSpace context + * @param request the HTTP request + * @param response the HTTP response + * @param item the item object whose home page we are on + * @throws PluginException any particular problem with the plugin execution + * @throws AuthorizeException Authorisation errors during plugin execution + */ + void process(Context context, HttpServletRequest request, + HttpServletResponse response, Item item) + throws PluginException, AuthorizeException; + +} diff --git a/dspace-api/src/main/java/org/dspace/plugin/PluginException.java b/dspace-api/src/main/java/org/dspace/plugin/PluginException.java index 2d6f0ff35d..5e6262e991 100644 --- a/dspace-api/src/main/java/org/dspace/plugin/PluginException.java +++ b/dspace-api/src/main/java/org/dspace/plugin/PluginException.java @@ -9,50 +9,43 @@ package org.dspace.plugin; /** * General exception class for all code that runs as a plugin in DSpace - * - * @author Richard Jones * + * @author Richard Jones */ -public class PluginException extends Exception -{ - /** - * basic constructor - * - */ - public PluginException() - { - super(); - } - - /** - * Construct an exception with the passed message - * - * @param message a message for the exception - */ - public PluginException(String message) - { - super(message); - } - - /** - * Construct an exception with the passed message to encapsulate - * the passed Throwable - * - * @param message a message for the exception - * @param e throwable which triggered this exception - */ - public PluginException(String message, Throwable e) - { - super(message, e); - } - - /** - * Construct an exception to encapsulate the passed Throwable - * - * @param e the throwable which triggered this exception - */ - public PluginException(Throwable e) - { - super(e); - } -} \ No newline at end of file +public class PluginException extends Exception { + /** + * basic constructor + */ + public PluginException() { + super(); + } + + /** + * Construct an exception with the passed message + * + * @param message a message for the exception + */ + public PluginException(String message) { + super(message); + } + + /** + * Construct an exception with the passed message to encapsulate + * the passed Throwable + * + * @param message a message for the exception + * @param e throwable which triggered this exception + */ + public PluginException(String message, Throwable e) { + super(message, e); + } + + /** + * Construct an exception to encapsulate the passed Throwable + * + * @param e the throwable which triggered this exception + */ + public PluginException(Throwable e) { + super(e); + } +} diff --git a/dspace-api/src/main/java/org/dspace/plugin/SiteHomeProcessor.java b/dspace-api/src/main/java/org/dspace/plugin/SiteHomeProcessor.java index bd2155a8cc..7a3bf461dc 100644 --- a/dspace-api/src/main/java/org/dspace/plugin/SiteHomeProcessor.java +++ b/dspace-api/src/main/java/org/dspace/plugin/SiteHomeProcessor.java @@ -19,24 +19,21 @@ import org.dspace.core.Context; * implement the process method and appear in the configuration will be run * before the at the start of preparing the home page has any chance * to continue its execution - * + * * @author Andrea Bollini - * */ -public interface SiteHomeProcessor -{ - /** - * execute the process - * - * @param context the DSpace context - * @param request the HTTP request - * @param response the HTTP response - * - * @throws PluginException any particular problem with the plugin execution - * @throws AuthorizeException Authorisation errors during plugin execution - */ - void process(Context context, HttpServletRequest request, - HttpServletResponse response) - throws PluginException, AuthorizeException; - -} \ No newline at end of file +public interface SiteHomeProcessor { + /** + * execute the process + * + * @param context the DSpace context + * @param request the HTTP request + * @param response the HTTP response + * @throws PluginException any particular problem with the plugin execution + * @throws AuthorizeException Authorisation errors during plugin execution + */ + void process(Context context, HttpServletRequest request, + HttpServletResponse response) + throws PluginException, AuthorizeException; + +} diff --git a/dspace-api/src/main/java/org/dspace/rdf/ItemNotArchivedException.java b/dspace-api/src/main/java/org/dspace/rdf/ItemNotArchivedException.java index e942b42346..5fdfb2a561 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/ItemNotArchivedException.java +++ b/dspace-api/src/main/java/org/dspace/rdf/ItemNotArchivedException.java @@ -9,12 +9,10 @@ package org.dspace.rdf; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class ItemNotArchivedException extends Exception { - public ItemNotArchivedException() - { + public ItemNotArchivedException() { super("The processed item is not part of the main archive."); } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/ItemNotDiscoverableException.java b/dspace-api/src/main/java/org/dspace/rdf/ItemNotDiscoverableException.java index 992bceabc3..53ef06cc35 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/ItemNotDiscoverableException.java +++ b/dspace-api/src/main/java/org/dspace/rdf/ItemNotDiscoverableException.java @@ -9,12 +9,10 @@ package org.dspace.rdf; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class ItemNotDiscoverableException extends Exception { - public ItemNotDiscoverableException() - { + public ItemNotDiscoverableException() { super("The processed item is not discoverable."); } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/ItemWithdrawnException.java b/dspace-api/src/main/java/org/dspace/rdf/ItemWithdrawnException.java index 2c2d037946..9f07fed300 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/ItemWithdrawnException.java +++ b/dspace-api/src/main/java/org/dspace/rdf/ItemWithdrawnException.java @@ -9,12 +9,10 @@ package org.dspace.rdf; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class ItemWithdrawnException extends Exception { - public ItemWithdrawnException() - { + public ItemWithdrawnException() { super("The processed item is withdrawn."); } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/RDFConsumer.java b/dspace-api/src/main/java/org/dspace/rdf/RDFConsumer.java index 4b3ea7f9b1..f127d7ff48 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/RDFConsumer.java +++ b/dspace-api/src/main/java/org/dspace/rdf/RDFConsumer.java @@ -8,13 +8,22 @@ package org.dspace.rdf; -import com.hp.hpl.jena.rdf.model.Model; import java.sql.SQLException; -import java.util.*; +import java.util.Arrays; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.UUID; +import com.hp.hpl.jena.rdf.model.Model; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.Site; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; @@ -28,13 +37,11 @@ import org.dspace.workflow.WorkflowItemService; import org.dspace.workflow.factory.WorkflowServiceFactory; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ -public class RDFConsumer implements Consumer -{ +public class RDFConsumer implements Consumer { private static final Logger log = Logger.getLogger(RDFConsumer.class); - + protected Deque toConvert; protected Deque toDelete; @@ -43,7 +50,7 @@ public class RDFConsumer implements Consumer protected SiteService siteService; protected WorkspaceItemService workspaceItemService; protected WorkflowItemService workflowItemService; - + @Override public void initialize() throws Exception { bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); @@ -55,139 +62,116 @@ public class RDFConsumer implements Consumer @Override public void consume(Context ctx, Event event) - throws SQLException - { - if (this.toConvert == null) - { + throws SQLException { + if (this.toConvert == null) { this.toConvert = new LinkedList<>(); } - if (this.toDelete == null) - { + if (this.toDelete == null) { this.toDelete = new LinkedList<>(); } - + int sType = event.getSubjectType(); - log.debug(event.getEventTypeAsString() + " for " - + event.getSubjectTypeAsString() + ":" + event.getSubjectID()); - switch (sType) - { - case (Constants.BITSTREAM) : - { + log.debug(event.getEventTypeAsString() + " for " + + event.getSubjectTypeAsString() + ":" + event.getSubjectID()); + switch (sType) { + case (Constants.BITSTREAM): { this.consumeBitstream(ctx, event); + return; } - case (Constants.BUNDLE) : - { + case (Constants.BUNDLE): { this.consumeBundles(ctx, event); return; } - case (Constants.ITEM) : - { + case (Constants.ITEM): { this.consumeCommunityCollectionItem(ctx, event); return; } - case (Constants.COLLECTION) : - { + case (Constants.COLLECTION): { this.consumeCommunityCollectionItem(ctx, event); return; } - case (Constants.COMMUNITY) : - { + case (Constants.COMMUNITY): { this.consumeCommunityCollectionItem(ctx, event); return; } - case (Constants.SITE) : - { - this.consumeSite(ctx,event); + case (Constants.SITE): { + this.consumeSite(ctx, event); return; } - default: - { + default: { log.warn("RDFConsumer should not have been given this kind of " - + "subject in an event, skipping: " + event.toString()); + + "subject in an event, skipping: " + event.toString()); } } - + } - - public void consumeBitstream(Context ctx, Event event) throws SQLException - { + + public void consumeBitstream(Context ctx, Event event) throws SQLException { if (event.getEventType() == Event.MODIFY - || event.getEventType() == Event.MODIFY_METADATA) - { + || event.getEventType() == Event.MODIFY_METADATA) { Bitstream bitstream = bitstreamService.find(ctx, event.getSubjectID()); - if (bitstream == null) - { + if (bitstream == null) { log.debug("Cannot find bitstream " + event.getSubjectID() + "! " - + "Ignoring, as it is likely it was deleted " - + "and we'll cover it by a REMOVE event on its bundle."); + + "Ignoring, as it is likely it was deleted " + + "and we'll cover it by a REMOVE event on its bundle."); return; } List bundles = bitstream.getBundles(); - for (Bundle b : bundles) - { + for (Bundle b : bundles) { List items = b.getItems(); - for (Item i : items) - { + for (Item i : items) { if (workspaceItemService.findByItem(ctx, i) != null - || workflowItemService.findByItem(ctx, i) != null) - { - log.debug("Ignoring Item " + i.getID() + " as a corresponding workspace or workflow item exists."); + || workflowItemService.findByItem(ctx, i) != null) { + log.debug( + "Ignoring Item " + i.getID() + " as a corresponding workspace or workflow item exists."); continue; } DSOIdentifier id = new DSOIdentifier(i, ctx); - if (!this.toDelete.contains(id) && !this.toConvert.contains(id)) - { + if (!this.toDelete.contains(id) && !this.toConvert.contains(id)) { this.toConvert.addLast(id); } } - + } return; } // ignore create and delete event on Bitstreams, as they should be // reported as ADD and REMOVE on their bundles as well. - if (event.getEventType() == Event.CREATE - || event.getEventType() == Event.DELETE) - { - return; + if (event.getEventType() == Event.CREATE + || event.getEventType() == Event.DELETE) { + return; } - + // Events of type ADD and REMOVE does currently (DSpace 4.1) not exist // on a bitstream - log.warn("Got an unexpected event type (" + event.getEventTypeAsString() - + ") for a bitstream. Ignoring."); + log.warn("Got an unexpected event type (" + event.getEventTypeAsString() + + ") for a bitstream. Ignoring."); } - - public void consumeBundles(Context ctx, Event event) throws SQLException - { - if (event.getEventType() == Event.ADD - || event.getEventType() == Event.REMOVE - || event.getEventType() == Event.MODIFY - || event.getEventType() == Event.MODIFY_METADATA) - { + + public void consumeBundles(Context ctx, Event event) throws SQLException { + if (event.getEventType() == Event.ADD + || event.getEventType() == Event.REMOVE + || event.getEventType() == Event.MODIFY + || event.getEventType() == Event.MODIFY_METADATA) { // either a Bitstream was added or removed or the Bundle was changed // update its item. Bundle bundle = bundleService.find(ctx, event.getSubjectID()); - if (bundle == null) - { + if (bundle == null) { log.debug("Cannot find bundle " + event.getSubjectID() + "! " - + "Ignoring, as it is likely it was deleted " - + "and we'll cover it by a REMOVE event on its item."); + + "Ignoring, as it is likely it was deleted " + + "and we'll cover it by a REMOVE event on its item."); return; } List items = bundle.getItems(); - for (Item i : items) - { + for (Item i : items) { if (workspaceItemService.findByItem(ctx, i) != null - || workflowItemService.findByItem(ctx, i) != null) - { - log.debug("Ignoring Item " + i.getID() + " as a corresponding workspace or workflow item exists."); - continue; - } + || workflowItemService.findByItem(ctx, i) != null) { + log.debug("Ignoring Item " + i.getID() + " as a corresponding workspace or workflow item exists."); + continue; + } DSOIdentifier id = new DSOIdentifier(i, ctx); - if (!this.toDelete.contains(id) && !this.toConvert.contains(id)) - { + if (!this.toDelete.contains(id) && !this.toConvert.contains(id)) { this.toConvert.addLast(id); } } @@ -196,71 +180,62 @@ public class RDFConsumer implements Consumer // ignore create and delete event on Bundles, as they should be // reported as ADD and REMOVE on their items as well. if (event.getEventType() == Event.CREATE - || event.getEventType() == Event.DELETE) - { + || event.getEventType() == Event.DELETE) { return; } - - log.warn("Got an unexpected event type (" + event.getEventTypeAsString() - + ") for a bundle. Ignoring."); + + log.warn("Got an unexpected event type (" + event.getEventTypeAsString() + + ") for a bundle. Ignoring."); } - - public void consumeCommunityCollectionItem(Context ctx, Event event) throws SQLException - { + + public void consumeCommunityCollectionItem(Context ctx, Event event) throws SQLException { if (event.getSubjectType() != Constants.COMMUNITY - && event.getSubjectType() != Constants.COLLECTION - && event.getSubjectType() != Constants.ITEM) - { - log.error("Called on an unexpected Event with subject type " - + event.getSubjectTypeAsString() + " and event type " - + event.getEventTypeAsString() + ", ignoring."); + && event.getSubjectType() != Constants.COLLECTION + && event.getSubjectType() != Constants.ITEM) { + log.error("Called on an unexpected Event with subject type " + + event.getSubjectTypeAsString() + " and event type " + + event.getEventTypeAsString() + ", ignoring."); return; } - - if (event.getEventType() == Event.DELETE) - { - DSOIdentifier id = new DSOIdentifier(event.getSubjectType(), - event.getSubjectID(), event.getDetail(), event.getIdentifiers()); - - if (this.toConvert.contains(id)) - { + + if (event.getEventType() == Event.DELETE) { + DSOIdentifier id = new DSOIdentifier(event.getSubjectType(), + event.getSubjectID(), event.getDetail(), event.getIdentifiers()); + + if (this.toConvert.contains(id)) { this.toConvert.remove(id); } - - if (!this.toDelete.contains(id)) - { + + if (!this.toDelete.contains(id)) { this.toDelete.addLast(id); } return; } - + if (event.getEventType() == Event.MODIFY - || event.getEventType() == Event.MODIFY_METADATA - || event.getEventType() == Event.ADD - || event.getEventType() == Event.REMOVE - || event.getEventType() == Event.CREATE) - { + || event.getEventType() == Event.MODIFY_METADATA + || event.getEventType() == Event.ADD + || event.getEventType() == Event.REMOVE + || event.getEventType() == Event.CREATE) { // we have to find the dso as the handle is set as detail only // if the event type is delete. DSpaceObject dso = event.getSubject(ctx); - if (dso == null) - { - log.debug("Cannot find " + event.getSubjectTypeAsString() + " " - + event.getSubjectID() + "! " + "Ignoring, as it is " - + "likely it was deleted and we'll cover it by another " - + "event with the type REMOVE."); + if (dso == null) { + log.debug("Cannot find " + event.getSubjectTypeAsString() + " " + + event.getSubjectID() + "! " + "Ignoring, as it is " + + "likely it was deleted and we'll cover it by another " + + "event with the type REMOVE."); return; } - + // ignore unfinished submissions here. Every unfinished submission // has an workspace item. The item flag "in_archive" doesn't help us // here as this is also set to false if a newer version was submitted. - if (dso instanceof Item) - { + if (dso instanceof Item) { if (workspaceItemService.findByItem(ctx, (Item) dso) != null - || workflowItemService.findByItem(ctx, (Item) dso) != null) - { - log.debug("Ignoring Item " + dso.getID() + " as a corresponding workspace or workflow item exists."); + || workflowItemService.findByItem(ctx, (Item) dso) != null) { + log.debug( + "Ignoring Item " + dso.getID() + " as a corresponding workspace or workflow item exists."); return; } } @@ -270,48 +245,42 @@ public class RDFConsumer implements Consumer // delete the item from the triple store instead of converting it. // we don't have to take care for reinstantions of items as they can // be processed as normal modify events. - if (dso instanceof Item - && event.getDetail() != null - && event.getDetail().equals("WITHDRAW")) - { - if (this.toConvert.contains(id)) - { + if (dso instanceof Item + && event.getDetail() != null + && event.getDetail().equals("WITHDRAW")) { + if (this.toConvert.contains(id)) { this.toConvert.remove(id); } - if (!this.toDelete.contains(id)) - { + if (!this.toDelete.contains(id)) { this.toDelete.add(id); return; } } - if (!this.toDelete.contains(id) - && !this.toConvert.contains(id)) - { + if (!this.toDelete.contains(id) + && !this.toConvert.contains(id)) { this.toConvert.addLast(id); } } } - + public void consumeSite(Context ctx, Event event) throws SQLException { if (event.getEventType() == Event.ADD - || event.getEventType() == Event.REMOVE - || event.getEventType() == Event.MODIFY - || event.getEventType() == Event.MODIFY_METADATA) - { + || event.getEventType() == Event.REMOVE + || event.getEventType() == Event.MODIFY + || event.getEventType() == Event.MODIFY_METADATA) { Site site = siteService.findSite(ctx); - + DSOIdentifier id = new DSOIdentifier(Constants.SITE, - site.getID(), site.getHandle(), Arrays.asList(site.getHandle())); - - if (!this.toConvert.contains(id)) - { + site.getID(), site.getHandle(), Arrays.asList(site.getHandle())); + + if (!this.toConvert.contains(id)) { this.toConvert.add(id); } return; } - log.warn("Got an unexpected Event for the SITE. Event type is " - + event.getEventTypeAsString() + ", ignoring."); + log.warn("Got an unexpected Event for the SITE. Event type is " + + event.getEventTypeAsString() + ", ignoring."); } @Override @@ -321,185 +290,160 @@ public class RDFConsumer implements Consumer // we don't want to store private data in a triplestore with public // SPARQL endpoint. ctx = new Context(Context.Mode.READ_ONLY); - if (toDelete == null) - { + if (toDelete == null) { log.debug("Deletion queue does not exists, creating empty queue."); this.toDelete = new LinkedList<>(); } - if (toConvert != null) - { + if (toConvert != null) { log.debug("Starting conversion of DSpaceObjects."); - while (true) - { + while (true) { DSOIdentifier id; - try { id = toConvert.removeFirst(); } - catch (NoSuchElementException ex) { break; } + try { + id = toConvert.removeFirst(); + } catch (NoSuchElementException ex) { + break; + } - if (toDelete.contains(id)) - { - log.debug("Skipping " + Constants.typeText[id.type] + " " - + id.id.toString() + " as it is marked for " - + "deletion as well."); + if (toDelete.contains(id)) { + log.debug("Skipping " + Constants.typeText[id.type] + " " + + id.id.toString() + " as it is marked for " + + "deletion as well."); continue; } - log.debug("Converting " + Constants.typeText[id.type] + " " - + id.id.toString() + "."); + log.debug("Converting " + Constants.typeText[id.type] + " " + + id.id.toString() + "."); convert(ctx, id); } log.debug("Conversion ended."); } log.debug("Starting to delete data from the triple store..."); - while (true) - { + while (true) { DSOIdentifier id; - try { id = toDelete.removeFirst(); } - catch (NoSuchElementException ex) { break; } - + try { + id = toDelete.removeFirst(); + } catch (NoSuchElementException ex) { + break; + } + log.debug("Going to delete data from " + - Constants.typeText[id.type] + " " - + id.id.toString() + "."); + Constants.typeText[id.type] + " " + + id.id.toString() + "."); delete(ctx, id); } ctx.abort(); log.debug("Deletion finished."); } - void convert(Context ctx, DSOIdentifier id) throws SQLException - { + void convert(Context ctx, DSOIdentifier id) throws SQLException { Model m = null; - try - { - if (id.type == Constants.SITE) - { + try { + if (id.type == Constants.SITE) { m = RDFUtil.convertAndStore(ctx, siteService.findSite(ctx)); return; } DSpaceObject dso = ContentServiceFactory.getInstance().getDSpaceObjectService(id.type).find(ctx, id.id); - if (dso == null) - { - log.error("Cannot find " + Constants.typeText[id.type] - + " " + id.id + " unexpectedly! Will delete all " - + "information about it in the triple store."); + if (dso == null) { + log.error("Cannot find " + Constants.typeText[id.type] + + " " + id.id + " unexpectedly! Will delete all " + + "information about it in the triple store."); toDelete.add(id); return; } m = RDFUtil.convertAndStore(ctx, dso); - } - catch(AuthorizeException ex) - { - log.debug(Constants.typeText[id.type] + " " + - id.id.toString() + " couldn't be converted: " - + "anonymous user doesn't have read permsission. " - + ex.getMessage()); + } catch (AuthorizeException ex) { + log.debug(Constants.typeText[id.type] + " " + + id.id.toString() + " couldn't be converted: " + + "anonymous user doesn't have read permsission. " + + ex.getMessage()); toDelete.add(id); - } - catch (IllegalArgumentException ex) - { - log.error("Ignoring an unexpected IllegalArgumentException: " - + ex.getMessage(), ex); - } - catch (ItemNotArchivedException ex) - { - log.info("Anonymous user cannot read " - + Constants.typeText[id.type] + " " - + id.id.toString() - + ": deleting it from the triplestore."); + } catch (IllegalArgumentException ex) { + log.error("Ignoring an unexpected IllegalArgumentException: " + + ex.getMessage(), ex); + } catch (ItemNotArchivedException ex) { + log.info("Anonymous user cannot read " + + Constants.typeText[id.type] + " " + + id.id.toString() + + ": deleting it from the triplestore."); toDelete.add(id); - } - catch (ItemNotDiscoverableException ex) - { + } catch (ItemNotDiscoverableException ex) { log.info("Item " + id.id.toString() + " is not " - + "discoverable: deleting it from the triplestore."); + + "discoverable: deleting it from the triplestore."); toDelete.add(id); - } - catch (ItemWithdrawnException ex) - { + } catch (ItemWithdrawnException ex) { log.info("Item " + id.id.toString() + " is withdrawn: " - + "deleting it from the triplestore."); + + "deleting it from the triplestore."); toDelete.add(id); - } - catch (RDFMissingIdentifierException ex) - { - log.warn("Cannot convert " + Constants.typeText[id.type] - + " " + id.id.toString() + ", as no RDF " - + "identifier could be generated: " - + ex.getMessage(), ex); - } - finally - { - if (m != null) - { + } catch (RDFMissingIdentifierException ex) { + log.warn("Cannot convert " + Constants.typeText[id.type] + + " " + id.id.toString() + ", as no RDF " + + "identifier could be generated: " + + ex.getMessage(), ex); + } finally { + if (m != null) { m.close(); } } } - + void delete(Context context, DSOIdentifier id) - throws SQLException { - try - { + throws SQLException { + try { RDFUtil.delete(context, id.type, id.id, id.handle, id.identifiers); - } - catch (RDFMissingIdentifierException ex) - { - log.warn("Cannot delete " + Constants.typeText[id.type] + " " - + id.id.toString() + ": " - + ex.getMessage(), ex); + } catch (RDFMissingIdentifierException ex) { + log.warn("Cannot delete " + Constants.typeText[id.type] + " " + + id.id.toString() + ": " + + ex.getMessage(), ex); } } - + @Override public void finish(Context ctx) throws Exception { } - - class DSOIdentifier - { + + class DSOIdentifier { int type; UUID id; String handle; List identifiers; - - DSOIdentifier(int type, UUID id, String handle, List identifiers) - { + + DSOIdentifier(int type, UUID id, String handle, List identifiers) { this.type = type; this.id = id; this.handle = handle; this.identifiers = identifiers; } - - DSOIdentifier(DSpaceObject dso, Context ctx) - { - if (dso.getType() != Constants.SITE - && dso.getType() != Constants.COMMUNITY - && dso.getType() != Constants.COLLECTION - && dso.getType() != Constants.ITEM) - { + + DSOIdentifier(DSpaceObject dso, Context ctx) { + if (dso.getType() != Constants.SITE + && dso.getType() != Constants.COMMUNITY + && dso.getType() != Constants.COLLECTION + && dso.getType() != Constants.ITEM) { throw new IllegalArgumentException( - ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getTypeText(dso) - + " is currently not supported as independent entity by dspace-rdf."); + ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getTypeText(dso) + + " is currently not supported as independent entity by dspace-rdf."); } this.type = dso.getType(); this.id = dso.getID(); this.handle = dso.getHandle(); this.identifiers = ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getIdentifiers(ctx, dso); } - + @Override - public boolean equals(Object o) - { - if (!(o instanceof DSOIdentifier)) return false; + public boolean equals(Object o) { + if (!(o instanceof DSOIdentifier)) { + return false; + } // Cast o to DSOIdentifier and compare the UUIDs for equality. return this.id.equals(((DSOIdentifier) o).id); } - + @Override - public int hashCode() - { - // as at least up to DSpace version 5.3 DSpaceObjectType is a + public int hashCode() { + // as at least up to DSpace version 5.3 DSpaceObjectType is a // one-digit number, this should produce an distinct hash. - return this.type + (10*this.id.hashCode()); + return this.type + (10 * this.id.hashCode()); } } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/rdf/RDFMissingIdentifierException.java b/dspace-api/src/main/java/org/dspace/rdf/RDFMissingIdentifierException.java index 746c72eff1..2aafea39ea 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/RDFMissingIdentifierException.java +++ b/dspace-api/src/main/java/org/dspace/rdf/RDFMissingIdentifierException.java @@ -8,22 +8,22 @@ package org.dspace.rdf; -import org.dspace.core.Constants; - import java.util.UUID; +import org.dspace.core.Constants; + /** * RDFConverter Exception + * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ class RDFMissingIdentifierException extends Exception { - public RDFMissingIdentifierException() - { + public RDFMissingIdentifierException() { super("Coudln't generate a necessary RDF Identifier."); } RDFMissingIdentifierException(int type, UUID id) { - super("Couldn't generate a necessary RDF Identifier for " - + Constants.typeText[type] + " " + id.toString() + "."); + super("Couldn't generate a necessary RDF Identifier for " + + Constants.typeText[type] + " " + id.toString() + "."); } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/RDFUtil.java b/dspace-api/src/main/java/org/dspace/rdf/RDFUtil.java index 55d82004bc..1280f18cd9 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/RDFUtil.java +++ b/dspace-api/src/main/java/org/dspace/rdf/RDFUtil.java @@ -8,11 +8,11 @@ package org.dspace.rdf; -import com.hp.hpl.jena.rdf.model.Model; import java.sql.SQLException; import java.util.List; import java.util.UUID; +import com.hp.hpl.jena.rdf.model.Model; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; @@ -28,13 +28,13 @@ import org.dspace.rdf.factory.RDFFactory; import org.dspace.services.factory.DSpaceServicesFactory; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class RDFUtil { private static final Logger log = Logger.getLogger(RDFUtil.class); - private static final AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); - + private static final AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance() + .getAuthorizeService(); + public static final String CONTENT_NEGOTIATION_KEY = "rdf.contentNegotiation.enable"; /** * Key of the Property to load the types of DSpaceObjects that should get @@ -83,294 +83,287 @@ public class RDFUtil { */ public static final String STORAGE_GRAPHSTORE_LOGIN_KEY = "rdf.storage.graphstore.login"; + /** + * Default constructor + */ + private RDFUtil() { } + /** * Loads converted data of a DSpaceObject identified by the URI provided * as {@code identifier}. This method uses the RDFStorage configurated in * the DSpace configuration. Close the model - * ({@link com.hp.hpl.jena.rdf.model.Model#close() Model.close()}) as soon + * ({@link com.hp.hpl.jena.rdf.model.Model#close() Model.close()}) as soon * as possible to free system resources. * * @param identifier A URI representing the object you want to load data about. - * @return A model containing the RDF data to the specified identifier or - * null if no data could be found. + * @return A model containing the RDF data to the specified identifier or + * null if no data could be found. */ - public static Model loadModel(String identifier) - { + public static Model loadModel(String identifier) { return RDFFactory.getInstance().getRDFStorage().load(identifier); } - + /** * Generates a URI identifying the provided DSpaceObject. This method * automatically loads and instantiates the URIGenerator configured in * DSpace configuration. - * Please note that URIs can be generated for DSpaceObjects of the - * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf + * Please note that URIs can be generated for DSpaceObjects of the + * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf * doesn't support Bundles or Bitstreams as independent entity. * * @param context DSpace Context. - * @param dso DSpace Object you want to get an identifier for. + * @param dso DSpace Object you want to get an identifier for. * @return URI to identify the DSO or null if no URI could be generated. - * This can happen f.e. if you use a URIGenerator that uses - * persistent identifier like DOIs or Handles but there is no such - * identifier assigned to the provided DSO. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * This can happen f.e. if you use a URIGenerator that uses + * persistent identifier like DOIs or Handles but there is no such + * identifier assigned to the provided DSO. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public static String generateIdentifier(Context context, DSpaceObject dso) - throws SQLException - { + throws SQLException { return RDFFactory.getInstance().getURIGenerator().generateIdentifier(context, dso); } - + /** * Generates a URI identifying the provided DSpaceObject. This method * automatically loads and instantiates the URIGenerator configured in * DSpace configuration. - * Please note that URIs can be generated for DSpaceObjects of the - * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf + * Please note that URIs can be generated for DSpaceObjects of the + * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf * doesn't support Bundles or Bitstreams as independent entity. * - * @param context DSpace Context. - * @param type Type of the DSpaceObject you want to generate a URI for (e.g. - * {@link org.dspace.core.Constants#ITEM Constants.ITEM}. - * @param id UUID of the DSpaceObject you want to generate a URI for. - * @param handle Handle of the DSpaceObject you want to generate a URI for. + * @param context DSpace Context. + * @param type Type of the DSpaceObject you want to generate a URI for (e.g. + * {@link org.dspace.core.Constants#ITEM Constants.ITEM}. + * @param id UUID of the DSpaceObject you want to generate a URI for. + * @param handle Handle of the DSpaceObject you want to generate a URI for. * @param identifier identifiers of the object. - * * @return URI to identify the DSO or null if no URI could be generated. - * This can happen f.e. if you use a URIGenerator that uses - * persistent identifier like DOIs or Handles but there is no such - * identifier assigned to the provided DSO. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * This can happen f.e. if you use a URIGenerator that uses + * persistent identifier like DOIs or Handles but there is no such + * identifier assigned to the provided DSO. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public static String generateIdentifier(Context context, int type, UUID id, - String handle, List identifier) - throws SQLException - { - return RDFFactory.getInstance().getURIGenerator().generateIdentifier(context, - type, id, handle, identifier); + String handle, List identifier) + throws SQLException { + return RDFFactory.getInstance().getURIGenerator().generateIdentifier(context, + type, id, handle, identifier); } + /** * Converts the the provided DSpaceObject into RDF and returns the model. - * Please note that dspace-rdf doesn't support Bundles or Bitstreams as + * Please note that dspace-rdf doesn't support Bundles or Bitstreams as * independent entity. You can convert DSpaceObjects of type SITE, * COMMUNITY, COLLECTION or ITEM. * * @param context Consider that the converted data will be stored in a * triple store, that is outside the range of the DSpace - * authorization mechanism. Unless you are really sure what - * you are doing, you should provide the context of an - * anonymous user here, as the triple store probably provides + * authorization mechanism. Unless you are really sure what + * you are doing, you should provide the context of an + * anonymous user here, as the triple store probably provides * a public SPARQL endpoint. - * @param dso DSpaceObject to convert. + * @param dso DSpaceObject to convert. * @return The converted data or null if the conversion result is empty. - * Remember to close the model as soon as you don't need it anymore. + * Remember to close the model as soon as you don't need it anymore. * @throws RDFMissingIdentifierException If no identifier could be generated. - * @throws SQLException if database error - * @throws ItemNotArchivedException If you want to convert an Item that is - * not archived. - * @throws ItemWithdrawnException If you want to convert an Item that is - * withdrawn. - * @throws ItemNotDiscoverableException If you want to convert an Item that - * is not discoverable. - * @throws AuthorizeException If the DSpaceObject does not have READ - * permissions with the provided context. - * @throws IllegalArgumentException If the DSpaceObject is not of type SITE, - * COMMUNITY, COLLECTION or ITEM. + * @throws SQLException if database error + * @throws ItemNotArchivedException If you want to convert an Item that is + * not archived. + * @throws ItemWithdrawnException If you want to convert an Item that is + * withdrawn. + * @throws ItemNotDiscoverableException If you want to convert an Item that + * is not discoverable. + * @throws AuthorizeException If the DSpaceObject does not have READ + * permissions with the provided context. + * @throws IllegalArgumentException If the DSpaceObject is not of type SITE, + * COMMUNITY, COLLECTION or ITEM. */ public static Model convert(Context context, DSpaceObject dso) - throws RDFMissingIdentifierException, SQLException, ItemNotArchivedException, - ItemWithdrawnException, ItemNotDiscoverableException, - AuthorizeException, IllegalArgumentException - { + throws RDFMissingIdentifierException, SQLException, ItemNotArchivedException, + ItemWithdrawnException, ItemNotDiscoverableException, + AuthorizeException, IllegalArgumentException { String[] dsoTypes = DSpaceServicesFactory.getInstance() - .getConfigurationService() - .getArrayProperty(CONVERTER_DSOTYPES_KEY); - if (dsoTypes == null || dsoTypes.length == 0) - { + .getConfigurationService() + .getArrayProperty(CONVERTER_DSOTYPES_KEY); + if (dsoTypes == null || dsoTypes.length == 0) { log.warn("Property rdf." + CONVERTER_DSOTYPES_KEY + " was not found " - + "or is empty. Will convert all type of DSpace Objects."); + + "or is empty. Will convert all type of DSpace Objects."); } else { boolean found = false; - for (String type : dsoTypes) - { - if (StringUtils.equalsIgnoreCase(Constants.typeText[dso.getType()], type.trim())) - { + for (String type : dsoTypes) { + if (StringUtils.equalsIgnoreCase(Constants.typeText[dso.getType()], type.trim())) { found = true; break; } } - if (!found) - { - log.warn("Configuration of DSpaceObjects of type " - + Constants.typeText[dso.getType()] - + " prohibitted by configuration."); + if (!found) { + log.warn("Configuration of DSpaceObjects of type " + + Constants.typeText[dso.getType()] + + " prohibitted by configuration."); return null; } } isPublic(context, dso); return RDFFactory.getInstance().getRDFConverter().convert(context, dso); } - + /** * Converts a DSpaceObject into RDF data and stores them using the configured - * {@link org.dspace.rdf.storage.RDFStorage RDFStorage}. - * Please note that dspace-rdf doesn't support Bundles or Bitstreams as + * {@link org.dspace.rdf.storage.RDFStorage RDFStorage}. + * Please note that dspace-rdf doesn't support Bundles or Bitstreams as * independent entity. You can convert DSpaceObjects of type SITE, * COMMUNITY, COLLECTION or ITEM. * * @param context Consider that the converted data will be stored in a * triple store, that is outside the range of the DSpace - * authorization mechanism. Unless you are really sure what - * you are doing, you should provide the context of an - * anonymous user here, as the triple store probably provides + * authorization mechanism. Unless you are really sure what + * you are doing, you should provide the context of an + * anonymous user here, as the triple store probably provides * a public SPARQL endpoint. - * @param dso DSpaceObject to convert. + * @param dso DSpaceObject to convert. * @return The converted data or null if the conversion result is empty. - * Remember to close the model as soon as you don't need it anymore. + * Remember to close the model as soon as you don't need it anymore. * @throws RDFMissingIdentifierException If no identifier could be generated. - * @throws SQLException if database error - * @throws ItemNotArchivedException If you want to convert an Item that is - * not archived. - * @throws ItemWithdrawnException If you want to convert an Item that is - * withdrawn. - * @throws ItemNotDiscoverableException If you want to convert an Item that - * is not discoverable. - * @throws AuthorizeException If the DSpaceObject does not have READ - * permissions with the provided context. - * @throws IllegalArgumentException If the DSpaceObject is not of type SITE, - * COMMUNITY, COLLECTION or ITEM. + * @throws SQLException if database error + * @throws ItemNotArchivedException If you want to convert an Item that is + * not archived. + * @throws ItemWithdrawnException If you want to convert an Item that is + * withdrawn. + * @throws ItemNotDiscoverableException If you want to convert an Item that + * is not discoverable. + * @throws AuthorizeException If the DSpaceObject does not have READ + * permissions with the provided context. + * @throws IllegalArgumentException If the DSpaceObject is not of type SITE, + * COMMUNITY, COLLECTION or ITEM. */ public static Model convertAndStore(Context context, DSpaceObject dso) - throws RDFMissingIdentifierException, SQLException, ItemNotArchivedException, - ItemWithdrawnException, ItemNotDiscoverableException, - AuthorizeException, IllegalArgumentException - { + throws RDFMissingIdentifierException, SQLException, ItemNotArchivedException, + ItemWithdrawnException, ItemNotDiscoverableException, + AuthorizeException, IllegalArgumentException { Model convertedData = convert(context, dso); - + String identifier = generateIdentifier(context, dso); - if (StringUtils.isEmpty(identifier)) - { - log.error("Cannot generate identifier for dso from type " - + ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getTypeText(dso) + " (id: " + dso.getID() + ")."); - if (convertedData != null) convertedData.close(); + if (StringUtils.isEmpty(identifier)) { + log.error("Cannot generate identifier for dso from type " + + ContentServiceFactory.getInstance().getDSpaceObjectService(dso) + .getTypeText(dso) + " (id: " + dso.getID() + ")."); + if (convertedData != null) { + convertedData.close(); + } throw new RDFMissingIdentifierException(dso.getType(), dso.getID()); } - if (convertedData == null) - { - // if data about this dso is stored in the triplestore already, we + if (convertedData == null) { + // if data about this dso is stored in the triplestore already, we // should remove it as a conversion currently result in no data RDFFactory.getInstance().getRDFStorage().delete(identifier); return null; } - + RDFFactory.getInstance().getRDFStorage().store(identifier, convertedData); return convertedData; } - + /** * Checks whether the provided DSpaceObject is readable within the provided * context and if the DSO is an Item whether it is archived, discoverable * and not withdrawn. - * + * * @param context Consider that the converted data will be stored in a * triple store, that is outside the range of the DSpace - * authorization mechanism. Unless you are really sure what - * you are doing, you should provide the context of an - * anonymous user here, as the triple store probably provides + * authorization mechanism. Unless you are really sure what + * you are doing, you should provide the context of an + * anonymous user here, as the triple store probably provides * a public SPARQL endpoint. - * @param dso The DSpaceObjet to check. - * @throws SQLException if database error - * @throws ItemNotArchivedException If {@code dso} is an Item and is not - * archived. - * @throws ItemWithdrawnException If {@code dso} is an Item and is withdrawn. + * @param dso The DSpaceObjet to check. + * @throws SQLException if database error + * @throws ItemNotArchivedException If {@code dso} is an Item and is not + * archived. + * @throws ItemWithdrawnException If {@code dso} is an Item and is withdrawn. * @throws ItemNotDiscoverableException If {@code dso} is an Item and is not * discoverable. - * @throws AuthorizeException If {@code context} does not grant {@code READ} - * permissions for {@code dso}. + * @throws AuthorizeException If {@code context} does not grant {@code READ} + * permissions for {@code dso}. */ public static void isPublic(Context context, DSpaceObject dso) - throws SQLException, ItemNotArchivedException, ItemWithdrawnException, - ItemNotDiscoverableException, AuthorizeException - { + throws SQLException, ItemNotArchivedException, ItemWithdrawnException, + ItemNotDiscoverableException, AuthorizeException { // as there is no way to set site permissions in XMLUI or JSPUI, we // ignore the permissions of the repository root (DSpaceObject of type // Site). - if (dso instanceof Site) - { + if (dso instanceof Site) { return; } authorizeService.authorizeAction(context, dso, Constants.READ); - if (dso instanceof Item) - { + if (dso instanceof Item) { Item item = (Item) dso; - if (!item.isArchived()) throw new ItemNotArchivedException(); - if (!item.isDiscoverable()) throw new ItemNotDiscoverableException(); - if (item.isWithdrawn()) throw new ItemWithdrawnException(); + if (!item.isArchived()) { + throw new ItemNotArchivedException(); + } + if (!item.isDiscoverable()) { + throw new ItemNotDiscoverableException(); + } + if (item.isWithdrawn()) { + throw new ItemWithdrawnException(); + } } } - + /** - * Does the same as {@link #isPublic(Context, DSpaceObject) + * Does the same as {@link #isPublic(Context, DSpaceObject) * isPublic(Context, DSpaceObject)} but returns a boolean instead of throwing * exceptions. For those who don't want to deal with catching exceptions. * * @param context Consider that the converted data will be stored in a * triple store, that is outside the range of the DSpace - * authorization mechanism. Unless you are really sure what - * you are doing, you should provide the context of an - * anonymous user here, as the triple store probably provides + * authorization mechanism. Unless you are really sure what + * you are doing, you should provide the context of an + * anonymous user here, as the triple store probably provides * a public SPARQL endpoint. - * @param dso The DSpaceObjet to check. - * @return true if {@link #isPublic(Context, DSpaceObject) - * isPublic(Context, DSpaceObject)} doesn't throw an exception, false if it + * @param dso The DSpaceObjet to check. + * @return true if {@link #isPublic(Context, DSpaceObject) + * isPublic(Context, DSpaceObject)} doesn't throw an exception, false if it * did. * @throws SQLException if database error */ - public static boolean isPublicBoolean(Context context, DSpaceObject dso) - throws SQLException - { + public static boolean isPublicBoolean(Context context, DSpaceObject dso) + throws SQLException { try { RDFUtil.isPublic(context, dso); - } catch (ItemNotArchivedException | ItemWithdrawnException - | ItemNotDiscoverableException | AuthorizeException ex) { + } catch (ItemNotArchivedException | ItemWithdrawnException + | ItemNotDiscoverableException | AuthorizeException ex) { return false; } return true; } - + /** * Deletes the data identified by the URI from the triple store. * * @param uri URI to identify the named graph to delete. */ - public static void delete(String uri) - { + public static void delete(String uri) { RDFFactory.getInstance().getRDFStorage().delete(uri); } - + /** * This is a shortcut to generate an RDF identifier for a DSpaceObject and * to delete the identified data from the named graph. * - * @param ctx - * The relevant DSpace Context. - * @param type DSpaceObject type (e.g. {@link Constants#ITEM Constants.ITEM}). - * @param id Id of the DspaceObject. - * @param handle Handle of the DSpaceObject. + * @param ctx The relevant DSpace Context. + * @param type DSpaceObject type (e.g. {@link Constants#ITEM Constants.ITEM}). + * @param id Id of the DspaceObject. + * @param handle Handle of the DSpaceObject. * @param identifiers list of identifiers - * @throws SQLException if database error + * @throws SQLException if database error * @throws RDFMissingIdentifierException In case that no Identifier could be generated. */ public static void delete(Context ctx, int type, UUID id, String handle, List identifiers) - throws SQLException, RDFMissingIdentifierException - { + throws SQLException, RDFMissingIdentifierException { String uri = RDFFactory.getInstance().getURIGenerator() - .generateIdentifier(ctx, type, id, handle, identifiers); - if (uri != null) - { + .generateIdentifier(ctx, type, id, handle, identifiers); + if (uri != null) { RDFFactory.getInstance().getRDFStorage().delete(uri); } else { throw new RDFMissingIdentifierException(type, id); diff --git a/dspace-api/src/main/java/org/dspace/rdf/RDFizer.java b/dspace-api/src/main/java/org/dspace/rdf/RDFizer.java index a398f24549..a6f8804756 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/RDFizer.java +++ b/dspace-api/src/main/java/org/dspace/rdf/RDFizer.java @@ -8,12 +8,31 @@ package org.dspace.rdf; +import java.io.PrintWriter; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CopyOnWriteArraySet; + import com.hp.hpl.jena.rdf.model.Model; -import org.apache.commons.cli.*; +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.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.Site; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; @@ -26,31 +45,23 @@ import org.dspace.rdf.storage.RDFStorage; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; -import java.io.PrintWriter; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CopyOnWriteArraySet; - /** * This class manages the handling of RDF data in DSpace. It generates * identifiers, it loads data, it manages the conversion of DSpace Objects into * RDF data. It can be used as instantiated object as well as CLI. - * + * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class RDFizer { - + private static final Logger log = Logger.getLogger(RDFizer.class); - + protected boolean stdout; protected boolean verbose; protected boolean dryrun; protected String lang; protected Context context; - + protected final ConfigurationService configurationService; protected final ContentServiceFactory contentServiceFactory; protected final CommunityService communityService; @@ -60,22 +71,21 @@ public class RDFizer { /** - * Set to remember with DSpaceObject were converted or deleted from the - * triplestore already. This set is helpful when converting or deleting + * Set to remember with DSpaceObject were converted or deleted from the + * triplestore already. This set is helpful when converting or deleting * multiple DSpaceObjects (e.g. Communities with all Subcommunities and * Items). */ protected Set processed; - public RDFizer() - { + public RDFizer() { this.stdout = false; this.verbose = false; this.dryrun = false; this.lang = "TURTLE"; this.processed = new CopyOnWriteArraySet(); this.context = new Context(Context.Mode.READ_ONLY); - + this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); this.contentServiceFactory = ContentServiceFactory.getInstance(); this.communityService = contentServiceFactory.getCommunityService(); @@ -83,26 +93,24 @@ public class RDFizer { this.handleService = HandleServiceFactory.getInstance().getHandleService(); this.storage = RDFFactory.getInstance().getRDFStorage(); } - + /** * This method allows you to override the context used for conversion and to * determine which DSpaceObjects should be deleted from the triplestore, * consider well if this is really necessary. - * If this method is not used the context of an anonymous user will be used. + * If this method is not used the context of an anonymous user will be used. *

    - * Please consider: If your triplestore offers a public sparql endpoint - * all information readable with the provided context will be exposed to + * Please consider: If your triplestore offers a public sparql endpoint + * all information readable with the provided context will be exposed to * public! - * If you store your data in a private triplestore that does not provides - * public access, you might consider to use this method to convert all data + * If you store your data in a private triplestore that does not provides + * public access, you might consider to use this method to convert all data * stored in your repository. *

    - * - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. */ - protected void overrideContext(Context context) - { + protected void overrideContext(Context context) { this.context = context; } @@ -121,15 +129,14 @@ public class RDFizer { * stored as well, unless {@code dryrun} is set true. Turtle will be used * as serialization. * - * @param stdout - * if {@code true}, print all data to standard output + * @param stdout if {@code true}, print all data to standard output */ public void setStdout(boolean stdout) { this.stdout = stdout; } - + /** - * Returns whether verbose information is printed to System.err. Probably + * Returns whether verbose information is printed to System.err. Probably * this is helpful for CLI only. * * @return {@code true} if verbose mode is on @@ -139,11 +146,10 @@ public class RDFizer { } /** - * Set this to true to print verbose information to System.err. Probably + * Set this to true to print verbose information to System.err. Probably * this is helpful for CLI only. * - * @param verbose - * print verbose information to stderr + * @param verbose print verbose information to stderr */ public void setVerbose(boolean verbose) { this.verbose = verbose; @@ -159,271 +165,260 @@ public class RDFizer { } /** - * Set this true to prevent any changes on the triple store. Probably this + * Set this true to prevent any changes on the triple store. Probably this * is helpful for CLI usage only. * - * @param dryrun - * test run without any changes to the triple store + * @param dryrun test run without any changes to the triple store */ public void setDryrun(boolean dryrun) { this.dryrun = dryrun; } - + /** * Deletes all data stored in the triplestore (drops all named graphs and * cleans the default graph). */ - public void deleteAll() - { + public void deleteAll() { report("Sending delete command to the triple store."); if (!this.dryrun) { storage.deleteAll(); } report("Deleted all data from the triplestore."); } - + /** * Delete the data about the DSpaceObject from the triplestore. - * All data about descendent Subcommunities, Collections and Items will be + * All data about descendent Subcommunities, Collections and Items will be * deleted as well. * - * @param dso - * DSpace object - * @param reset - * reset processed status (converted or deleted from the triplestore) - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param dso DSpace object + * @param reset reset processed status (converted or deleted from the triplestore) + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void delete(DSpaceObject dso, boolean reset) - throws SQLException - { + throws SQLException { if (dso.getType() != Constants.SITE && dso.getType() != Constants.COMMUNITY && dso.getType() != Constants.COLLECTION - && dso.getType() != Constants.ITEM) - { + && dso.getType() != Constants.ITEM) { throw new IllegalArgumentException(contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) - + " is currently not supported as independent entity."); + + " is currently not supported as independent entity."); } - if (dso.getType() == Constants.SITE) - { + if (dso.getType() == Constants.SITE) { // we don't need to iterate over all objects, use a shorctut: this.deleteAll(); } Callback callback = new Callback() { @Override protected void callback(DSpaceObject dso) - throws SQLException - { + throws SQLException { String identifier = RDFUtil.generateIdentifier(context, dso); - - if (StringUtils.isEmpty(identifier)) - { - System.err.println("Cannot determine RDF URI for " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID() + "(handle " - + dso.getHandle() + ")" + ", skipping. Please " - + "delete it specifying the RDF URI."); - log.error("Cannot detgermine RDF URI for " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID() + "(handle " - + dso.getHandle() + ")" + ", skipping deletion."); + + if (StringUtils.isEmpty(identifier)) { + System.err.println("Cannot determine RDF URI for " + + contentServiceFactory.getDSpaceObjectService(dso) + .getTypeText(dso) + " " + dso.getID() + "(handle " + + dso.getHandle() + ")" + ", skipping. Please " + + "delete it specifying the RDF URI."); + log.error("Cannot detgermine RDF URI for " + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso + .getID() + "(handle " + + dso.getHandle() + ")" + ", skipping deletion."); return; } - + report("Deleting Named Graph" + identifier); - if (!dryrun) - { + if (!dryrun) { storage.delete(identifier); } } }; this.dspaceDFS(dso, callback, false, reset); } - + /** - * Converts and stores all DSpaceObjects that are readable for an anonymous + * Converts and stores all DSpaceObjects that are readable for an anonymous * user. * - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public void convertAll() - throws SQLException - { + throws SQLException { report("Starting conversion of all DSpaceItems, this may take a while..."); this.convert(contentServiceFactory.getSiteService().findSite(context), true); report("Conversion ended."); } - + protected void convert(DSpaceObject dso, boolean reset) - throws SQLException - { + throws SQLException { if (dso.getType() != Constants.SITE - && dso.getType() != Constants.COMMUNITY - && dso.getType() != Constants.COLLECTION - && dso.getType() != Constants.ITEM) - { + && dso.getType() != Constants.COMMUNITY + && dso.getType() != Constants.COLLECTION + && dso.getType() != Constants.ITEM) { throw new IllegalArgumentException(contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) - + " is currently not supported as independent entity."); + + " is currently not supported as independent entity."); } - + Callback callback = new Callback() { @Override protected void callback(DSpaceObject dso) - throws SQLException - { + throws SQLException { Model converted = null; - try - { - if (dryrun) - { + try { + if (dryrun) { converted = RDFUtil.convert(context, dso); } else { converted = RDFUtil.convertAndStore(context, dso); } } catch (ItemNotArchivedException ex) { - if (!(dso instanceof Item)) throw new IllegalStateException(ex.getMessage(), ex); - report("Skipping conversion of Item " + dso.getID() - + " (handle " + dso.getHandle() + "): Item is not " - + "archived."); + if (!(dso instanceof Item)) { + throw new IllegalStateException(ex.getMessage(), ex); + } + report("Skipping conversion of Item " + dso.getID() + + " (handle " + dso.getHandle() + "): Item is not " + + "archived."); return; } catch (ItemWithdrawnException ex) { - if (!(dso instanceof Item)) throw new IllegalStateException(ex.getMessage(), ex); - report("Skipping conversion of Item " + dso.getID() - + " (handle " + dso.getHandle() + "): Item is " - + "withdrawn."); + if (!(dso instanceof Item)) { + throw new IllegalStateException(ex.getMessage(), ex); + } + report("Skipping conversion of Item " + dso.getID() + + " (handle " + dso.getHandle() + "): Item is " + + "withdrawn."); return; } catch (ItemNotDiscoverableException ex) { - if (!(dso instanceof Item)) throw new IllegalStateException(ex.getMessage(), ex); - report("Skipping conversion of Item " + dso.getID() - + " (handle " + dso.getHandle() + "): Item is not " - + "discoverable."); + if (!(dso instanceof Item)) { + throw new IllegalStateException(ex.getMessage(), ex); + } + report("Skipping conversion of Item " + dso.getID() + + " (handle " + dso.getHandle() + "): Item is not " + + "discoverable."); return; } catch (AuthorizeException ex) { - report("Skipping conversion of " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " - + dso.getID() + " (handle " + dso.getHandle() + ")" - + ", not authorized: " + ex.getMessage()); + report("Skipping conversion of " + contentServiceFactory.getDSpaceObjectService(dso) + .getTypeText(dso) + " " + + dso.getID() + " (handle " + dso.getHandle() + ")" + + ", not authorized: " + ex.getMessage()); return; } catch (RDFMissingIdentifierException ex) { - String errormessage = "Skipping conversion of " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID() - + " (handle " + dso.getHandle() + ")."; + String errormessage = "Skipping conversion of " + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID() + + " (handle " + dso.getHandle() + ")."; log.error(errormessage, ex); - System.err.println(errormessage - + " Error while converting: " + ex.getMessage()); - + System.err.println(errormessage + + " Error while converting: " + ex.getMessage()); + return; } - + if (stdout) { - if (converted == null) - { - System.err.println("Conversion of " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + if (converted == null) { + System.err.println( + "Conversion of " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID() + " resulted in no data."); } else { converted.write(System.out, lang); } } - if (converted != null) converted.close(); + if (converted != null) { + converted.close(); + } } }; - + this.dspaceDFS(dso, callback, true, reset); } - + protected void dspaceDFS(DSpaceObject dso, Callback callback, boolean check, boolean reset) - throws SQLException - { + throws SQLException { if (dso.getType() != Constants.SITE - && dso.getType() != Constants.COMMUNITY - && dso.getType() != Constants.COLLECTION - && dso.getType() != Constants.ITEM) - { + && dso.getType() != Constants.COMMUNITY + && dso.getType() != Constants.COLLECTION + && dso.getType() != Constants.ITEM) { throw new IllegalArgumentException(contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) - + " is currently not supported as independent entity."); + + " is currently not supported as independent entity."); } - if (reset) - { + if (reset) { this.processed.clear(); } - - if (isProcessed(dso)) - { - log.debug("Skipping processing of " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " - + dso.getID() + " (handle " + dso.getHandle() + + if (isProcessed(dso)) { + log.debug( + "Skipping processing of " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + + dso.getID() + " (handle " + dso.getHandle() + "), already processed."); return; } markProcessed(dso); // this is useful to debug depth first search, but it is really noisy. - //log.debug("Procesing " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID() + ":" + dso.getHandle() + "."); - + //log.debug("Procesing " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso + // .getID() + ":" + dso.getHandle() + "."); + // if this method is used for conversion we should check if we have the // permissions to read a DSO before converting all of it decendents // (e.g. check read permission on a community before converting all of // its subcommunties and collections). // just skip items with missing permissions and report them. - if (check) - { - try - { + if (check) { + try { RDFUtil.isPublic(context, dso); } catch (ItemNotArchivedException ex) { - if (!(dso instanceof Item)) throw new IllegalStateException(ex.getMessage(), ex); - report("Skipping processing of Item " + dso.getID() - + " (handle " + dso.getHandle() + "): Item is not " - + "archived."); + if (!(dso instanceof Item)) { + throw new IllegalStateException(ex.getMessage(), ex); + } + report("Skipping processing of Item " + dso.getID() + + " (handle " + dso.getHandle() + "): Item is not " + + "archived."); return; } catch (ItemWithdrawnException ex) { - if (!(dso instanceof Item)) throw new IllegalStateException(ex.getMessage(), ex); - report("Skipping processing of Item " + dso.getID() - + " (handle " + dso.getHandle() + "): Item is " - + "withdrawn."); + if (!(dso instanceof Item)) { + throw new IllegalStateException(ex.getMessage(), ex); + } + report("Skipping processing of Item " + dso.getID() + + " (handle " + dso.getHandle() + "): Item is " + + "withdrawn."); return; } catch (ItemNotDiscoverableException ex) { - if (!(dso instanceof Item)) throw new IllegalStateException(ex.getMessage(), ex); - report("Skipping processing of Item " + dso.getID() - + " (handle " + dso.getHandle() + "): Item is not " - + "discoverable."); + if (!(dso instanceof Item)) { + throw new IllegalStateException(ex.getMessage(), ex); + } + report("Skipping processing of Item " + dso.getID() + + " (handle " + dso.getHandle() + "): Item is not " + + "discoverable."); return; } catch (AuthorizeException ex) { - report("Skipping processing of " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " - + dso.getID() + " (handle " + dso.getHandle() + ")" + report( + "Skipping processing of " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + + dso.getID() + " (handle " + dso.getHandle() + ")" + ", not authorized: " + ex.getMessage()); return; } } - if (dso instanceof Site) - { + if (dso instanceof Site) { List communities = communityService.findAllTop(context); - for (Community community : communities) - { + for (Community community : communities) { this.dspaceDFS(community, callback, check, false); } } - - if (dso instanceof Community) - { + + if (dso instanceof Community) { List subcommunities = ((Community) dso).getSubcommunities(); - for (Community sub : subcommunities) - { + for (Community sub : subcommunities) { this.dspaceDFS(sub, callback, check, false); } List collections = ((Community) dso).getCollections(); - for (Collection collection : collections) - { + for (Collection collection : collections) { this.dspaceDFS(collection, callback, check, false); } } - - if (dso instanceof Collection) - { + + if (dso instanceof Collection) { Iterator items = itemService.findAllByCollection(context, (Collection) dso); - while (items.hasNext()) - { + while (items.hasNext()) { Item item = items.next(); this.dspaceDFS(item, callback, check, false); } @@ -435,7 +430,7 @@ public class RDFizer { // of the callback call below. // The following code is left here for the day, we decide to also convert // bundles and/or bitstreams. -// +// // if (dso instanceof Item) // { // Bundle[] bundles = ((Item) dso).getBundles(); @@ -444,7 +439,7 @@ public class RDFizer { // this.dspaceDFS(bundle, callback, check, false); // } // } -// +// // if (dso instanceof Bundle) // { // Bitstream[] bistreams = ((Bundle) dso).getBitstreams(); @@ -453,169 +448,147 @@ public class RDFizer { // this.dspaceDFS(bitstream, callback, check, false); // } // } - + callback.callback(dso); report("Processed " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID() - + " (handle " + dso.getHandle() + ")."); + + " (handle " + dso.getHandle() + ")."); context.uncacheEntity(dso); } - - protected boolean isProcessed(DSpaceObject dso) - { + + protected boolean isProcessed(DSpaceObject dso) { return this.processed.contains(dso.getID()); } - - protected void markProcessed(DSpaceObject dso) - { + + protected void markProcessed(DSpaceObject dso) { this.processed.add(dso.getID()); } - - protected void report(String message) - { - if (this.verbose) - { + + protected void report(String message) { + if (this.verbose) { System.err.println(message); } log.debug(message); } - - protected void runCLI(String[] args) - { + + protected void runCLI(String[] args) { // prepare CLI and parse arguments Options options = createOptions(); CommandLineParser parser = new PosixParser(); CommandLine line = null; - try - { + try { line = parser.parse(options, args); - } - catch (ParseException ex) - { + } catch (ParseException ex) { usage(options); System.err.println(); System.err.println(ex.getMessage()); log.fatal(ex); System.exit(1); } - + String[] remainingArgs = line.getArgs(); - if (remainingArgs.length > 0) - { + if (remainingArgs.length > 0) { this.usage(options); System.err.println(); StringBuilder builder = new StringBuilder(100); - for (String argument : remainingArgs) - { - if (builder.length() > 0) builder.append(", "); + for (String argument : remainingArgs) { + if (builder.length() > 0) { + builder.append(", "); + } builder.append(argument); } String argumentsLine = builder.toString().trim(); System.err.print("Cannot recognize the following argument"); - if (remainingArgs.length >= 2) System.err.print("s"); + if (remainingArgs.length >= 2) { + System.err.print("s"); + } System.err.println(": " + argumentsLine + "."); System.exit(1); } // set member variables depending on CLI arguments. - if (line.hasOption("verbose")) - { + if (line.hasOption("verbose")) { setVerbose(true); } - - if (line.hasOption("dry-run")) - { + + if (line.hasOption("dry-run")) { setDryrun(true); } - if (line.hasOption("stdout")) - { + if (line.hasOption("stdout")) { setStdout(true); } - + // check mutual exclusive arguments - if (line.hasOption("delete") && line.hasOption("delete-all")) - { + if (line.hasOption("delete") && line.hasOption("delete-all")) { usage(options); System.err.println("\n\nYou cannot use the options --delete " - + "and --delete-all together."); + + "and --delete-all together."); System.exit(1); } if (line.hasOption("convert-all") - && (line.hasOption("delete") || line.hasOption("delete-all"))) - { + && (line.hasOption("delete") || line.hasOption("delete-all"))) { usage(options); System.err.println("\n\nYou cannot use the option --convert-all " - + "together with --delete or --delete-all."); + + "together with --delete or --delete-all."); System.exit(1); } if (line.hasOption("identifiers") - && (line.hasOption("delete") || line.hasOption("delete-all"))) - { + && (line.hasOption("delete") || line.hasOption("delete-all"))) { usage(options); System.err.println("\n\nYou cannot use the option --identifiers " - + "together with --delete or --delete-all."); + + "together with --delete or --delete-all."); System.exit(1); } - if (line.hasOption("stdout") - && (line.hasOption("delete") || line.hasOption("delete-all"))) - { + if (line.hasOption("stdout") + && (line.hasOption("delete") || line.hasOption("delete-all"))) { usage(options); System.err.println("\n\nYou cannot use the option --stdout together " - + "with --delete or --deleta-all."); + + "with --delete or --deleta-all."); System.exit(1); } // Run commands depending on CLI arguments. // process help first to prevent further evaluation of given options. - if (line.hasOption('h')) - { + if (line.hasOption('h')) { usage(options); System.exit(0); } - - if (line.hasOption("delete")) - { + + if (line.hasOption("delete")) { String[] identifiers = line.getOptionValues("delete"); - for (String identifier : identifiers) - { - if (!StringUtils.startsWithIgnoreCase(identifier, "hdl:")) - { - if (!this.dryrun) - { + for (String identifier : identifiers) { + if (!StringUtils.startsWithIgnoreCase(identifier, "hdl:")) { + if (!this.dryrun) { storage.delete(identifier); } - if (this.verbose) - { + if (this.verbose) { System.err.println("Deleted " + identifier + "."); } continue; } String handle = identifier.substring(4); - + log.debug("Trying to resolve identifier " + handle + "."); - + DSpaceObject dso = resolveHandle(handle); if (dso == null) { - // resolveHandle reports problems and return null in case + // resolveHandle reports problems and return null in case // of an error or an unresolvable handle. // Don't report it a second time, just continue... continue; } - - log.debug("Resolved identifier " + handle + " as " - + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID()); - - try - { + + log.debug("Resolved identifier " + handle + " as " + + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " " + dso.getID()); + + try { this.delete(dso, true); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error(ex); System.err.println("A problem with the database connection " - + "occurred. Canceled pending actions."); + + "occurred. Canceled pending actions."); System.err.println(ex.getMessage()); ex.printStackTrace(System.err); System.exit(1); @@ -623,40 +596,34 @@ public class RDFizer { } System.exit(0); } - - if (line.hasOption("delete-all")) - { + + if (line.hasOption("delete-all")) { this.deleteAll(); System.exit(0); } - - if (line.hasOption("identifiers")) - { + + if (line.hasOption("identifiers")) { String[] identifiers = line.getOptionValues("identifiers"); report("Starting conversion of specified DSpaceObjects..."); - + this.processed.clear(); - for (String handle : identifiers) - { + for (String handle : identifiers) { log.debug("Trying to resolve identifier " + handle + "."); - + DSpaceObject dso = resolveHandle(handle); if (dso == null) { - // resolveHandle reports problems and return null in case + // resolveHandle reports problems and return null in case // of an error or an unresolvable handle. // Don't report it a second time, just continue... continue; } - - try - { + + try { this.convert(dso, false); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error(ex); System.err.println("A problem with the database connection " - + "occurred. Canceled pending actions."); + + "occurred. Canceled pending actions."); System.err.println(ex.getMessage()); ex.printStackTrace(System.err); System.exit(1); @@ -666,144 +633,134 @@ public class RDFizer { System.exit(0); } - if (line.hasOption("convert-all")) - { + if (line.hasOption("convert-all")) { try { this.convertAll(); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error(ex); System.err.println("A problem with the database connection " - + "occurred. Canceled pending actions."); + + "occurred. Canceled pending actions."); System.err.println(ex.getMessage()); ex.printStackTrace(System.err); System.exit(1); } System.exit(0); } - + this.usage(options); System.exit(0); } - protected DSpaceObject resolveHandle(String handle) - { + protected DSpaceObject resolveHandle(String handle) { DSpaceObject dso = null; - try - { + try { dso = handleService.resolveToObject(this.context, handle); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error(ex); System.err.println("A problem with the database connection " - + "occurred. Canceled pending actions."); + + "occurred. Canceled pending actions."); System.err.println(ex.getMessage()); ex.printStackTrace(System.err); System.exit(1); - } - catch (IllegalStateException ex) - { + } catch (IllegalStateException ex) { log.error(ex); - System.err.println("Cannot recognize identifier '" - + handle + "', skipping."); + System.err.println("Cannot recognize identifier '" + + handle + "', skipping."); return null; } - if (dso == null) - { - System.err.println("Cannot resolve identifier '" + handle - + "', skipping."); - log.debug("Couldn't resolve identifier '" + handle - + "', dso was null."); + if (dso == null) { + System.err.println("Cannot resolve identifier '" + handle + + "', skipping."); + log.debug("Couldn't resolve identifier '" + handle + + "', dso was null."); return null; } if (dso.getType() != Constants.SITE - && dso.getType() != Constants.COMMUNITY - && dso.getType() != Constants.COLLECTION - && dso.getType() != Constants.ITEM) - { - System.err.println(contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " are currently not " - + "supported as independent entities. Bundles and Bitstreams " - + "should be processed as part of their item."); + && dso.getType() != Constants.COMMUNITY + && dso.getType() != Constants.COLLECTION + && dso.getType() != Constants.ITEM) { + System.err + .println(contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " are currently not " + + "supported as independent entities. Bundles and Bitstreams " + + "should be processed as part of their item."); return null; } return dso; } - + protected Options createOptions() { Options options = new Options(); options.addOption("h", "help", false, "Print usage information and exit."); options.addOption("v", "verbose", false, "Print verbose information to " - + "stderr while converting data."); + + "stderr while converting data."); options.addOption("n", "dry-run", false, "Don't store the converted " - + "data in the triple store, don't delete data from the " - + "triplestore. Make a dry run, simulation what would happen."); + + "data in the triple store, don't delete data from the " + + "triplestore. Make a dry run, simulation what would happen."); options.addOption("o", "stdout", false, "Print all converted data to " + - "stdout using turtle as serialization."); + "stdout using turtle as serialization."); options.addOption("n", "dry-run", false, "Don't send any data or commands " + - "to the triplestore. Usefull for debugging or in conjunction " + - "with --stdout."); + "to the triplestore. Usefull for debugging or in conjunction " + + "with --stdout."); options.addOption("c", "convert-all", false, "Convert all DSpace Objects" + - " that are readable for an anonymous user. This may take a long time" + - "depending on the number of stored communties, collections and " + - "items. Existing information in the triple store will be updated."); + " that are readable for an anonymous user. This may take a long time" + + "depending on the number of stored communties, collections and " + + "items. Existing information in the triple store will be updated."); Option optIdentifiers = OptionBuilder.withLongOpt("identifiers") - .hasArgs() - .withArgName("handle") - .withValueSeparator(' ') - .withDescription("Only convert these DSpace Objects. If you specify " - + "a Community or Collection all of their Items will be " - + "converted as well. Separate multiple identifiers with a " - + "space.") - .create('i'); + .hasArgs() + .withArgName("handle") + .withValueSeparator(' ') + .withDescription("Only convert these DSpace Objects. If you specify " + + "a Community or Collection all of their Items " + + "will be " + + "converted as well. Separate multiple identifiers" + + " with a " + + "space.") + .create('i'); options.addOption(optIdentifiers); - + Option optDelete = OptionBuilder.withLongOpt("delete") - .hasArgs() - .withArgName("hdl:handle | URI") - .withValueSeparator(' ') - .withDescription("Delete previously converted data. Specify " - + "either the handle of a DSpaceObject in the format " - + "'hdl:' or the URI used to identify the rdf " - + "data in the triplestore. If you specify a Community, " - + "Collection or Item by its handle all converted " - + "information about attached Subcommunities, " - + "Collections, Items, Bundles and Bitstreams will be " - + "deleted as well. Separate multiple identifiers with " - + "a space.") - .create(); + .hasArgs() + .withArgName("hdl:handle | URI") + .withValueSeparator(' ') + .withDescription("Delete previously converted data. Specify " + + "either the handle of a DSpaceObject in the format " + + "'hdl:' or the URI used to identify the rdf " + + "data in the triplestore. If you specify a Community, " + + "Collection or Item by its handle all converted " + + "information about attached Subcommunities, " + + "Collections, Items, Bundles and Bitstreams will be " + + "deleted as well. Separate multiple identifiers with " + + "a space.") + .create(); options.addOption(optDelete); - + Option optDeleteAll = OptionBuilder.withLongOpt("delete-all") - .withDescription("Delete all converted data from the triplestore.") - .create(); + .withDescription("Delete all converted data from the triplestore.") + .create(); options.addOption(optDeleteAll); - + return options; } - - protected static void usage(Options options) - { + + protected static void usage(Options options) { String cliSyntax = "[dspace-bin]/bin/dspace rdfizer [OPTIONS...]"; String header = ""; String footer = "\nYou cannot use the options --convert-all, --identifiers " + - "or --stdout together with --delete or --delete-all.\n" + - "Please use at least one option out of --convert-all, --delete, " + - "--delete-all or --identifiers.\n"; - + "or --stdout together with --delete or --delete-all.\n" + + "Please use at least one option out of --convert-all, --delete, " + + "--delete-all or --identifiers.\n"; + PrintWriter err = new PrintWriter(System.err); HelpFormatter helpformater = new HelpFormatter(); helpformater.printHelp(err, 79, cliSyntax, header, options, 2, 2, footer); err.flush(); // don't close PrintWriter err, as it would close System.err! } - - public static void main(String[] args) - { + + public static void main(String[] args) { // get a context from an anonymous user. // don't switch off authorization system! We'll export the converted // data into a triple store that provides a public sparql endpoint. @@ -812,17 +769,16 @@ public class RDFizer { Context context = new Context(Context.Mode.READ_ONLY); RDFizer myself = null; - myself = new RDFizer(); + myself = new RDFizer(); myself.overrideContext(context); myself.runCLI(args); - + // we don't change anything in the database, so abort the context. context.abort(); } - - protected abstract class Callback - { + + protected abstract class Callback { protected abstract void callback(DSpaceObject dso) - throws SQLException; + throws SQLException; } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/ConverterPlugin.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/ConverterPlugin.java index 4cb7c608ab..f0ad88c582 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/ConverterPlugin.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/ConverterPlugin.java @@ -8,37 +8,37 @@ package org.dspace.rdf.conversion; -import com.hp.hpl.jena.rdf.model.Model; import java.sql.SQLException; + +import com.hp.hpl.jena.rdf.model.Model; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.services.ConfigurationService; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public interface ConverterPlugin { public void setConfigurationService(ConfigurationService configurationService); - + /** * Convert the specified DSpaceObject or a part of it into RDF. + * * @param context Please check the READ permission for the provided context * before converting any data! - * @param dso The DSpaceObject that should be converted. + * @param dso The DSpaceObject that should be converted. * @return A Jena Model containing the generated RDF. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public Model convert(Context context, DSpaceObject dso) throws SQLException, AuthorizeException; - + /** * Returns all type of DSpaceObjects that are supported by this plugin. + * * @param type Resource type as defined in org.dspace.core.Constants. * @return A boolean whether the requested type is supported by this plugin. * @see org.dspace.core.Constants diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/DMRM.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/DMRM.java index 9a77b02d84..0d0f955e0a 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/DMRM.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/DMRM.java @@ -2,12 +2,12 @@ * 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.rdf.conversion; - + import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; @@ -15,84 +15,145 @@ import com.hp.hpl.jena.rdf.model.Resource; /** * Schema for DSpace Metadata RDF Mappings. + * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) - * @see http://digital-repositories.org/ontologies/dspace-metadata-mapping/0.2.0 + * @see http://digital + * -repositories.org/ontologies/dspace-metadata-mapping/0.2.0 */ public class DMRM { - /**

    The RDF model that holds the vocabulary terms

    */ + /** + *

    The RDF model that holds the vocabulary terms

    + */ private static Model m_model = ModelFactory.createDefaultModel(); - - /**

    The namespace of the vocabulary as a string

    */ - public static final String NS = "http://digital-repositories.org/ontologies/dspace-metadata-mapping/0.2.0#"; - - /**

    The namespace of the vocabulary as a string

    - * @return Namespace URI - * @see #NS */ - public static String getURI() {return NS;} - - /**

    The namespace of the vocabulary as a resource

    */ - public static final Resource NAMESPACE = m_model.createResource( NS ); - /**

    Represents the mapping of a DSpace metadata value to an RDF equivalent.

    */ + /** + *

    The namespace of the vocabulary as a string

    + */ + public static final String NS = "http://digital-repositories.org/ontologies/dspace-metadata-mapping/0.2.0#"; + + /** + *

    The namespace of the vocabulary as a string

    + * + * @return Namespace URI + * @see #NS + */ + public static String getURI() { + return NS; + } + + /** + *

    The namespace of the vocabulary as a resource

    + */ + public static final Resource NAMESPACE = m_model.createResource(NS); + + /** + *

    Represents the mapping of a DSpace metadata value to an RDF equivalent.

    + */ public static final Resource DSpaceMetadataRDFMapping = m_model.createResource(NS + "DSpaceMetadataRDFMapping"); - - /**

    A reified statement that describes the result of the DSpaceMetadataRDFMapping.

    */ + + /** + *

    A reified statement that describes the result of the DSpaceMetadataRDFMapping.

    + */ public static final Resource Result = m_model.createResource(NS + "Result"); - - /**

    Processes a metadata value into an RDF value or an IRI.

    */ + + /** + *

    Processes a metadata value into an RDF value or an IRI.

    + */ public static final Resource ValueProcessor = m_model.createResource(NS + "ValueProcessor"); - - /**

    A regular expression to be used with java, composed of a matching and a replaying expression.

    */ - public static final Resource ValueModifier = m_model.createResource( NS + "ValueModifier" ); - - /**

    Generates a literal depending on a DSpace metadata value.

    */ + + /** + *

    A regular expression to be used with java, composed of a matching and a replaying expression.

    + */ + public static final Resource ValueModifier = m_model.createResource(NS + "ValueModifier"); + + /** + *

    Generates a literal depending on a DSpace metadata value.

    + */ public static final Resource LiteralGenerator = m_model.createResource(NS + "LiteralGenerator"); - - /**

    Generates an IRI used for a rdfs:Resource depending on the converted DSpace Object and one of its metadata values.

    */ + + /** + *

    Generates an IRI used for a rdfs:Resource depending on the converted DSpace Object and one of its metadata + * values.

    + */ public static final Resource ResourceGenerator = m_model.createResource(NS + "ResourceGenerator"); - - /**

    Placeholder for the IRI of the DSpace Object that gets converted.

    */ - public static final Resource DSpaceObjectIRI = m_model.createResource( NS + "DSpaceObjectIRI" ); - - /**

    Shortcut to generate a Literal containing an unchanged metadata value.

    */ + + /** + *

    Placeholder for the IRI of the DSpace Object that gets converted.

    + */ + public static final Resource DSpaceObjectIRI = m_model.createResource(NS + "DSpaceObjectIRI"); + + /** + *

    Shortcut to generate a Literal containing an unchanged metadata value.

    + */ public static final Resource DSpaceValue = m_model.createResource(NS + "DSpaceValue"); - - /**

    Specifies the RDF to generate for a specified matadata.

    */ - public static final Property creates = m_model.createProperty( NS + "creates" ); - - /**

    The subject of a DSpace metadata RDF mapping result.

    */ - public static final Property subject = m_model.createProperty( NS + "subject" ); - - /**

    The predicate of a DSpace metadata RDF mapping result.

    */ - public static final Property predicate = m_model.createProperty( NS + "predicate" ); - - /**

    The object of a DSpace metadata RDF mapping result.

    */ - public static final Property object = m_model.createProperty( NS + "object" ); - - /**

    The name of the metadata to convert (e.g. dc.title).

    */ - public static final Property metadataName = m_model.createProperty( NS + "metadataName" ); - - /**

    A regex that the metadata value has to fulfill if the mapping should become active.

    */ - public static final Property condition = m_model.createProperty( NS + "condition" ); - - /**

    Information how the metadata value should be modified before it is inserted in the pattern.

    */ - public static final Property modifier = m_model.createProperty( NS + "modifier" ); - - /**

    A regex that matches those subsequences of a metadata value, that should be replaced.

    */ - public static final Property matcher = m_model.createProperty( NS + "matcher" ); - - /**

    A regex that replaces previously matched subsequences of a metadata value.

    */ - public static final Property replacement = m_model.createProperty( NS + "replacement" ); - - /**

    A pattern that contains $DSpaceValue as placeholder for the metadata value.

    */ - public static final Property pattern = m_model.createProperty( NS + "pattern" ); - - /**

    Defines the datatype a generated literal gets.

    */ - public static final Property literalType = m_model.createProperty( NS + "literalType" ); - - /**

    Defines the language a literal uses. Maybe overridden by #dspaceLanguageTag.

    */ - public static final Property literalLanguage = m_model.createProperty( NS + "literalLanguage" ); - - /**

    Defines to use the language tag of a DSpace metadata value.

    */ - public static final Property dspaceLanguageTag = m_model.createProperty( NS + "dspaceLanguageTag"); + + /** + *

    Specifies the RDF to generate for a specified matadata.

    + */ + public static final Property creates = m_model.createProperty(NS + "creates"); + + /** + *

    The subject of a DSpace metadata RDF mapping result.

    + */ + public static final Property subject = m_model.createProperty(NS + "subject"); + + /** + *

    The predicate of a DSpace metadata RDF mapping result.

    + */ + public static final Property predicate = m_model.createProperty(NS + "predicate"); + + /** + *

    The object of a DSpace metadata RDF mapping result.

    + */ + public static final Property object = m_model.createProperty(NS + "object"); + + /** + *

    The name of the metadata to convert (e.g. dc.title).

    + */ + public static final Property metadataName = m_model.createProperty(NS + "metadataName"); + + /** + *

    A regex that the metadata value has to fulfill if the mapping should become active.

    + */ + public static final Property condition = m_model.createProperty(NS + "condition"); + + /** + *

    Information how the metadata value should be modified before it is inserted in the pattern.

    + */ + public static final Property modifier = m_model.createProperty(NS + "modifier"); + + /** + *

    A regex that matches those subsequences of a metadata value, that should be replaced.

    + */ + public static final Property matcher = m_model.createProperty(NS + "matcher"); + + /** + *

    A regex that replaces previously matched subsequences of a metadata value.

    + */ + public static final Property replacement = m_model.createProperty(NS + "replacement"); + + /** + *

    A pattern that contains $DSpaceValue as placeholder for the metadata value.

    + */ + public static final Property pattern = m_model.createProperty(NS + "pattern"); + + /** + *

    Defines the datatype a generated literal gets.

    + */ + public static final Property literalType = m_model.createProperty(NS + "literalType"); + + /** + *

    Defines the language a literal uses. Maybe overridden by #dspaceLanguageTag.

    + */ + public static final Property literalLanguage = m_model.createProperty(NS + "literalLanguage"); + + /** + *

    Defines to use the language tag of a DSpace metadata value.

    + */ + public static final Property dspaceLanguageTag = m_model.createProperty(NS + "dspaceLanguageTag"); + + /** + * Default constructor + */ + private DMRM() { } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataConverterPlugin.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataConverterPlugin.java index d1fc834ec3..5dcd8c2e4a 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataConverterPlugin.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataConverterPlugin.java @@ -2,12 +2,19 @@ * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at - * + * * http://www.dspace.org/license/ */ package org.dspace.rdf.conversion; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import com.hp.hpl.jena.rdf.model.InfModel; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; @@ -18,17 +25,15 @@ import com.hp.hpl.jena.reasoner.ValidityReport; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.FileUtils; import com.hp.hpl.jena.vocabulary.RDF; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.util.factory.UtilServiceFactory; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; +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.DSpaceObjectService; import org.dspace.core.Constants; @@ -38,19 +43,17 @@ import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ -public class MetadataConverterPlugin implements ConverterPlugin -{ +public class MetadataConverterPlugin implements ConverterPlugin { public final static String METADATA_MAPPING_PATH_KEY = "rdf.metadata.mappings"; public final static String METADATA_SCHEMA_URL_KEY = "rdf.metadata.schema"; public final static String METADATA_PREFIXES_KEY = "rdf.metadata.prefixes"; - + private final static Logger log = Logger.getLogger(MetadataConverterPlugin.class); - @Autowired(required=true) + @Autowired(required = true) protected ConfigurationService configurationService; - + @Override public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; @@ -58,41 +61,35 @@ public class MetadataConverterPlugin implements ConverterPlugin @Override public Model convert(Context context, DSpaceObject dso) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { String uri = RDFUtil.generateIdentifier(context, dso); DSpaceObjectService dsoService = ContentServiceFactory.getInstance().getDSpaceObjectService(dso); - if (uri == null) - { - log.error("Cannot create URI for " + dsoService.getTypeText(dso) + " " - + dso.getID() + " stopping conversion."); + if (uri == null) { + log.error("Cannot create URI for " + dsoService.getTypeText(dso) + " " + + dso.getID() + " stopping conversion."); return null; } Model convertedData = ModelFactory.createDefaultModel(); String prefixesPath = configurationService.getProperty(METADATA_PREFIXES_KEY); - if (!StringUtils.isEmpty(prefixesPath)) - { + if (!StringUtils.isEmpty(prefixesPath)) { InputStream is = FileManager.get().open(prefixesPath); - if (is == null) - { + if (is == null) { log.warn("Cannot find file '" + prefixesPath + "', ignoring..."); } else { convertedData.read(is, null, FileUtils.guessLang(prefixesPath)); try { is.close(); - } - catch (IOException ex) - { + } catch (IOException ex) { // nothing to do here. } } } - + Model config = loadConfiguration(); - if (config == null) - { + if (config == null) { log.error("Cannot load MetadataConverterPlugin configuration, " - + "skipping this plugin."); + + "skipping this plugin."); return null; } /* @@ -111,86 +108,76 @@ public class MetadataConverterPlugin implements ConverterPlugin } */ - ResIterator mappingIter = - config.listSubjectsWithProperty(RDF.type, DMRM.DSpaceMetadataRDFMapping); - if (!mappingIter.hasNext()) - { + ResIterator mappingIter = + config.listSubjectsWithProperty(RDF.type, DMRM.DSpaceMetadataRDFMapping); + if (!mappingIter.hasNext()) { log.warn("No metadata mappings found, returning null."); return null; } - + List mappings = new ArrayList<>(); - while (mappingIter.hasNext()) - { + while (mappingIter.hasNext()) { MetadataRDFMapping mapping = MetadataRDFMapping.getMetadataRDFMapping( - mappingIter.nextResource(), uri); - if (mapping != null) mappings.add(mapping); + mappingIter.nextResource(), uri); + if (mapping != null) { + mappings.add(mapping); + } } - + // should be changed, if Communities and Collections have metadata as well. - if (!(dso instanceof Item)) - { - log.error("This DspaceObject (" + dsoService.getTypeText(dso) + " " - + dso.getID() + ") should not have bin submitted to this " - + "plugin, as it supports Items only!"); + if (!(dso instanceof Item)) { + log.error("This DspaceObject (" + dsoService.getTypeText(dso) + " " + + dso.getID() + ") should not have bin submitted to this " + + "plugin, as it supports Items only!"); return null; } - - List metadata_values = dsoService.getMetadata(dso, MetadataSchema.DC_SCHEMA, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue value : metadata_values) - { + + List metadata_values = dsoService + .getMetadata(dso, MetadataSchema.DC_SCHEMA, Item.ANY, Item.ANY, Item.ANY); + for (MetadataValue value : metadata_values) { MetadataField metadataField = value.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); String fieldname = metadataSchema.getName() + "." + metadataField.getElement(); - if (metadataField.getQualifier() != null) - { + if (metadataField.getQualifier() != null) { fieldname = fieldname + "." + metadataField.getQualifier(); } - if (UtilServiceFactory.getInstance().getMetadataExposureService().isHidden(context, metadataSchema.getName(), metadataField.getElement(), - metadataField.getQualifier())) - { + if (UtilServiceFactory.getInstance().getMetadataExposureService() + .isHidden(context, metadataSchema.getName(), metadataField.getElement(), + metadataField.getQualifier())) { log.debug(fieldname + " is a hidden metadata field, won't " - + "convert it."); + + "convert it."); continue; } boolean converted = false; - if (metadataField.getQualifier() != null) - { + if (metadataField.getQualifier() != null) { Iterator iter = mappings.iterator(); - while (iter.hasNext()) - { + while (iter.hasNext()) { MetadataRDFMapping mapping = iter.next(); - if (mapping.matchesName(fieldname) && mapping.fulfills(value.getValue())) - { + if (mapping.matchesName(fieldname) && mapping.fulfills(value.getValue())) { mapping.convert(value.getValue(), value.getLanguage(), uri, convertedData); converted = true; } } } - if (!converted) - { + if (!converted) { String name = metadataSchema.getName() + "." + metadataField.getElement(); Iterator iter = mappings.iterator(); - while (iter.hasNext() && !converted) - { + while (iter.hasNext() && !converted) { MetadataRDFMapping mapping = iter.next(); - if (mapping.matchesName(name) && mapping.fulfills(value.getValue())) - { + if (mapping.matchesName(name) && mapping.fulfills(value.getValue())) { mapping.convert(value.getValue(), value.getLanguage(), uri, convertedData); converted = true; } } } - if (!converted) - { + if (!converted) { log.debug("Did not convert " + fieldname + ". Found no " - + "corresponding mapping."); + + "corresponding mapping."); } } config.close(); - if (convertedData.isEmpty()) - { + if (convertedData.isEmpty()) { convertedData.close(); return null; } @@ -202,53 +189,42 @@ public class MetadataConverterPlugin implements ConverterPlugin // should be changed, if Communities and Collections have metadata as well. return (type == Constants.ITEM); } - - protected Model loadConfiguration() - { + + protected Model loadConfiguration() { InputStream is = null; Model config = ModelFactory.createDefaultModel(); String mapping = configurationService.getProperty(METADATA_MAPPING_PATH_KEY); - if (StringUtils.isEmpty(mapping)) - { + if (StringUtils.isEmpty(mapping)) { log.error("Cannot find metadata mappings (looking for " - + "property " + METADATA_MAPPING_PATH_KEY + ")!"); + + "property " + METADATA_MAPPING_PATH_KEY + ")!"); return null; - } - else - { + } else { is = FileManager.get().open(mapping); - if (is == null) - { + if (is == null) { log.warn("Cannot find file '" + mapping + "', ignoring..."); } config.read(is, "file://" + mapping, FileUtils.guessLang(mapping)); try { // Make sure that we have an input stream to avoid NullPointer - if(is != null) - { + if (is != null) { is.close(); } - } - catch (IOException ex) - { + } catch (IOException ex) { // nothing to do here. } } - if (config.isEmpty()) - { + if (config.isEmpty()) { config.close(); log.warn("Metadata RDF Mapping did not contain any triples!"); return null; } - + String schemaURL = configurationService.getProperty(METADATA_SCHEMA_URL_KEY); - if (schemaURL == null) - { + if (schemaURL == null) { log.error("Cannot find metadata rdf mapping schema (looking for " - + "property " + METADATA_SCHEMA_URL_KEY + ")!"); + + "property " + METADATA_SCHEMA_URL_KEY + ")!"); } - if (!StringUtils.isEmpty(schemaURL)) - { + if (!StringUtils.isEmpty(schemaURL)) { log.debug("Going to inference over the rdf metadata mapping."); // Inferencing over the configuration data let us detect some rdf:type // properties out of rdfs:domain and rdfs:range properties @@ -260,19 +236,16 @@ public class MetadataConverterPlugin implements ConverterPlugin // If we do inferencing, we can easily check for consistency. ValidityReport reports = inf.validate(); - if (!reports.isValid()) - { + if (!reports.isValid()) { StringBuilder sb = new StringBuilder(); sb.append("The configuration of the MetadataConverterPlugin is "); sb.append("not valid regarding the schema ("); sb.append(DMRM.getURI()); sb.append(").\nThe following problems were encountered:\n"); for (Iterator iter = reports.getReports(); - iter.hasNext() ; ) - { + iter.hasNext(); ) { ValidityReport.Report report = iter.next(); - if (report.isError) - { + if (report.isError) { sb.append(" - " + iter.next() + "\n"); } } @@ -283,5 +256,5 @@ public class MetadataConverterPlugin implements ConverterPlugin } return config; } - + } diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataMappingException.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataMappingException.java index bb638b39e4..300df7c17d 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataMappingException.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataMappingException.java @@ -2,30 +2,26 @@ * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at - * + * * http://www.dspace.org/license/ */ package org.dspace.rdf.conversion; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class MetadataMappingException extends Exception { - public MetadataMappingException(String msg) - { + public MetadataMappingException(String msg) { super(msg); } - - public MetadataMappingException(Exception cause) - { + + public MetadataMappingException(Exception cause) { super(cause); } - - public MetadataMappingException(String msg, Exception cause) - { + + public MetadataMappingException(String msg, Exception cause) { super(msg, cause); } - + } diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataRDFMapping.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataRDFMapping.java index 11011ccedc..9fdf139197 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataRDFMapping.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataRDFMapping.java @@ -2,12 +2,18 @@ * 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.rdf.conversion; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.Property; @@ -16,183 +22,147 @@ import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.vocabulary.RDF; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class MetadataRDFMapping { - + private static final Logger log = Logger.getLogger(MetadataRDFMapping.class); - + protected final String name; protected final Pattern fulfills; protected final List results; - - protected MetadataRDFMapping(String name, Pattern fulfills, List results) - { + + protected MetadataRDFMapping(String name, Pattern fulfills, List results) { this.name = name; this.fulfills = fulfills; this.results = results; } - - + + public static MetadataRDFMapping getMetadataRDFMapping( - Resource mappingResource, String dsoIdentifier) - { + Resource mappingResource, String dsoIdentifier) { // For better log message: try to get the uri of this mapping. String uri = null; - if (mappingResource.getURI() != null) - { + if (mappingResource.getURI() != null) { uri = " (" + mappingResource.getURI() + ")"; } - - if (log.isDebugEnabled()) - { - if (uri.equals("")) - { + + if (log.isDebugEnabled()) { + if (uri.equals("")) { log.debug("Processing blank node MetadataRDFMapping."); - } - else - { + } else { log.debug("Processing MetadataRDFMapping" + uri + "."); } } - + // Parse the property DMRM.metadataName RDFNode nameNode; - try - { + try { nameNode = getSingularProperty(mappingResource, DMRM.metadataName); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { log.error("The Property 'metadataName' exists multiple times in one " - + "DSpaceMetadataRDFMapping, ignoring it" + uri + "."); + + "DSpaceMetadataRDFMapping, ignoring it" + uri + "."); return null; } - if (nameNode == null) - { + if (nameNode == null) { log.error("Cannot find property 'metadataName', ignoring mapping" + uri + "."); return null; } - if (!nameNode.isLiteral()) - { - log.error("Property 'metadataName' is not a literal, ignoring mapping" - + uri + "."); + if (!nameNode.isLiteral()) { + log.error("Property 'metadataName' is not a literal, ignoring mapping" + + uri + "."); return null; } String name = nameNode.asLiteral().getLexicalForm(); log.debug("Found mapping name '" + name + "'."); - - // Parse the property condition, if it exists. + + // Parse the property condition, if it exists. RDFNode conditionNode; - try - { + try { conditionNode = getSingularProperty(mappingResource, DMRM.condition); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { log.error("There are multiple properties 'condition' in one " - + "DSpaceMetadataRDFMapping, ignoring it" + uri + "."); + + "DSpaceMetadataRDFMapping, ignoring it" + uri + "."); return null; } String regex = null; Pattern condition = null; - if (conditionNode != null) - { - if (conditionNode.isLiteral()) - { + if (conditionNode != null) { + if (conditionNode.isLiteral()) { regex = conditionNode.asLiteral().getLexicalForm(); log.debug("Found property condition '" + regex + "'."); } else { log.error("Property 'condition' is not a literal, ignoring " - + "mapping" + uri + "."); + + "mapping" + uri + "."); return null; } } else { - // there is no property "condition". As this property is optional + // there is no property "condition". As this property is optional // there is nothing to be done here. log.debug("Didn't find a property \"condition\"."); } - if (regex != null) - { - try - { + if (regex != null) { + try { condition = Pattern.compile(regex); - } - catch (PatternSyntaxException ex) - { + } catch (PatternSyntaxException ex) { log.error("Property 'condition' does not specify a valid java " - + "regex pattern. Will ignore mapping" + uri + ".", ex); + + "regex pattern. Will ignore mapping" + uri + ".", ex); return null; } } - + // parse all properties DMRM.creates. List results = new ArrayList<>(); StmtIterator mappingIter = mappingResource.listProperties(DMRM.creates); - if (!mappingIter.hasNext()) - { + if (!mappingIter.hasNext()) { log.warn("No 'creates' property in a DSpaceMetadataRDFMapping, " - + "ignonring it" + uri + "."); + + "ignonring it" + uri + "."); return null; } - while (mappingIter.hasNext()) - { + while (mappingIter.hasNext()) { RDFNode result = mappingIter.nextStatement().getObject(); - if (!result.isResource()) - { + if (!result.isResource()) { log.error("Mapping result" + uri + " is a Literal not a resource. " - + "Ignoring mapping."); + + "Ignoring mapping."); return null; } results.add(result.asResource()); } - + // create mapping return new MetadataRDFMapping(name, condition, results); } - - public boolean matchesName(String name) - { + + public boolean matchesName(String name) { return StringUtils.equalsIgnoreCase(this.name, name); } - - public boolean fulfills(String value) - { + + public boolean fulfills(String value) { // if fulfills exists, we have to check the field value - if (this.fulfills == null) - { + if (this.fulfills == null) { return true; } - - if (!this.fulfills.matcher(value).matches()) - { + + if (!this.fulfills.matcher(value).matches()) { log.debug("Value '" + value + "' does not match regex '" + fulfills.toString() + "'."); return false; } else { return true; } - + //return this.fulfills.matcher(value).matches(); } - - public void convert(String value, String lang, String dsoIRI, Model m) - { - log.debug("Using convertion for field " + name + " on value: " + value - + " for " + dsoIRI + "."); + + public void convert(String value, String lang, String dsoIRI, Model m) { + log.debug("Using convertion for field " + name + " on value: " + value + + " for " + dsoIRI + "."); // run over all results - for (Iterator iter = this.results.iterator() ; iter.hasNext() ; ) - { + for (Iterator iter = this.results.iterator(); iter.hasNext(); ) { try { compileResult(m, iter.next(), dsoIRI, name, value, lang); } catch (MetadataMappingException ex) { @@ -201,290 +171,248 @@ public class MetadataRDFMapping { } } - protected void compileResult(Model m, Resource result, - String dsoIRI, String name, String value, String lang) throws MetadataMappingException - { + protected void compileResult(Model m, Resource result, + String dsoIRI, String name, String value, String lang) + throws MetadataMappingException { // for better debug messages. String uri = ""; - if (result.isURIResource()) uri = " (" + result.getURI() + ")"; - + if (result.isURIResource()) { + uri = " (" + result.getURI() + ")"; + } + // check the subject RDFNode subjectNode; - try - { + try { subjectNode = getSingularProperty(result, DMRM.subject); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { throw new MetadataMappingException("There are multiple 'subject' " - + "properties in a mapping result" + uri + "."); + + "properties in a mapping result" + uri + "."); } - if (subjectNode == null) - { - throw new MetadataMappingException("Mapping result" + uri - + " does not have a subject."); + if (subjectNode == null) { + throw new MetadataMappingException("Mapping result" + uri + + " does not have a subject."); } - if (!subjectNode.isResource()) - { - throw new MetadataMappingException("Subject of a result" + uri - + " is a Literal not a URIResource."); + if (!subjectNode.isResource()) { + throw new MetadataMappingException("Subject of a result" + uri + + " is a Literal not a URIResource."); } - + log.debug("Found subject: " + subjectNode.toString()); - + // check the predicate RDFNode predicateNode; - try - { + try { predicateNode = getSingularProperty(result, DMRM.predicate); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { throw new MetadataMappingException("There are multiple 'predicate' " - + "properties in a mapping result" + uri + "."); + + "properties in a mapping result" + uri + "."); } - if (predicateNode == null) - { - throw new MetadataMappingException("Mapping result" + uri - + " does not have a predicate."); + if (predicateNode == null) { + throw new MetadataMappingException("Mapping result" + uri + + " does not have a predicate."); } - if (!predicateNode.isResource()) - { - throw new MetadataMappingException("Predicate of a result" + uri - + " is a Literal not a URIResource."); + if (!predicateNode.isResource()) { + throw new MetadataMappingException("Predicate of a result" + uri + + " is a Literal not a URIResource."); } log.debug("Found predicate: " + predicateNode.toString()); - + RDFNode objectNode; - try - { + try { objectNode = getSingularProperty(result, DMRM.object); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { throw new MetadataMappingException("There are multiple 'object' " - + "properties in a mapping result" + uri + "."); + + "properties in a mapping result" + uri + "."); } - if (objectNode == null) - { - throw new MetadataMappingException("Mapping result" + uri - + " does not have a object."); + if (objectNode == null) { + throw new MetadataMappingException("Mapping result" + uri + + " does not have a object."); } log.debug("Found object: " + objectNode.toString()); - - Resource subject = parseSubject(m, subjectNode.asResource(), - dsoIRI, name, value); - if (subject == null) - { + + Resource subject = parseSubject(m, subjectNode.asResource(), + dsoIRI, name, value); + if (subject == null) { throw new MetadataMappingException("Cannot parse subject of a " - + "reified statement " + uri + "."); + + "reified statement " + uri + "."); } - Property predicate = parsePredicate(m, predicateNode.asResource(), - dsoIRI, name, value); - if (predicate == null) - { + Property predicate = parsePredicate(m, predicateNode.asResource(), + dsoIRI, name, value); + if (predicate == null) { throw new MetadataMappingException("Cannot parse predicate of a " - + "reified statement " + uri + "."); + + "reified statement " + uri + "."); } RDFNode object = parseObject(m, objectNode, dsoIRI, name, value, lang); - if (object == null) - { + if (object == null) { throw new MetadataMappingException("Cannot parse object of a " - + "reified statement " + uri + "."); + + "reified statement " + uri + "."); } - + m.add(subject, predicate, object); } - - protected Resource parseSubject(Model m, Resource subject, String dsoIRI, - String name, String value) - { - if (subject.hasProperty(RDF.type, DMRM.ResourceGenerator)) - { + + protected Resource parseSubject(Model m, Resource subject, String dsoIRI, + String name, String value) { + if (subject.hasProperty(RDF.type, DMRM.ResourceGenerator)) { String generatedIRI = parseResourceGenerator(subject, value, dsoIRI); - if (generatedIRI == null) - { + if (generatedIRI == null) { log.debug("Generated subject IRI is null."); return null; } - + log.debug("Subject ResourceGenerator generated '" + generatedIRI + "'."); return m.createResource(generatedIRI); } - + return subject; } protected Property parsePredicate(Model m, Resource predicate, String dsoIRI, - String name, String value) - { - if (predicate.hasProperty(RDF.type, DMRM.ResourceGenerator)) - { + String name, String value) { + if (predicate.hasProperty(RDF.type, DMRM.ResourceGenerator)) { String generatedIRI = parseResourceGenerator(predicate, value, dsoIRI); - if (generatedIRI == null) - { + if (generatedIRI == null) { log.debug("Generated predicate IRI is null."); return null; } - + log.debug("Property ResourceGenerator generated '" + generatedIRI + "'."); return m.createProperty(generatedIRI); } String uri = predicate.getURI(); - if (uri == null) - { + if (uri == null) { log.debug("A result predicate is blank node, but not a " - + "ResourceGenerator. Ingoring this result."); + + "ResourceGenerator. Ingoring this result."); return null; } return m.createProperty(uri); } protected RDFNode parseObject(Model m, RDFNode objectNode, String dsoIRI, - String name, String value, String lang) - { - if (objectNode.isLiteral()) return objectNode; - + String name, String value, String lang) { + if (objectNode.isLiteral()) { + return objectNode; + } + Resource object = objectNode.asResource(); - - if (object.hasProperty(RDF.type, DMRM.LiteralGenerator)) - { + + if (object.hasProperty(RDF.type, DMRM.LiteralGenerator)) { Literal literalValue = parseLiteralGenerator(m, object, value, lang); - if (literalValue == null) return null; + if (literalValue == null) { + return null; + } return literalValue; } - - if (object.hasProperty(RDF.type, DMRM.ResourceGenerator)) - { + + if (object.hasProperty(RDF.type, DMRM.ResourceGenerator)) { String generatedIRI = parseResourceGenerator(object, value, dsoIRI); - if (generatedIRI == null) - { + if (generatedIRI == null) { log.debug("Generated predicate IRI is null."); return null; } - + log.debug("Property ResourceGenerator generated '" + generatedIRI + "'."); return m.createProperty(generatedIRI); } - - if (object.isAnon()) - { + + if (object.isAnon()) { Resource blank = m.createResource(); StmtIterator iter = object.listProperties(); - while (iter.hasNext()) - { + while (iter.hasNext()) { Statement stmt = iter.nextStatement(); Property predicate = stmt.getPredicate(); // iterate recursive over the object of a blank node. blank.addProperty(predicate, - parseObject(m, stmt.getObject(), dsoIRI, name, value, lang)); + parseObject(m, stmt.getObject(), dsoIRI, name, value, lang)); } return blank; } - - // object is not a literal, is not a blank node, is neither a - // IRIGenerator nor a LiteralGenerator => it must be a Resource => use + + // object is not a literal, is not a blank node, is neither a + // IRIGenerator nor a LiteralGenerator => it must be a Resource => use // it as it is. return object; } - - protected String parseResourceGenerator(Resource resourceGenerator, - String value, String dsoIRI) - { - if (resourceGenerator.isURIResource() - && resourceGenerator.equals(DMRM.DSpaceObjectIRI)) - { + + protected String parseResourceGenerator(Resource resourceGenerator, + String value, String dsoIRI) { + if (resourceGenerator.isURIResource() + && resourceGenerator.equals(DMRM.DSpaceObjectIRI)) { return dsoIRI; } return parseValueProcessor(resourceGenerator, value); } - - protected Literal parseLiteralGenerator(Model m, Resource literalGenerator, - String value, String lang) - { - if (literalGenerator.isURIResource() - && literalGenerator.equals(DMRM.DSpaceValue)) - { + + protected Literal parseLiteralGenerator(Model m, Resource literalGenerator, + String value, String lang) { + if (literalGenerator.isURIResource() + && literalGenerator.equals(DMRM.DSpaceValue)) { return m.createLiteral(value); } - + String modifiedValue = parseValueProcessor(literalGenerator, value); - if (modifiedValue == null) return null; - + if (modifiedValue == null) { + return null; + } + // check if we should produce a typed literal - // Up the RDF spec lang tags are not significant on typed literals, so + // Up the RDF spec lang tags are not significant on typed literals, so // we can ignore them if we have a typed literal. - try - { + try { RDFNode literalTypeNode = getSingularProperty(literalGenerator, DMRM.literalType); - if (literalTypeNode != null) - { - if (literalTypeNode.isURIResource()) - { - return m.createTypedLiteral(modifiedValue, - literalTypeNode.asResource().getURI()); + if (literalTypeNode != null) { + if (literalTypeNode.isURIResource()) { + return m.createTypedLiteral(modifiedValue, + literalTypeNode.asResource().getURI()); } else { log.warn("A LiteralGenerator has a property 'literalType' that " - + "either is a blank node or a Literal. Ignoring it."); + + "either is a blank node or a Literal. Ignoring it."); } } - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { log.error("A LiteralGenerator has multiple properties " - + "'literalType'. Will ignore them."); + + "'literalType'. Will ignore them."); } - - + + // check if a language tag should be generated String languageTag = null; - try - { + try { RDFNode langNode = getSingularProperty(literalGenerator, DMRM.literalLanguage); - if (langNode != null) - { - if (langNode.isLiteral()) - { + if (langNode != null) { + if (langNode.isLiteral()) { languageTag = langNode.asLiteral().getLexicalForm(); } else { log.warn("Found a property 'literalLanguage', but its " - + "object is not a literal! Ignoring it."); + + "object is not a literal! Ignoring it."); } } - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { log.warn("A LiteralGenerator has multiple properties " - + "'literalLanguage'. Will ignore them."); + + "'literalLanguage'. Will ignore them."); } - + try { - RDFNode dspaceLangNode = getSingularProperty(literalGenerator, - DMRM.dspaceLanguageTag); - if (dspaceLangNode != null) - { + RDFNode dspaceLangNode = getSingularProperty(literalGenerator, + DMRM.dspaceLanguageTag); + if (dspaceLangNode != null) { boolean useDSpaceLang = false; - if (dspaceLangNode.isLiteral()) - { + if (dspaceLangNode.isLiteral()) { try { useDSpaceLang = dspaceLangNode.asLiteral().getBoolean(); - } - catch (Exception ex) - { + } catch (Exception ex) { /* * nothing to do here. * - * this is for sure not the best coding style, but the - * one that works best here as jena throws some undeclared + * this is for sure not the best coding style, but the + * one that works best here as jena throws some undeclared * RuntimeExceptions if the detection of the boolean fails. */ } } - if (useDSpaceLang && !StringUtils.isEmpty(lang)) - { - if (lang.indexOf("_") == 2) - { + if (useDSpaceLang && !StringUtils.isEmpty(lang)) { + if (lang.indexOf("_") == 2) { languageTag = lang.replaceFirst("_", "-"); } else { languageTag = lang; @@ -493,157 +421,132 @@ public class MetadataRDFMapping { } } catch (IllegalArgumentException ex) { log.error("A LiteralGenerator has multiple properties " - + "'dspaceLanguageTag'. Will ignore them."); + + "'dspaceLanguageTag'. Will ignore them."); + } + + if (languageTag != null) { + return m.createLiteral(modifiedValue, languageTag); } - - if (languageTag != null) return m.createLiteral(modifiedValue, languageTag); return m.createLiteral(modifiedValue); } - - protected String parseValueProcessor(Resource valueProcessor, String value) - { + + protected String parseValueProcessor(Resource valueProcessor, String value) { // look if there's a modifier. RDFNode modifierNode; - try - { + try { modifierNode = getSingularProperty(valueProcessor, DMRM.modifier); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { log.error("The ResourceGenerator of a mapping result has " - + "multiple 'modifier' properties, skipping this result."); + + "multiple 'modifier' properties, skipping this result."); return null; } - if (modifierNode != null) - { + if (modifierNode != null) { // in case there is a modifier find its matcher, its replacement and // modifies the value - if (!modifierNode.isResource()) - { + if (!modifierNode.isResource()) { log.error("The modifier of a result is a Literal not an Resource! " - + "Ingoring this result."); + + "Ingoring this result."); return null; } Resource modifier = modifierNode.asResource(); RDFNode matcherNode; - try - { + try { matcherNode = getSingularProperty(modifier, DMRM.matcher); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { log.error("The modifier of a mapping result has multiple " - + "'matcher' properties. Ignoring this result."); + + "'matcher' properties. Ignoring this result."); return null; } - if (matcherNode == null) - { + if (matcherNode == null) { log.error("Found a modifier property to a result, but no " - + "matcher property! Ignoring this result!"); + + "matcher property! Ignoring this result!"); return null; } - if (!matcherNode.isLiteral()) - { + if (!matcherNode.isLiteral()) { log.error("A matcher of a result modifier is not a Literal! " - + "Ignoring this result."); + + "Ignoring this result."); return null; } // get the replacement string RDFNode replacementNode; - try - { + try { replacementNode = getSingularProperty(modifier, DMRM.replacement); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { log.error("The modifier of a mapping result has multiple " - + "'replacement' properties. Ignoring this result."); + + "'replacement' properties. Ignoring this result."); return null; } - if (replacementNode == null) - { + if (replacementNode == null) { log.error("Found a modifier property to a result, but no " - + "replacement property! Ignoring this result!"); + + "replacement property! Ignoring this result!"); return null; } - if (!replacementNode.isLiteral()) - { + if (!replacementNode.isLiteral()) { log.error("A replacement of a result modifier is not a Literal! " - + "Ignoring this result."); + + "Ignoring this result."); return null; } String matcher = matcherNode.asLiteral().getLexicalForm(); String replacement = replacementNode.asLiteral().getLexicalForm(); - try - { + try { Pattern pattern = Pattern.compile(matcher); String modifiedValue = pattern.matcher(value).replaceAll(replacement); log.debug("Found matcher '" + matcher + "'.\n" - + "Found replacement '" + replacement + "'.\n" - + "modified '" + value + "' => '" + modifiedValue + "'."); + + "Found replacement '" + replacement + "'.\n" + + "modified '" + value + "' => '" + modifiedValue + "'."); value = modifiedValue; - } - catch (PatternSyntaxException ex) - { + } catch (PatternSyntaxException ex) { log.error("Property 'matcher' of a ValueModifider didn't specify a " - + "valid java regex pattern. Will ignore this result.", ex); + + "valid java regex pattern. Will ignore this result.", ex); return null; } } - + // in case there is a modifier, we modified the value. Insert the // (possibly modified) value in the pattern RDFNode patternNode; - try - { + try { patternNode = getSingularProperty(valueProcessor, DMRM.pattern); - } - catch (IllegalArgumentException ex) - { + } catch (IllegalArgumentException ex) { log.error("The ValueProcessor of a mapping result has " - + "multiple 'pattern' properties, skipping this result."); + + "multiple 'pattern' properties, skipping this result."); return null; } - if (patternNode == null) - { + if (patternNode == null) { log.debug("Cannot find the property 'pattern' of a " - + "ValueProcessor, will use \"$DSpaceValue\"."); + + "ValueProcessor, will use \"$DSpaceValue\"."); patternNode = valueProcessor.getModel().createLiteral("$DSpaceValue"); } - if (!patternNode.isLiteral()) - { + if (!patternNode.isLiteral()) { log.error("A 'pattern' property of a ValueProcessor is not a " - + "Literal! Skipping this result."); + + "Literal! Skipping this result."); return null; } String pattern = patternNode.asLiteral().getLexicalForm(); String result = pattern.replace("$DSpaceValue", value); log.debug("Found pattern " + pattern + ".\n" - + "Created result: " + result); + + "Created result: " + result); return result; } - + protected static RDFNode getSingularProperty(Resource r, Property p) - throws IllegalArgumentException - { + throws IllegalArgumentException { List stmts = r.listProperties(p).toList(); - if (stmts.isEmpty()) - { + if (stmts.isEmpty()) { return null; } - if (stmts.size() > 1) - { + if (stmts.size() > 1) { throw new IllegalArgumentException("Property '" + p.getURI() - + "' exists multiple times."); + + "' exists multiple times."); } return stmts.get(0).getObject(); } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/RDFConverter.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/RDFConverter.java index bd0c9bd2bf..d8e71856a1 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/RDFConverter.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/RDFConverter.java @@ -8,8 +8,9 @@ package org.dspace.rdf.conversion; -import com.hp.hpl.jena.rdf.model.Model; import java.sql.SQLException; + +import com.hp.hpl.jena.rdf.model.Model; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; @@ -17,5 +18,5 @@ import org.dspace.core.Context; public interface RDFConverter { public Model convert(Context context, DSpaceObject dso) - throws SQLException, AuthorizeException; + throws SQLException, AuthorizeException; } diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/RDFConverterImpl.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/RDFConverterImpl.java index 7750c6c538..382915cacc 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/RDFConverterImpl.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/RDFConverterImpl.java @@ -8,10 +8,11 @@ package org.dspace.rdf.conversion; -import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.rdf.model.ModelFactory; import java.sql.SQLException; import java.util.List; + +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; @@ -20,33 +21,26 @@ import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ -public class RDFConverterImpl implements RDFConverter -{ +public class RDFConverterImpl implements RDFConverter { private static final Logger log = Logger.getLogger(RDFConverterImpl.class); - + protected ConfigurationService configurationService; protected List plugins; - - @Autowired(required=true) - public void setConfigurationService(ConfigurationService configurationService) - { + + @Autowired(required = true) + public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } - - @Autowired(required=true) - public void setPlugins(List plugins) - { + + @Autowired(required = true) + public void setPlugins(List plugins) { this.plugins = plugins; - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { StringBuilder pluginNames = new StringBuilder(); - for (ConverterPlugin plugin : plugins) - { - if (pluginNames.length() > 0) - { + for (ConverterPlugin plugin : plugins) { + if (pluginNames.length() > 0) { pluginNames.append(", "); } pluginNames.append(plugin.getClass().getCanonicalName()); @@ -54,39 +48,32 @@ public class RDFConverterImpl implements RDFConverter log.debug("Loaded the following plugins: " + pluginNames.toString()); } } - - public List getConverterPlugins() - { + + public List getConverterPlugins() { return this.plugins; } - + @Override public Model convert(Context context, DSpaceObject dso) - throws SQLException, AuthorizeException - { - if (this.plugins.isEmpty()) - { + throws SQLException, AuthorizeException { + if (this.plugins.isEmpty()) { log.warn("No RDFConverterPlugins were loaded, cannot convert any data!"); return null; } Model model = ModelFactory.createDefaultModel(); - - for (ConverterPlugin plugin : this.plugins) - { - if (plugin.supports(dso.getType())) - { + + for (ConverterPlugin plugin : this.plugins) { + if (plugin.supports(dso.getType())) { Model convertedData = plugin.convert(context, dso); - if (convertedData != null) - { + if (convertedData != null) { model.setNsPrefixes(convertedData); model.add(convertedData); convertedData.close(); } } } - - if (model.isEmpty()) - { + + if (model.isEmpty()) { model.close(); return null; } else { diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/SimpleDSORelationsConverterPlugin.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/SimpleDSORelationsConverterPlugin.java index 155d63b9fe..96927fc3b2 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/SimpleDSORelationsConverterPlugin.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/SimpleDSORelationsConverterPlugin.java @@ -7,10 +7,6 @@ */ package org.dspace.rdf.conversion; -import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.util.FileManager; -import com.hp.hpl.jena.util.FileUtils; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -18,10 +14,20 @@ import java.sql.SQLException; import java.util.Iterator; import java.util.List; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.util.FileManager; +import com.hp.hpl.jena.util.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.util.Util; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.Site; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; @@ -33,543 +39,464 @@ import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class SimpleDSORelationsConverterPlugin -implements ConverterPlugin -{ + implements ConverterPlugin { public static final String SIMPLE_RELATIONS_PREFIXES_KEY = "rdf.simplerelations.prefixes"; public static final String SIMPLE_RELATIONS_SITE2COMMUNITY_KEY = "rdf.simplerelations.site2community"; public static final String SIMPLE_RELATIONS_COMMUNITY2SITE_KEY = "rdf.simplerelations.community2site"; - public static final String SIMPLE_RELATIONS_COMMUNITY2SUBCOMMUNITY_KEY= "rdf.simplerelations.community2subcommunity"; - public static final String SIMPLE_RELATIONS_SUBCOMMUNITY2COMMUNITY_KEY= "rdf.simplerelations.subcommunity2community"; + public static final String SIMPLE_RELATIONS_COMMUNITY2SUBCOMMUNITY_KEY = "rdf.simplerelations" + + ".community2subcommunity"; + public static final String SIMPLE_RELATIONS_SUBCOMMUNITY2COMMUNITY_KEY = "rdf.simplerelations" + + ".subcommunity2community"; public static final String SIMPLE_RELATIONS_COMMUNITY2COLLECTION_KEY = "rdf.simplerelations.community2collection"; public static final String SIMPLE_RELATIONS_COLLECTION2COMMUNITY_KEY = "rdf.simplerelations.collection2community"; public static final String SIMPLE_RELATIONS_COLLECTION2ITEM_KEY = "rdf.simplerelations.collection2item"; public static final String SIMPLE_RELATIONS_ITEM2COLLECTION_KEY = "rdf.simplerelations.item2collection"; public static final String SIMPLE_RELATIONS_ITEM2BITSTREAM_KEY = "rdf.simplerelations.item2bitstream"; - + private static final Logger log = Logger.getLogger(SimpleDSORelationsConverterPlugin.class); - - @Autowired(required=true) + + @Autowired(required = true) protected BitstreamService bitstreamService; - @Autowired(required=true) + @Autowired(required = true) protected ItemService itemService; - @Autowired(required=true) + @Autowired(required = true) protected CommunityService communityService; - @Autowired(required=true) + @Autowired(required = true) protected SiteService siteService; - @Autowired(required=true) + @Autowired(required = true) protected ConfigurationService configurationService; - + /** - * Loads the prefixes that should be used by the - * SimpleDSORelationsConverterPlugin. Please remember to close the model + * Loads the prefixes that should be used by the + * SimpleDSORelationsConverterPlugin. Please remember to close the model * returned by this method. + * * @return A model containing the content of the file used to configure the * RDF-Prefixes that should be used by this plugin. */ - protected Model getPrefixes() - { + protected Model getPrefixes() { Model m = ModelFactory.createDefaultModel(); String prefixesPath = configurationService - .getProperty(SIMPLE_RELATIONS_PREFIXES_KEY); - if (!StringUtils.isEmpty(prefixesPath)) - { + .getProperty(SIMPLE_RELATIONS_PREFIXES_KEY); + if (!StringUtils.isEmpty(prefixesPath)) { InputStream is = FileManager.get().open(prefixesPath); - if (is == null) - { + if (is == null) { log.warn("Cannot find file '" + prefixesPath + "', ignoring..."); } else { m.read(is, null, FileUtils.guessLang(prefixesPath)); try { is.close(); - } - catch (IOException ex) - { + } catch (IOException ex) { // nothing to do here. } } } else { log.warn("Configuration does not contain path to prefixes file for " - + "SimpleDSORelationsConverterPlugin. Will proceed without " - + "prefixes."); + + "SimpleDSORelationsConverterPlugin. Will proceed without " + + "prefixes."); } return m; } - + @Override - public void setConfigurationService(ConfigurationService configurationService) - { + public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } @Override public Model convert(Context context, DSpaceObject dso) - throws SQLException - { - - switch(dso.getType()) - { - case (Constants.SITE) : - { + throws SQLException { + + switch (dso.getType()) { + case (Constants.SITE): return convertSite(context, (Site) dso); - } - case (Constants.COMMUNITY) : - { + case (Constants.COMMUNITY): return convertCommunity(context, (Community) dso); - } - case (Constants.COLLECTION) : - { + case (Constants.COLLECTION): return convertCollection(context, (Collection) dso); - } - case (Constants.ITEM) : - { + case (Constants.ITEM): return convertItem(context, (Item) dso); - } + default: + return null; } - return null; } - + public Model convertSite(Context context, Site site) - throws SQLException - { + throws SQLException { String[] site2community = configurationService.getArrayProperty(SIMPLE_RELATIONS_SITE2COMMUNITY_KEY); - if (site2community == null || site2community.length == 0) - { + if (site2community == null || site2community.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from the repository (SITE) to the top level " - + "communities is disabled. Won't link from the repostitory " - + "(SITE) to the top level communities."); + + "linking from the repository (SITE) to the top level " + + "communities is disabled. Won't link from the repostitory " + + "(SITE) to the top level communities."); return null; } - + Model m = ModelFactory.createDefaultModel(); Model prefixes = this.getPrefixes(); m.setNsPrefixes(prefixes); prefixes.close(); - + String myId = RDFUtil.generateIdentifier(context, site); - if (myId == null) - { + if (myId == null) { return null; } List topLevelCommies = communityService.findAllTop(context); - for (Community community : topLevelCommies) - { - if (!RDFUtil.isPublicBoolean(context, community)) - { + for (Community community : topLevelCommies) { + if (!RDFUtil.isPublicBoolean(context, community)) { continue; } String id = RDFUtil.generateIdentifier(context, community); - if (id == null) - { + if (id == null) { continue; } - for (String link : site2community) - { + for (String link : site2community) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(id)); + m.createProperty(link), + m.createResource(id)); } } - - if (m.isEmpty()) - { + + if (m.isEmpty()) { log.info("There were no public sub communities we could link to."); m.close(); return null; } return m; } - + public Model convertCommunity(Context context, Community community) - throws SQLException - { + throws SQLException { String[] community2site = configurationService.getArrayProperty(SIMPLE_RELATIONS_COMMUNITY2SITE_KEY); - if (community2site == null || community2site.length == 0) - { + if (community2site == null || community2site.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from the top level communities to the repository " - + "(SITE) is disabled. Won't link from the top level " - + "communities to the repository (SITE)."); + + "linking from the top level communities to the repository " + + "(SITE) is disabled. Won't link from the top level " + + "communities to the repository (SITE)."); // don't return here, as we might have to add other links. // ensure community2site is not null community2site = new String[] {}; } - - String[] community2subcommunity = configurationService.getArrayProperty(SIMPLE_RELATIONS_COMMUNITY2SUBCOMMUNITY_KEY); - if (community2subcommunity == null || community2subcommunity.length == 0) - { + + String[] community2subcommunity = configurationService + .getArrayProperty(SIMPLE_RELATIONS_COMMUNITY2SUBCOMMUNITY_KEY); + if (community2subcommunity == null || community2subcommunity.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from communities to subcommunities was disabled. " - + "Won't link from communities to subcommunities."); + + "linking from communities to subcommunities was disabled. " + + "Won't link from communities to subcommunities."); // don't return here, as we might have to add other links. // ensure community2subcommunity is not null community2subcommunity = new String[] {}; } - - String[] subcommunity2community = configurationService.getArrayProperty(SIMPLE_RELATIONS_SUBCOMMUNITY2COMMUNITY_KEY); - if (subcommunity2community == null || subcommunity2community.length == 0) - { + + String[] subcommunity2community = configurationService + .getArrayProperty(SIMPLE_RELATIONS_SUBCOMMUNITY2COMMUNITY_KEY); + if (subcommunity2community == null || subcommunity2community.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from subcommunities to communities was disabled. " - + "Won't link from subcommunities to communities."); + + "linking from subcommunities to communities was disabled. " + + "Won't link from subcommunities to communities."); // don't return here, as we might have to add other links. // ensure subcommunity2community is not null subcommunity2community = new String[] {}; } - - String[] community2collection = configurationService.getArrayProperty(SIMPLE_RELATIONS_COMMUNITY2COLLECTION_KEY); - if (community2collection == null || community2collection.length == 0) - { + + String[] community2collection = configurationService + .getArrayProperty(SIMPLE_RELATIONS_COMMUNITY2COLLECTION_KEY); + if (community2collection == null || community2collection.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from communities to collections was disabled. " - + "Won't link from collections to subcommunities."); + + "linking from communities to collections was disabled. " + + "Won't link from collections to subcommunities."); // don't return here, as we might have to add other links. // ensure community2collection is not null community2collection = new String[] {}; } if (community2site.length == 0 && community2subcommunity.length == 0 - && subcommunity2community.length == 0 && community2collection.length == 0) - { + && subcommunity2community.length == 0 && community2collection.length == 0) { return null; } - + Model m = ModelFactory.createDefaultModel(); Model prefixes = this.getPrefixes(); m.setNsPrefixes(prefixes); prefixes.close(); - + String myId = RDFUtil.generateIdentifier(context, community); - if (myId == null) - { + if (myId == null) { return null; } - + // add all parents List communityParentList = communityService.getAllParents(context, community); DSpaceObject[] parents = communityParentList.toArray(new DSpaceObject[communityParentList.size()]); // check whether this is a top level community - if (parents.length == 0) - { + if (parents.length == 0) { parents = new DSpaceObject[] {siteService.findSite(context)}; } - for (DSpaceObject parent : parents) - { - if (!RDFUtil.isPublicBoolean(context, parent)) - { + for (DSpaceObject parent : parents) { + if (!RDFUtil.isPublicBoolean(context, parent)) { continue; } - + String id = RDFUtil.generateIdentifier(context, parent); - if (id != null) - { - if (parent instanceof Site) - { - for (String link : community2site) - { + if (id != null) { + if (parent instanceof Site) { + for (String link : community2site) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(id)); + m.createProperty(link), + m.createResource(id)); } - } - else if (parent instanceof Community) - { - for (String link : subcommunity2community) - { + } else if (parent instanceof Community) { + for (String link : subcommunity2community) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(id)); + m.createProperty(link), + m.createResource(id)); } } } } - + // add all subcommunities - for (Community sub : community.getSubcommunities()) - { - if (!RDFUtil.isPublicBoolean(context, sub)) - { + for (Community sub : community.getSubcommunities()) { + if (!RDFUtil.isPublicBoolean(context, sub)) { continue; } String id = RDFUtil.generateIdentifier(context, sub); - if (id == null) - { + if (id == null) { continue; } - for (String link : community2subcommunity) - { + for (String link : community2subcommunity) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(id)); + m.createProperty(link), + m.createResource(id)); } } // add all collections. - for (Collection col : communityService.getAllCollections(context, community)) - { - if (!RDFUtil.isPublicBoolean(context, col)) - { + for (Collection col : communityService.getAllCollections(context, community)) { + if (!RDFUtil.isPublicBoolean(context, col)) { continue; } String id = RDFUtil.generateIdentifier(context, col); - if (id == null) - { + if (id == null) { continue; } - for (String link : community2collection) - { + for (String link : community2collection) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(id)); + m.createProperty(link), + m.createResource(id)); } } - - if (m.isEmpty()) - { + + if (m.isEmpty()) { m.close(); return null; } return m; } - + public Model convertCollection(Context context, Collection collection) - throws SQLException - { - String[] collection2community = configurationService.getArrayProperty(SIMPLE_RELATIONS_COLLECTION2COMMUNITY_KEY); - if (collection2community == null || collection2community.length == 0) - { + throws SQLException { + String[] collection2community = configurationService + .getArrayProperty(SIMPLE_RELATIONS_COLLECTION2COMMUNITY_KEY); + if (collection2community == null || collection2community.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from collections to communities was disabled. " - + "Won't link from collections to communities."); + + "linking from collections to communities was disabled. " + + "Won't link from collections to communities."); // don't return here, as we might have to link to items. // ensure collection2community is not null collection2community = new String[] {}; } - + String[] collection2item = configurationService.getArrayProperty(SIMPLE_RELATIONS_COLLECTION2ITEM_KEY); - if (collection2item == null || collection2item.length == 0) - { + if (collection2item == null || collection2item.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from collections to items was disabled. " - + "Won't link from collections to items."); + + "linking from collections to items was disabled. " + + "Won't link from collections to items."); // don't return here, as we might have to link to communities. // ensure collection2item is not null collection2item = new String[] {}; } - if (collection2community.length == 0 && collection2item.length == 0) - { + if (collection2community.length == 0 && collection2item.length == 0) { return null; } - + Model m = ModelFactory.createDefaultModel(); Model prefixes = this.getPrefixes(); m.setNsPrefixes(prefixes); prefixes.close(); - + String myId = RDFUtil.generateIdentifier(context, collection); - if (myId == null) - { + if (myId == null) { return null; } - + // add all parents - for (DSpaceObject parent : communityService.getAllParents(context, collection)) - { - if (!RDFUtil.isPublicBoolean(context, parent)) - { + for (DSpaceObject parent : communityService.getAllParents(context, collection)) { + if (!RDFUtil.isPublicBoolean(context, parent)) { continue; } - + String id = RDFUtil.generateIdentifier(context, parent); - if (id != null) - { - for (String link : collection2community) - { + if (id != null) { + for (String link : collection2community) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(id)); + m.createProperty(link), + m.createResource(id)); } } } - + // add all items Iterator items = itemService.findAllByCollection(context, collection); - while (items.hasNext()) - { + while (items.hasNext()) { String id = RDFUtil.generateIdentifier(context, items.next()); - if (id != null) - { - for (String link : collection2item) - { + if (id != null) { + for (String link : collection2item) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(id)); + m.createProperty(link), + m.createResource(id)); } } } - - if (m.isEmpty()) - { + + if (m.isEmpty()) { m.close(); return null; } return m; } - + public Model convertItem(Context context, Item item) - throws SQLException - { + throws SQLException { String[] item2collection = configurationService.getArrayProperty(SIMPLE_RELATIONS_ITEM2COLLECTION_KEY); - if (item2collection == null || item2collection.length == 0) - { + if (item2collection == null || item2collection.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from items to collections was disabled. " - + "Won't link from items to collections."); + + "linking from items to collections was disabled. " + + "Won't link from items to collections."); // don't return here, as we might have to link to bitstreams. // ensure item2collection is not null item2collection = new String[] {}; } - + String[] item2bitstream = configurationService.getArrayProperty(SIMPLE_RELATIONS_ITEM2BITSTREAM_KEY); - if (item2bitstream == null || item2bitstream.length == 0) - { + if (item2bitstream == null || item2bitstream.length == 0) { log.info("Either there was a problem loading the configuration or " - + "linking from items to bitstreams was disabled. " - + "Won't link from items to bitstreams."); + + "linking from items to bitstreams was disabled. " + + "Won't link from items to bitstreams."); // don't return here, as we might have to link to collections. // ensure item2bitstream is not null item2bitstream = new String[] {}; } - if (item2collection.length == 0 && item2bitstream.length == 0) - { + if (item2collection.length == 0 && item2bitstream.length == 0) { return null; } - + Model m = ModelFactory.createDefaultModel(); Model prefixes = this.getPrefixes(); m.setNsPrefixes(prefixes); prefixes.close(); - + String myId = RDFUtil.generateIdentifier(context, item); - if (myId == null) - { + if (myId == null) { return null; } - + // add all parents - for (DSpaceObject parent : item.getCollections()) - { - if (!RDFUtil.isPublicBoolean(context, parent)) - { + for (DSpaceObject parent : item.getCollections()) { + if (!RDFUtil.isPublicBoolean(context, parent)) { continue; } - + String id = RDFUtil.generateIdentifier(context, parent); - if (id != null) - { - for (String link : item2collection) - { + if (id != null) { + for (String link : item2collection) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(id)); + m.createProperty(link), + m.createResource(id)); } } } - + // add all items - for(Bundle bundle : item.getBundles()) - { + for (Bundle bundle : item.getBundles()) { // currently link only the original files // TODO: Discuss if LICENSEs, THUMBNAILs and/or extracted TEXTs - // should be linked/exported as well (and if sutch a feature should + // should be linked/exported as well (and if sutch a feature should // be configurable). - if (bundle.getName().equals("ORIGINAL")) - { - for (Bitstream bs : bundle.getBitstreams()) - { - if (RDFUtil.isPublicBoolean(context, bs)) - { + if (bundle.getName().equals("ORIGINAL")) { + for (Bitstream bs : bundle.getBitstreams()) { + if (RDFUtil.isPublicBoolean(context, bs)) { String url = bitstreamURI(context, bs); - if (url != null) - { - for (String link : item2bitstream) - { + if (url != null) { + for (String link : item2bitstream) { m.add(m.createResource(myId), - m.createProperty(link), - m.createResource(url)); + m.createProperty(link), + m.createResource(url)); } } } } } } - - if (m.isEmpty()) - { + + if (m.isEmpty()) { m.close(); return null; } return m; } - + /** * This methods generataes a link to the provieded Bitstream. * As bitstreams currently don't get Persistent Identifier in DSpace, we have * to link them using a link to the repository. This link should work with * JSPUI and XMLUI (at least it does in DSpace 4.x). - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. * @param bitstream Bitstream for which a URL should be generated. - * @return The link to the URL or null if the Bistream is is a Community or + * @return The link to the URL or null if the Bistream is is a Community or * Collection logo. * @throws SQLException if database error */ public String bitstreamURI(Context context, Bitstream bitstream) - throws SQLException - { + throws SQLException { DSpaceObject parent = bitstreamService.getParentObject(context, bitstream); - if (!(parent instanceof Item)) - { + if (!(parent instanceof Item)) { // Bitstream is a community or collection logo. // we currently ignore those return null; } String dspaceURL = configurationService.getProperty("dspace.url"); String link = ""; - try - { + try { // this currently (DSpace 4.1) works with xmlui and jspui. - link = dspaceURL + "/bitstream/" + parent.getHandle() + "/" - + bitstream.getSequenceID() + "/" + link = dspaceURL + "/bitstream/" + parent.getHandle() + "/" + + bitstream.getSequenceID() + "/" + Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING); - } - catch (UnsupportedEncodingException ex) - { + } catch (UnsupportedEncodingException ex) { throw new RuntimeException("DSpace's default encoding is not supported.", ex); } return link; } @Override - public boolean supports(int type) - { - switch (type) - { - case (Constants.COLLECTION) : + public boolean supports(int type) { + switch (type) { + case (Constants.COLLECTION): return true; - case (Constants.COMMUNITY) : + case (Constants.COMMUNITY): return true; - case (Constants.ITEM) : + case (Constants.ITEM): return true; - case (Constants.SITE) : + case (Constants.SITE): return true; - default : + default: return false; } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/StaticDSOConverterPlugin.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/StaticDSOConverterPlugin.java index 23d37821f1..cf52167325 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/StaticDSOConverterPlugin.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/StaticDSOConverterPlugin.java @@ -8,13 +8,14 @@ package org.dspace.rdf.conversion; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; + import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.FileUtils; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; import org.apache.log4j.Logger; import org.dspace.content.DSpaceObject; import org.dspace.content.factory.ContentServiceFactory; @@ -25,111 +26,102 @@ import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class StaticDSOConverterPlugin -implements ConverterPlugin -{ + implements ConverterPlugin { private static final Logger log = Logger.getLogger(StaticDSOConverterPlugin.class); - + public static final String CONSTANT_DATA_FILENAME_KEY_PREFIX = "rdf.constant.data."; public static final String CONSTANT_DATA_GENERAL_KEY_SUFFIX = "GENERAL"; - @Autowired(required=true) + @Autowired(required = true) protected ConfigurationService configurationService; - + @Override public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } @Override - public Model convert(Context context, DSpaceObject dso) - throws SQLException - { + public Model convert(Context context, DSpaceObject dso) + throws SQLException { // As we do not use data of any DSpaceObject, we do not have to check // permissions here. We provide only static data out of configuration // files. - + Model general = this.readFile(CONSTANT_DATA_GENERAL_KEY_SUFFIX, - RDFUtil.generateIdentifier(context, dso)); - Model typeSpecific = this.readFile(ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getTypeText(dso), - RDFUtil.generateIdentifier(context, dso)); - - if (general == null) + RDFUtil.generateIdentifier(context, dso)); + Model typeSpecific = this + .readFile(ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getTypeText(dso), + RDFUtil.generateIdentifier(context, dso)); + + if (general == null) { return typeSpecific; - if (typeSpecific == null) + } + if (typeSpecific == null) { return general; + } typeSpecific.setNsPrefixes(general); typeSpecific.add(general); general.close(); return typeSpecific; } - - protected Model readFile(String fileSuffix, String base) - { + + protected Model readFile(String fileSuffix, String base) { String path = configurationService.getProperty( - CONSTANT_DATA_FILENAME_KEY_PREFIX + fileSuffix); - if (path == null) - { + CONSTANT_DATA_FILENAME_KEY_PREFIX + fileSuffix); + if (path == null) { log.error("Cannot find dspace-rdf configuration (looking for " - + "property " + CONSTANT_DATA_FILENAME_KEY_PREFIX - + fileSuffix + ")!"); - + + "property " + CONSTANT_DATA_FILENAME_KEY_PREFIX + + fileSuffix + ")!"); + throw new RuntimeException("Cannot find dspace-rdf configuration " - + "(looking for property " + - CONSTANT_DATA_FILENAME_KEY_PREFIX + fileSuffix + ")!"); + + "(looking for property " + + CONSTANT_DATA_FILENAME_KEY_PREFIX + fileSuffix + ")!"); } - + log.debug("Going to read static data from file '" + path + "'."); InputStream is = null; Model staticDataModel = null; try { is = FileManager.get().open(path); - if (is == null) - { - log.warn("StaticDSOConverterPlugin cannot find file '" + path - + "', ignoring..."); + if (is == null) { + log.warn("StaticDSOConverterPlugin cannot find file '" + path + + "', ignoring..."); return null; } staticDataModel = ModelFactory.createDefaultModel(); staticDataModel.read(is, base, FileUtils.guessLang(path)); } finally { - if (is != null) - { + if (is != null) { try { is.close(); - } - catch (IOException ex) - { + } catch (IOException ex) { // nothing to do here. } } } - if (staticDataModel.isEmpty()) - { + if (staticDataModel.isEmpty()) { staticDataModel.close(); return null; } return staticDataModel; } - + @Override - public boolean supports(int type) - { - switch (type) - { - case (Constants.COLLECTION) : + public boolean supports(int type) { + switch (type) { + case (Constants.COLLECTION): return true; - case (Constants.COMMUNITY) : + case (Constants.COMMUNITY): return true; - case (Constants.ITEM) : + case (Constants.ITEM): return true; - case (Constants.SITE) : + case (Constants.SITE): return true; - default : + default: return false; } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/factory/RDFFactory.java b/dspace-api/src/main/java/org/dspace/rdf/factory/RDFFactory.java index 37a936e75c..b763f8ca4f 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/factory/RDFFactory.java +++ b/dspace-api/src/main/java/org/dspace/rdf/factory/RDFFactory.java @@ -15,18 +15,17 @@ import org.dspace.utils.DSpace; /** * Abstract factory to get services for the rdf package, use RDFFactory.getInstance() to retrieve an implementation. + * * @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de) */ -public abstract class RDFFactory -{ +public abstract class RDFFactory { public abstract RDFStorage getRDFStorage(); public abstract URIGenerator getURIGenerator(); public abstract RDFConverter getRDFConverter(); - public static RDFFactory getInstance() - { + public static RDFFactory getInstance() { return new DSpace().getServiceManager().getServiceByName("rdfFactory", RDFFactory.class); } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/rdf/factory/RDFFactoryImpl.java b/dspace-api/src/main/java/org/dspace/rdf/factory/RDFFactoryImpl.java index 8fa5166fba..2f6b66bda6 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/factory/RDFFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/rdf/factory/RDFFactoryImpl.java @@ -15,11 +15,9 @@ import org.dspace.rdf.storage.URIGenerator; import org.springframework.beans.factory.annotation.Required; /** - * * @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de) */ -public class RDFFactoryImpl extends RDFFactory -{ +public class RDFFactoryImpl extends RDFFactory { // we have several URIGenerators that use each other as fallback // following we have to instantiate all of them and cannot use autowiring // by type here. So we use setters and properties in Spring configuration @@ -38,10 +36,9 @@ public class RDFFactoryImpl extends RDFFactory @Required public void setGenerator(URIGenerator generator) { - if (log.isDebugEnabled()) - { - log.debug("Using '" + generator.getClass().getCanonicalName() - + "' as URIGenerator."); + if (log.isDebugEnabled()) { + log.debug("Using '" + generator.getClass().getCanonicalName() + + "' as URIGenerator."); } this.generator = generator; } @@ -65,5 +62,5 @@ public class RDFFactoryImpl extends RDFFactory public RDFConverter getRDFConverter() { return converter; } - + } diff --git a/dspace-api/src/main/java/org/dspace/rdf/negotiation/MediaRange.java b/dspace-api/src/main/java/org/dspace/rdf/negotiation/MediaRange.java index ecd6d04805..f0cd45b8fa 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/negotiation/MediaRange.java +++ b/dspace-api/src/main/java/org/dspace/rdf/negotiation/MediaRange.java @@ -12,21 +12,20 @@ import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ -public class MediaRange -{ +public class MediaRange { // defined in RFC 2616 public static final double DEFAULT_QVALUE = 1.0; - + // RFC 2616 defines syntax of the accept header using several patterns // the patterns are defined in the parts 2.2, 3.6, 3.7, 3.9 and 14.1 of the rfc - + // SEPARATOR: ( ) < > @ , ; : \ " / [ ] ? = { } // the separators can be used in as class inside square brackets. To be able // to negate the class, the spearators necessary square brackets are not @@ -41,13 +40,13 @@ public class MediaRange // any 8 bit sequence, except CTLs (00-037, 0177) and " (042) but including LWS public static final String qdtext = "(?:[\\040\\041\\043-\\0176\\0178-\\0377]|" - + "(?:\\r\\n)?[ \\t]+)"; + + "(?:\\r\\n)?[ \\t]+)"; // ( <"> *(qdtext | quoted-pair) <"> public static final String quotedString = "(?:\"(?:" + qdtext + "|" + quotedPair + ")*\")"; - public static final String nonQualityParam = "(?:\\s*;\\s*(?!q\\s*=)(" + token + ")=" - + "(" + token + "|" + quotedString + ")" + ")"; + public static final String nonQualityParam = "(?:\\s*;\\s*(?!q\\s*=)(" + token + ")=" + + "(" + token + "|" + quotedString + ")" + ")"; public static final String qualityParam = "(?:;\\s*q\\s*=\\s*(0(?:\\.\\d{0,3})?|1(?:\\.0{0,3})?))"; // group 0 contains the hole matched media range @@ -61,112 +60,98 @@ public class MediaRange // group 8 contains the name of the last parameter after the quality paremeter if any // group 9 contains the value of the laster parameter after the quality paremeter if any public static final String mediaRangeRegex = "(?:(" + token + ")/(" + token + "?)" - + "(" + nonQualityParam + "*)" + qualityParam + "?(" + nonQualityParam + "*))"; - + + "(" + nonQualityParam + "*)" + qualityParam + "?(" + nonQualityParam + "*))"; + private final static Logger log = Logger.getLogger(MediaRange.class); - + protected final String type; protected final String subtype; protected final double qvalue; - // would be good to take a Map for the parameters, but if we get multiple + // would be good to take a Map for the parameters, but if we get multiple // parameters with the same name, we would have a problem. protected final List parameterNames; protected final List parameterValues; - + private MediaRange() { throw new RuntimeException("Default constructor of MediaRange must " - + "not be called. Use static methods instead."); + + "not be called. Use static methods instead."); } - + public MediaRange(String mediarange) - throws IllegalArgumentException, IllegalStateException - { + throws IllegalArgumentException, IllegalStateException { Pattern mediaRangePattern = Pattern.compile("^" + mediaRangeRegex + "$"); Matcher rangeMatcher = mediaRangePattern.matcher(mediarange.trim()); - if (!rangeMatcher.matches()) - { + if (!rangeMatcher.matches()) { log.warn("Provided media range ('" + mediarange.trim() + "') " - + "does not comply with RFC 2616."); - throw new IllegalArgumentException("Provided media range ('" - + mediarange + "') does not comply with RFC 2616."); + + "does not comply with RFC 2616."); + throw new IllegalArgumentException("Provided media range ('" + + mediarange + "') does not comply with RFC 2616."); } - + String type = rangeMatcher.group(1); String subtype = rangeMatcher.group(2); - if (StringUtils.isEmpty(type) || StringUtils.isEmpty(subtype)) - { + if (StringUtils.isEmpty(type) || StringUtils.isEmpty(subtype)) { throw new IllegalArgumentException("A media range had an unparsable type or subtype."); } type = type.trim().toLowerCase(); subtype = subtype.trim().toLowerCase(); - if (type.equals("*") && !subtype.equals("*")) - { + if (type.equals("*") && !subtype.equals("*")) { throw new IllegalArgumentException("A media range's type cannot " - + "be wildcarded if its subtype isn't as well."); + + "be wildcarded if its subtype isn't as well."); } // initalize with defualt value, parse later double qvalue = DEFAULT_QVALUE; // initialize empty lists, parse parameters later List parameterNames = new ArrayList<>(); List parameterValues = new ArrayList<>(); - + // parse qvalue - if (!StringUtils.isEmpty(rangeMatcher.group(6))) - { + if (!StringUtils.isEmpty(rangeMatcher.group(6))) { // parse provided quality value - try - { + try { qvalue = Double.parseDouble(rangeMatcher.group(6)); - } - catch (NumberFormatException ex) - { + } catch (NumberFormatException ex) { // the regex should assure that the qvalue is parseable. - // if we get a NumberFormatException, we did something terribly + // if we get a NumberFormatException, we did something terribly // wrong. log.fatal("A quality value ('" + rangeMatcher.group(6) + "') " - + "was unparsable. We probably have a problem with our " - + "regex!", ex); + + "was unparsable. We probably have a problem with our " + + "regex!", ex); throw new IllegalStateException(ex); } } - + // parse parameters StringBuilder sb = new StringBuilder(); - if (!StringUtils.isEmpty(rangeMatcher.group(3))) - { + if (!StringUtils.isEmpty(rangeMatcher.group(3))) { sb.append(rangeMatcher.group(3)); } - if (!StringUtils.isEmpty(rangeMatcher.group(7))) - { + if (!StringUtils.isEmpty(rangeMatcher.group(7))) { sb.append(rangeMatcher.group(7)); } - if (sb.length() > 0) - { + if (sb.length() > 0) { String unparsedParameters = sb.toString(); Pattern paramPattern = Pattern.compile(nonQualityParam); Matcher m = paramPattern.matcher(unparsedParameters); - if (!m.matches()) - { + if (!m.matches()) { // the mediarange string matched our mediaRangeRegex, but the // parsed parameters doesn't?! log.fatal("Unable to parse the parameters ('" - + unparsedParameters + "') of a previously parsed media " - + "range!"); + + unparsedParameters + "') of a previously parsed media " + + "range!"); throw new IllegalStateException("Run into problems while parsing " - + "a substring of a previuosly succesfully parsed string."); + + "a substring of a previuosly succesfully parsed string."); } - while (m.find()) - { - if (!StringUtils.isEmpty(m.group(1))) - { + while (m.find()) { + if (!StringUtils.isEmpty(m.group(1))) { parameterNames.add(m.group(1).trim().toLowerCase()); parameterValues.add(StringUtils.isEmpty(m.group(2)) ? "" : m.group(2).trim()); } } } - + this.type = type; this.subtype = subtype; this.qvalue = qvalue; @@ -189,18 +174,16 @@ public class MediaRange public List getParameterNames() { return parameterNames; } - + public List getParameterValues() { return parameterValues; } - - public boolean typeIsWildcard() - { + + public boolean typeIsWildcard() { return (StringUtils.equals(type, "*")); } - - public boolean subtypeIsWildcard() - { + + public boolean subtypeIsWildcard() { return (StringUtils.equals(subtype, "*")); } diff --git a/dspace-api/src/main/java/org/dspace/rdf/negotiation/NegotiationFilter.java b/dspace-api/src/main/java/org/dspace/rdf/negotiation/NegotiationFilter.java index c30f76c2de..ed8840bb7a 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/negotiation/NegotiationFilter.java +++ b/dspace-api/src/main/java/org/dspace/rdf/negotiation/NegotiationFilter.java @@ -20,51 +20,42 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; - import org.dspace.rdf.RDFUtil; import org.dspace.services.factory.DSpaceServicesFactory; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ -public class NegotiationFilter implements Filter -{ +public class NegotiationFilter implements Filter { public static final String ACCEPT_HEADER_NAME = "Accept"; - + private static final Logger log = Logger.getLogger(NegotiationFilter.class); - + @Override public void init(FilterConfig filterConfig) throws ServletException { // nothing to todo here. } @Override - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) - throws IOException, ServletException - { - try - { + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) + throws IOException, ServletException { + try { if (!DSpaceServicesFactory.getInstance().getConfigurationService() - .getBooleanProperty(RDFUtil.CONTENT_NEGOTIATION_KEY, false)) - { + .getBooleanProperty(RDFUtil.CONTENT_NEGOTIATION_KEY, false)) { chain.doFilter(request, response); return; } - } - catch (Exception ex) - { + } catch (Exception ex) { log.warn("Will deliver HTML, as I cannot determine if content " - + "negotiation should be enabled or not:\n" - + ex.getMessage(), ex); + + "negotiation should be enabled or not:\n" + + ex.getMessage(), ex); chain.doFilter(request, response); return; } - if (!(request instanceof HttpServletRequest) - || !(response instanceof HttpServletResponse)) - { + if (!(request instanceof HttpServletRequest) + || !(response instanceof HttpServletResponse)) { // just pass request and response to the next filter, if we don't // have a HttpServletRequest. chain.doFilter(request, response); @@ -73,17 +64,16 @@ public class NegotiationFilter implements Filter // cast HttpServletRequest and HttpServletResponse HttpServletRequest hrequest = (HttpServletRequest) request; HttpServletResponse hresponse = (HttpServletResponse) response; - + String acceptHeader = hrequest.getHeader(ACCEPT_HEADER_NAME); - + String handle = null; String extraPathInfo = null; String path = hrequest.getPathInfo(); // in JSPUI the pathInfo starts after /handle, in XMLUI it starts with /handle Pattern handleCheckPattern = Pattern.compile("^/*handle/(.*)$"); Matcher handleCheckMatcher = handleCheckPattern.matcher(path); - if (handleCheckMatcher.matches()) - { + if (handleCheckMatcher.matches()) { // remove trailing /handle path = handleCheckMatcher.group(1); } @@ -91,22 +81,22 @@ public class NegotiationFilter implements Filter // where is a handle prefix, is the handle suffix // and may be further information. log.debug("PathInfo: " + path); - if (path == null) path = ""; - Pattern pathPattern = - Pattern.compile("^/*([^/]+)/+([^/]+)(?:/*||/+(.*))?$"); + if (path == null) { + path = ""; + } + Pattern pathPattern = + Pattern.compile("^/*([^/]+)/+([^/]+)(?:/*||/+(.*))?$"); Matcher pathMatcher = pathPattern.matcher(path); - if (pathMatcher.matches()) - { + if (pathMatcher.matches()) { handle = pathMatcher.group(1) + "/" + pathMatcher.group(2); extraPathInfo = pathMatcher.group(3); } log.debug("handle: " + handle + "\n" + "extraPathInfo: " + extraPathInfo); - + int requestedContent = Negotiator.negotiate(acceptHeader); - - if (!Negotiator.sendRedirect(hresponse, handle, extraPathInfo, - requestedContent, false)) - { + + if (!Negotiator.sendRedirect(hresponse, handle, extraPathInfo, + requestedContent, false)) { // as we do content negotiation, we should send a vary caching so // browsers can adopt their caching strategy // the method Negotiator.sendRedirect does this only if it actually diff --git a/dspace-api/src/main/java/org/dspace/rdf/negotiation/Negotiator.java b/dspace-api/src/main/java/org/dspace/rdf/negotiation/Negotiator.java index 488577a376..fe7a0029a4 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/negotiation/Negotiator.java +++ b/dspace-api/src/main/java/org/dspace/rdf/negotiation/Negotiator.java @@ -13,17 +13,17 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import javax.servlet.http.HttpServletResponse; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.rdf.RDFUtil; import org.dspace.services.factory.DSpaceServicesFactory; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class Negotiator { - + // Serialiazation codes public static final int UNSPECIFIED = -1; public static final int WILDCARD = 0; @@ -32,41 +32,40 @@ public class Negotiator { public static final int TURTLE = 3; public static final int N3 = 4; - public static final String DEFAULT_LANG="html"; - + public static final String DEFAULT_LANG = "html"; + private static final Logger log = Logger.getLogger(Negotiator.class); - - public static int negotiate(String acceptHeader) - { - if (acceptHeader == null) return UNSPECIFIED; - - String[] mediaRangeSpecs = acceptHeader.split(","); - ArrayList requestedMediaRanges = new ArrayList<>(); - for (String mediaRangeSpec : mediaRangeSpecs) - { - try - { - requestedMediaRanges.add(new MediaRange(mediaRangeSpec)); - } - catch (IllegalArgumentException | IllegalStateException ex) - { - log.warn("Couldn't parse part of an AcceptHeader, ignoring it.\n" - + ex.getMessage(), ex); - } - } - if (requestedMediaRanges.isEmpty()) - { + + /** + * Default constructor + */ + private Negotiator() { } + + public static int negotiate(String acceptHeader) { + if (acceptHeader == null) { return UNSPECIFIED; } - + + String[] mediaRangeSpecs = acceptHeader.split(","); + ArrayList requestedMediaRanges = new ArrayList<>(); + for (String mediaRangeSpec : mediaRangeSpecs) { + try { + requestedMediaRanges.add(new MediaRange(mediaRangeSpec)); + } catch (IllegalArgumentException | IllegalStateException ex) { + log.warn("Couldn't parse part of an AcceptHeader, ignoring it.\n" + + ex.getMessage(), ex); + } + } + if (requestedMediaRanges.isEmpty()) { + return UNSPECIFIED; + } + Collections.sort(requestedMediaRanges, getMediaRangeComparator()); Collections.reverse(requestedMediaRanges); - - if (log.isDebugEnabled()) - { + + if (log.isDebugEnabled()) { StringBuilder sb = new StringBuilder("Parsed Accept header '" + acceptHeader + "':\n"); - for (Iterator it = requestedMediaRanges.iterator(); it.hasNext(); ) - { + for (Iterator it = requestedMediaRanges.iterator(); it.hasNext(); ) { MediaRange mr = it.next(); sb.append(mr.getType()).append("/").append(mr.getSubtype()); sb.append(" has a qvalue of ").append(Double.toString(mr.getQvalue())); @@ -74,102 +73,87 @@ public class Negotiator { } log.debug(sb.toString()); } - + boolean wildcard = false; boolean html = false; boolean rdf = false; boolean n3 = false; boolean turtle = false; Iterator it = requestedMediaRanges.iterator(); - + MediaRange lookahead = it.hasNext() ? it.next() : null; - while (lookahead != null) - { + while (lookahead != null) { double qvalue = lookahead.getQvalue(); String type = lookahead.getType(); String subtype = lookahead.getSubtype(); lookahead = it.hasNext() ? it.next() : null; - - if (qvalue <= 0.0) - { - // a quality of 0.0 means that the defined media range should + + if (qvalue <= 0.0) { + // a quality of 0.0 means that the defined media range should // not to be send => don't parse it. continue; } - - if ("*".equals(type)) - { + + if ("*".equals(type)) { wildcard = true; } if (("text".equals(type) && "html".equals(subtype)) - || ("application".equals(type) && "xhtml+xml".equals(subtype))) - { + || ("application".equals(type) && "xhtml+xml".equals(subtype))) { html = true; } - if ("application".equals(type) && "rdf+xml".equals(subtype)) - { + if ("application".equals(type) && "rdf+xml".equals(subtype)) { rdf = true; } if (("text".equals(type) && "n3".equals(subtype)) - || ("text".equals(type) && "rdf+n3".equals(subtype)) - || ("application".equals(type) && "n3".equals(subtype))) - { + || ("text".equals(type) && "rdf+n3".equals(subtype)) + || ("application".equals(type) && "n3".equals(subtype))) { n3 = true; } if (("text".equals(type) && "turtle".equals(subtype)) - || ("application".equals(type) && "turtle".equals(subtype)) - || ("application".equals(type) && "x-turtle".equals(subtype)) - || ("application".equals(type) && "rdf+turtle".equals(subtype))) - { + || ("application".equals(type) && "turtle".equals(subtype)) + || ("application".equals(type) && "x-turtle".equals(subtype)) + || ("application".equals(type) && "rdf+turtle".equals(subtype))) { turtle = true; } - + if (lookahead != null - && qvalue != lookahead.qvalue - && (wildcard || html || rdf || n3 || turtle)) - { + && qvalue != lookahead.qvalue + && (wildcard || html || rdf || n3 || turtle)) { // we've looked over all media range with the same precedence // and found one, we can serve break; } } - - if (html) - { + + if (html) { return HTML; } - if (wildcard) - { + if (wildcard) { return WILDCARD; - } - else if (turtle) - { + } else if (turtle) { return TURTLE; - } - else if (n3) - { + } else if (n3) { return N3; - } - else if (rdf) - { + } else if (rdf) { return RDFXML; } - + return UNSPECIFIED; } /** - * Method to get a comparator to compare media ranges regarding their - * content negotiation precedence. Following RFC 2616 a media range is - * higher prioritized then another media range if the first one has a higher - * quality value then the second. If both quality values are equal, the + * Method to get a comparator to compare media ranges regarding their + * content negotiation precedence. Following RFC 2616 a media range is + * higher prioritized then another media range if the first one has a higher + * quality value then the second. If both quality values are equal, the * media range that is more specific should be used. - * - *

    Note: this comparator imposes orderings that are inconsistent with + * + *

    Note: this comparator imposes orderings that are inconsistent with * equals! Caution should be exercised when using it to order a sorted set - * or a sorted map. Take a look at the java.util.Comparator for further + * or a sorted map. Take a look at the java.util.Comparator for further * information.

    + * * @return A comparator that imposes orderings that are inconsistent with equals! */ public static Comparator getMediaRangeComparator() { @@ -177,19 +161,30 @@ public class Negotiator { @Override public int compare(MediaRange mr1, MediaRange mr2) { - if (Double.compare(mr1.qvalue, mr2.getQvalue()) != 0) - { + if (Double.compare(mr1.qvalue, mr2.getQvalue()) != 0) { return Double.compare(mr1.qvalue, mr2.getQvalue()); } - if (mr1.typeIsWildcard() && mr2.typeIsWildcard()) return 0; - if (mr1.typeIsWildcard() && !mr2.typeIsWildcard()) return -1; - if (!mr1.typeIsWildcard() && mr2.typeIsWildcard()) return 1; - if (mr1.subtypeIsWildcard() && mr2.subtypeIsWildcard()) return 0; - if (mr1.subtypeIsWildcard() && !mr2.subtypeIsWildcard()) return -1; - if (!mr1.subtypeIsWildcard() && mr2.subtypeIsWildcard()) return 1; + if (mr1.typeIsWildcard() && mr2.typeIsWildcard()) { + return 0; + } + if (mr1.typeIsWildcard() && !mr2.typeIsWildcard()) { + return -1; + } + if (!mr1.typeIsWildcard() && mr2.typeIsWildcard()) { + return 1; + } + if (mr1.subtypeIsWildcard() && mr2.subtypeIsWildcard()) { + return 0; + } + if (mr1.subtypeIsWildcard() && !mr2.subtypeIsWildcard()) { + return -1; + } + if (!mr1.subtypeIsWildcard() && mr2.subtypeIsWildcard()) { + return 1; + } - // if the quality of two media ranges is equal and both don't - // use an asterisk either as type or subtype, they are equal in + // if the quality of two media ranges is equal and both don't + // use an asterisk either as type or subtype, they are equal in // the sense of content negotiation precedence. return 0; } @@ -197,76 +192,66 @@ public class Negotiator { } public static boolean sendRedirect(HttpServletResponse response, String handle, - String extraPathInfo, int serialization, boolean redirectHTML) - throws IOException - { - if (extraPathInfo == null) extraPathInfo = ""; - + String extraPathInfo, int serialization, boolean redirectHTML) + throws IOException { + if (extraPathInfo == null) { + extraPathInfo = ""; + } + StringBuilder urlBuilder = new StringBuilder(); String lang = null; - switch (serialization) - { + switch (serialization) { case (Negotiator.UNSPECIFIED): - case (Negotiator.WILDCARD): - { + case (Negotiator.WILDCARD): { lang = DEFAULT_LANG; break; } - case (Negotiator.HTML): - { + case (Negotiator.HTML): { lang = "html"; break; } - case (Negotiator.RDFXML): - { + case (Negotiator.RDFXML): { lang = "rdf"; break; } - case (Negotiator.TURTLE): - { + case (Negotiator.TURTLE): { lang = "turtle"; break; } - case (Negotiator.N3): - { + case (Negotiator.N3): { lang = "n3"; break; } - default: - { + default: { lang = DEFAULT_LANG; break; } } assert (lang != null); - - if (StringUtils.isEmpty(handle)) - { + + if (StringUtils.isEmpty(handle)) { log.warn("Handle is empty, set it to Site Handle."); handle = DSpaceServicesFactory.getInstance().getConfigurationService() - .getProperty("handle.prefix") + "/0"; + .getProperty("handle.prefix") + "/0"; } - + // don't redirect if HTML is requested and content negotiation is done // in a ServletFilter, as the ServletFilter should just let the request // pass. - if ("html".equals(lang) && !redirectHTML) - { + if ("html".equals(lang) && !redirectHTML) { return false; } - // as we do content negotiation and we'll redirect the request, we + // as we do content negotiation and we'll redirect the request, we // should send a vary caching so browsers can adopt their caching strategy response.setHeader("Vary", "Accept"); // if html is requested we have to forward to the repositories webui. - if ("html".equals(lang)) - { + if ("html".equals(lang)) { urlBuilder.append(DSpaceServicesFactory.getInstance() - .getConfigurationService().getProperty("dspace.url")); + .getConfigurationService().getProperty("dspace.url")); if (!handle.equals(DSpaceServicesFactory.getInstance() - .getConfigurationService().getProperty("handle.prefix") + "/0")) - { + .getConfigurationService().getProperty("handle.prefix") + "/0")) { urlBuilder.append("/handle/"); urlBuilder.append(handle).append("/").append(extraPathInfo); } @@ -278,24 +263,22 @@ public class Negotiator { response.flushBuffer(); return true; } - + // currently we cannot serve statistics as rdf - if("statistics".equals(extraPathInfo)) - { + if ("statistics".equals(extraPathInfo)) { log.info("Cannot send statistics as RDF yet. => 406 Not Acceptable."); response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE); response.flushBuffer(); return true; } - + // load the URI of the dspace-rdf module. urlBuilder.append(DSpaceServicesFactory.getInstance() - .getConfigurationService() - .getProperty(RDFUtil.CONTEXT_PATH_KEY)); - if (urlBuilder.length() == 0) - { + .getConfigurationService() + .getProperty(RDFUtil.CONTEXT_PATH_KEY)); + if (urlBuilder.length() == 0) { log.error("Cannot load URL of dspace-rdf module. " - + "=> 500 Internal Server Error"); + + "=> 500 Internal Server Error"); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.flushBuffer(); return true; diff --git a/dspace-api/src/main/java/org/dspace/rdf/storage/DOIHandleURIGenerator.java b/dspace-api/src/main/java/org/dspace/rdf/storage/DOIHandleURIGenerator.java index 8158345674..8a7c658922 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/storage/DOIHandleURIGenerator.java +++ b/dspace-api/src/main/java/org/dspace/rdf/storage/DOIHandleURIGenerator.java @@ -14,22 +14,22 @@ import org.springframework.beans.factory.annotation.Required; /** * Extends the DOIURIGenerator but uses handles as fallback to DOIs. + * * @author pbecker */ public class DOIHandleURIGenerator -extends DOIURIGenerator -implements URIGenerator -{ + extends DOIURIGenerator + implements URIGenerator { protected static URIGenerator fallback; @Required public static void setFallback(URIGenerator fallback) { DOIURIGenerator.fallback = fallback; } - - @Autowired(required=true) + + @Autowired(required = true) public void setDoiService(DOIService doiService) { this.doiService = doiService; } - + } diff --git a/dspace-api/src/main/java/org/dspace/rdf/storage/DOIURIGenerator.java b/dspace-api/src/main/java/org/dspace/rdf/storage/DOIURIGenerator.java index 3e855af0f3..935a4ed610 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/storage/DOIURIGenerator.java +++ b/dspace-api/src/main/java/org/dspace/rdf/storage/DOIURIGenerator.java @@ -8,27 +8,24 @@ package org.dspace.rdf.storage; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + import org.apache.log4j.Logger; import org.dspace.content.DSpaceObject; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.identifier.IdentifierException; -import org.dspace.identifier.factory.IdentifierServiceFactory; import org.dspace.identifier.service.DOIService; - -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; /** - * * @author pbecker */ -public class DOIURIGenerator implements URIGenerator -{ +public class DOIURIGenerator implements URIGenerator { private static final Logger log = Logger.getLogger(DOIURIGenerator.class); protected static URIGenerator fallback; @@ -37,27 +34,23 @@ public class DOIURIGenerator implements URIGenerator public static void setFallback(URIGenerator fallback) { DOIURIGenerator.fallback = fallback; } - - @Autowired(required=true) + + @Autowired(required = true) protected DOIService doiService; - + @Override public String generateIdentifier(Context context, int type, UUID id, String handle, List identifiers) - throws SQLException - { + throws SQLException { if (type != Constants.SITE && type != Constants.COMMUNITY && type != Constants.COLLECTION - && type != Constants.ITEM) - { + && type != Constants.ITEM) { return null; } String doi = null; - for (String identifier : identifiers) - { - try - { + for (String identifier : identifiers) { + try { doi = doiService.DOIToExternalForm(identifier); } catch (IdentifierException ex) { // identifier is not a DOI: no problem, keep on looking. @@ -67,23 +60,22 @@ public class DOIURIGenerator implements URIGenerator return doi; } else { log.info("Didn't find a DOI for " + Constants.typeText[type] + ", id " + id.toString() - + ", will use fallback URIGenerator."); + + ", will use fallback URIGenerator."); return fallback.generateIdentifier(context, type, id, handle, identifiers); } } @Override public String generateIdentifier(Context context, DSpaceObject dso) - throws SQLException - { + throws SQLException { return generateIdentifier( context, dso.getType(), dso.getID(), dso.getHandle(), ContentServiceFactory.getInstance().getDSpaceObjectService(dso) - .getIdentifiers(context, dso) + .getIdentifiers(context, dso) ); } - + } diff --git a/dspace-api/src/main/java/org/dspace/rdf/storage/HandleURIGenerator.java b/dspace-api/src/main/java/org/dspace/rdf/storage/HandleURIGenerator.java index c5d5646439..7ed4c9f552 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/storage/HandleURIGenerator.java +++ b/dspace-api/src/main/java/org/dspace/rdf/storage/HandleURIGenerator.java @@ -8,72 +8,65 @@ package org.dspace.rdf.storage; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.DSpaceObject; -import org.dspace.content.Site; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.SiteService; import org.dspace.core.Constants; import org.dspace.core.Context; -import org.dspace.handle.HandleServiceImpl; -import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; - -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class HandleURIGenerator implements URIGenerator { private static final Logger log = Logger.getLogger(HandleURIGenerator.class); - @Autowired(required=true) + @Autowired(required = true) protected SiteService siteService; - @Autowired(required=true) + @Autowired(required = true) protected HandleService handleService; @Override public String generateIdentifier(Context context, int type, UUID id, - String handle, List identifiers) throws SQLException { - if (type == Constants.SITE) - { + String handle, List identifiers) throws SQLException { + if (type == Constants.SITE) { return handleService.getCanonicalForm(siteService.findSite(context).getHandle()); } - - if (type == Constants.COMMUNITY - || type == Constants.COLLECTION - || type == Constants.ITEM) - { - if (StringUtils.isEmpty(handle)) - { + + if (type == Constants.COMMUNITY + || type == Constants.COLLECTION + || type == Constants.ITEM) { + if (StringUtils.isEmpty(handle)) { throw new IllegalArgumentException("Handle is null"); } - log.debug("Generated identifier " - + handleService.getCanonicalForm(handle) + " for " - + Constants.typeText[type] + " " + id.toString() + "."); + log.debug("Generated identifier " + + handleService.getCanonicalForm(handle) + " for " + + Constants.typeText[type] + " " + id.toString() + "."); return handleService.getCanonicalForm(handle); } - + return null; } - + @Override public String generateIdentifier(Context context, DSpaceObject dso) throws SQLException { if (dso.getType() != Constants.SITE - && dso.getType() != Constants.COMMUNITY - && dso.getType() != Constants.COLLECTION - && dso.getType() != Constants.ITEM) - { + && dso.getType() != Constants.COMMUNITY + && dso.getType() != Constants.COLLECTION + && dso.getType() != Constants.ITEM) { return null; } - + return generateIdentifier(context, dso.getType(), dso.getID(), - dso.getHandle(), ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getIdentifiers(context, dso)); + dso.getHandle(), ContentServiceFactory.getInstance().getDSpaceObjectService(dso) + .getIdentifiers(context, dso)); } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/storage/LocalURIGenerator.java b/dspace-api/src/main/java/org/dspace/rdf/storage/LocalURIGenerator.java index 3f8dd8ab3b..2aa9209ac1 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/storage/LocalURIGenerator.java +++ b/dspace-api/src/main/java/org/dspace/rdf/storage/LocalURIGenerator.java @@ -24,53 +24,49 @@ import org.dspace.services.factory.DSpaceServicesFactory; import org.springframework.beans.factory.annotation.Autowired; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class LocalURIGenerator implements URIGenerator { private static final Logger log = Logger.getLogger(LocalURIGenerator.class); - @Autowired(required=true) + @Autowired(required = true) protected SiteService siteService; @Override public String generateIdentifier(Context context, int type, UUID id, - String handle, List identifiers) - throws SQLException - { + String handle, List identifiers) + throws SQLException { String urlPrefix = DSpaceServicesFactory.getInstance().getConfigurationService() - .getProperty(RDFUtil.CONTEXT_PATH_KEY) + "/resource/"; - - if (type == Constants.SITE) - { + .getProperty(RDFUtil.CONTEXT_PATH_KEY) + "/resource/"; + + if (type == Constants.SITE) { return urlPrefix + siteService.findSite(context).getHandle(); } - - if (type == Constants.COMMUNITY - || type == Constants.COLLECTION - || type == Constants.ITEM) - { - if (StringUtils.isEmpty(handle)) - { + + if (type == Constants.COMMUNITY + || type == Constants.COLLECTION + || type == Constants.ITEM) { + if (StringUtils.isEmpty(handle)) { throw new IllegalArgumentException("Handle is null"); } return urlPrefix + handle; } - + return null; } @Override public String generateIdentifier(Context context, DSpaceObject dso) throws SQLException { if (dso.getType() != Constants.SITE - && dso.getType() != Constants.COMMUNITY - && dso.getType() != Constants.COLLECTION - && dso.getType() != Constants.ITEM) - { + && dso.getType() != Constants.COMMUNITY + && dso.getType() != Constants.COLLECTION + && dso.getType() != Constants.ITEM) { return null; } - - return generateIdentifier(context, dso.getType(), dso.getID(), dso.getHandle(), ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getIdentifiers(context, dso)); + + return generateIdentifier(context, dso.getType(), dso.getID(), dso.getHandle(), + ContentServiceFactory.getInstance().getDSpaceObjectService(dso) + .getIdentifiers(context, dso)); } } diff --git a/dspace-api/src/main/java/org/dspace/rdf/storage/RDFStorage.java b/dspace-api/src/main/java/org/dspace/rdf/storage/RDFStorage.java index 05a7fe6f71..31294323c7 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/storage/RDFStorage.java +++ b/dspace-api/src/main/java/org/dspace/rdf/storage/RDFStorage.java @@ -8,37 +8,41 @@ package org.dspace.rdf.storage; -import com.hp.hpl.jena.rdf.model.Model; import java.util.List; +import com.hp.hpl.jena.rdf.model.Model; + /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public interface RDFStorage { /** - * Don't use this method directly, use - * {@link org.dspace.rdf.RDFUtil#convert(org.dspace.core.Context, org.dspace.content.DSpaceObject) RDFizer.convert(...)} + * Don't use this method directly, use + * {@link org.dspace.rdf.RDFUtil#convert(org.dspace.core.Context, + * org.dspace.content.DSpaceObject) RDFizer.convert(...)} * to convert and store DSpaceObjets. - * @param uri Identifier for this DSO - * ({@link org.dspace.rdf.RDFUtil#generateIdentifier(org.dspace.core.Context, org.dspace.content.DSpaceObject) RDFizer.generateIdentifier(...)}). - * You can load this model by using this URI. + * + * @param uri Identifier for this DSO + * ({@link org.dspace.rdf.RDFUtil#generateIdentifier(org.dspace.core.Context, + * org.dspace.content.DSpaceObject) RDFizer.generateIdentifier(...)}). + * You can load this model by using this URI. * @param model The model to store. * @see org.dspace.rdf.RDFizer#RDFizer */ public void store(String uri, Model model); - + /** * Don't use this method directly, use * {@link org.dspace.rdf.RDFUtil#loadModel(String) RDFizer.loadModel(...)} instead. - * @param uri Identifier for this DSO + * + * @param uri Identifier for this DSO * @return the model */ public Model load(String uri); - + public void delete(String uri); - + public void deleteAll(); - + public List getAllStoredGraphs(); } diff --git a/dspace-api/src/main/java/org/dspace/rdf/storage/RDFStorageImpl.java b/dspace-api/src/main/java/org/dspace/rdf/storage/RDFStorageImpl.java index 6ee2e91a6d..5656f409d7 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/storage/RDFStorageImpl.java +++ b/dspace-api/src/main/java/org/dspace/rdf/storage/RDFStorageImpl.java @@ -8,6 +8,10 @@ package org.dspace.rdf.storage; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import com.hp.hpl.jena.graph.Graph; import com.hp.hpl.jena.graph.Node; import com.hp.hpl.jena.graph.NodeFactory; @@ -21,9 +25,6 @@ import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.sparql.core.DatasetGraph; import com.hp.hpl.jena.update.GraphStore; import com.hp.hpl.jena.update.GraphStoreFactory; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.jena.atlas.web.auth.HttpAuthenticator; import org.apache.jena.atlas.web.auth.SimpleAuthenticator; @@ -35,20 +36,17 @@ import org.dspace.services.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class RDFStorageImpl -implements RDFStorage -{ + implements RDFStorage { private static final Logger log = Logger.getLogger(RDFStorageImpl.class); - @Autowired(required=true) + @Autowired(required = true) protected ConfigurationService configurationService; - + @Override - public void store(String uri, Model model) - { + public void store(String uri, Model model) { Node graphNode = NodeFactory.createURI(uri); DatasetGraphAccessor accessor = this.getAccessor(); Dataset ds = DatasetFactory.create(model); @@ -56,15 +54,13 @@ implements RDFStorage Graph g = dsg.getDefaultGraph(); accessor.httpPut(graphNode, g); } - + @Override - public Model load(String uri) - { + public Model load(String uri) { Node graphNode = NodeFactory.createURI(uri); DatasetGraphAccessor accessor = this.getAccessor(); Graph g = accessor.httpGet(graphNode); - if (g == null || g.isEmpty()) - { + if (g == null || g.isEmpty()) { return null; } GraphStore gs = GraphStoreFactory.create(g); @@ -72,26 +68,24 @@ implements RDFStorage Model m = ds.getDefaultModel(); return m; } - - protected DatasetGraphAccessor getAccessor() - { + + protected DatasetGraphAccessor getAccessor() { DatasetGraphAccessor accessor; if (configurationService.hasProperty(RDFUtil.STORAGE_GRAPHSTORE_LOGIN_KEY) - && configurationService.hasProperty(RDFUtil.STORAGE_GRAPHSTORE_PASSWORD_KEY)) - { + && configurationService.hasProperty(RDFUtil.STORAGE_GRAPHSTORE_PASSWORD_KEY)) { HttpAuthenticator httpAuthenticator = new SimpleAuthenticator( - configurationService.getProperty(RDFUtil.STORAGE_GRAPHSTORE_LOGIN_KEY), - configurationService.getProperty(RDFUtil.STORAGE_GRAPHSTORE_PASSWORD_KEY).toCharArray()); + configurationService.getProperty(RDFUtil.STORAGE_GRAPHSTORE_LOGIN_KEY), + configurationService.getProperty(RDFUtil.STORAGE_GRAPHSTORE_PASSWORD_KEY).toCharArray()); accessor = new DatasetGraphAccessorHTTP(getGraphStoreEndpoint(), - httpAuthenticator); + httpAuthenticator); } else { log.debug("Did not found credential to use for our connection to the " - + "Graph Store HTTP endpoint, trying to connect unauthenticated."); + + "Graph Store HTTP endpoint, trying to connect unauthenticated."); accessor = new DatasetGraphAccessorHTTP(getGraphStoreEndpoint()); } return accessor; } - + @Override public void delete(String uri) { this.getAccessor().httpDelete(NodeFactory.createURI(uri)); @@ -99,76 +93,67 @@ implements RDFStorage @Override public void deleteAll() { - for (String graph : this.getAllStoredGraphs()) - { + for (String graph : this.getAllStoredGraphs()) { this.delete(graph); } // clean default graph: this.getAccessor().httpDelete(); } - + @Override public List getAllStoredGraphs() { String queryString = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }"; QueryExecution qexec; if (configurationService.hasProperty(RDFUtil.STORAGE_SPARQL_LOGIN_KEY) - && configurationService.hasProperty(RDFUtil.STORAGE_SPARQL_PASSWORD_KEY)) - { + && configurationService.hasProperty(RDFUtil.STORAGE_SPARQL_PASSWORD_KEY)) { HttpAuthenticator httpAuthenticator = new SimpleAuthenticator( - configurationService.getProperty(RDFUtil.STORAGE_SPARQL_LOGIN_KEY), - configurationService.getProperty(RDFUtil.STORAGE_GRAPHSTORE_PASSWORD_KEY).toCharArray()); - qexec = QueryExecutionFactory.sparqlService(getSparqlEndpoint(), - queryString, httpAuthenticator); + configurationService.getProperty(RDFUtil.STORAGE_SPARQL_LOGIN_KEY), + configurationService.getProperty(RDFUtil.STORAGE_GRAPHSTORE_PASSWORD_KEY).toCharArray()); + qexec = QueryExecutionFactory.sparqlService(getSparqlEndpoint(), + queryString, httpAuthenticator); } else { qexec = QueryExecutionFactory.sparqlService(getSparqlEndpoint(), - queryString); + queryString); } - + ResultSet rs = qexec.execSelect(); List graphs = Collections.synchronizedList(new ArrayList()); - while (rs.hasNext()) - { + while (rs.hasNext()) { QuerySolution solution = rs.next(); - if (solution.contains("g")) - { + if (solution.contains("g")) { graphs.add(solution.get("g").asResource().getURI()); } } qexec.close(); return graphs; } - - protected String getGraphStoreEndpoint() - { + + protected String getGraphStoreEndpoint() { String endpoint = configurationService.getProperty(RDFUtil.STORAGE_GRAPHSTORE_ENDPOINT_KEY); - if (StringUtils.isEmpty(endpoint)) - { + if (StringUtils.isEmpty(endpoint)) { log.warn("Cannot load Graph Store HTTP Protocol endpoint! Property " - + RDFUtil.STORAGE_GRAPHSTORE_ENDPOINT_KEY + " does not " - + "exist or is empty."); + + RDFUtil.STORAGE_GRAPHSTORE_ENDPOINT_KEY + " does not " + + "exist or is empty."); throw new RuntimeException("Cannot load Graph Store HTTP Protocol " - + "endpoint! Property " - + RDFUtil.STORAGE_GRAPHSTORE_ENDPOINT_KEY + " does not " - + "exist or is empty."); + + "endpoint! Property " + + RDFUtil.STORAGE_GRAPHSTORE_ENDPOINT_KEY + " does not " + + "exist or is empty."); } return endpoint; } - - protected String getSparqlEndpoint() - { + + protected String getSparqlEndpoint() { // Lets see if a SPARQL endpoint is defined to be used by RDFStorageImpl String endpoint = configurationService.getProperty(RDFUtil.STORAGE_SPARQL_ENDPOINT_KEY); - if (StringUtils.isEmpty(endpoint)) - { + if (StringUtils.isEmpty(endpoint)) { // try to load the public sparql endpoint endpoint = configurationService.getProperty(RDFUtil.SPARQL_ENDPOINT_KEY); } // check if we found an endpoint - if (StringUtils.isEmpty(endpoint)) - { + if (StringUtils.isEmpty(endpoint)) { log.warn("Cannot load internal or public SPARQL endpoint!"); throw new RuntimeException("Cannot load internal or public SPARQL " - + "endpoint!"); + + "endpoint!"); } return endpoint; } diff --git a/dspace-api/src/main/java/org/dspace/rdf/storage/URIGenerator.java b/dspace-api/src/main/java/org/dspace/rdf/storage/URIGenerator.java index fe9493bbf0..74f0ce2ef6 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/storage/URIGenerator.java +++ b/dspace-api/src/main/java/org/dspace/rdf/storage/URIGenerator.java @@ -15,53 +15,50 @@ import org.dspace.content.DSpaceObject; import org.dspace.core.Context; /** - * Please use - * {@link org.dspace.rdf.RDFUtil#generateIdentifier(Context, DSpaceObject)} to + * Please use + * {@link org.dspace.rdf.RDFUtil#generateIdentifier(Context, DSpaceObject)} to * get URIs for RDF data. - * Please note that URIs can be generated for DSpaceObjects of the - * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf + * Please note that URIs can be generated for DSpaceObjects of the + * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf * doesn't support Bundles or Bitstreams as independent entity. - * + * * {@link org.dspace.rdf.RDFizer#RDFizer} uses a URIGenerator to generate URIs to * Identify DSpaceObjects in RDF. You can configure which URIGenerator should be * used. See DSpace documentation on how to configure RDFizer. + * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) * @see org.dspace.rdf.RDFizer#RDFizer * @see org.dspace.rdf.RDFUtil#RDFUtil */ public interface URIGenerator { - + /** * Generate a URI that can be used to identify the specified DSpaceObject in - * RDF data. Please note that URIs can be generated for DSpaceObjects of the - * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf + * RDF data. Please note that URIs can be generated for DSpaceObjects of the + * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf * doesn't support Bundles or Bitstreams as independent entity. This method * should work even if the DSpaceObject does not exist anymore. - * @param context DSpace Context. - * @param type Type of the DSpaceObject you want to generate a URI for (e.g. - * {@link org.dspace.core.Constants#ITEM Constants.ITEM}. - * @param id UUID of the DSpaceObject you want to generate a URI for. - * @param handle Handle of the DSpaceObject you want to generate a URI for. - * @param identifiers - * list of identifiers + * + * @param context DSpace Context. + * @param type Type of the DSpaceObject you want to generate a URI for (e.g. + * {@link org.dspace.core.Constants#ITEM Constants.ITEM}. + * @param id UUID of the DSpaceObject you want to generate a URI for. + * @param handle Handle of the DSpaceObject you want to generate a URI for. + * @param identifiers list of identifiers * @return May return null, if no URI could be generated. + * @throws SQLException An exception that provides information on a database access error or other errors. * @see org.dspace.rdf.RDFUtil#generateIdentifier(Context, DSpaceObject) - * @throws SQLException - * An exception that provides information on a database access error or other errors. */ public String generateIdentifier(Context context, int type, UUID id, String handle, List identifiers) throws SQLException; - + /** * Shortcut for {@code generateIdentifier(context, dso.getType(), dso.getID(), dso.getHandle())}. - * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to generate identifier for + * + * @param context The relevant DSpace Context. + * @param dso DSpace object to generate identifier for * @return May return null, if no URI could be generated. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public String generateIdentifier(Context context, DSpaceObject dso) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/search/Harvest.java b/dspace-api/src/main/java/org/dspace/search/Harvest.java index cce88bfc90..083a32d89d 100644 --- a/dspace-api/src/main/java/org/dspace/search/Harvest.java +++ b/dspace-api/src/main/java/org/dspace/search/Harvest.java @@ -7,11 +7,21 @@ */ package org.dspace.search; +import java.sql.SQLException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; -import org.dspace.content.*; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DCDate; +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; @@ -24,26 +34,30 @@ import org.dspace.eperson.Group; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; -import java.sql.SQLException; -import java.text.ParseException; -import java.util.*; - /** * Utility class for extracting information about items, possibly just within a * certain community or collection, that have been created, modified or * withdrawn within a particular range of dates. - * + * * @author Robert Tansley * @version $Revision$ */ -public class Harvest -{ - /** log4j logger */ +public class Harvest { + /** + * log4j logger + */ private static final Logger log = Logger.getLogger(Harvest.class); - protected static final AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); + protected static final AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance() + .getAuthorizeService(); protected static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); + + /** + * Default constructor + */ + private Harvest() { } + /** * Obtain information about items that have been created, modified or * withdrawn within a given date range. You can also specify 'offset' and @@ -54,66 +68,56 @@ public class Harvest *

    * FIXME: Assumes all in_archive items have public metadata * - * @param context - * DSpace context - * @param scope - * a Collection, Community, or null indicating the scope is - * all of DSpace - * @param startDate - * start of date range, or null - * @param endDate - * end of date range, or null - * @param offset - * for a partial harvest, the point in the overall list of - * matching items to start at. 0 means just start at the - * beginning. - * @param limit - * the number of matching items to return in a partial harvest. - * Specify 0 to return the whole list (or the rest of the list if - * an offset was specified.) - * @param items - * if true the item field of each - * HarvestedItemInfo object is filled out - * @param collections - * if true the collectionHandles - * field of each HarvestedItemInfo object is - * filled out - * @param withdrawn - * If true, information about withdrawn items is - * included - * @param nonAnon - * If items without anonymous access should be included or not + * @param context DSpace context + * @param scope a Collection, Community, or null indicating the scope is + * all of DSpace + * @param startDate start of date range, or null + * @param endDate end of date range, or null + * @param offset for a partial harvest, the point in the overall list of + * matching items to start at. 0 means just start at the + * beginning. + * @param limit the number of matching items to return in a partial harvest. + * Specify 0 to return the whole list (or the rest of the list if + * an offset was specified.) + * @param items if true the item field of each + * HarvestedItemInfo object is filled out + * @param collections if true the collectionHandles + * field of each HarvestedItemInfo object is + * filled out + * @param withdrawn If true, information about withdrawn items is + * included + * @param nonAnon If items without anonymous access should be included or not * @return List of HarvestedItemInfo objects - * @throws SQLException if database error + * @throws SQLException if database error * @throws java.text.ParseException If the date is not in a supported format */ public static List harvest(Context context, DSpaceObject scope, - String startDate, String endDate, int offset, int limit, - boolean items, boolean collections, boolean withdrawn, - boolean nonAnon) throws SQLException, ParseException - { + String startDate, String endDate, int offset, int limit, + boolean items, boolean collections, boolean withdrawn, + boolean nonAnon) throws SQLException, ParseException { DiscoverQuery discoverQuery = new DiscoverQuery(); discoverQuery.addFilterQueries("search.resourcetype:" + Constants.ITEM); - if (scope != null) - { - discoverQuery.addFieldPresentQueries("location:" + scope.getID()); + if (scope != null) { + if (scope instanceof Community) { + discoverQuery.addFilterQueries("location:m" + scope.getID()); + } else if (scope instanceof Collection) { + discoverQuery.addFilterQueries("location:l" + scope.getID()); + } } - if (startDate != null) - { - discoverQuery.addFilterQueries("lastModified => " + new DCDate(startDate).toString()); + if (startDate != null && endDate != null) { + discoverQuery.addFilterQueries("lastModified:[" + new DCDate(startDate).toString() + + " TO " + new DCDate(endDate).toString() + "]"); + } else if (startDate != null) { + discoverQuery.addFilterQueries("lastModified:[" + new DCDate(startDate).toString() + " TO *]"); + } else if (endDate != null) { + discoverQuery.addFilterQueries("lastModified:[* TO " + new DCDate(endDate).toString() + " ]"); } - if (endDate != null) - { - discoverQuery.addFilterQueries("lastModified <= " + new DCDate(startDate).toString()); - } - - if (!withdrawn) - { + if (!withdrawn) { discoverQuery.addFilterQueries("archived: true OR withdrawn: false"); - }else{ + } else { discoverQuery.addFilterQueries("archived: true OR withdrawn: true"); } @@ -136,8 +140,7 @@ public class Harvest // Process results of query into HarvestedItemInfo objects Iterator dsoIterator = discoverResult.getDspaceObjects().iterator(); - while (dsoIterator.hasNext() && ((limit == 0) || (itemCounter < limit))) - { + while (dsoIterator.hasNext() && ((limit == 0) || (itemCounter < limit))) { DSpaceObject dso = dsoIterator.next(); HarvestedItemInfo itemInfo = new HarvestedItemInfo(); itemInfo.context = context; @@ -146,35 +149,27 @@ public class Harvest itemInfo.datestamp = ((Item) dso).getLastModified(); itemInfo.withdrawn = ((Item) dso).isWithdrawn(); - if (collections) - { + if (collections) { // Add collections data fillCollections(context, itemInfo); } - if (items) - { + if (items) { // Add the item reference itemInfo.item = itemService.find(context, itemInfo.itemID); } - if ((nonAnon) || (itemInfo.item == null) || (withdrawn && itemInfo.withdrawn)) - { + if ((nonAnon) || (itemInfo.item == null) || (withdrawn && itemInfo.withdrawn)) { index++; - if (index > offset) - { + if (index > offset) { infoObjects.add(itemInfo); itemCounter++; } - } - else - { + } else { // We only want items that allow for anonymous access. - if (anonAccessAllowed(context, itemInfo)) - { + if (anonAccessAllowed(context, itemInfo)) { index++; - if (index > offset) - { + if (index > offset) { infoObjects.add(itemInfo); itemCounter++; } @@ -192,27 +187,21 @@ public class Harvest * Get harvested item info for a single item. item field in * returned HarvestedItemInfo object is always filled out. * - * @param context - * DSpace context - * @param handle - * Prefix-less Handle of item - * @param collections - * if true the collectionHandles - * field of the HarvestedItemInfo object is filled - * out - * + * @param context DSpace context + * @param handle Prefix-less Handle of item + * @param collections if true the collectionHandles + * field of the HarvestedItemInfo object is filled + * out * @return HarvestedItemInfo object for the single item, or - * null + * null * @throws SQLException if database error */ public static HarvestedItemInfo getSingle(Context context, String handle, - boolean collections) throws SQLException - { + boolean collections) throws SQLException { // FIXME: Assume Handle is item Item i = (Item) handleService.resolveToObject(context, handle); - if (i == null) - { + if (i == null) { return null; } @@ -227,8 +216,7 @@ public class Harvest itemInfo.itemID = i.getID(); // Get the sets - if (collections) - { + if (collections) { fillCollections(context, itemInfo); } @@ -238,15 +226,12 @@ public class Harvest /** * Fill out the containers field of the HarvestedItemInfo object * - * @param context - * DSpace context - * @param itemInfo - * HarvestedItemInfo object to fill out + * @param context DSpace context + * @param itemInfo HarvestedItemInfo object to fill out * @throws SQLException if database error */ private static void fillCollections(Context context, - HarvestedItemInfo itemInfo) throws SQLException - { + HarvestedItemInfo itemInfo) throws SQLException { // Get the collection Handles from DB List collections = itemInfo.item.getCollections(); itemInfo.collectionHandles = new ArrayList<>(); @@ -258,14 +243,11 @@ public class Harvest /** * Does the item allow anonymous access ? ie. authorizedGroups must include id=0. */ - private static boolean anonAccessAllowed(Context context, HarvestedItemInfo itemInfo) throws SQLException - { + private static boolean anonAccessAllowed(Context context, HarvestedItemInfo itemInfo) throws SQLException { List authorizedGroups = authorizeService.getAuthorizedGroups(context, itemInfo.item, Constants.READ); - for (Group authorizedGroup : authorizedGroups) - { - if (authorizedGroup.getName().equals(Group.ANONYMOUS)) - { + for (Group authorizedGroup : authorizedGroups) { + if (authorizedGroup.getName().equals(Group.ANONYMOUS)) { return true; } } diff --git a/dspace-api/src/main/java/org/dspace/search/HarvestedItemInfo.java b/dspace-api/src/main/java/org/dspace/search/HarvestedItemInfo.java index 6ba4e2bd3c..e4d45da700 100644 --- a/dspace-api/src/main/java/org/dspace/search/HarvestedItemInfo.java +++ b/dspace-api/src/main/java/org/dspace/search/HarvestedItemInfo.java @@ -16,25 +16,34 @@ import org.dspace.core.Context; /** * Simple container class containing information about a harvested DSpace item. - * + * * @author Robert Tansley * @version $Revision$ */ -public class HarvestedItemInfo -{ - /** Context used when creating this object */ +public class HarvestedItemInfo { + /** + * Context used when creating this object + */ public Context context; - - /** Internal item ID (as opposed to item's OAI ID, which is the Handle) */ + + /** + * Internal item ID (as opposed to item's OAI ID, which is the Handle) + */ public UUID itemID; - /** The Handle, with no prefix */ + /** + * The Handle, with no prefix + */ public String handle; - /** The datestamp */ + /** + * The datestamp + */ public Date datestamp; - /** The item. Only filled out if requested */ + /** + * The item. Only filled out if requested + */ public Item item; /** @@ -44,6 +53,8 @@ public class HarvestedItemInfo */ public List collectionHandles; - /** True if this item has been withdrawn */ + /** + * True if this item has been withdrawn + */ public boolean withdrawn; } diff --git a/dspace-api/src/main/java/org/dspace/service/DSpaceCRUDService.java b/dspace-api/src/main/java/org/dspace/service/DSpaceCRUDService.java index 8dcf7ecc15..9abe40948a 100644 --- a/dspace-api/src/main/java/org/dspace/service/DSpaceCRUDService.java +++ b/dspace-api/src/main/java/org/dspace/service/DSpaceCRUDService.java @@ -7,12 +7,12 @@ */ package org.dspace.service; -import org.dspace.authorize.AuthorizeException; -import org.dspace.core.Context; - import java.sql.SQLException; import java.util.List; +import org.dspace.authorize.AuthorizeException; +import org.dspace.core.Context; + /** * Interface containing the simple CRUD methods so we don't have to add them over and again to every service which * requires these methods diff --git a/dspace-api/src/main/java/org/dspace/sort/AbstractTextFilterOFD.java b/dspace-api/src/main/java/org/dspace/sort/AbstractTextFilterOFD.java index 5f97db621d..ec98ee874a 100644 --- a/dspace-api/src/main/java/org/dspace/sort/AbstractTextFilterOFD.java +++ b/dspace-api/src/main/java/org/dspace/sort/AbstractTextFilterOFD.java @@ -9,90 +9,77 @@ package org.dspace.sort; import org.apache.log4j.Logger; import org.dspace.text.filter.TextFilter; -import org.dspace.sort.OrderFormatDelegate; /** * Helper class for creating order delegates. * * To configure the filters create a subclass and, in an object initializer, * create an array of classes that implement TextFilter: - * + * * class MyLocaleDelegate extends AbstractTextFilterOFD { - * { - * filters = new TextFilter[] { new LocaleOrderingFilter(); } - * } + * { + * filters = new TextFilter[] { new LocaleOrderingFilter(); } * } - * + * } + * * The order they are in the array, is the order that they are executed. * (this may be important for some filters - read their documentation!) - * + * * Example configurations that could be used: * { new DecomposeDiactritics(), new StripDiacritics(), new LowerCaseAndTrim() } - * - Decompose and then strip the diacritics, lowercase and trim the string. - * + * - Decompose and then strip the diacritics, lowercase and trim the string. + * * { new MARC21InitialArticleWord(), new DecomposeDiactritics(), new LowerCaseTrim() } - * - Parse the initial article words based on the Library of Congress list of - * definite/indefinite article words, decompose diacritics, and lowercase/trim. + * - Parse the initial article words based on the Library of Congress list of + * definite/indefinite article words, decompose diacritics, and lowercase/trim. * * { new LowerCaseTrim(), new LocaleOrderingFilter() } - * - Lowercase the string, then make a locale dependent sort text - * (note that the sort text is not human readable) - * + * - Lowercase the string, then make a locale dependent sort text + * (note that the sort text is not human readable) + * * @author Graham Triggs */ -public abstract class AbstractTextFilterOFD implements OrderFormatDelegate -{ - private static final Logger log = Logger.getLogger(AbstractTextFilterOFD.class); - - // Initialised in subclass in an object initializer - protected TextFilter[] filters; +public abstract class AbstractTextFilterOFD implements OrderFormatDelegate { + private static final Logger log = Logger.getLogger(AbstractTextFilterOFD.class); - /** - * Prepare the appropriate sort string for the given value in the - * given language. Language should be supplied with the ISO-6390-1 - * or ISO-639-2 standards. For example "en" or "eng". - * - * @param value the string value - * @param language the language to interpret in - */ - @Override - public String makeSortString(String value, String language) - { - if (filters == null) - { - // Log an error if the class is not configured correctly - log.error("No filters defined for " + this.getClass().getName()); - } - else - { - // Normalize language into a two or three character code - if (language != null) - { - if (language.length() > 2 && language.charAt(2) == '_') - { + // Initialised in subclass in an object initializer + protected TextFilter[] filters; + + /** + * Prepare the appropriate sort string for the given value in the + * given language. Language should be supplied with the ISO-6390-1 + * or ISO-639-2 standards. For example "en" or "eng". + * + * @param value the string value + * @param language the language to interpret in + */ + @Override + public String makeSortString(String value, String language) { + if (filters == null) { + // Log an error if the class is not configured correctly + log.error("No filters defined for " + this.getClass().getName()); + } else { + // Normalize language into a two or three character code + if (language != null) { + if (language.length() > 2 && language.charAt(2) == '_') { language = language.substring(0, 2); } - if (language.length() > 3) - { + if (language.length() > 3) { language = language.substring(0, 3); } - } + } - // Iterate through filters, applying each in turn - for (int idx = 0; idx < filters.length; idx++) - { - if (language != null) - { + // Iterate through filters, applying each in turn + for (int idx = 0; idx < filters.length; idx++) { + if (language != null) { value = filters[idx].filter(value, language); - } - else - { + } else { value = filters[idx].filter(value); } - } - } - + } + } + return value; } } diff --git a/dspace-api/src/main/java/org/dspace/sort/OrderFormat.java b/dspace-api/src/main/java/org/dspace/sort/OrderFormat.java index 01964b32c0..4b3e188662 100644 --- a/dspace-api/src/main/java/org/dspace/sort/OrderFormat.java +++ b/dspace-api/src/main/java/org/dspace/sort/OrderFormat.java @@ -14,103 +14,96 @@ import org.dspace.core.factory.CoreServiceFactory; * (ie. ItemsByAuthor.sort_author, ItemsByTitle.sort_title) * * This class maps index 'types' to delegates that implement the sort string creation - * + * * Types can be defined or configured using the plugin manager: - * + * * plugin.named.org.dspace.sort.OrderFormatDelegate= - * org.dspace.sort.OrderFormatTitleMarc21=title - * org.dspace.sort.OrderFormatAuthor=author - * + * org.dspace.sort.OrderFormatTitleMarc21=title + * org.dspace.sort.OrderFormatAuthor=author + * * The following standard types have been defined by default, but can be reconfigured * via the plugin manager: - * + * * author = org.dspace.sort.OrderFormatAuthor * title = org.dspace.sort.OrderFormatTitle * text = org.dspace.sort.OrderFormatText - * + * * IMPORTANT - If you change any of the orderings, you need to rebuild the browse sort columns * (ie. run 'index-all', or 'dsrun org.dspace.browse.InitializeBrowse') - * + * * @author Graham Triggs * @version $Revision$ */ -public class OrderFormat -{ +public class OrderFormat { public static final String AUTHOR = "author"; - public static final String TITLE = "title"; - public static final String TEXT = "text"; - public static final String DATE = "date"; + public static final String TITLE = "title"; + public static final String TEXT = "text"; + public static final String DATE = "date"; public static final String AUTHORITY = "authority"; - + // Array of all available order delegates - avoids excessive calls to plugin manager - private static final String[] delegates = CoreServiceFactory.getInstance().getPluginService().getAllPluginNames(OrderFormatDelegate.class); + private static final String[] delegates = CoreServiceFactory.getInstance().getPluginService() + .getAllPluginNames(OrderFormatDelegate.class); private static final OrderFormatDelegate authorDelegate = new OrderFormatAuthor(); - private static final OrderFormatDelegate titleDelegate = new OrderFormatTitle(); - private static final OrderFormatDelegate textDelegate = new OrderFormatText(); - private static final OrderFormatDelegate dateDelegate = new OrderFormatDate(); + private static final OrderFormatDelegate titleDelegate = new OrderFormatTitle(); + private static final OrderFormatDelegate textDelegate = new OrderFormatText(); + private static final OrderFormatDelegate dateDelegate = new OrderFormatDate(); private static final OrderFormatDelegate authorityDelegate = new OrderFormatText(); - + + /** + * Default constructor + */ + private OrderFormat() { } + /** * Generate a sort string for the given DC metadata - * @param value - * metadata value - * @param language - * metadata language code - * @param type - * metadata type + * + * @param value metadata value + * @param language metadata language code + * @param type metadata type * @return sort string - * * @see OrderFormat#AUTHOR * @see OrderFormat#TITLE * @see OrderFormat#TEXT * @see OrderFormat#DATE * @see #AUTHORITY */ - public static String makeSortString(String value, String language, String type) - { + public static String makeSortString(String value, String language, String type) { OrderFormatDelegate delegate = null; - + // If there is no value, return null - if (value == null) - { + if (value == null) { return null; } // If a named index has been supplied - if (type != null && type.length() > 0) - { + if (type != null && type.length() > 0) { // Use a delegate if one is configured delegate = OrderFormat.getDelegate(type); - if (delegate != null) - { + if (delegate != null) { return delegate.makeSortString(value, language); } // No delegates found, so apply defaults - if (type.equalsIgnoreCase(OrderFormat.AUTHOR) && authorDelegate != null) - { - return authorDelegate.makeSortString(value, language); + if (type.equalsIgnoreCase(OrderFormat.AUTHOR) && authorDelegate != null) { + return authorDelegate.makeSortString(value, language); } - if (type.equalsIgnoreCase(OrderFormat.TITLE) && titleDelegate != null) - { - return titleDelegate.makeSortString(value, language); + if (type.equalsIgnoreCase(OrderFormat.TITLE) && titleDelegate != null) { + return titleDelegate.makeSortString(value, language); } - if (type.equalsIgnoreCase(OrderFormat.TEXT) && textDelegate != null) - { - return textDelegate.makeSortString(value, language); - } - - if (type.equalsIgnoreCase(OrderFormat.DATE) && dateDelegate != null) - { - return dateDelegate.makeSortString(value, language); + if (type.equalsIgnoreCase(OrderFormat.TEXT) && textDelegate != null) { + return textDelegate.makeSortString(value, language); } - if (type.equalsIgnoreCase(OrderFormat.AUTHORITY) && authorityDelegate != null) - { - return authorityDelegate.makeSortString(value, language); + if (type.equalsIgnoreCase(OrderFormat.DATE) && dateDelegate != null) { + return dateDelegate.makeSortString(value, language); + } + + if (type.equalsIgnoreCase(OrderFormat.AUTHORITY) && authorityDelegate != null) { + return authorityDelegate.makeSortString(value, language); } } @@ -120,20 +113,17 @@ public class OrderFormat /** * Retrieve the named delegate */ - private static OrderFormatDelegate getDelegate(String name) - { - if (name != null && name.length() > 0) - { - // Check the cached array of names to see if the delegate has been configured - for (int idx = 0; idx < delegates.length; idx++) - { - if (delegates[idx].equals(name)) - { - return (OrderFormatDelegate)CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(OrderFormatDelegate.class, name); - } - } - } - + private static OrderFormatDelegate getDelegate(String name) { + if (name != null && name.length() > 0) { + // Check the cached array of names to see if the delegate has been configured + for (int idx = 0; idx < delegates.length; idx++) { + if (delegates[idx].equals(name)) { + return (OrderFormatDelegate) CoreServiceFactory.getInstance().getPluginService() + .getNamedPlugin(OrderFormatDelegate.class, name); + } + } + } + return null; } } diff --git a/dspace-api/src/main/java/org/dspace/sort/OrderFormatAuthor.java b/dspace-api/src/main/java/org/dspace/sort/OrderFormatAuthor.java index ddb3cb4770..a38530606e 100644 --- a/dspace-api/src/main/java/org/dspace/sort/OrderFormatAuthor.java +++ b/dspace-api/src/main/java/org/dspace/sort/OrderFormatAuthor.java @@ -10,17 +10,15 @@ package org.dspace.sort; import org.dspace.text.filter.DecomposeDiactritics; import org.dspace.text.filter.LowerCaseAndTrim; import org.dspace.text.filter.TextFilter; -import org.dspace.sort.AbstractTextFilterOFD; /** * Standard author ordering delegate implementation - * + * * @author Graham Triggs */ -public class OrderFormatAuthor extends AbstractTextFilterOFD -{ - { - filters = new TextFilter[] { new DecomposeDiactritics(), - new LowerCaseAndTrim() }; - } +public class OrderFormatAuthor extends AbstractTextFilterOFD { + { + filters = new TextFilter[] {new DecomposeDiactritics(), + new LowerCaseAndTrim()}; + } } diff --git a/dspace-api/src/main/java/org/dspace/sort/OrderFormatDate.java b/dspace-api/src/main/java/org/dspace/sort/OrderFormatDate.java index 515ef84812..f56a97776f 100644 --- a/dspace-api/src/main/java/org/dspace/sort/OrderFormatDate.java +++ b/dspace-api/src/main/java/org/dspace/sort/OrderFormatDate.java @@ -10,35 +10,27 @@ package org.dspace.sort; /** * Standard date ordering delegate implementation. The only "special" need is * to treat dates with less than 4-digit year. - * + * * @author Andrea Bollini */ -public class OrderFormatDate implements OrderFormatDelegate -{ +public class OrderFormatDate implements OrderFormatDelegate { @Override - public String makeSortString(String value, String language) - { + public String makeSortString(String value, String language) { int padding = 0; int endYearIdx = value.indexOf('-'); - if (endYearIdx >= 0 && endYearIdx < 4) - { + if (endYearIdx >= 0 && endYearIdx < 4) { padding = 4 - endYearIdx; - } - else if (value.length() < 4) - { + } else if (value.length() < 4) { padding = 4 - value.length(); } - if (padding > 0) - { + if (padding > 0) { // padding the value from left with 0 so that 87 -> 0087, 687-11-24 // -> 0687-11-24 return String.format("%1$0" + padding + "d", 0) - + value; - } - else - { + + value; + } else { return value; } } diff --git a/dspace-api/src/main/java/org/dspace/sort/OrderFormatDelegate.java b/dspace-api/src/main/java/org/dspace/sort/OrderFormatDelegate.java index bba8265fa4..12996913b8 100644 --- a/dspace-api/src/main/java/org/dspace/sort/OrderFormatDelegate.java +++ b/dspace-api/src/main/java/org/dspace/sort/OrderFormatDelegate.java @@ -9,21 +9,18 @@ package org.dspace.sort; /** * Interface for browse order delegates - * + * * @author Graham Triggs */ -public interface OrderFormatDelegate -{ - /** - * Prepare the appropriate sort string for the given value in the - * given language. Language should be supplied with the ISO-6390-1 - * or ISO-639-2 standards. For example "en" or "eng". - * - * @param value - * the string value - * @param language - * the language to interpret in - * @return the sort string - */ +public interface OrderFormatDelegate { + /** + * Prepare the appropriate sort string for the given value in the + * given language. Language should be supplied with the ISO-6390-1 + * or ISO-639-2 standards. For example "en" or "eng". + * + * @param value the string value + * @param language the language to interpret in + * @return the sort string + */ public String makeSortString(String value, String language); } diff --git a/dspace-api/src/main/java/org/dspace/sort/OrderFormatText.java b/dspace-api/src/main/java/org/dspace/sort/OrderFormatText.java index c82b9ff67c..403034f675 100644 --- a/dspace-api/src/main/java/org/dspace/sort/OrderFormatText.java +++ b/dspace-api/src/main/java/org/dspace/sort/OrderFormatText.java @@ -10,17 +10,15 @@ package org.dspace.sort; import org.dspace.text.filter.DecomposeDiactritics; import org.dspace.text.filter.LowerCaseAndTrim; import org.dspace.text.filter.TextFilter; -import org.dspace.sort.AbstractTextFilterOFD; /** * Standard text ordering delegate implementation - * + * * @author Graham Triggs */ -public class OrderFormatText extends AbstractTextFilterOFD -{ - { - filters = new TextFilter[] { new DecomposeDiactritics(), - new LowerCaseAndTrim() }; - } +public class OrderFormatText extends AbstractTextFilterOFD { + { + filters = new TextFilter[] {new DecomposeDiactritics(), + new LowerCaseAndTrim()}; + } } diff --git a/dspace-api/src/main/java/org/dspace/sort/OrderFormatTitle.java b/dspace-api/src/main/java/org/dspace/sort/OrderFormatTitle.java index 81ae396371..eb3586dc61 100644 --- a/dspace-api/src/main/java/org/dspace/sort/OrderFormatTitle.java +++ b/dspace-api/src/main/java/org/dspace/sort/OrderFormatTitle.java @@ -11,18 +11,16 @@ import org.dspace.text.filter.DecomposeDiactritics; import org.dspace.text.filter.LowerCaseAndTrim; import org.dspace.text.filter.StandardInitialArticleWord; import org.dspace.text.filter.TextFilter; -import org.dspace.sort.AbstractTextFilterOFD; /** * Standard title ordering delegate implementation - * + * * @author Graham Triggs */ -public class OrderFormatTitle extends AbstractTextFilterOFD -{ - { - filters = new TextFilter[] { new StandardInitialArticleWord(), - new DecomposeDiactritics(), - new LowerCaseAndTrim() }; - } +public class OrderFormatTitle extends AbstractTextFilterOFD { + { + filters = new TextFilter[] {new StandardInitialArticleWord(), + new DecomposeDiactritics(), + new LowerCaseAndTrim()}; + } } diff --git a/dspace-api/src/main/java/org/dspace/sort/OrderFormatTitleMarc21.java b/dspace-api/src/main/java/org/dspace/sort/OrderFormatTitleMarc21.java index c6f906eb87..670e5c87e5 100644 --- a/dspace-api/src/main/java/org/dspace/sort/OrderFormatTitleMarc21.java +++ b/dspace-api/src/main/java/org/dspace/sort/OrderFormatTitleMarc21.java @@ -7,20 +7,22 @@ */ package org.dspace.sort; -import org.dspace.text.filter.*; -import org.dspace.sort.AbstractTextFilterOFD; +import org.dspace.text.filter.DecomposeDiactritics; +import org.dspace.text.filter.LowerCaseAndTrim; +import org.dspace.text.filter.MARC21InitialArticleWord; +import org.dspace.text.filter.StripLeadingNonAlphaNum; +import org.dspace.text.filter.TextFilter; /** * MARC 21 title ordering delegate implementation - * + * * @author Graham Triggs */ -public class OrderFormatTitleMarc21 extends AbstractTextFilterOFD -{ - { - filters = new TextFilter[] { new MARC21InitialArticleWord(), - new DecomposeDiactritics(), - new StripLeadingNonAlphaNum(), - new LowerCaseAndTrim() }; - } +public class OrderFormatTitleMarc21 extends AbstractTextFilterOFD { + { + filters = new TextFilter[] {new MARC21InitialArticleWord(), + new DecomposeDiactritics(), + new StripLeadingNonAlphaNum(), + new LowerCaseAndTrim()}; + } } diff --git a/dspace-api/src/main/java/org/dspace/sort/SortException.java b/dspace-api/src/main/java/org/dspace/sort/SortException.java index 754583eb93..5fa90cf8c6 100644 --- a/dspace-api/src/main/java/org/dspace/sort/SortException.java +++ b/dspace-api/src/main/java/org/dspace/sort/SortException.java @@ -10,27 +10,22 @@ package org.dspace.sort; /** * Just a quick SortException class to give us the relevant data type */ -public class SortException extends Exception -{ +public class SortException extends Exception { - public SortException() - { + public SortException() { super(); } - public SortException(String message) - { + public SortException(String message) { super(message); } - public SortException(String message, Throwable cause) - { - super(message, cause); - } + public SortException(String message, Throwable cause) { + super(message, cause); + } - public SortException(Throwable cause) - { - super(cause); - } + public SortException(Throwable cause) { + super(cause); + } } diff --git a/dspace-api/src/main/java/org/dspace/sort/SortOption.java b/dspace-api/src/main/java/org/dspace/sort/SortOption.java index aea11e718e..5c1cdfa95d 100644 --- a/dspace-api/src/main/java/org/dspace/sort/SortOption.java +++ b/dspace-api/src/main/java/org/dspace/sort/SortOption.java @@ -8,7 +8,10 @@ package org.dspace.sort; import java.io.IOException; -import java.util.*; +import java.util.Comparator; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -19,40 +22,52 @@ import org.dspace.core.ConfigurationManager; /** * Class to mediate with the sort configuration - * - * @author Richard Jones * + * @author Richard Jones */ -public class SortOption -{ +public class SortOption { private static final Logger log = Logger.getLogger(SortOption.class); - public static final String ASCENDING = "ASC"; + public static final String ASCENDING = "ASC"; public static final String DESCENDING = "DESC"; - /** the number of the sort option as given in the config file */ + /** + * the number of the sort option as given in the config file + */ private int number; - - /** the name of the sort */ + + /** + * the name of the sort + */ private String name; - - /** the metadata field to sort on */ + + /** + * the metadata field to sort on + */ private String metadata; - - /** the type of data we are sorting by */ + + /** + * the type of data we are sorting by + */ private String type; - - /** the metadata broken down into bits for convenience */ + + /** + * the metadata broken down into bits for convenience + */ private String[] mdBits; - /** should the sort option be visible for user selection */ + /** + * should the sort option be visible for user selection + */ private boolean visible; - /** the sort options available for this index */ + /** + * the sort options available for this index + */ private static Set sortOptionsSet = null; + static { - try - { + try { Set newSortOptionsSet = new TreeSet(new Comparator() { @Override public int compare(SortOption sortOption, SortOption sortOption1) { @@ -62,36 +77,29 @@ public class SortOption int idx = 1; String option; - while ( ((option = ConfigurationManager.getProperty("webui.itemlist.sort-option." + idx))) != null) - { + while (((option = ConfigurationManager.getProperty("webui.itemlist.sort-option." + idx))) != null) { SortOption so = new SortOption(idx, option); newSortOptionsSet.add(so); idx++; } SortOption.sortOptionsSet = newSortOptionsSet; - } - catch (SortException se) - { + } catch (SortException se) { log.fatal("Unable to load SortOptions", se); } } + /** * Construct a new SortOption object with the given parameters - * - * @param number - * the number of the sort option as given in the config file - * @param name - * sort option name - * @param md - * the metadata field to sort on - * @param type - * the type of data we are sorting by + * + * @param number the number of the sort option as given in the config file + * @param name sort option name + * @param md the metadata field to sort on + * @param type the type of data we are sorting by * @throws SortException if sort error */ public SortOption(int number, String name, String md, String type) - throws SortException - { + throws SortException { this.name = name; this.type = type; this.metadata = md; @@ -102,40 +110,33 @@ public class SortOption /** * Construct a new SortOption object using the definition from the configuration - * - * @param number - * the number of the sort option as given in the config file - * @param definition - * definition from the configuration + * + * @param number the number of the sort option as given in the config file + * @param definition definition from the configuration * @throws SortException if sort error */ public SortOption(int number, String definition) - throws SortException - { + throws SortException { this.number = number; - + String rx = "(\\w+):([\\w\\.\\*]+):(\\w+):?(\\w*)"; Pattern pattern = Pattern.compile(rx); Matcher matcher = pattern.matcher(definition); - - if (!matcher.matches()) - { + + if (!matcher.matches()) { throw new SortException("Sort Order configuration is not valid: webui.itemlist.sort-option." + - number + " = " + definition); + number + " = " + definition); } - + name = matcher.group(1); metadata = matcher.group(2); type = matcher.group(3); // If the option is configured to be hidden, then set the visible flag to false // otherwise, flag it as visible (true) - if (matcher.groupCount() > 3 && "hide".equalsIgnoreCase(matcher.group(4))) - { + if (matcher.groupCount() > 3 && "hide".equalsIgnoreCase(matcher.group(4))) { visible = false; - } - else - { + } else { visible = true; } @@ -145,158 +146,139 @@ public class SortOption /** * @return Returns the metadata. */ - public String getMetadata() - { + public String getMetadata() { return metadata; } /** * @param metadata The metadata to set. */ - public void setMetadata(String metadata) - { + public void setMetadata(String metadata) { this.metadata = metadata; } /** * @return Returns the name. */ - public String getName() - { + public String getName() { return name; } /** * @param name The name to set. */ - public void setName(String name) - { + public void setName(String name) { this.name = name; } /** * @return Returns the type. */ - public String getType() - { + public String getType() { return type; } /** * @param type The type to set. */ - public void setType(String type) - { + public void setType(String type) { this.type = type; } /** * @return Returns the sort option number (as given in the config file). */ - public int getNumber() - { + public int getNumber() { return number; } /** * @param number The number to set. */ - public void setNumber(int number) - { + public void setNumber(int number) { this.number = number; } /** * Should this sort option be made visible in the UI + * * @return true if visible, false otherwise */ - public boolean isVisible() - { + public boolean isVisible() { return visible; } /** - * @return a 3-element array of the metadata bits + * @return a 3-element array of the metadata bits */ - public String[] getMdBits() - { + public String[] getMdBits() { return (String[]) ArrayUtils.clone(mdBits); } - + /** * Tell the class to generate the metadata bits - * + * * @throws SortException if sort error */ private void generateMdBits() - throws SortException - { - try - { + throws SortException { + try { mdBits = interpretField(metadata, null); - } - catch(IOException e) - { + } catch (IOException e) { throw new SortException(e); } } - + /** * Take a string representation of a metadata field, and return it as an array. - * This is just a convenient utility method to basically break the metadata + * This is just a convenient utility method to basically break the metadata * representation up by its delimiter (.), and stick it in an array, inserting * the value of the init parameter when there is no metadata field part. - * - * @param mfield the string representation of the metadata - * @param init the default value of the array elements - * @return a 3-element array with schema, element and qualifier respectively - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * + * @param mfield the string representation of the metadata + * @param init the default value of the array elements + * @return a 3-element array with schema, element and qualifier respectively + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ public final String[] interpretField(String mfield, String init) - throws IOException - { + throws IOException { StringTokenizer sta = new StringTokenizer(mfield, "."); String[] field = {init, init, init}; - + int i = 0; - while (sta.hasMoreTokens()) - { + while (sta.hasMoreTokens()) { field[i++] = sta.nextToken(); } - + // error checks to make sure we have at least a schema and qualifier for both - if (field[0] == null || field[1] == null) - { + if (field[0] == null || field[1] == null) { throw new IOException("at least a schema and element be " + - "specified in configuration. You supplied: " + mfield); + "specified in configuration. You supplied: " + mfield); } - + return field; } - + /** * Is this a date field? + * * @return true if is date */ - public boolean isDate() - { - if ("date".equals(type)) - { + public boolean isDate() { + if ("date".equals(type)) { return true; } return false; } - + /** * Is the default sort option? + * * @return true if is default sort option */ - public boolean isDefault() - { - if (number == 0) - { + public boolean isDefault() { + if (number == 0) { return true; } return false; @@ -304,71 +286,63 @@ public class SortOption /** * Return all the configured sort options. + * * @return a set of the configured sort options * @throws SortException if sort error */ - public static Set getSortOptions() throws SortException - { - if (SortOption.sortOptionsSet == null) - { + public static Set getSortOptions() throws SortException { + if (SortOption.sortOptionsSet == null) { throw new SortException("Sort options not loaded"); } return SortOption.sortOptionsSet; } - + /** * Get the defined sort option by name - * @param name - * the name of the sort option as given in the config file + * + * @param name the name of the sort option as given in the config file * @return the configured sort option with given name * @throws SortException if sort error */ - public static SortOption getSortOption(String name) throws SortException - { - for (SortOption so : SortOption.getSortOptions()) - { - if (StringUtils.equals(name, so.getName())) - { + public static SortOption getSortOption(String name) throws SortException { + for (SortOption so : SortOption.getSortOptions()) { + if (StringUtils.equals(name, so.getName())) { return so; } } - + return null; } - + /** * Get the defined sort option by number (.1, .2, etc). - * @param number - * the number of the sort option as given in the config file + * + * @param number the number of the sort option as given in the config file * @return the configured sort option with given number * @throws SortException if sort error */ - public static SortOption getSortOption(int number) throws SortException - { - for (SortOption so : SortOption.getSortOptions()) - { - if (so.getNumber() == number) - { + public static SortOption getSortOption(int number) throws SortException { + for (SortOption so : SortOption.getSortOptions()) { + if (so.getNumber() == number) { return so; } } - + return null; } - + /** * Get the default sort option - initially, just the first one defined. + * * @return the first configured sort option * @throws SortException if sort error */ - public static SortOption getDefaultSortOption() throws SortException - { - for (SortOption so : getSortOptions()) - { + public static SortOption getDefaultSortOption() throws SortException { + for (SortOption so : getSortOptions()) { return so; } - + return null; } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/DataTermsFacet.java b/dspace-api/src/main/java/org/dspace/statistics/DataTermsFacet.java index fb43b5fd7b..9de06b7bb8 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/DataTermsFacet.java +++ b/dspace-api/src/main/java/org/dspace/statistics/DataTermsFacet.java @@ -7,14 +7,13 @@ */ package org.dspace.statistics; -import com.google.gson.Gson; - import java.util.ArrayList; import java.util.List; +import com.google.gson.Gson; + /** * A neutral data object to hold data for statistics. - * */ public class DataTermsFacet { private List terms; @@ -22,7 +21,8 @@ public class DataTermsFacet { public DataTermsFacet() { terms = new ArrayList(); } - public void addTermFacet(TermsFacet termsFacet ) { + + public void addTermFacet(TermsFacet termsFacet) { terms.add(termsFacet); } @@ -31,6 +31,7 @@ public class DataTermsFacet { * * An example of the output could be of the format: * [{"term":"247166","count":10},{"term":"247168","count":6}] + * * @return JSON-formatted data. */ public String toJson() { @@ -39,12 +40,10 @@ public class DataTermsFacet { } - - public static class TermsFacet { private String term; private Integer count; - + public TermsFacet(String term, Integer count) { setTerm(term); setCount(count); diff --git a/dspace-api/src/main/java/org/dspace/statistics/Dataset.java b/dspace-api/src/main/java/org/dspace/statistics/Dataset.java index ab8b3a88b9..1993dc5847 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/Dataset.java +++ b/dspace-api/src/main/java/org/dspace/statistics/Dataset.java @@ -22,11 +22,9 @@ import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; /** - * * @author kevinvandevelde at atmire.com * Date: 21-jan-2009 * Time: 13:44:48 - * */ public class Dataset { @@ -43,13 +41,12 @@ public class Dataset { /* The attributes for the rows */ private List> rowLabelsAttrs; /* The data in a matrix */ - private String[][]matrix; + private String[][] matrix; /* The format in which we format our floats */ private String format = "0"; - - public Dataset(int rows, int cols){ + public Dataset(int rows, int cols) { matrix = new String[rows][cols]; nbRows = rows; nbCols = cols; @@ -57,11 +54,10 @@ public class Dataset { initRowLabels(rows); } - public Dataset(float[][] matrix){ + public Dataset(float[][] matrix) { this.matrix = (String[][]) ArrayUtils.clone(matrix); nbRows = matrix.length; - if(0 < matrix.length && 0 < matrix[0].length) - { + if (0 < matrix.length && 0 < matrix[0].length) { nbCols = matrix[0].length; } initColumnLabels(nbCols); @@ -72,7 +68,7 @@ public class Dataset { rowLabels = new ArrayList(rows); rowLabelsAttrs = new ArrayList>(); for (int i = 0; i < rows; i++) { - rowLabels.add("Row " + (i+1)); + rowLabels.add("Row " + (i + 1)); rowLabelsAttrs.add(new HashMap()); } } @@ -81,16 +77,16 @@ public class Dataset { colLabels = new ArrayList(nbCols); colLabelsAttrs = new ArrayList>(); for (int i = 0; i < nbCols; i++) { - colLabels.add("Column " + (i+1)); + colLabels.add("Column " + (i + 1)); colLabelsAttrs.add(new HashMap()); } } - public void setColLabel(int n, String label){ + public void setColLabel(int n, String label) { colLabels.set(n, label); } - public void setRowLabel(int n, String label){ + public void setRowLabel(int n, String label) { rowLabels.set(n, label); } @@ -111,17 +107,17 @@ public class Dataset { this.rowTitle = rowTitle; } - public void setRowLabelAttr(int pos, String attrName, String attr){ + public void setRowLabelAttr(int pos, String attrName, String attr) { Map attrs = rowLabelsAttrs.get(pos); attrs.put(attrName, attr); rowLabelsAttrs.set(pos, attrs); } - public void setRowLabelAttr(int pos, Map attrMap){ + public void setRowLabelAttr(int pos, Map attrMap) { rowLabelsAttrs.set(pos, attrMap); } - public void setColLabelAttr(int pos, String attrName, String attr){ + public void setColLabelAttr(int pos, String attrName, String attr) { Map attrs = colLabelsAttrs.get(pos); attrs.put(attrName, attr); colLabelsAttrs.set(pos, attrs); @@ -164,7 +160,7 @@ public class Dataset { this.format = format; } - public String[][] getMatrix(){ + public String[][] getMatrix() { if (matrix.length == 0) { return new String[0][0]; } else { @@ -187,12 +183,11 @@ public class Dataset { * * @return false if this dataset only contains zeroes. */ - public boolean containsNonZeroValues(){ + public boolean containsNonZeroValues() { if (matrix != null) { for (String[] vector : matrix) { for (String v : vector) { - if (StringUtils.isBlank(v) || v.equals("0")) - { + if (StringUtils.isBlank(v) || v.equals("0")) { return true; } } @@ -202,10 +197,9 @@ public class Dataset { } - - public void flipRowCols(){ + public void flipRowCols() { //Lets make sure we at least have something to flip - if(0 < matrix.length && 0 < matrix[0].length){ + if (0 < matrix.length && 0 < matrix[0].length) { //Flip the data first String[][] newMatrix = new String[matrix[0].length][matrix.length]; for (int i = 0; i < matrix.length; i++) { @@ -248,7 +242,7 @@ public class Dataset { String[][] matrix = getMatrix(); for (int i = 0; i < rowLabels.size(); i++) { String rowLabel = rowLabels.get(i); - ecsvp.writeNext((String[]) ArrayUtils.addAll(new String[]{rowLabel}, matrix[i])); + ecsvp.writeNext((String[]) ArrayUtils.addAll(new String[] {rowLabel}, matrix[i])); } ecsvp.flush(); ecsvp.close(); diff --git a/dspace-api/src/main/java/org/dspace/statistics/ElasticSearchLoggerEventListener.java b/dspace-api/src/main/java/org/dspace/statistics/ElasticSearchLoggerEventListener.java deleted file mode 100644 index aa1afc81d9..0000000000 --- a/dspace-api/src/main/java/org/dspace/statistics/ElasticSearchLoggerEventListener.java +++ /dev/null @@ -1,50 +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.statistics; - -import org.apache.log4j.Logger; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.eperson.EPerson; -import org.dspace.services.model.Event; -import org.dspace.statistics.factory.StatisticsServiceFactory; -import org.dspace.usage.AbstractUsageEventListener; -import org.dspace.usage.UsageEvent; -import org.springframework.beans.factory.annotation.Autowired; - -/* - * @deprecated As of DSpace 6.0, ElasticSearch statistics are replaced by Solr statistics - * @see org.dspace.statistics.service.SolrLoggerUsageEventListener#SolrLoggerUsageEventListener - */ -public class ElasticSearchLoggerEventListener extends AbstractUsageEventListener { - - private static Logger log = Logger.getLogger(ElasticSearchLoggerEventListener.class); - - @Autowired(required = true) - protected ContentServiceFactory contentServiceFactory; - - @Override - public void receiveEvent(Event event) { - - if(event instanceof UsageEvent && (((UsageEvent) event).getAction() == UsageEvent.Action.VIEW)) - { - try{ - - UsageEvent ue = (UsageEvent) event; - - EPerson currentUser = ue.getContext() == null ? null : ue.getContext().getCurrentUser(); - - StatisticsServiceFactory.getInstance().getElasticSearchLoggerService().post(ue.getObject(), ue.getRequest(), currentUser); - log.info("Successfully logged " + contentServiceFactory.getDSpaceObjectService(ue.getObject()).getTypeText(ue.getObject()) + "_" + ue.getObject().getID() + " " + ue.getObject().getName()); - } - catch(Exception e) - { - log.error("General Exception: " + e.getMessage()); - } - } - } -} diff --git a/dspace-api/src/main/java/org/dspace/statistics/ElasticSearchLoggerServiceImpl.java b/dspace-api/src/main/java/org/dspace/statistics/ElasticSearchLoggerServiceImpl.java deleted file mode 100644 index a9e5431b23..0000000000 --- a/dspace-api/src/main/java/org/dspace/statistics/ElasticSearchLoggerServiceImpl.java +++ /dev/null @@ -1,632 +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.statistics; - - -import com.google.common.base.Charsets; -import com.google.common.io.Resources; -import com.maxmind.geoip.Location; -import com.maxmind.geoip.LookupService; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.exception.ExceptionUtils; -import org.apache.commons.lang.time.DateFormatUtils; -import org.apache.log4j.Logger; -import org.dspace.content.*; -import org.dspace.content.Collection; -import org.dspace.core.ConfigurationManager; -import org.dspace.core.Constants; -import org.dspace.eperson.EPerson; -import org.dspace.statistics.service.ElasticSearchLoggerService; -import org.dspace.statistics.util.DnsLookup; -import org.dspace.statistics.util.LocationUtils; -import org.dspace.statistics.util.SpiderDetector; - -import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; -import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus; -import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder; -import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; -import org.elasticsearch.action.index.IndexRequestBuilder; -import org.elasticsearch.client.Client; - -import org.elasticsearch.client.transport.TransportClient; -import org.elasticsearch.common.settings.ImmutableSettings; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.transport.InetSocketTransportAddress; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.node.Node; -import org.elasticsearch.node.NodeBuilder; -import org.springframework.beans.factory.InitializingBean; - -import javax.servlet.http.HttpServletRequest; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.URL; -import java.sql.SQLException; -import java.util.*; - -/* - * @deprecated As of DSpace 6.0, ElasticSearch statistics are replaced by Solr statistics - * @see org.dspace.statistics.SolrLoggerServiceImpl#SolrLoggerServiceImpl - */ -public class ElasticSearchLoggerServiceImpl implements ElasticSearchLoggerService, InitializingBean { - - private static Logger log = Logger.getLogger(ElasticSearchLoggerServiceImpl.class); - - protected boolean useProxies; - - public static final String DATE_FORMAT_8601 = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; - - public static final String DATE_FORMAT_DCDATE = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - - protected static LookupService locationService; - - protected String clusterName = "dspacestatslogging"; - protected String indexName = "dspaceindex"; - protected String indexType = "stats"; - protected String address = "127.0.0.1"; - protected int port = 9300; - - protected Client client; - - protected ElasticSearchLoggerServiceImpl() { - // nobody should be instantiating this... - } - - @Override - public void afterPropertiesSet() throws Exception { - log.info("DSpace ElasticSearchLogger Initializing"); - try { - LookupService service = null; - // Get the db file for the location - String dbfile = ConfigurationManager.getProperty("usage-statistics", "dbfile"); - if (dbfile != null) { - try { - service = new LookupService(dbfile, LookupService.GEOIP_STANDARD); - } catch (FileNotFoundException fe) { - log.error("The GeoLite Database file is missing (" + dbfile + ")! Usage Statistics cannot generate location based reports! Please see the DSpace installation instructions for instructions to install this file.", fe); - } catch (IOException e) { - log.error("Unable to load GeoLite Database file (" + dbfile + ")! You may need to reinstall it. See the DSpace installation instructions for more details.", e); - } - } else { - log.error("The required 'dbfile' configuration is missing in usage-statistics.cfg!"); - } - locationService = service; - - if ("true".equals(ConfigurationManager.getProperty("useProxies"))) { - useProxies = true; - } else { - useProxies = false; - } - - log.info("useProxies=" + useProxies); - - // Configurable values for all elasticsearch connection constants - clusterName = getConfigurationStringWithFallBack("elastic-search-statistics", "clusterName", clusterName); - indexName = getConfigurationStringWithFallBack("elastic-search-statistics", "indexName", indexName); - indexType = getConfigurationStringWithFallBack("elastic-search-statistics", "indexType", indexType); - address = getConfigurationStringWithFallBack("elastic-search-statistics", "address", address); - port = ConfigurationManager.getIntProperty("elastic-search-statistics", "port", port); - - //Initialize the connection to Elastic Search, and ensure our index is available. - client = getClient(); - boolean hasIndex = false; - try { - log.info("Checking Elastic Search cluster health..."); - ClusterHealthResponse healthResponse = client.admin().cluster().prepareHealth(indexName).setWaitForYellowStatus() - .setTimeout(TimeValue.timeValueSeconds(30)).execute() - .actionGet(); - - if (healthResponse.isTimedOut() || healthResponse.getStatus() == ClusterHealthStatus.RED) { - throw new IllegalStateException("cluster not ready due to health: " + healthResponse.toString()); - } - - log.info("DS ES Checking if index exists"); - hasIndex = client.admin().indices().prepareExists(indexName).execute().actionGet().isExists(); - } catch (Exception e) { - log.error("Exception during health check, likely have to create index and put mapping still. Exception:" + e.getMessage()); - hasIndex = false; - } - - if(! hasIndex) { - //If elastic search index exists, then we are good to go, otherwise, we need to create that index. Should only need to happen once ever. - log.info("DS ES index didn't exist, we need to create it."); - - String mappingPath = ElasticSearchLoggerServiceImpl.class.getPackage().getName().replaceAll("\\.", "/") ; - URL url = Resources.getResource(mappingPath + "/elasticsearch-statistics-mapping.json"); - String stringMappingJSON = Resources.toString(url, Charsets.UTF_8); - stringMappingJSON = stringMappingJSON.replace("stats", indexType); - - //Necessary to post, in order for index/type to be created. - client.prepareIndex(indexName, indexType, "1") - .setSource(XContentFactory.jsonBuilder() - .startObject() - .field("user", "kimchy") - .field("postDate", new Date()) - .field("message", "trying out Elastic Search") - .endObject() - ) - .execute() - .actionGet(); - - log.info("Create INDEX ["+indexName+"]/["+indexType+"]"); - - // Wait for create to be finished. - client.admin().indices().prepareRefresh(indexName).execute().actionGet(); - - //Put the schema/mapping - log.info("Put Mapping for ["+indexName+"]/["+indexType+"]="+stringMappingJSON); - PutMappingRequestBuilder putMappingRequestBuilder = client.admin().indices().preparePutMapping(indexName).setType(indexType); - putMappingRequestBuilder.setSource(stringMappingJSON); - PutMappingResponse response = putMappingRequestBuilder.execute().actionGet(); - - if(!response.isAcknowledged()) { - log.info("Could not define mapping for type ["+indexName+"]/["+indexType+"]"); - } else { - log.info("Successfully put mapping for ["+indexName+"]/["+indexType+"]"); - } - - log.info("DS ES index didn't exist, but we created it."); - } else { - log.info("DS ES index already exists"); - } - - log.info("DSpace ElasticSearchLogger Initialized Successfully (I suppose)"); - - } catch (Exception e) { - log.error("Elastic Search crashed during init. " + e.getMessage(), e); - } - } - - @Override - public void post(DSpaceObject dspaceObject, HttpServletRequest request, EPerson currentUser) { - //log.info("DS-ES post for type:"+dspaceObject.getType() + " -- " + dspaceObject.getName()); - - client = getClient(); - - boolean isSpiderBot = SpiderDetector.isSpider(request); - - try { - if (isSpiderBot && - !ConfigurationManager.getBooleanProperty("usage-statistics", "logBots", true)) { - return; - } - - - // Save our basic info that we already have - - String ip = request.getRemoteAddr(); - - if (isUseProxies() && request.getHeader("X-Forwarded-For") != null) { - /* This header is a comma delimited list */ - for (String xfip : request.getHeader("X-Forwarded-For").split(",")) { - /* proxy itself will sometime populate this header with the same value in - remote address. ordering in spec is vague, we'll just take the last - not equal to the proxy - */ - if (!request.getHeader("X-Forwarded-For").contains(ip)) { - ip = xfip.trim(); - } - } - } - - if (!isUseProxies() && request.getHeader("X-Forwarded-For") != null){ - log.warn("X-Forwarded-For header detected but useProxies is not enabled. If your dspace is behind a proxy set it to true"); - } - - XContentBuilder docBuilder = null; - - - docBuilder = XContentFactory.jsonBuilder().startObject(); - - - docBuilder.field("ip", ip); - - docBuilder.field("id", dspaceObject.getID()); - - // The numerical constant that represents the DSpaceObject TYPE. i.e. 0=bitstream, 2=item, ... - docBuilder.field("typeIndex", dspaceObject.getType()); - - // The text that represent the DSpaceObject TYPE. i.e. BITSTREAM, ITEM, COLLECTION, COMMUNITY - docBuilder.field("type", Constants.typeText[dspaceObject.getType()]); - - // Save the current time - docBuilder.field("time", DateFormatUtils.format(new Date(), DATE_FORMAT_8601)); - if (currentUser != null) { - docBuilder.field("epersonid", currentUser.getID()); - } - - try { - String dns = DnsLookup.reverseDns(ip); - docBuilder.field("dns", dns.toLowerCase()); - } catch (Exception e) { - log.info("Failed DNS Lookup for IP:" + ip); - log.debug(e.getMessage(), e); - } - - // Save the location information if valid, save the event without - // location information if not valid - Location location = locationService.getLocation(ip); - if (location != null - && !("--".equals(location.countryCode) - && location.latitude == -180 && location.longitude == -180)) { - try { - docBuilder.field("continent", LocationUtils - .getContinentCode(location.countryCode)); - } catch (Exception e) { - System.out - .println("COUNTRY ERROR: " + location.countryCode); - } - docBuilder.field("countryCode", location.countryCode); - docBuilder.field("city", location.city); - docBuilder.field("latitude", location.latitude); - docBuilder.field("longitude", location.longitude); - docBuilder.field("isBot", isSpiderBot); - - if (request.getHeader("User-Agent") != null) { - docBuilder.field("userAgent", request.getHeader("User-Agent")); - } - } - - if (dspaceObject instanceof Bitstream) { - Bitstream bit = (Bitstream) dspaceObject; - List bundles = bit.getBundles(); - docBuilder.field("bundleName").startArray(); - for (Bundle bundle : bundles) { - docBuilder.value(bundle.getName()); - } - docBuilder.endArray(); - } - - storeParents(docBuilder, getParents(dspaceObject)); - - docBuilder.endObject(); - - if (docBuilder != null) { - IndexRequestBuilder irb = client.prepareIndex(indexName, indexType) - .setSource(docBuilder); - //log.info("Executing document insert into index"); - if(client == null) { - log.error("Hey, client is null"); - } - irb.execute().actionGet(); - } - - } catch (RuntimeException re) { - log.error("RunTimer in ESL:\n" + ExceptionUtils.getStackTrace(re)); - throw re; - } catch (Exception e) { - log.error(e.getMessage()); - } finally { - client.close(); - } - } - - @Override - public void post(DSpaceObject dspaceObject, String ip, String userAgent, String xforwardedfor, EPerson currentUser) { - //log.info("DS-ES post for type:"+dspaceObject.getType() + " -- " + dspaceObject.getName()); - - client = getClient(); - - boolean isSpiderBot = SpiderDetector.isSpider(ip); - - try { - if (isSpiderBot && - !ConfigurationManager.getBooleanProperty("usage-statistics", "logBots", true)) { - return; - } - - - // Save our basic info that we already have - - if (isUseProxies() && xforwardedfor != null) { - /* This header is a comma delimited list */ - for (String xfip : xforwardedfor.split(",")) { - /* proxy itself will sometime populate this header with the same value in - remote address. ordering in spec is vague, we'll just take the last - not equal to the proxy - */ - if (!xforwardedfor.contains(ip)) { - ip = xfip.trim(); - } - } - } - - if (!isUseProxies() && xforwardedfor != null){ - log.warn("X-Forwarded-For header detected but useProxies is not enabled. If your dspace is behind a proxy set it to true"); - } - - XContentBuilder docBuilder = null; - - - docBuilder = XContentFactory.jsonBuilder().startObject(); - - - docBuilder.field("ip", ip); - - docBuilder.field("id", dspaceObject.getID()); - - // The numerical constant that represents the DSpaceObject TYPE. i.e. 0=bitstream, 2=item, ... - docBuilder.field("typeIndex", dspaceObject.getType()); - - // The text that represent the DSpaceObject TYPE. i.e. BITSTREAM, ITEM, COLLECTION, COMMUNITY - docBuilder.field("type", Constants.typeText[dspaceObject.getType()]); - - // Save the current time - docBuilder.field("time", DateFormatUtils.format(new Date(), DATE_FORMAT_8601)); - if (currentUser != null) { - docBuilder.field("epersonid", currentUser.getID()); - } - - try { - String dns = DnsLookup.reverseDns(ip); - docBuilder.field("dns", dns.toLowerCase()); - } catch (Exception e) { - log.info("Failed DNS Lookup for IP:" + ip); - log.debug(e.getMessage(), e); - } - - // Save the location information if valid, save the event without - // location information if not valid - Location location = locationService.getLocation(ip); - if (location != null - && !("--".equals(location.countryCode) - && location.latitude == -180 && location.longitude == -180)) { - try { - docBuilder.field("continent", LocationUtils - .getContinentCode(location.countryCode)); - } catch (Exception e) { - System.out - .println("COUNTRY ERROR: " + location.countryCode); - } - docBuilder.field("countryCode", location.countryCode); - docBuilder.field("city", location.city); - docBuilder.field("latitude", location.latitude); - docBuilder.field("longitude", location.longitude); - docBuilder.field("isBot", isSpiderBot); - - if (userAgent != null) { - docBuilder.field("userAgent", userAgent); - } - } - - if (dspaceObject instanceof Bitstream) { - Bitstream bit = (Bitstream) dspaceObject; - List bundles = bit.getBundles(); - docBuilder.field("bundleName").startArray(); - for (Bundle bundle : bundles) { - docBuilder.value(bundle.getName()); - } - docBuilder.endArray(); - } - - storeParents(docBuilder, getParents(dspaceObject)); - - docBuilder.endObject(); - - if (docBuilder != null) { - IndexRequestBuilder irb = client.prepareIndex(indexName, indexType) - .setSource(docBuilder); - //log.info("Executing document insert into index"); - if(client == null) { - log.error("Hey, client is null"); - } - irb.execute().actionGet(); - } - - } catch (RuntimeException re) { - log.error("RunTimer in ESL:\n" + ExceptionUtils.getStackTrace(re)); - throw re; - } catch (Exception e) { - log.error(e.getMessage()); - } finally { - client.close(); - } - } - - - @Override - public String getClusterName() { - return clusterName; - } - - @Override - public void setClusterName(String clusterName) { - this.clusterName = clusterName; - } - - @Override - public String getIndexName() { - return indexName; - } - - @Override - public void setIndexName(String indexName) { - this.indexName = indexName; - } - - @Override - public String getIndexType() { - return indexType; - } - - @Override - public void setIndexType(String indexType) { - this.indexType = indexType; - } - - @Override - public String getAddress() { - return address; - } - - @Override - public void setAddress(String address) { - this.address = address; - } - - @Override - public int getPort() { - return port; - } - - @Override - public void setPort(int port) { - this.port = port; - } - - @Override - public void buildParents(DSpaceObject dso, HashMap> parents) - throws SQLException { - if (dso instanceof Community) { - Community comm = (Community) dso; - while (comm != null && CollectionUtils.isNotEmpty(comm.getParentCommunities())) { - comm = comm.getParentCommunities().get(0); - parents.get("owningComm").add(comm.getID().toString()); - } - } else if (dso instanceof Collection) { - Collection coll = (Collection) dso; - for (Community community : coll.getCommunities()) { - parents.get("owningComm").add(community.getID().toString()); - buildParents(community, parents); - } - } else if (dso instanceof Item) { - Item item = (Item) dso; - for (Collection collection : item.getCollections()) { - parents.get("owningColl").add(collection.getID().toString()); - buildParents(collection, parents); - } - } else if (dso instanceof Bitstream) { - Bitstream bitstream = (Bitstream) dso; - - for (Bundle bundle : bitstream.getBundles()) { - for (Item item : bundle.getItems()) { - - parents.get("owningItem").add(item.getID().toString()); - buildParents(item, parents); - } - } - } - - } - - @Override - public HashMap> getParents(DSpaceObject dso) - throws SQLException { - HashMap> parents = new HashMap<>(); - parents.put("owningComm", new ArrayList()); - parents.put("owningColl", new ArrayList()); - parents.put("owningItem", new ArrayList()); - - buildParents(dso, parents); - return parents; - } - - @Override - public void storeParents(XContentBuilder docBuilder, HashMap> parents) throws IOException { - - Iterator it = parents.keySet().iterator(); - while (it.hasNext()) { - - String key = (String) it.next(); - - ArrayList ids = parents.get(key); - - if (ids.size() > 0) { - docBuilder.field(key).startArray(); - for (String i : ids) { - docBuilder.value(i); - } - docBuilder.endArray(); - } - } - } - - - @Override - public boolean isUseProxies() { - return useProxies; - } - - // Transport Client will talk to server on 9300 - @Override - public void createTransportClient() { - // Configurable values for all elasticsearch connection constants - // Can't guarantee that these values are already loaded, since this can be called by a different JVM - clusterName = getConfigurationStringWithFallBack("elastic-search-statistics", "clusterName", clusterName); - indexName = getConfigurationStringWithFallBack("elastic-search-statistics", "indexName", indexName); - indexType = getConfigurationStringWithFallBack("elastic-search-statistics", "indexType", indexType); - address = getConfigurationStringWithFallBack("elastic-search-statistics", "address", address); - port = ConfigurationManager.getIntProperty("elastic-search-statistics", "port", port); - - log.info("Creating TransportClient to [Address:" + address + "] [Port:" + port + "] [cluster.name:" + clusterName + "]"); - - Settings settings = ImmutableSettings.settingsBuilder().put("cluster.name", clusterName).build(); - client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress(address, port)); - } - - @Override - public Client getClient() { - //Get an available client, otherwise new default is NODE. - return getClient(ClientType.NODE); - } - - // Get the already available client, otherwise we will create a new client. - // TODO Allow for config to determine which architecture / topology to use. - // - Local Node, store Data - // - Node Client, must discover a master within ES cluster - // - Transport Client, specify IP address of server running ES. - @Override - public Client getClient(ClientType clientType) { - if(client == null) { - log.error("getClient reports null client"); - - if(clientType == ClientType.TRANSPORT) { - createTransportClient(); - } else { - createNodeClient(clientType); - } - } - - return client; - } - - @Override - public Client createNodeClient(ClientType clientType) { - String dspaceDir = ConfigurationManager.getProperty("dspace.dir"); - Settings settings = ImmutableSettings.settingsBuilder().put("path.data", dspaceDir + "/elasticsearch/").build(); - - NodeBuilder nodeBuilder = NodeBuilder.nodeBuilder().clusterName(clusterName).data(true).settings(settings); - - if(clientType == ClientType.LOCAL) { - log.info("Create a Local Node."); - nodeBuilder = nodeBuilder.local(true); - } else if(clientType == ClientType.NODE) { - log.info("Create a nodeClient, allows transport clients to connect"); - nodeBuilder = nodeBuilder.local(false); - } - - Node node = nodeBuilder.node(); - log.info("Got node"); - client = node.client(); - log.info("Created new node client"); - return client; - } - - @Override - public String getConfigurationStringWithFallBack(String module, String configurationKey, String defaultFallbackValue) { - String configDrivenValue = ConfigurationManager.getProperty(module, configurationKey); - if(configDrivenValue == null || configDrivenValue.trim().equalsIgnoreCase("")) { - return defaultFallbackValue; - } else { - return configDrivenValue; - } - } - -} diff --git a/dspace-api/src/main/java/org/dspace/statistics/ObjectCount.java b/dspace-api/src/main/java/org/dspace/statistics/ObjectCount.java index 1f6941c7e4..2272e68279 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/ObjectCount.java +++ b/dspace-api/src/main/java/org/dspace/statistics/ObjectCount.java @@ -9,7 +9,7 @@ package org.dspace.statistics; /** * Data structure for returning results from statistics searches. - * + * * @author mdiggory at atmire.com * @author ben at atmire.com * @author kevinvandevelde at atmire.com @@ -18,7 +18,7 @@ public class ObjectCount { private long count; private String value; - public ObjectCount(){ + public ObjectCount() { } public long getCount() { diff --git a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java index 640ce08fde..007b4defaa 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java @@ -7,10 +7,37 @@ */ package org.dspace.statistics; +import java.io.File; +import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.URLEncoder; +import java.sql.SQLException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.servlet.http.HttpServletRequest; + import au.com.bytecode.opencsv.CSVReader; import au.com.bytecode.opencsv.CSVWriter; -import com.maxmind.geoip.Location; -import com.maxmind.geoip.LookupService; +import com.maxmind.geoip2.DatabaseReader; +import com.maxmind.geoip2.exception.GeoIp2Exception; +import com.maxmind.geoip2.model.CityResponse; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; @@ -18,8 +45,8 @@ import org.apache.commons.lang.time.DateFormatUtils; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.log4j.Logger; import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.request.AbstractUpdateRequest; @@ -36,9 +63,18 @@ import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.luke.FieldFlag; -import org.apache.solr.common.params.*; -import org.dspace.content.*; +import org.apache.solr.common.params.CommonParams; +import org.apache.solr.common.params.FacetParams; +import org.apache.solr.common.params.MapSolrParams; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.params.ShardParams; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DCDate; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.DSpaceObjectLegacySupportService; @@ -52,44 +88,38 @@ import org.dspace.statistics.util.DnsLookup; import org.dspace.statistics.util.LocationUtils; import org.dspace.statistics.util.SpiderDetector; import org.dspace.usage.UsageWorkflowEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import javax.servlet.http.HttpServletRequest; -import java.io.*; -import java.net.URLEncoder; -import java.sql.SQLException; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; - /** * Static holder for a HttpSolrClient connection pool to issue * usage logging events to Solr from DSpace libraries, and some static query * composers. - * + * * @author ben at atmire.com * @author kevinvandevelde at atmire.com * @author mdiggory at atmire.com */ -public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBean -{ - private static final Logger log = Logger.getLogger(SolrLoggerServiceImpl.class); +public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBean { + private static final Logger log + = LoggerFactory.getLogger(SolrLoggerServiceImpl.class); + private static final String MULTIPLE_VALUES_SPLITTER = "|"; - protected HttpSolrServer solr; + protected SolrServer solr; public static final String DATE_FORMAT_8601 = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; public static final String DATE_FORMAT_DCDATE = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - protected LookupService locationService; + protected DatabaseReader locationService; protected boolean useProxies; private static List statisticYearCores = new ArrayList(); private static boolean statisticYearCoresInit = false; - + @Autowired(required = true) protected BitstreamService bitstreamService; @Autowired(required = true) @@ -98,38 +128,36 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea private ConfigurationService configurationService; public static enum StatisticsType { - VIEW ("view"), - SEARCH ("search"), - SEARCH_RESULT ("search_result"), + VIEW("view"), + SEARCH("search"), + SEARCH_RESULT("search_result"), WORKFLOW("workflow"); - private final String text; + private final String text; StatisticsType(String text) { - this.text = text; - } - public String text() { return text; } - } + this.text = text; + } - protected SolrLoggerServiceImpl() - { + public String text() { + return text; + } + } + + protected SolrLoggerServiceImpl() { } @Override - public void afterPropertiesSet() throws Exception - { - log.info("solr-statistics.spidersfile:" + configurationService.getProperty("solr-statistics.spidersfile")); + public void afterPropertiesSet() throws Exception { log.info("solr-statistics.server:" + configurationService.getProperty("solr-statistics.server")); log.info("usage-statistics.dbfile:" + configurationService.getProperty("usage-statistics.dbfile")); - + HttpSolrServer server = null; - - if (configurationService.getProperty("solr-statistics.server") != null) - { - try - { + + if (configurationService.getProperty("solr-statistics.server") != null) { + try { server = new HttpSolrServer(configurationService.getProperty("solr-statistics.server")); } catch (Exception e) { log.error(e.getMessage(), e); @@ -140,27 +168,26 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea // Read in the file so we don't have to do it all the time //spiderIps = SpiderDetector.getSpiderIpAddresses(); - LookupService service = null; + DatabaseReader service = null; // Get the db file for the location - String dbfile = configurationService.getProperty("usage-statistics.dbfile"); - if (dbfile != null) - { - try - { - service = new LookupService(dbfile, - LookupService.GEOIP_STANDARD); + String dbPath = configurationService.getProperty("usage-statistics.dbfile"); + if (dbPath != null) { + try { + File dbFile = new File(dbPath); + service = new DatabaseReader.Builder(dbFile).build(); + } catch (FileNotFoundException fe) { + log.error( + "The GeoLite Database file is missing (" + dbPath + ")! Solr Statistics cannot generate location " + + "based reports! Please see the DSpace installation instructions for instructions to install " + + "this file.", + fe); + } catch (IOException e) { + log.error( + "Unable to load GeoLite Database file (" + dbPath + ")! You may need to reinstall it. See the " + + "DSpace installation instructions for more details.", + e); } - catch (FileNotFoundException fe) - { - log.error("The GeoLite Database file is missing (" + dbfile + ")! Solr Statistics cannot generate location based reports! Please see the DSpace installation instructions for instructions to install this file.", fe); - } - catch (IOException e) - { - log.error("Unable to load GeoLite Database file (" + dbfile + ")! You may need to reinstall it. See the DSpace installation instructions for more details.", e); - } - } - else - { + } else { log.error("The required 'dbfile' configuration is missing in solr-statistics.cfg!"); } locationService = service; @@ -171,28 +198,25 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override public void post(DSpaceObject dspaceObject, HttpServletRequest request, - EPerson currentUser) - { - postView(dspaceObject, request, currentUser); + EPerson currentUser) { + postView(dspaceObject, request, currentUser); } @Override public void postView(DSpaceObject dspaceObject, HttpServletRequest request, - EPerson currentUser) - { - if (solr == null || locationService == null) - { + EPerson currentUser) { + if (solr == null || locationService == null) { return; } initSolrYearCores(); - try - { + try { SolrInputDocument doc1 = getCommonSolrDoc(dspaceObject, request, currentUser); - if (doc1 == null) return; - if (dspaceObject instanceof Bitstream) - { + if (doc1 == null) { + return; + } + if (dspaceObject instanceof Bitstream) { Bitstream bit = (Bitstream) dspaceObject; List bundles = bit.getBundles(); for (Bundle bundle : bundles) { @@ -207,20 +231,16 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea //commits are executed automatically using the solr autocommit // solr.commit(false, false); - } - catch (RuntimeException re) - { + } catch (RuntimeException re) { throw re; - } - catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); } } - + @Override public void postView(DSpaceObject dspaceObject, - String ip, String userAgent, String xforwardedfor, EPerson currentUser) { + String ip, String userAgent, String xforwardedfor, EPerson currentUser) { if (solr == null || locationService == null) { return; } @@ -228,9 +248,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea try { SolrInputDocument doc1 = getCommonSolrDoc(dspaceObject, ip, userAgent, xforwardedfor, - currentUser); - if (doc1 == null) + currentUser); + if (doc1 == null) { return; + } if (dspaceObject instanceof Bitstream) { Bitstream bit = (Bitstream) dspaceObject; List bundles = bit.getBundles(); @@ -255,17 +276,18 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea /** * Returns a solr input document containing common information about the statistics * regardless if we are logging a search or a view of a DSpace object + * * @param dspaceObject the object used. - * @param request the current request context. - * @param currentUser the current session's user. + * @param request the current request context. + * @param currentUser the current session's user. * @return a solr input document * @throws SQLException in case of a database exception */ - protected SolrInputDocument getCommonSolrDoc(DSpaceObject dspaceObject, HttpServletRequest request, EPerson currentUser) throws SQLException { + protected SolrInputDocument getCommonSolrDoc(DSpaceObject dspaceObject, HttpServletRequest request, + EPerson currentUser) throws SQLException { boolean isSpiderBot = request != null && SpiderDetector.isSpider(request); if (isSpiderBot && - !configurationService.getBooleanProperty("usage-statistics.logBots", true)) - { + !configurationService.getBooleanProperty("usage-statistics.logBots", true)) { return null; } @@ -287,8 +309,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } } } - if (!isUseProxies() && request.getHeader("X-Forwarded-For") != null){ - log.warn("X-Forwarded-For header detected but useProxies is not enabled. If your dspace is behind a proxy set it to true"); + if (!isUseProxies() && request.getHeader("X-Forwarded-For") != null) { + log.warn( + "X-Forwarded-For header detected but useProxies is not enabled. If your dspace is behind a proxy " + + "set it to true"); } doc1.addField("ip", ip); @@ -298,47 +322,45 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea doc1.addField("referrer", request.getHeader("referer")); } - try - { + try { String dns = DnsLookup.reverseDns(ip); doc1.addField("dns", dns.toLowerCase()); - } - catch (Exception e) - { + } catch (Exception e) { log.info("Failed DNS Lookup for IP:" + ip); - log.debug(e.getMessage(),e); + log.debug(e.getMessage(), e); } - if (request.getHeader("User-Agent") != null) - { + if (request.getHeader("User-Agent") != null) { doc1.addField("userAgent", request.getHeader("User-Agent")); } - doc1.addField("isBot",isSpiderBot); + doc1.addField("isBot", isSpiderBot); // Save the location information if valid, save the event without // location information if not valid - if (locationService != null) - { - Location location = locationService.getLocation(ip); - if (location != null - && !("--".equals(location.countryCode) - && location.latitude == -180 && location.longitude == -180)) - { - try - { - doc1.addField("continent", LocationUtils - .getContinentCode(location.countryCode)); + if (locationService != null) { + try { + InetAddress ipAddress = InetAddress.getByName(ip); + CityResponse location = locationService.city(ipAddress); + String countryCode = location.getCountry().getIsoCode(); + double latitude = location.getLocation().getLatitude(); + double longitude = location.getLocation().getLongitude(); + if (!( + "--".equals(countryCode) + && latitude == -180 + && longitude == -180) + ) { + try { + doc1.addField("continent", LocationUtils + .getContinentCode(countryCode)); + } catch (Exception e) { + System.out + .println("COUNTRY ERROR: " + countryCode); + } + doc1.addField("countryCode", countryCode); + doc1.addField("city", location.getCity().getName()); + doc1.addField("latitude", latitude); + doc1.addField("longitude", longitude); } - catch (Exception e) - { - System.out - .println("COUNTRY ERROR: " + location.countryCode); - } - doc1.addField("countryCode", location.countryCode); - doc1.addField("city", location.city); - doc1.addField("latitude", location.latitude); - doc1.addField("longitude", location.longitude); - - - + } catch (IOException | GeoIp2Exception e) { + log.error("Unable to get location of request: {}", e.getMessage()); } } } @@ -350,83 +372,82 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } // Save the current time doc1.addField("time", DateFormatUtils.format(new Date(), DATE_FORMAT_8601)); - if (currentUser != null) - { + if (currentUser != null) { doc1.addField("epersonid", currentUser.getID()); } return doc1; } - protected SolrInputDocument getCommonSolrDoc(DSpaceObject dspaceObject, String ip, String userAgent, String xforwardedfor, EPerson currentUser) throws SQLException { + protected SolrInputDocument getCommonSolrDoc(DSpaceObject dspaceObject, String ip, String userAgent, + String xforwardedfor, EPerson currentUser) throws SQLException { boolean isSpiderBot = SpiderDetector.isSpider(ip); if (isSpiderBot && - !configurationService.getBooleanProperty("usage-statistics.logBots", true)) - { + !configurationService.getBooleanProperty("usage-statistics.logBots", true)) { return null; } SolrInputDocument doc1 = new SolrInputDocument(); // Save our basic info that we already have - if (!isUseProxies() && xforwardedfor != null){ - log.warn("X-Forwarded-For header detected but useProxies is not enabled. If your dspace is behind a proxy set it to true"); - } - if (isUseProxies() && xforwardedfor != null) { - /* This header is a comma delimited list */ - for (String xfip : xforwardedfor.split(",")) { + if (!isUseProxies() && xforwardedfor != null) { + log.warn( + "X-Forwarded-For header detected but useProxies is not enabled. If your dspace is behind a proxy set " + + "it to true"); + } + if (isUseProxies() && xforwardedfor != null) { + /* This header is a comma delimited list */ + for (String xfip : xforwardedfor.split(",")) { /* proxy itself will sometime populate this header with the same value in remote address. ordering in spec is vague, we'll just take the last not equal to the proxy */ - if (!xforwardedfor.contains(ip)) { - ip = xfip.trim(); - } + if (!xforwardedfor.contains(ip)) { + ip = xfip.trim(); } + } doc1.addField("ip", ip); - try - { + try { String dns = DnsLookup.reverseDns(ip); doc1.addField("dns", dns.toLowerCase()); - } - catch (Exception e) - { + } catch (Exception e) { log.info("Failed DNS Lookup for IP:" + ip); - log.debug(e.getMessage(),e); + log.debug(e.getMessage(), e); } - if (userAgent != null) - { + if (userAgent != null) { doc1.addField("userAgent", userAgent); } - doc1.addField("isBot",isSpiderBot); + doc1.addField("isBot", isSpiderBot); // Save the location information if valid, save the event without // location information if not valid - if (locationService != null) - { - Location location = locationService.getLocation(ip); - if (location != null - && !("--".equals(location.countryCode) - && location.latitude == -180 && location.longitude == -180)) - { - try - { - doc1.addField("continent", LocationUtils - .getContinentCode(location.countryCode)); + if (locationService != null) { + try { + InetAddress ipAddress = InetAddress.getByName(ip); + CityResponse location = locationService.city(ipAddress); + String countryCode = location.getCountry().getIsoCode(); + double latitude = location.getLocation().getLatitude(); + double longitude = location.getLocation().getLongitude(); + if (!( + "--".equals(countryCode) + && latitude == -180 + && longitude == -180) + ) { + try { + doc1.addField("continent", LocationUtils + .getContinentCode(countryCode)); + } catch (Exception e) { + System.out + .println("COUNTRY ERROR: " + countryCode); + } + doc1.addField("countryCode", countryCode); + doc1.addField("city", location.getCity().getName()); + doc1.addField("latitude", latitude); + doc1.addField("longitude", longitude); } - catch (Exception e) - { - System.out - .println("COUNTRY ERROR: " + location.countryCode); - } - doc1.addField("countryCode", location.countryCode); - doc1.addField("city", location.city); - doc1.addField("latitude", location.latitude); - doc1.addField("longitude", location.longitude); - - - + } catch (GeoIp2Exception | IOException e) { + log.error("Unable to get location of request: {}", e.getMessage()); } } } @@ -438,22 +459,22 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } // Save the current time doc1.addField("time", DateFormatUtils.format(new Date(), DATE_FORMAT_8601)); - if (currentUser != null) - { + if (currentUser != null) { doc1.addField("epersonid", currentUser.getID()); } return doc1; } - + @Override public void postSearch(DSpaceObject resultObject, HttpServletRequest request, EPerson currentUser, - List queries, int rpp, String sortBy, String order, int page, DSpaceObject scope) { - try - { + List queries, int rpp, String sortBy, String order, int page, DSpaceObject scope) { + try { SolrInputDocument solrDoc = getCommonSolrDoc(resultObject, request, currentUser); - if (solrDoc == null) return; + if (solrDoc == null) { + return; + } initSolrYearCores(); for (String query : queries) { @@ -488,13 +509,9 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } solr.add(solrDoc); - } - catch (RuntimeException re) - { + } catch (RuntimeException re) { throw re; - } - catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); } } @@ -540,9 +557,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } solr.add(solrDoc); - } - catch (Exception e) - { + } catch (Exception e) { //Log the exception, no need to send it through, the workflow shouldn't crash because of this ! log.error(e.getMessage(), e); } @@ -551,37 +566,29 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override public void storeParents(SolrInputDocument doc1, DSpaceObject dso) - throws SQLException - { - if (dso instanceof Community) - { + throws SQLException { + if (dso instanceof Community) { Community comm = (Community) dso; List parentCommunities = comm.getParentCommunities(); for (Community parent : parentCommunities) { doc1.addField("owningComm", parent.getID()); storeParents(doc1, parent); } - } - else if (dso instanceof Collection) - { + } else if (dso instanceof Collection) { Collection coll = (Collection) dso; List communities = coll.getCommunities(); for (Community community : communities) { doc1.addField("owningComm", community.getID()); storeParents(doc1, community); } - } - else if (dso instanceof Item) - { + } else if (dso instanceof Item) { Item item = (Item) dso; List collections = item.getCollections(); for (Collection collection : collections) { doc1.addField("owningColl", collection.getID()); storeParents(doc1, collection); } - } - else if (dso instanceof Bitstream) - { + } else if (dso instanceof Bitstream) { Bitstream bitstream = (Bitstream) dso; List bundles = bitstream.getBundles(); for (Bundle bundle : bundles) { @@ -595,26 +602,22 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } @Override - public boolean isUseProxies() - { + public boolean isUseProxies() { return useProxies; } @Override public void removeIndex(String query) throws IOException, - SolrServerException - { + SolrServerException { solr.deleteByQuery(query); solr.commit(); } @Override public Map> queryField(String query, - List oldFieldVals, String field) - { + List oldFieldVals, String field) { Map> currentValsStored = new HashMap>(); - try - { + try { // Get one document (since all the metadata for all the values // should be the same just get the first one we find Map params = new HashMap(); @@ -623,21 +626,17 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea MapSolrParams solrParams = new MapSolrParams(params); QueryResponse response = solr.query(solrParams); // Make sure we at least got a document - if (response.getResults().getNumFound() == 0) - { + if (response.getResults().getNumFound() == 0) { return currentValsStored; } - } - catch (SolrServerException e) - { + } catch (SolrServerException e) { e.printStackTrace(); } return currentValsStored; } - public class ResultProcessor - { + public class ResultProcessor { public void execute(String query) throws SolrServerException, IOException { Map params = new HashMap(); @@ -648,15 +647,14 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } MapSolrParams solrParams = new MapSolrParams(params); QueryResponse response = solr.query(solrParams); - + long numbFound = response.getResults().getNumFound(); // process the first batch process(response.getResults()); // Run over the rest - for (int i = 10; i < numbFound; i += 10) - { + for (int i = 10; i < numbFound; i += 10) { params.put("start", String.valueOf(i)); solrParams = new MapSolrParams(params); response = solr.query(solrParams); @@ -671,12 +669,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea /** * Override to manage pages of documents - * @param docs - * a list of Solr documents - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SolrServerException - * Exception from the Solr server to the solrj Java client. + * + * @param docs a list of Solr documents + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SolrServerException Exception from the Solr server to the solrj Java client. */ public void process(List docs) throws IOException, SolrServerException { for (SolrDocument doc : docs) { @@ -686,12 +682,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea /** * Override to manage individual documents - * @param doc - * Solr document - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SolrServerException - * Exception from the Solr server to the solrj Java client. + * + * @param doc Solr document + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SolrServerException Exception from the Solr server to the solrj Java client. */ public void process(SolrDocument doc) throws IOException, SolrServerException { @@ -701,8 +695,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override - public void markRobotsByIP() - { + public void markRobotsByIP() { for (String ip : SpiderDetector.getSpiderIpAddresses()) { try { @@ -720,12 +713,12 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea }; /* query for ip, exclude results previously set as bots. */ - processor.execute("ip:"+ip+ "* AND -isBot:true"); + processor.execute("ip:" + ip + "* AND -isBot:true"); solr.commit(); } catch (Exception e) { - log.error(e.getMessage(),e); + log.error(e.getMessage(), e); } @@ -737,49 +730,46 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea public void markRobotByUserAgent(String agent) { try { - /* Result Process to alter record to be identified as a bot */ - ResultProcessor processor = new ResultProcessor() { - @Override - public void process(SolrDocument doc) throws IOException, SolrServerException { - doc.removeFields("isBot"); - doc.addField("isBot", true); - SolrInputDocument newInput = ClientUtils.toSolrInputDocument(doc); - solr.add(newInput); - } - }; + /* Result Process to alter record to be identified as a bot */ + ResultProcessor processor = new ResultProcessor() { + @Override + public void process(SolrDocument doc) throws IOException, SolrServerException { + doc.removeFields("isBot"); + doc.addField("isBot", true); + SolrInputDocument newInput = ClientUtils.toSolrInputDocument(doc); + solr.add(newInput); + } + }; - /* query for ip, exclude results previously set as bots. */ - processor.execute("userAgent:"+agent+ " AND -isBot:true"); + /* query for ip, exclude results previously set as bots. */ + processor.execute("userAgent:" + agent + " AND -isBot:true"); - solr.commit(); - } catch (Exception e) { - log.error(e.getMessage(),e); - } - } - - @Override - public void deleteRobotsByIsBotFlag() - { - try { - solr.deleteByQuery("isBot:true"); + solr.commit(); } catch (Exception e) { - log.error(e.getMessage(),e); + log.error(e.getMessage(), e); } } @Override - public void deleteIP(String ip) - { + public void deleteRobotsByIsBotFlag() { try { - solr.deleteByQuery("ip:"+ip + "*"); + solr.deleteByQuery("isBot:true"); } catch (Exception e) { - log.error(e.getMessage(),e); + log.error(e.getMessage(), e); } } @Override - public void deleteRobotsByIP() - { + public void deleteIP(String ip) { + try { + solr.deleteByQuery("ip:" + ip + "*"); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + + @Override + public void deleteRobotsByIP() { for (String ip : SpiderDetector.getSpiderIpAddresses()) { deleteIP(ip); } @@ -787,9 +777,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override public void update(String query, String action, - List fieldNames, List> fieldValuesList) - throws SolrServerException, IOException - { + List fieldNames, List> fieldValuesList) + throws SolrServerException, IOException { // Since there is NO update // We need to get our documents // QueryResponse queryResponse = solr.query()//query(query, null, -1, @@ -798,11 +787,11 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea final List docsToUpdate = new ArrayList(); ResultProcessor processor = new ResultProcessor() { - @Override - public void process(List docs) throws IOException, SolrServerException { - docsToUpdate.addAll(docs); - } - }; + @Override + public void process(List docs) throws IOException, SolrServerException { + docsToUpdate.addAll(docs); + } + }; processor.execute(query); @@ -810,45 +799,36 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea solr.deleteByQuery(query); // Add the new (updated onces - for (int i = 0; i < docsToUpdate.size(); i++) - { + for (int i = 0; i < docsToUpdate.size(); i++) { SolrDocument solrDocument = docsToUpdate.get(i); // Now loop over our fieldname actions - for (int j = 0; j < fieldNames.size(); j++) - { + for (int j = 0; j < fieldNames.size(); j++) { String fieldName = fieldNames.get(j); List fieldValues = fieldValuesList.get(j); - if (action.equals("addOne") || action.equals("replace")) - { - if (action.equals("replace")) - { + if (action.equals("addOne") || action.equals("replace")) { + if (action.equals("replace")) { solrDocument.removeFields(fieldName); } - for (Object fieldValue : fieldValues) - { + for (Object fieldValue : fieldValues) { solrDocument.addField(fieldName, fieldValue); } - } - else if (action.equals("remOne")) - { + } else if (action.equals("remOne")) { // Remove the field java.util.Collection values = solrDocument - .getFieldValues(fieldName); + .getFieldValues(fieldName); solrDocument.removeFields(fieldName); - for (Object value : values) - { + for (Object value : values) { // Keep all the values besides the one we need to remove - if (!fieldValues.contains((value))) - { + if (!fieldValues.contains((value))) { solrDocument.addField(fieldName, value); } } } } SolrInputDocument newInput = ClientUtils - .toSolrInputDocument(solrDocument); + .toSolrInputDocument(solrDocument); solr.add(newInput); } solr.commit(); @@ -857,49 +837,41 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } @Override - public void query(String query, int max) throws SolrServerException - { - query(query, null, null,0, max, null, null, null, null, null, false); + public void query(String query, int max) throws SolrServerException { + query(query, null, null, 0, max, null, null, null, null, null, false); } @Override public ObjectCount[] queryFacetField(String query, - String filterQuery, String facetField, int max, boolean showTotal, - List facetQueries) throws SolrServerException - { + String filterQuery, String facetField, int max, boolean showTotal, + List facetQueries) throws SolrServerException { QueryResponse queryResponse = query(query, filterQuery, facetField, - 0,max, null, null, null, facetQueries, null, false); - if (queryResponse == null) - { + 0, max, null, null, null, facetQueries, null, false); + if (queryResponse == null) { return new ObjectCount[0]; } FacetField field = queryResponse.getFacetField(facetField); // At least make sure we have one value - if (0 < field.getValueCount()) - { + if (0 < field.getValueCount()) { // Create an array for our result ObjectCount[] result = new ObjectCount[field.getValueCount() - + (showTotal ? 1 : 0)]; + + (showTotal ? 1 : 0)]; // Run over our results & store them - for (int i = 0; i < field.getValues().size(); i++) - { + for (int i = 0; i < field.getValues().size(); i++) { FacetField.Count fieldCount = field.getValues().get(i); result[i] = new ObjectCount(); result[i].setCount(fieldCount.getCount()); result[i].setValue(fieldCount.getName()); } - if (showTotal) - { + if (showTotal) { result[result.length - 1] = new ObjectCount(); result[result.length - 1].setCount(queryResponse.getResults() - .getNumFound()); + .getNumFound()); result[result.length - 1].setValue("total"); } return result; - } - else - { + } else { // Return an empty array cause we got no data return new ObjectCount[0]; } @@ -907,13 +879,11 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override public ObjectCount[] queryFacetDate(String query, - String filterQuery, int max, String dateType, String dateStart, - String dateEnd, boolean showTotal, Context context) throws SolrServerException - { + String filterQuery, int max, String dateType, String dateStart, + String dateEnd, boolean showTotal, Context context) throws SolrServerException { QueryResponse queryResponse = query(query, filterQuery, null, 0, max, - dateType, dateStart, dateEnd, null, null, false); - if (queryResponse == null) - { + dateType, dateStart, dateEnd, null, null, false); + if (queryResponse == null) { return new ObjectCount[0]; } @@ -921,20 +891,18 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea // TODO: check if this cannot crash I checked it, it crashed!!! // Create an array for our result ObjectCount[] result = new ObjectCount[dateFacet.getValueCount() - + (showTotal ? 1 : 0)]; + + (showTotal ? 1 : 0)]; // Run over our datefacet & store all the values - for (int i = 0; i < dateFacet.getValues().size(); i++) - { + for (int i = 0; i < dateFacet.getValues().size(); i++) { FacetField.Count dateCount = dateFacet.getValues().get(i); result[i] = new ObjectCount(); result[i].setCount(dateCount.getCount()); result[i].setValue(getDateView(dateCount.getName(), dateType, context)); } - if (showTotal) - { + if (showTotal) { result[result.length - 1] = new ObjectCount(); result[result.length - 1].setCount(queryResponse.getResults() - .getNumFound()); + .getNumFound()); // TODO: Make sure that this total is gotten out of the msgs.xml result[result.length - 1].setValue("total"); } @@ -943,30 +911,26 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override public Map queryFacetQuery(String query, - String filterQuery, List facetQueries) - throws SolrServerException - { - QueryResponse response = query(query, filterQuery, null,0, 1, null, null, - null, facetQueries, null, false); + String filterQuery, List facetQueries) + throws SolrServerException { + QueryResponse response = query(query, filterQuery, null, 0, 1, null, null, + null, facetQueries, null, false); return response.getFacetQuery(); } @Override public ObjectCount queryTotal(String query, String filterQuery) - throws SolrServerException - { - QueryResponse queryResponse = query(query, filterQuery, null,0, -1, null, - null, null, null, null, false); + throws SolrServerException { + QueryResponse queryResponse = query(query, filterQuery, null, 0, -1, null, + null, null, null, null, false); ObjectCount objCount = new ObjectCount(); objCount.setCount(queryResponse.getResults().getNumFound()); return objCount; } - protected String getDateView(String name, String type, Context context) - { - if (name != null && name.matches("^[0-9]{4}\\-[0-9]{2}.*")) - { + protected String getDateView(String name, String type, Context context) { + if (name != null && name.matches("^[0-9]{4}\\-[0-9]{2}.*")) { /* * if ("YEAR".equalsIgnoreCase(type)) return name.substring(0, 4); * else if ("MONTH".equalsIgnoreCase(type)) return name.substring(0, @@ -976,45 +940,33 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea */ // Get our date Date date = null; - try - { + try { SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT_8601, context.getCurrentLocale()); date = format.parse(name); - } - catch (ParseException e) - { - try - { + } catch (ParseException e) { + try { // We should use the dcdate (the dcdate is used when // generating random data) SimpleDateFormat format = new SimpleDateFormat( - DATE_FORMAT_DCDATE, context.getCurrentLocale()); + DATE_FORMAT_DCDATE, context.getCurrentLocale()); date = format.parse(name); - } - catch (ParseException e1) - { + } catch (ParseException e1) { e1.printStackTrace(); } // e.printStackTrace(); } String dateformatString = "dd-MM-yyyy"; - if ("DAY".equals(type)) - { + if ("DAY".equals(type)) { dateformatString = "dd-MM-yyyy"; - } - else if ("MONTH".equals(type)) - { + } else if ("MONTH".equals(type)) { dateformatString = "MMMM yyyy"; - } - else if ("YEAR".equals(type)) - { + } else if ("YEAR".equals(type)) { dateformatString = "yyyy"; } SimpleDateFormat simpleFormat = new SimpleDateFormat( - dateformatString, context.getCurrentLocale()); - if (date != null) - { + dateformatString, context.getCurrentLocale()); + if (date != null) { name = simpleFormat.format(date); } @@ -1024,56 +976,48 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override public QueryResponse query(String query, String filterQuery, - String facetField, int rows, int max, String dateType, String dateStart, - String dateEnd, List facetQueries, String sort, boolean ascending) - throws SolrServerException - { - if (solr == null) - { + String facetField, int rows, int max, String dateType, String dateStart, + String dateEnd, List facetQueries, String sort, boolean ascending) + throws SolrServerException { + if (solr == null) { return null; } // System.out.println("QUERY"); SolrQuery solrQuery = new SolrQuery().setRows(rows).setQuery(query) - .setFacetMinCount(1); + .setFacetMinCount(1); addAdditionalSolrYearCores(solrQuery); // Set the date facet if present - if (dateType != null) - { + if (dateType != null) { solrQuery.setParam("facet.date", "time") - . - // EXAMPLE: NOW/MONTH+1MONTH + . + // EXAMPLE: NOW/MONTH+1MONTH setParam("facet.date.end", - "NOW/" + dateType + dateEnd + dateType).setParam( - "facet.date.gap", "+1" + dateType) - . - // EXAMPLE: NOW/MONTH-" + nbMonths + "MONTHS + "NOW/" + dateType + dateEnd + dateType).setParam( + "facet.date.gap", "+1" + dateType) + . + // EXAMPLE: NOW/MONTH-" + nbMonths + "MONTHS setParam("facet.date.start", - "NOW/" + dateType + dateStart + dateType + "S") - .setFacet(true); + "NOW/" + dateType + dateStart + dateType + "S") + .setFacet(true); } - if (facetQueries != null) - { - for (int i = 0; i < facetQueries.size(); i++) - { + if (facetQueries != null) { + for (int i = 0; i < facetQueries.size(); i++) { String facetQuery = facetQueries.get(i); solrQuery.addFacetQuery(facetQuery); } - if (0 < facetQueries.size()) - { + if (0 < facetQueries.size()) { solrQuery.setFacet(true); } } - if (facetField != null) - { + if (facetField != null) { solrQuery.addFacetField(facetField); } // Set the top x of if present - if (max != -1) - { + if (max != -1) { solrQuery.setFacetLimit(max); } @@ -1082,15 +1026,13 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea // not be influenced // Choose to filter by the Legacy spider IP list (may get too long to properly filter all IP's - if (configurationService.getBooleanProperty("solr-statistics.query.filter.spiderIp",false)) - { + if (configurationService.getBooleanProperty("solr-statistics.query.filter.spiderIp", false)) { solrQuery.addFilterQuery(getIgnoreSpiderIPs()); } // Choose to filter by isBot field, may be overriden in future // to allow views on stats based on bots. - if (configurationService.getBooleanProperty("solr-statistics.query.filter.isBot",true)) - { + if (configurationService.getBooleanProperty("solr-statistics.query.filter.isBot", true)) { solrQuery.addFilterQuery("-isBot:true"); } @@ -1121,19 +1063,15 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea solrQuery.addFilterQuery(bundleQuery.toString()); } - if (filterQuery != null) - { + if (filterQuery != null) { solrQuery.addFilterQuery(filterQuery); } QueryResponse response; - try - { + try { // solr.set response = solr.query(solrQuery); - } - catch (SolrServerException e) - { + } catch (SolrServerException e) { System.err.println("Error using query " + query); throw e; } @@ -1141,12 +1079,13 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } - /** String of IP and Ranges in IPTable as a Solr Query */ + /** + * String of IP and Ranges in IPTable as a Solr Query + */ protected String filterQuery = null; @Override - public String getIgnoreSpiderIPs() - { + public String getIgnoreSpiderIPs() { if (filterQuery == null) { StringBuilder query = new StringBuilder(); boolean first = true; @@ -1164,16 +1103,16 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea return filterQuery; } - + @Override public void optimizeSOLR() { try { long start = System.currentTimeMillis(); - System.out.println("SOLR Optimize -- Process Started:"+start); + System.out.println("SOLR Optimize -- Process Started:" + start); solr.optimize(); long finish = System.currentTimeMillis(); - System.out.println("SOLR Optimize -- Process Finished:"+finish); - System.out.println("SOLR Optimize -- Total time taken:"+(finish-start) + " (ms)."); + System.out.println("SOLR Optimize -- Process Finished:" + finish); + System.out.println("SOLR Optimize -- Total time taken:" + (finish - start) + " (ms)."); } catch (SolrServerException sse) { System.err.println(sse.getMessage()); } catch (IOException ioe) { @@ -1183,6 +1122,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override public void shardSolrIndex() throws IOException, SolrServerException { + if (!(solr instanceof HttpSolrServer)) { + return; + } + /* Start by faceting by year so we can include each year in a separate core ! */ @@ -1193,14 +1136,16 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea yearRangeQuery.add(FacetParams.FACET_RANGE, "time"); //We go back to 2000 the year 2000, this is a bit overkill but this way we ensure we have everything //The alternative would be to sort but that isn't recommended since it would be a very costly query ! - yearRangeQuery.add(FacetParams.FACET_RANGE_START, "NOW/YEAR-" + (Calendar.getInstance().get(Calendar.YEAR) - 2000) + "YEARS"); + yearRangeQuery.add(FacetParams.FACET_RANGE_START, + "NOW/YEAR-" + (Calendar.getInstance().get(Calendar.YEAR) - 2000) + "YEARS"); //Add the +0year to ensure that we DO NOT include the current year yearRangeQuery.add(FacetParams.FACET_RANGE_END, "NOW/YEAR+0YEARS"); yearRangeQuery.add(FacetParams.FACET_RANGE_GAP, "+1YEAR"); yearRangeQuery.add(FacetParams.FACET_MINCOUNT, String.valueOf(1)); //Create a temp directory to store our files in ! - File tempDirectory = new File(configurationService.getProperty("dspace.dir") + File.separator + "temp" + File.separator); + File tempDirectory = new File( + configurationService.getProperty("dspace.dir") + File.separator + "temp" + File.separator); tempDirectory.mkdirs(); @@ -1243,21 +1188,22 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea //Start by creating a new core String coreName = "statistics-" + dcStart.getYearUTC(); - HttpSolrServer statisticsYearServer = createCore(solr, coreName); + HttpSolrServer statisticsYearServer = createCore((HttpSolrServer) solr, coreName); System.out.println("Moving: " + totalRecords + " into core " + coreName); log.info("Moving: " + totalRecords + " records into core " + coreName); List filesToUpload = new ArrayList(); - for (int i = 0; i < totalRecords; i+=10000) { - String solrRequestUrl = solr.getBaseURL() + "/select"; + for (int i = 0; i < totalRecords; i += 10000) { + String solrRequestUrl = ((HttpSolrServer) solr).getBaseURL() + "/select"; solrRequestUrl = generateURL(solrRequestUrl, yearQueryParams); HttpGet get = new HttpGet(solrRequestUrl); HttpResponse response = new DefaultHttpClient().execute(get); InputStream csvInputstream = response.getEntity().getContent(); //Write the csv ouput to a file ! - File csvFile = new File(tempDirectory.getPath() + File.separatorChar + "temp." + dcStart.getYearUTC() + "." + i + ".csv"); + File csvFile = new File( + tempDirectory.getPath() + File.separatorChar + "temp." + dcStart.getYearUTC() + "." + i + ".csv"); FileUtils.copyInputStreamToFile(csvInputstream, csvFile); filesToUpload.add(csvFile); @@ -1276,10 +1222,12 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea contentStreamUpdateRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true); contentStreamUpdateRequest.addFile(tempCsv, "text/plain;charset=utf-8"); - //Add parsing directives for the multivalued fields so that they are stored as separate values instead of one value + //Add parsing directives for the multivalued fields so that they are stored as separate values + // instead of one value for (String multivaluedField : multivaluedFields) { contentStreamUpdateRequest.setParam("f." + multivaluedField + ".split", Boolean.TRUE.toString()); - contentStreamUpdateRequest.setParam("f." + multivaluedField + ".separator", MULTIPLE_VALUES_SPLITTER); + contentStreamUpdateRequest + .setParam("f." + multivaluedField + ".separator", MULTIPLE_VALUES_SPLITTER); } statisticsYearServer.request(contentStreamUpdateRequest); @@ -1301,22 +1249,24 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea protected HttpSolrServer createCore(HttpSolrServer solr, String coreName) throws IOException, SolrServerException { String solrDir = configurationService.getProperty("dspace.dir") + File.separator + "solr" + File.separator; String baseSolrUrl = solr.getBaseURL().replace("statistics", ""); - - //DS-3458: Test to see if a solr core already exists. If it exists, return that server. Otherwise create a new one. + + //DS-3458: Test to see if a solr core already exists. If it exists, return that server. Otherwise create a + // new one. HttpSolrServer returnServer = new HttpSolrServer(baseSolrUrl + "/" + coreName); try { SolrPingResponse ping = returnServer.ping(); log.debug(String.format("Ping of Solr Core [%s] Returned with Status [%d]", coreName, ping.getStatus())); return returnServer; - } catch(Exception e) { - log.debug(String.format("Ping of Solr Core [%s] Failed with [%s]. New Core Will be Created", coreName, e.getClass().getName())); + } catch (Exception e) { + log.debug(String.format("Ping of Solr Core [%s] Failed with [%s]. New Core Will be Created", coreName, + e.getClass().getName())); } - + //Unfortunately, this class is documented as "experimental and subject to change" on the Lucene website. //http://lucene.apache.org/solr/4_4_0/solr-solrj/org/apache/solr/client/solrj/request/CoreAdminRequest.html CoreAdminRequest.Create create = new CoreAdminRequest.Create(); create.setCoreName(coreName); - + //The config files for a statistics shard reside wihtin the statistics repository create.setInstanceDir("statistics"); create.setDataDir(solrDir + coreName + File.separator + "data"); @@ -1328,9 +1278,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea /** * Retrieves a list of all the multi valued fields in the solr core + * * @return all fields tagged as multivalued * @throws SolrServerException When getting the schema information from the SOLR core fails - * @throws IOException When connection to the SOLR server fails + * @throws IOException When connection to the SOLR server fails */ public Set getMultivaluedFieldNames() throws SolrServerException, IOException { Set multivaluedFields = new HashSet(); @@ -1338,14 +1289,11 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea lukeRequest.setShowSchema(true); LukeResponse process = lukeRequest.process(solr); Map fields = process.getFieldInfo(); - for(String fieldName : fields.keySet()) - { + for (String fieldName : fields.keySet()) { LukeResponse.FieldInfo fieldInfo = fields.get(fieldName); EnumSet flags = fieldInfo.getFlags(); - for(FieldFlag fieldFlag : flags) - { - if(fieldFlag.getAbbreviation() == FieldFlag.MULTI_VALUED.getAbbreviation()) - { + for (FieldFlag fieldFlag : flags) { + if (fieldFlag.getAbbreviation() == FieldFlag.MULTI_VALUED.getAbbreviation()) { multivaluedFields.add(fieldName); } } @@ -1356,6 +1304,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea @Override public void reindexBitstreamHits(boolean removeDeletedBitstreams) throws Exception { + if (!(solr instanceof HttpSolrServer)) { + return; + } + Context context = new Context(); try { @@ -1369,10 +1321,11 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea addAdditionalSolrYearCores(query); long totalRecords = solr.query(query).getResults().getNumFound(); - File tempDirectory = new File(configurationService.getProperty("dspace.dir") + File.separator + "temp" + File.separator); + File tempDirectory = new File( + configurationService.getProperty("dspace.dir") + File.separator + "temp" + File.separator); tempDirectory.mkdirs(); List tempCsvFiles = new ArrayList(); - for (int i = 0; i < totalRecords; i+=10000) { + for (int i = 0; i < totalRecords; i += 10000) { Map params = new HashMap(); params.put(CommonParams.Q, "*:*"); params.put(CommonParams.FQ, "-bundleName:[* TO *] AND type:" + Constants.BITSTREAM); @@ -1380,13 +1333,13 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea params.put(CommonParams.ROWS, String.valueOf(10000)); params.put(CommonParams.START, String.valueOf(i)); - String solrRequestUrl = solr.getBaseURL() + "/select"; + String solrRequestUrl = ((HttpSolrServer) solr).getBaseURL() + "/select"; solrRequestUrl = generateURL(solrRequestUrl, params); HttpGet get = new HttpGet(solrRequestUrl); HttpResponse response = new DefaultHttpClient().execute(get); - InputStream csvOutput = response.getEntity().getContent(); + InputStream csvOutput = response.getEntity().getContent(); Reader csvReader = new InputStreamReader(csvOutput); List rows = new CSVReader(csvReader).readAll(); String[][] csvParsed = rows.toArray(new String[rows.size()][]); @@ -1428,8 +1381,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea DSpaceObject parentObject = bitstreamService.getParentObject(context, bitstream); if (parentObject instanceof Collection) { bundleName = "LOGO-COLLECTION"; - } else - if (parentObject instanceof Community) { + } else if (parentObject instanceof Community) { bundleName = "LOGO-COMMUNITY"; } @@ -1439,7 +1391,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea //Remove the bitstream from cache } //Check if we don't have a bundlename - //If we don't have one & we do not need to delete the deleted bitstreams ensure that a BITSTREAM_DELETED bundle name is given ! + //If we don't have one & we do not need to delete the deleted bitstreams ensure that a + // BITSTREAM_DELETED bundle name is given ! if (bundleName == null && !removeDeletedBitstreams) { bundleName = "BITSTREAM_DELETED"; } @@ -1481,7 +1434,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea public void exportHits() throws Exception { Context context = new Context(); - File tempDirectory = new File(configurationService.getProperty("dspace.dir") + File.separator + "temp" + File.separator); + File tempDirectory = new File( + configurationService.getProperty("dspace.dir") + File.separator + "temp" + File.separator); tempDirectory.mkdirs(); try { @@ -1498,7 +1452,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea long totalRecords = solr.query(query).getResults().getNumFound(); System.out.println("There are " + totalRecords + " usage events in SOLR for download/view."); - for (int i = 0; i < totalRecords; i+=10000) { + for (int i = 0; i < totalRecords; i += 10000) { solrParams.set(CommonParams.START, String.valueOf(i)); QueryResponse queryResponse = solr.query(solrParams); SolrDocumentList docs = queryResponse.getResults(); @@ -1508,7 +1462,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea //export docs addDocumentsToFile(context, docs, exportOutput); - System.out.println("Export hits [" + i + " - " + String.valueOf(i+9999) + "] to " + exportOutput.getCanonicalPath()); + System.out.println( + "Export hits [" + i + " - " + String.valueOf(i + 9999) + "] to " + exportOutput.getCanonicalPath()); } } catch (Exception e) { log.error("Error while exporting SOLR data", e); @@ -1518,7 +1473,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } } - protected void addDocumentsToFile(Context context, SolrDocumentList docs, File exportOutput) throws SQLException, ParseException, IOException { + protected void addDocumentsToFile(Context context, SolrDocumentList docs, File exportOutput) + throws SQLException, ParseException, IOException { for (SolrDocument doc : docs) { String ip = doc.get("ip").toString(); if (ip.equals("::1")) { @@ -1530,7 +1486,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea String time = doc.get("time").toString(); //20140527162409835,view_bitstream,1292,2014-05-27T16:24:09,anonymous,127.0.0.1 - DSpaceObjectLegacySupportService dsoService = contentServiceFactory.getDSpaceLegacyObjectService(Integer.parseInt(type)); + DSpaceObjectLegacySupportService dsoService = contentServiceFactory + .getDSpaceLegacyObjectService(Integer.parseInt(type)); DSpaceObject dso = dsoService.findByIdOrLegacyId(context, id); if (dso == null) { log.debug("Document no longer exists in DB. type:" + type + " id:" + id); @@ -1544,7 +1501,9 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea //OutputFormat: 2014-05-27T16:24:09 DateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - String out = time + "," + "view_" + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso).toLowerCase() + "," + id + "," + outputDateFormat.format(solrDate) + ",anonymous," + ip + "\n"; + String out = time + "," + "view_" + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + .toLowerCase() + "," + id + "," + outputDateFormat + .format(solrDate) + ",anonymous," + ip + "\n"; FileUtils.writeStringToFile(exportOutput, out, true); } @@ -1553,15 +1512,11 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea protected String generateURL(String baseURL, Map parameters) throws UnsupportedEncodingException { boolean first = true; StringBuilder result = new StringBuilder(baseURL); - for (String key : parameters.keySet()) - { - if (first) - { + for (String key : parameters.keySet()) { + if (first) { result.append("?"); first = false; - } - else - { + } else { result.append("&"); } @@ -1574,26 +1529,27 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea protected void addAdditionalSolrYearCores(SolrQuery solrQuery) { //Only add if needed initSolrYearCores(); - if(0 < statisticYearCores.size()){ + if (0 < statisticYearCores.size()) { //The shards are a comma separated list of the urls to the cores solrQuery.add(ShardParams.SHARDS, StringUtils.join(statisticYearCores.iterator(), ",")); } } - + /* * The statistics shards should not be initialized until all tomcat webapps are fully initialized. - * DS-3457 uncovered an issue in DSpace 6x in which this code triggered tomcat to hang when statistics shards are present. + * DS-3457 uncovered an issue in DSpace 6x in which this code triggered tomcat to hang when statistics shards are + * present. * This code is synchonized in the event that 2 threads trigger the initialization at the same time. */ protected synchronized void initSolrYearCores() { - if (statisticYearCoresInit) { + if (statisticYearCoresInit || !(solr instanceof HttpSolrServer)) { return; } - try - { + try { //Attempt to retrieve all the statistic year cores - File solrDir = new File(configurationService.getProperty("dspace.dir") + File.separator + "solr" + File.separator); + File solrDir = new File( + configurationService.getProperty("dspace.dir") + File.separator + "solr" + File.separator); File[] solrCoreFiles = solrDir.listFiles(new FileFilter() { @Override @@ -1603,16 +1559,17 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea } }); //Base url should like : http://localhost:{port.number}/solr - String baseSolrUrl = solr.getBaseURL().replace("statistics", ""); + String baseSolrUrl = ((HttpSolrServer) solr).getBaseURL().replace("statistics", ""); for (File solrCoreFile : solrCoreFiles) { log.info("Loading core with name: " + solrCoreFile.getName()); - createCore(solr, solrCoreFile.getName()); + createCore((HttpSolrServer) solr, solrCoreFile.getName()); //Add it to our cores list so we can query it ! - statisticYearCores.add(baseSolrUrl.replace("http://", "").replace("https://", "") + solrCoreFile.getName()); + statisticYearCores + .add(baseSolrUrl.replace("http://", "").replace("https://", "") + solrCoreFile.getName()); } //Also add the core containing the current year ! - statisticYearCores.add(solr.getBaseURL().replace("http://", "").replace("https://", "")); + statisticYearCores.add(((HttpSolrServer) solr).getBaseURL().replace("http://", "").replace("https://", "")); } catch (Exception e) { log.error(e.getMessage(), e); } diff --git a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerUsageEventListener.java b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerUsageEventListener.java index 7fb3bd4efa..deb0a92d5b 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerUsageEventListener.java +++ b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerUsageEventListener.java @@ -10,71 +10,69 @@ package org.dspace.statistics; import org.apache.log4j.Logger; import org.dspace.eperson.EPerson; import org.dspace.services.model.Event; -import org.dspace.statistics.factory.StatisticsServiceFactory; import org.dspace.statistics.service.SolrLoggerService; import org.dspace.usage.AbstractUsageEventListener; import org.dspace.usage.UsageEvent; import org.dspace.usage.UsageSearchEvent; import org.dspace.usage.UsageWorkflowEvent; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; /** - * Simple SolrLoggerUsageEvent facade to separate Solr specific + * Simple SolrLoggerUsageEvent facade to separate Solr specific * logging implementation from DSpace. - * - * @author mdiggory * + * @author mdiggory */ public class SolrLoggerUsageEventListener extends AbstractUsageEventListener { - private static Logger log = Logger.getLogger(SolrLoggerUsageEventListener.class); + private static Logger log = Logger.getLogger(SolrLoggerUsageEventListener.class); protected SolrLoggerService solrLoggerService; - public SolrLoggerUsageEventListener() { - solrLoggerService = StatisticsServiceFactory.getInstance().getSolrLoggerService(); - } + @Autowired + public void setSolrLoggerService(SolrLoggerService solrLoggerService) { + this.solrLoggerService = solrLoggerService; + } - @Override - public void receiveEvent(Event event) { + @Override + public void receiveEvent(Event event) { - if(event instanceof UsageEvent) - { - log.debug("Usage event received " + event.getName()); - try{ - UsageEvent ue = (UsageEvent)event; - - EPerson currentUser = ue.getContext() == null ? null : ue.getContext().getCurrentUser(); + if (event instanceof UsageEvent) { + log.debug("Usage event received " + event.getName()); + try { + UsageEvent ue = (UsageEvent) event; - if(UsageEvent.Action.VIEW == ue.getAction()){ - if(ue.getRequest()!=null){ + EPerson currentUser = ue.getContext() == null ? null : ue.getContext().getCurrentUser(); + + if (UsageEvent.Action.VIEW == ue.getAction()) { + if (ue.getRequest() != null) { solrLoggerService.postView(ue.getObject(), ue.getRequest(), currentUser); - } else { - solrLoggerService.postView(ue.getObject(), ue.getIp(), ue.getUserAgent(), ue.getXforwardedfor(), currentUser); - } - }else - if(UsageEvent.Action.SEARCH == ue.getAction()){ + } else { + solrLoggerService.postView(ue.getObject(), ue.getIp(), ue.getUserAgent(), ue.getXforwardedfor(), + currentUser); + } + } else if (UsageEvent.Action.SEARCH == ue.getAction()) { UsageSearchEvent usageSearchEvent = (UsageSearchEvent) ue; //Only log if the user has already filled in a query ! - if(!CollectionUtils.isEmpty(((UsageSearchEvent) ue).getQueries())){ + if (!CollectionUtils.isEmpty(((UsageSearchEvent) ue).getQueries())) { solrLoggerService.postSearch(ue.getObject(), ue.getRequest(), currentUser, - usageSearchEvent.getQueries(), usageSearchEvent.getRpp(), usageSearchEvent.getSortBy(), - usageSearchEvent.getSortOrder(), usageSearchEvent.getPage(), usageSearchEvent.getScope()); + usageSearchEvent.getQueries(), usageSearchEvent.getRpp(), + usageSearchEvent.getSortBy(), + usageSearchEvent.getSortOrder(), usageSearchEvent.getPage(), + usageSearchEvent.getScope()); } - }else - if(UsageEvent.Action.WORKFLOW == ue.getAction()){ + } else if (UsageEvent.Action.WORKFLOW == ue.getAction()) { UsageWorkflowEvent usageWorkflowEvent = (UsageWorkflowEvent) ue; solrLoggerService.postWorkflow(usageWorkflowEvent); } - } - catch(Exception e) - { - log.error(e.getMessage()); - } - } - - } + } catch (Exception e) { + log.error(e.getMessage()); + } + } + + } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/StatisticsLoggingConsumer.java b/dspace-api/src/main/java/org/dspace/statistics/StatisticsLoggingConsumer.java index cf5a2ade39..23e5b49716 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/StatisticsLoggingConsumer.java +++ b/dspace-api/src/main/java/org/dspace/statistics/StatisticsLoggingConsumer.java @@ -8,7 +8,12 @@ package org.dspace.statistics; import java.sql.SQLException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import org.dspace.content.Collection; import org.dspace.content.Community; @@ -33,8 +38,7 @@ import org.dspace.statistics.service.SolrLoggerService; * @author kevinvandevelde at atmire.com * @author ben at atmrie.com */ -public class StatisticsLoggingConsumer implements Consumer -{ +public class StatisticsLoggingConsumer implements Consumer { protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); @@ -42,8 +46,7 @@ public class StatisticsLoggingConsumer implements Consumer private Set toRemoveQueries = null; @Override - public void initialize() throws Exception - { + public void initialize() throws Exception { } @@ -51,10 +54,8 @@ public class StatisticsLoggingConsumer implements Consumer // TODO: use async threaded consumer as this might require some processing time // TODO: we might be able to improve the performance: changing the collection will trigger 4 update commands @Override - public void consume(Context ctx, Event event) throws Exception - { - if (toRemoveQueries == null) - { + public void consume(Context ctx, Event event) throws Exception { + if (toRemoveQueries == null) { toRemoveQueries = new HashSet(); } @@ -63,43 +64,37 @@ public class StatisticsLoggingConsumer implements Consumer int eventType = event.getEventType(); // Check if we are deleting something - if (eventType == Event.DELETE) - { + if (eventType == Event.DELETE) { // First make sure we delete everything for this dso String query = "id:" + dsoId + " AND type:" + dsoType; toRemoveQueries.add(query); - } - else if (eventType == Event.MODIFY && dsoType == Constants.ITEM) - { + } else if (eventType == Event.MODIFY && dsoType == Constants.ITEM) { // We have a modified item check for a withdraw/reinstate - } - else if (eventType == Event.MODIFY_METADATA - && event.getSubjectType() == Constants.ITEM) - { + } else if (eventType == Event.MODIFY_METADATA + && event.getSubjectType() == Constants.ITEM) { Item item = itemService.find(ctx, event.getSubjectID()); String updateQuery = "id:" + item.getID() + " AND type:" - + item.getType(); + + item.getType(); Map> indexedValues = solrLoggerService.queryField( - updateQuery, null, null); + updateQuery, null, null); // Get all the metadata List storageFieldList = new ArrayList(); List> storageValuesList = new ArrayList>(); solrLoggerService.update(updateQuery, "replace", storageFieldList, - storageValuesList); + storageValuesList); } if (eventType == Event.ADD && dsoType == Constants.COLLECTION - && event.getObject(ctx) instanceof Item) - { + && event.getObject(ctx) instanceof Item) { // We are mapping a new item make sure that the owning collection is // updated Item newItem = (Item) event.getObject(ctx); String updateQuery = "id: " + newItem.getID() + " AND type:" - + newItem.getType(); + + newItem.getType(); List fieldNames = new ArrayList(); List> valuesList = new ArrayList>(); @@ -117,14 +112,12 @@ public class StatisticsLoggingConsumer implements Consumer // Now make sure we also update the communities solrLoggerService.update(updateQuery, "addOne", fieldNames, valuesList); - } - else if (eventType == Event.REMOVE && dsoType == Constants.COLLECTION - && event.getObject(ctx) instanceof Item) - { + } else if (eventType == Event.REMOVE && dsoType == Constants.COLLECTION + && event.getObject(ctx) instanceof Item) { // Unmapping items Item newItem = (Item) event.getObject(ctx); String updateQuery = "id: " + newItem.getID() + " AND type:" - + newItem.getType(); + + newItem.getType(); List fieldNames = new ArrayList(); List> valuesList = new ArrayList>(); @@ -144,13 +137,11 @@ public class StatisticsLoggingConsumer implements Consumer } private List findOwningCommunities(Context context, UUID collId) - throws SQLException - { + throws SQLException { Collection coll = collectionService.find(context, collId); List owningComms = new ArrayList(); - for (int i = 0; i < coll.getCommunities().size(); i++) - { + for (int i = 0; i < coll.getCommunities().size(); i++) { Community community = coll.getCommunities().get(i); findComms(community, owningComms); } @@ -159,14 +150,11 @@ public class StatisticsLoggingConsumer implements Consumer } private void findComms(Community comm, List parentComms) - throws SQLException - { - if (comm == null) - { + throws SQLException { + if (comm == null) { return; } - if (!parentComms.contains(comm.getID())) - { + if (!parentComms.contains(comm.getID())) { parentComms.add(comm.getID()); } List parentCommunities = comm.getParentCommunities(); @@ -175,12 +163,9 @@ public class StatisticsLoggingConsumer implements Consumer } @Override - public void end(Context ctx) throws Exception - { - if (toRemoveQueries != null) - { - for (String query : toRemoveQueries) - { + public void end(Context ctx) throws Exception { + if (toRemoveQueries != null) { + for (String query : toRemoveQueries) { solrLoggerService.removeIndex(query); } } @@ -189,8 +174,7 @@ public class StatisticsLoggingConsumer implements Consumer } @Override - public void finish(Context ctx) throws Exception - { + public void finish(Context ctx) throws Exception { } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/DSORepresentation.java b/dspace-api/src/main/java/org/dspace/statistics/content/DSORepresentation.java index dbc7b2dddd..d9900c4453 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/DSORepresentation.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/DSORepresentation.java @@ -12,27 +12,37 @@ import org.dspace.core.Constants; /** * Describes the displayed representation of the statistics on a DSpaceObject * and its children. + * * @author TODO */ public class DSORepresentation { - /** The type of DSpaceObject to be shown. */ + /** + * The type of DSpaceObject to be shown. + */ private Integer type; - /** The maximum number of children to show. **/ + /** + * The maximum number of children to show. + **/ private Integer max; - /** Determines if should show the DSOs as separate entities or use the sum of them. */ + /** + * Determines if should show the DSOs as separate entities or use the sum of them. + */ private Boolean separate; private Integer nameLength; - /** Construct a representation assumed to be of an ITEM. */ + /** + * Construct a representation assumed to be of an ITEM. + */ public DSORepresentation() { setType(Constants.ITEM); } - /** Construct a representation as described. - * - * @param type Object type, e.g. Constants.COLLECTION - * @param max Maximum number of children to display + /** + * Construct a representation as described. + * + * @param type Object type, e.g. Constants.COLLECTION + * @param max Maximum number of children to display * @param separate True if children's statistics are distinct; false if summed */ public DSORepresentation(Integer type, Integer max, Boolean separate) { diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetDSpaceObjectGenerator.java b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetDSpaceObjectGenerator.java index 02045c55ec..ce75c2e605 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetDSpaceObjectGenerator.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetDSpaceObjectGenerator.java @@ -16,11 +16,12 @@ import java.util.List; * @author kevinvandevelde at atmire.com * Date: 23-dec-2008 * Time: 11:38:20 - * */ public class DatasetDSpaceObjectGenerator extends DatasetGenerator { - /** The children of our dspaceobject to be shown **/ + /** + * The children of our dspaceobject to be shown + **/ private List dsoRepresentations; public DatasetDSpaceObjectGenerator() { @@ -28,11 +29,11 @@ public class DatasetDSpaceObjectGenerator extends DatasetGenerator { } - public void addDsoChild(DSORepresentation representation){ + public void addDsoChild(DSORepresentation representation) { dsoRepresentations.add(representation); } - public void addDsoChild(int type, int max, boolean separate, int nameLength){ + public void addDsoChild(int type, int max, boolean separate, int nameLength) { DSORepresentation rep = new DSORepresentation(type, max, separate); rep.setNameLength(nameLength); dsoRepresentations.add(rep); diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetGenerator.java b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetGenerator.java index 9fb5dc6bc5..85bff41593 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetGenerator.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetGenerator.java @@ -11,27 +11,28 @@ package org.dspace.statistics.content; /** * Represents a single facet for filtering. * Can be one of the axes in a table. - * + * * @author kevinvandevelde at atmire.com * Date: 23-dec-2008 * Time: 9:39:37 - * */ public abstract class DatasetGenerator { - - /** The type of generator can either be CATEGORY or SERIE **/ + + /** + * The type of generator can either be CATEGORY or SERIE + **/ protected int datasetType; protected boolean includeTotal = false; - public int getDatasetType(){ + public int getDatasetType() { return datasetType; } - public void setDatasetType(int datasetType){ + public void setDatasetType(int datasetType) { this.datasetType = datasetType; } - + public boolean isIncludeTotal() { return includeTotal; } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetSearchGenerator.java b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetSearchGenerator.java index 50f7bf7ac9..2bd6056687 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetSearchGenerator.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetSearchGenerator.java @@ -15,15 +15,18 @@ package org.dspace.statistics.content; public class DatasetSearchGenerator extends DatasetTypeGenerator { public static enum Mode { - SEARCH_OVERVIEW ("search_overview"), - SEARCH_OVERVIEW_TOTAL ("search_overview_total"); + SEARCH_OVERVIEW("search_overview"), + SEARCH_OVERVIEW_TOTAL("search_overview_total"); private final String text; Mode(String text) { - this.text = text; - } - public String text() { return text; } + this.text = text; + } + + public String text() { + return text; + } } private Mode mode; @@ -38,7 +41,7 @@ public class DatasetSearchGenerator extends DatasetTypeGenerator { this.retrievePageViews = retrievePageViews; } - public void setPercentage(boolean percentage){ + public void setPercentage(boolean percentage) { this.percentage = percentage; } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetTimeGenerator.java b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetTimeGenerator.java index c2267480fb..12c8bab6d3 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetTimeGenerator.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetTimeGenerator.java @@ -12,11 +12,10 @@ import java.util.Date; /** * Represents a date facet for filtering. - * + * * @author kevinvandevelde at atmire.com * Date: 23-dec-2008 * Time: 9:44:57 - * */ public class DatasetTimeGenerator extends DatasetGenerator { @@ -28,9 +27,11 @@ public class DatasetTimeGenerator extends DatasetGenerator { private Date actualEndDate; //TODO: process includetotal - public DatasetTimeGenerator() { - - } + + /** + * Default constructor + */ + private DatasetTimeGenerator() { } /** * Sets the date interval. @@ -39,12 +40,12 @@ public class DatasetTimeGenerator extends DatasetGenerator { * datatype = "month" * start = "-6" * end = "+1" // the +1 indicates this month also - * + * * @param dateType type can be days, months, years - * @param start the start of the interval - * @param end the end of the interval + * @param start the start of the interval + * @param end the end of the interval */ - public void setDateInterval(String dateType, String start, String end){ + public void setDateInterval(String dateType, String start, String end) { this.startDate = start; this.endDate = end; this.dateType = dateType; @@ -52,26 +53,23 @@ public class DatasetTimeGenerator extends DatasetGenerator { } public void setDateInterval(String dateType, Date start, Date end) - throws IllegalArgumentException - { + throws IllegalArgumentException { actualStartDate = (start == null ? null : new Date(start.getTime())); actualEndDate = (end == null ? null : new Date(end.getTime())); - + this.dateType = dateType; //Check if end comes before start Calendar startCal1 = Calendar.getInstance(); Calendar endCal1 = Calendar.getInstance(); - if (startCal1 == null || endCal1 == null) - { - throw new IllegalStateException("Unable to create calendar instances"); + if (startCal1 == null || endCal1 == null) { + throw new IllegalStateException("Unable to create calendar instances"); } startCal1.setTime(start); endCal1.setTime(end); - if(endCal1.before(startCal1)) - { + if (endCal1.before(startCal1)) { throw new IllegalArgumentException(); } @@ -79,16 +77,13 @@ public class DatasetTimeGenerator extends DatasetGenerator { // have visits from the future. //Depending on our dateType check if we need to use days/months/years. int type = -1; - if("year".equalsIgnoreCase(dateType)){ + if ("year".equalsIgnoreCase(dateType)) { type = Calendar.YEAR; - }else - if("month".equalsIgnoreCase(dateType)){ + } else if ("month".equalsIgnoreCase(dateType)) { type = Calendar.MONTH; - }else - if("day".equalsIgnoreCase(dateType)){ + } else if ("day".equalsIgnoreCase(dateType)) { type = Calendar.DATE; - }else - if("hour".equalsIgnoreCase(dateType)){ + } else if ("hour".equalsIgnoreCase(dateType)) { type = Calendar.HOUR; } @@ -97,22 +92,19 @@ public class DatasetTimeGenerator extends DatasetGenerator { // System.out.println(difStart + " " + difEnd); boolean endPos = false; - if(difEnd == 0){ + if (difEnd == 0) { //Includes the current difEnd = 1; endPos = true; - }else - if(0 < difEnd) - { + } else if (0 < difEnd) { endPos = true; - } - else{ + } else { difEnd++; } startDate = "" + difStart; //We need +1 so we can count the current month/year/... - endDate = (endPos ? "+" : "") + difEnd; + endDate = (endPos ? "+" : "") + difEnd; } public String getStartDate() { @@ -163,23 +155,23 @@ public class DatasetTimeGenerator extends DatasetGenerator { this.type = type; } - /** Get the difference between two Dates in terms of a given interval. + /** + * Get the difference between two Dates in terms of a given interval. * That is: if you specify the difference in months, you get back the * number of months between the dates. * * @param date1 the first date * @param date2 the other date - * @param type Calendar.HOUR or .DATE or .MONTH + * @param type Calendar.HOUR or .DATE or .MONTH * @return number of {@code type} intervals between {@code date1} and - * {@code date2} + * {@code date2} */ - private int getTimeDifference(Date date1, Date date2, int type){ + private int getTimeDifference(Date date1, Date date2, int type) { int toAdd; int elapsed = 0; //We need calendar objects to compare - Calendar cal1, cal2; - cal1 = Calendar.getInstance(); - cal2 = Calendar.getInstance(); + Calendar cal1 = Calendar.getInstance(); + Calendar cal2 = Calendar.getInstance(); cal1.setTime(date1); cal2.setTime(date2); @@ -190,7 +182,7 @@ public class DatasetTimeGenerator extends DatasetGenerator { cal2.clear(Calendar.SECOND); cal1.clear(Calendar.MINUTE); cal2.clear(Calendar.MINUTE); - if(type != Calendar.HOUR){ + if (type != Calendar.HOUR) { cal1.clear(Calendar.HOUR); cal2.clear(Calendar.HOUR); cal1.clear(Calendar.HOUR_OF_DAY); @@ -199,34 +191,33 @@ public class DatasetTimeGenerator extends DatasetGenerator { cal1.set(Calendar.HOUR_OF_DAY, 0); cal2.set(Calendar.HOUR_OF_DAY, 0); } - if(type != Calendar.DATE){ + if (type != Calendar.DATE) { cal1.set(Calendar.DATE, 1); cal2.set(Calendar.DATE, 1); } - if(type != Calendar.MONTH){ + if (type != Calendar.MONTH) { cal1.clear(Calendar.MONTH); cal2.clear(Calendar.MONTH); } //Switch em if needed - if(cal1.after(cal2) || cal1.equals(cal2)){ + if (cal1.after(cal2) || cal1.equals(cal2)) { Calendar backup = cal1; cal1 = cal2; cal2 = backup; toAdd = 1; - }else - { + } else { toAdd = -1; } - + /*if(type != Calendar.YEAR){ cal1.clear(Calendar.YEAR); cal2.clear(Calendar.YEAR); } */ - while(cal1.before(cal2)){ + while (cal1.before(cal2)) { cal1.add(type, 1); elapsed += toAdd; } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetTypeGenerator.java b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetTypeGenerator.java index dd31ff9cfd..41fc24f765 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/DatasetTypeGenerator.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/DatasetTypeGenerator.java @@ -15,13 +15,16 @@ package org.dspace.statistics.content; * @author kevinvandevelde at atmire.com * Date: 23-dec-2008 * Time: 12:44:27 - * */ public class DatasetTypeGenerator extends DatasetGenerator { - /** The type of our generator (EXAMPLE: country) **/ + /** + * The type of our generator (EXAMPLE: country) + **/ private String type; - /** The number of values shown (max) **/ + /** + * The number of values shown (max) + **/ private int max; diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsBSAdapter.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsBSAdapter.java index d74a779ce6..f30f2c9be7 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsBSAdapter.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsBSAdapter.java @@ -20,7 +20,7 @@ import org.dspace.statistics.service.SolrLoggerService; /** * Class that will hold the data needed to show * statistics in the browse and search pages. - * + * * @author Kevin Van de Velde (kevin at atmire dot com) */ @@ -31,11 +31,17 @@ public class StatisticsBSAdapter { protected boolean displayTotalViews; protected List filters; - /** visitType is ITEM */ + /** + * visitType is ITEM + */ public static final int ITEM_VISITS = 0; - /** visitType is BITSTREAM */ + /** + * visitType is BITSTREAM + */ public static final int BITSTREAM_VISITS = 1; - /** visitType is TOTAL */ + /** + * visitType is TOTAL + */ public static final int TOTAL_VISITS = 2; protected final SolrLoggerService solrLoggerService; @@ -49,34 +55,35 @@ public class StatisticsBSAdapter { /** * Returns the number of visits for the item. * Depending on the visitType it can either be item, bitstream, total, ... - * + * * @param visitType the type of visits we want, from the item, bitstream, total - * @param item the item from which we need our visits + * @param item the item from which we need our visits * @return the number of visits - * @throws SolrServerException - * Exception from the Solr server to the solrj Java client. + * @throws SolrServerException Exception from the Solr server to the solrj Java client. */ public long getNumberOfVisits(int visitType, Item item) throws SolrServerException { - switch (visitType){ + switch (visitType) { case ITEM_VISITS: - return solrLoggerService.queryTotal("type: " + Constants.ITEM + " AND id: " + item.getID(), resolveFilterQueries()).getCount(); + return solrLoggerService + .queryTotal("type: " + Constants.ITEM + " AND id: " + item.getID(), resolveFilterQueries()) + .getCount(); case BITSTREAM_VISITS: - return solrLoggerService.queryTotal("type: " + Constants.BITSTREAM + " AND owningItem: " + item.getID(), resolveFilterQueries()).getCount(); + return solrLoggerService.queryTotal("type: " + Constants.BITSTREAM + " AND owningItem: " + item.getID(), + resolveFilterQueries()).getCount(); case TOTAL_VISITS: return getNumberOfVisits(ITEM_VISITS, item) + getNumberOfVisits(BITSTREAM_VISITS, item); - + default: + return -1; } - return -1; } - private String resolveFilterQueries(){ + private String resolveFilterQueries() { StringBuilder out = new StringBuilder(); for (int i = 0; i < filters.size(); i++) { StatisticsFilter statisticsFilter = filters.get(i); out.append(statisticsFilter.toQuery()); - if(i != 0 && (i != filters.size() -1)) - { + if (i != 0 && (i != filters.size() - 1)) { out.append(" AND "); } } @@ -111,12 +118,11 @@ public class StatisticsBSAdapter { } - public List getFilters() { return filters; } - public void addFilter(StatisticsFilter filter){ + public void addFilter(StatisticsFilter filter) { this.filters.add(filter); } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsData.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsData.java index 962f0dca77..1b09859362 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsData.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsData.java @@ -7,21 +7,22 @@ */ package org.dspace.statistics.content; +import java.io.IOException; +import java.sql.SQLException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.solr.client.solrj.SolrServerException; +import org.dspace.core.Context; import org.dspace.statistics.Dataset; import org.dspace.statistics.content.filter.StatisticsFilter; -import org.dspace.core.Context; -import org.apache.solr.client.solrj.SolrServerException; import org.dspace.statistics.factory.StatisticsServiceFactory; import org.dspace.statistics.service.SolrLoggerService; -import java.util.List; -import java.util.ArrayList; -import java.sql.SQLException; -import java.io.IOException; -import java.text.ParseException; - /** * Abstract "factory" for statistical queries. + * * @author kevinvandevelde at atmire.com * Date: 23-feb-2009 * Time: 12:37:04 @@ -35,7 +36,9 @@ public abstract class StatisticsData { protected final SolrLoggerService solrLoggerService; - /** Construct a blank query factory. */ + /** + * Construct a blank query factory. + */ protected StatisticsData() { datasetgenerators = new ArrayList(2); filters = new ArrayList(); @@ -45,8 +48,7 @@ public abstract class StatisticsData { /** * Wrap an existing Dataset in an unconfigured query factory. * - * @param dataset - * statistics dataset + * @param dataset statistics dataset */ protected StatisticsData(Dataset dataset) { this.dataset = dataset; @@ -55,25 +57,26 @@ public abstract class StatisticsData { solrLoggerService = StatisticsServiceFactory.getInstance().getSolrLoggerService(); } - /** Augment the list of facets (generators). + /** + * Augment the list of facets (generators). * - * @param set - * generator of statistics datasets + * @param set generator of statistics datasets */ - public void addDatasetGenerator(DatasetGenerator set){ + public void addDatasetGenerator(DatasetGenerator set) { datasetgenerators.add(set); } - /** Augment the list of filters. + /** + * Augment the list of filters. * - * @param filter - * statistics filter + * @param filter statistics filter */ - public void addFilters(StatisticsFilter filter){ + public void addFilters(StatisticsFilter filter) { filters.add(filter); } - /** Return the current list of generators. + /** + * Return the current list of generators. * * @return list of dataset generators */ @@ -81,7 +84,8 @@ public abstract class StatisticsData { return datasetgenerators; } - /** Return the current list of filters. + /** + * Return the current list of filters. * * @return list of dataset filters */ @@ -89,7 +93,8 @@ public abstract class StatisticsData { return filters; } - /** Return the existing query result if there is one. + /** + * Return the existing query result if there is one. * * @return dataset existing query result dataset */ @@ -97,29 +102,26 @@ public abstract class StatisticsData { return dataset; } - /** Jam an existing query result in. + /** + * Jam an existing query result in. * - * @param dataset - * statistics dataset + * @param dataset statistics dataset */ public void setDataset(Dataset dataset) { this.dataset = dataset; } - /** Run the accumulated query and return its results. + /** + * Run the accumulated query and return its results. * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return accumulated query results - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws SolrServerException - * Exception from the Solr server to the solrj Java client. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws ParseException if the dataset cannot be parsed + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws SolrServerException Exception from the Solr server to the solrj Java client. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws ParseException if the dataset cannot be parsed */ public abstract Dataset createDataset(Context context) throws SQLException, - SolrServerException, IOException, ParseException; + SolrServerException, IOException, ParseException; } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataSearches.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataSearches.java index c145f01dc7..a7c20688be 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataSearches.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataSearches.java @@ -7,18 +7,6 @@ */ package org.dspace.statistics.content; -import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.util.ClientUtils; -import org.dspace.content.DSpaceObject; -import org.dspace.core.Context; -import org.dspace.services.factory.DSpaceServicesFactory; -import org.dspace.statistics.Dataset; -import org.dspace.statistics.ObjectCount; -import org.dspace.statistics.SolrLoggerServiceImpl; -import org.dspace.statistics.content.filter.StatisticsFilter; - import java.io.IOException; import java.sql.SQLException; import java.text.DecimalFormat; @@ -26,6 +14,19 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.util.ClientUtils; +import org.dspace.content.DSpaceObject; +import org.dspace.content.DSpaceObjectLegacySupport; +import org.dspace.core.Context; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.dspace.statistics.Dataset; +import org.dspace.statistics.ObjectCount; +import org.dspace.statistics.SolrLoggerServiceImpl; +import org.dspace.statistics.content.filter.StatisticsFilter; + /** * A statistics data implementation that will query the statistics backend for search information * @@ -37,7 +38,9 @@ public class StatisticsDataSearches extends StatisticsData { private static final DecimalFormat pageViewFormat = new DecimalFormat("0.00"); private static final DecimalFormat percentageFormat = new DecimalFormat("0.00%"); - /** Current DSpaceObject for which to generate the statistics. */ + /** + * Current DSpaceObject for which to generate the statistics. + */ protected DSpaceObject currentDso; public StatisticsDataSearches(DSpaceObject dso) { @@ -46,13 +49,12 @@ public class StatisticsDataSearches extends StatisticsData { } - @Override - public Dataset createDataset(Context context) throws SQLException, SolrServerException, IOException, ParseException { + public Dataset createDataset(Context context) + throws SQLException, SolrServerException, IOException, ParseException { // Check if we already have one. // If we do then give it back. - if(getDataset() != null) - { + if (getDataset() != null) { return getDataset(); } @@ -66,25 +68,26 @@ public class StatisticsDataSearches extends StatisticsData { String query = getQuery(); - Dataset dataset = new Dataset(0,0); + Dataset dataset = new Dataset(0, 0); List datasetGenerators = getDatasetGenerators(); - if(0 < datasetGenerators.size()){ + if (0 < datasetGenerators.size()) { //At the moment we can only have one dataset generator DatasetGenerator datasetGenerator = datasetGenerators.get(0); - if(datasetGenerator instanceof DatasetSearchGenerator){ + if (datasetGenerator instanceof DatasetSearchGenerator) { DatasetSearchGenerator typeGenerator = (DatasetSearchGenerator) datasetGenerator; - if(typeGenerator.getMode() == DatasetSearchGenerator.Mode.SEARCH_OVERVIEW){ + if (typeGenerator.getMode() == DatasetSearchGenerator.Mode.SEARCH_OVERVIEW) { StringBuilder fqBuffer = new StringBuilder(defaultFilterQuery); - if(0 < fqBuffer.length()) - { + if (0 < fqBuffer.length()) { fqBuffer.append(" AND "); } fqBuffer.append(getSearchFilterQuery()); - ObjectCount[] topCounts = solrLoggerService.queryFacetField(query, fqBuffer.toString(), typeGenerator.getType(), typeGenerator.getMax(), (typeGenerator.isPercentage() || typeGenerator.isIncludeTotal()), null); + ObjectCount[] topCounts = solrLoggerService + .queryFacetField(query, fqBuffer.toString(), typeGenerator.getType(), typeGenerator.getMax(), + (typeGenerator.isPercentage() || typeGenerator.isIncludeTotal()), null); long totalCount = -1; - if(typeGenerator.isPercentage() && 0 < topCounts.length){ + if (typeGenerator.isPercentage() && 0 < topCounts.length) { //Retrieve the total required to calculate the percentage totalCount = topCounts[topCounts.length - 1].getCount(); //Remove the total count from view ! @@ -92,20 +95,20 @@ public class StatisticsDataSearches extends StatisticsData { } int nrColumns = 2; - if(typeGenerator.isPercentage()){ + if (typeGenerator.isPercentage()) { nrColumns++; } - if(typeGenerator.isRetrievePageViews()){ + if (typeGenerator.isRetrievePageViews()) { nrColumns++; } dataset = new Dataset(topCounts.length, nrColumns); dataset.setColLabel(0, "search-terms"); dataset.setColLabel(1, "searches"); - if(typeGenerator.isPercentage()){ + if (typeGenerator.isPercentage()) { dataset.setColLabel(2, "percent-total"); } - if(typeGenerator.isRetrievePageViews()){ + if (typeGenerator.isRetrievePageViews()) { dataset.setColLabel(3, "views-search"); } for (int i = 0; i < topCounts.length; i++) { @@ -113,34 +116,35 @@ public class StatisticsDataSearches extends StatisticsData { dataset.setRowLabel(i, String.valueOf(i + 1)); String displayedValue = queryCount.getValue(); - if(DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyAsType("usage-statistics.search.statistics.unescape.queries", Boolean.TRUE)){ + if (DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyAsType( + "usage-statistics.search.statistics.unescape.queries", Boolean.TRUE)) { displayedValue = displayedValue.replace("\\", ""); } dataset.addValueToMatrix(i, 0, displayedValue); dataset.addValueToMatrix(i, 1, queryCount.getCount()); - if(typeGenerator.isPercentage()){ + if (typeGenerator.isPercentage()) { //Calculate our percentage from the total ! - dataset.addValueToMatrix(i, 2, percentageFormat.format(((float) queryCount.getCount() / totalCount))); + dataset.addValueToMatrix(i, 2, percentageFormat + .format(((float) queryCount.getCount() / totalCount))); } - if(typeGenerator.isRetrievePageViews()){ + if (typeGenerator.isRetrievePageViews()) { String queryString = ClientUtils.escapeQueryChars(queryCount.getValue()); - if(queryString.equals("")){ + if (queryString.equals("")) { queryString = "\"\""; } ObjectCount totalPageViews = getTotalPageViews("query:" + queryString, defaultFilterQuery); - dataset.addValueToMatrix(i, 3, pageViewFormat.format((float) totalPageViews.getCount() / queryCount.getCount())); + dataset.addValueToMatrix(i, 3, pageViewFormat + .format((float) totalPageViews.getCount() / queryCount.getCount())); } } - }else - if(typeGenerator.getMode() == DatasetSearchGenerator.Mode.SEARCH_OVERVIEW_TOTAL){ + } else if (typeGenerator.getMode() == DatasetSearchGenerator.Mode.SEARCH_OVERVIEW_TOTAL) { //Retrieve the total counts ! ObjectCount totalCount = solrLoggerService.queryTotal(query, getSearchFilterQuery()); //Retrieve the filtered count by using the default filter query StringBuilder fqBuffer = new StringBuilder(defaultFilterQuery); - if(0 < fqBuffer.length()) - { + if (0 < fqBuffer.length()) { fqBuffer.append(" AND "); } fqBuffer.append(getSearchFilterQuery()); @@ -149,11 +153,11 @@ public class StatisticsDataSearches extends StatisticsData { fqBuffer = new StringBuilder(defaultFilterQuery); - if(0 < fqBuffer.length()) - { + if (0 < fqBuffer.length()) { fqBuffer.append(" AND "); } - fqBuffer.append("statistics_type:").append(SolrLoggerServiceImpl.StatisticsType.SEARCH_RESULT.text()); + fqBuffer.append("statistics_type:") + .append(SolrLoggerServiceImpl.StatisticsType.SEARCH_RESULT.text()); ObjectCount totalPageViews = getTotalPageViews(query, defaultFilterQuery); @@ -166,9 +170,9 @@ public class StatisticsDataSearches extends StatisticsData { dataset.setColLabel(1, "percent-total"); //Ensure that we do NOT divide by 0 float percentTotal; - if(totalCount.getCount() == 0){ + if (totalCount.getCount() == 0) { percentTotal = 0; - }else{ + } else { percentTotal = (float) totalFiltered.getCount() / totalCount.getCount(); } @@ -177,16 +181,18 @@ public class StatisticsDataSearches extends StatisticsData { dataset.setColLabel(2, "views-search"); //Ensure that we do NOT divide by 0 float pageViews; - if(totalFiltered.getCount() == 0){ + if (totalFiltered.getCount() == 0) { pageViews = 0; - }else{ + } else { pageViews = (float) totalPageViews.getCount() / totalFiltered.getCount(); } dataset.addValueToMatrix(0, 2, pageViewFormat.format(pageViews)); } - }else{ - throw new IllegalArgumentException("Data generator with class" + datasetGenerator.getClass().getName() + " is not supported by the statistics search engine !"); + } else { + throw new IllegalArgumentException("Data generator with class" + datasetGenerator.getClass() + .getName() + " is " + + "not supported by the statistics search engine !"); } } @@ -196,14 +202,20 @@ public class StatisticsDataSearches extends StatisticsData { /** * Returns the query to be used in solr * in case of a dso a scopeDso query will be returned otherwise the default *:* query will be used + * * @return the query as a string */ protected String getQuery() { String query; - if(currentDso != null){ - query = "scopeType: " + currentDso.getType() + " AND scopeId: " + currentDso.getID(); - - }else{ + if (currentDso != null) { + query = "scopeType: " + currentDso.getType() + " AND "; + if (currentDso instanceof DSpaceObjectLegacySupport) { + query += " (scopeId:" + currentDso.getID() + " OR scopeId:" + ((DSpaceObjectLegacySupport) currentDso) + .getLegacyId() + ")"; + } else { + query += "scopeId:" + currentDso.getID(); + } + } else { query = "*:*"; } return query; @@ -212,8 +224,7 @@ public class StatisticsDataSearches extends StatisticsData { protected ObjectCount getTotalPageViews(String query, String defaultFilterQuery) throws SolrServerException { StringBuilder fqBuffer; fqBuffer = new StringBuilder(defaultFilterQuery); - if(0 < fqBuffer.length()) - { + if (0 < fqBuffer.length()) { fqBuffer.append(" AND "); } fqBuffer.append("statistics_type:").append(SolrLoggerServiceImpl.StatisticsType.SEARCH_RESULT.text()); @@ -226,6 +237,7 @@ public class StatisticsDataSearches extends StatisticsData { /** * Returns a filter query that only allows new searches to pass * new searches are searches that haven't been paged through + * * @return a solr filterquery */ protected String getSearchFilterQuery() { diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java index 2307ebdc1b..cdd0cbbb73 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java @@ -7,14 +7,35 @@ */ package org.dspace.statistics.content; +import java.io.UnsupportedEncodingException; +import java.sql.SQLException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + import org.apache.commons.lang.StringUtils; -import org.dspace.content.*; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.util.ClientUtils; +import org.dspace.app.util.Util; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.DSpaceObjectLegacySupport; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; import org.dspace.statistics.Dataset; @@ -25,17 +46,6 @@ import org.dspace.statistics.content.filter.StatisticsSolrDateFilter; import org.dspace.statistics.factory.StatisticsServiceFactory; import org.dspace.statistics.service.SolrLoggerService; import org.dspace.statistics.util.LocationUtils; -import org.dspace.core.Context; -import org.dspace.core.Constants; -import org.dspace.core.ConfigurationManager; -import org.dspace.app.util.Util; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.util.ClientUtils; - -import java.util.*; -import java.sql.SQLException; -import java.text.ParseException; -import java.io.UnsupportedEncodingException; /** * Query factory associated with a DSpaceObject. @@ -43,21 +53,22 @@ import java.io.UnsupportedEncodingException; *

    * To use: *

      - *
    1. Instantiate, passing a reference to the interesting DSO.
    2. - *
    3. Add a {@link DatasetDSpaceObjectGenerator} for the appropriate object type.
    4. - *
    5. Add other generators as required to get the statistic you want.
    6. - *
    7. Add {@link org.dspace.statistics.content.filter filters} as required.
    8. - *
    9. {@link #createDataset(Context)} will run the query and return a result matrix. - * Subsequent calls skip the query and return the same matrix.
    10. + *
    11. Instantiate, passing a reference to the interesting DSO.
    12. + *
    13. Add a {@link DatasetDSpaceObjectGenerator} for the appropriate object type.
    14. + *
    15. Add other generators as required to get the statistic you want.
    16. + *
    17. Add {@link org.dspace.statistics.content.filter filters} as required.
    18. + *
    19. {@link #createDataset(Context)} will run the query and return a result matrix. + * Subsequent calls skip the query and return the same matrix.
    20. *
    * * @author kevinvandevelde at atmire.com * Date: 23-feb-2009 * Time: 12:25:20 */ -public class StatisticsDataVisits extends StatisticsData -{ - /** Current DSpaceObject for which to generate the statistics. */ +public class StatisticsDataVisits extends StatisticsData { + /** + * Current DSpaceObject for which to generate the statistics. + */ protected DSpaceObject currentDso; protected final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); @@ -67,20 +78,19 @@ public class StatisticsDataVisits extends StatisticsData protected final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); - /** Construct a completely uninitialized query. */ - public StatisticsDataVisits() - { + /** + * Construct a completely uninitialized query. + */ + public StatisticsDataVisits() { super(); } /** * Construct an empty query concerning a given DSpaceObject. * - * @param dso - * the target DSpace object + * @param dso the target DSpace object */ - public StatisticsDataVisits(DSpaceObject dso) - { + public StatisticsDataVisits(DSpaceObject dso) { super(); this.currentDso = dso; } @@ -88,13 +98,10 @@ public class StatisticsDataVisits extends StatisticsData /** * Construct an unconfigured query around a given DSO and Dataset. * - * @param currentDso - * the target DSpace object - * @param dataset - * the target dataset + * @param currentDso the target DSpace object + * @param dataset the target dataset */ - public StatisticsDataVisits(DSpaceObject currentDso, Dataset dataset) - { + public StatisticsDataVisits(DSpaceObject currentDso, Dataset dataset) { super(dataset); this.currentDso = currentDso; } @@ -102,22 +109,18 @@ public class StatisticsDataVisits extends StatisticsData /** * Construct an unconfigured query around a given Dataset. * - * @param dataset - * the target dataset + * @param dataset the target dataset */ - public StatisticsDataVisits(Dataset dataset) - { + public StatisticsDataVisits(Dataset dataset) { super(dataset); } @Override public Dataset createDataset(Context context) throws SQLException, - SolrServerException, ParseException - { + SolrServerException, ParseException { // Check if we already have one. // If we do then give it back. - if (getDataset() != null) - { + if (getDataset() != null) { return getDataset(); } @@ -134,15 +137,11 @@ public class StatisticsDataVisits extends StatisticsData // First check if we have a date facet & if so find it. DatasetTimeGenerator dateFacet = null; if (getDatasetGenerators().get(0) instanceof DatasetTimeGenerator - || (1 < getDatasetGenerators().size() && getDatasetGenerators() - .get(1) instanceof DatasetTimeGenerator)) - { - if (getDatasetGenerators().get(0) instanceof DatasetTimeGenerator) - { + || (1 < getDatasetGenerators().size() && getDatasetGenerators() + .get(1) instanceof DatasetTimeGenerator)) { + if (getDatasetGenerators().get(0) instanceof DatasetTimeGenerator) { dateFacet = (DatasetTimeGenerator) getDatasetGenerators().get(0); - } - else - { + } else { dateFacet = (DatasetTimeGenerator) getDatasetGenerators().get(1); } } @@ -153,26 +152,22 @@ public class StatisticsDataVisits extends StatisticsData boolean showTotal = false; // Check if we need our total if ((getDatasetGenerators().get(0) != null && getDatasetGenerators() - .get(0).isIncludeTotal()) - || (1 < getDatasetGenerators().size() - && getDatasetGenerators().get(1) != null && getDatasetGenerators() - .get(1).isIncludeTotal())) - { + .get(0).isIncludeTotal()) + || (1 < getDatasetGenerators().size() + && getDatasetGenerators().get(1) != null && getDatasetGenerators() + .get(1).isIncludeTotal())) { showTotal = true; } if (dateFacet != null && dateFacet.getActualStartDate() != null - && dateFacet.getActualEndDate() != null) - { + && dateFacet.getActualEndDate() != null) { StatisticsSolrDateFilter dateFilter = new StatisticsSolrDateFilter(); dateFilter.setStartDate(dateFacet.getActualStartDate()); dateFilter.setEndDate(dateFacet.getActualEndDate()); dateFilter.setTypeStr(dateFacet.getDateType()); addFilters(dateFilter); - } - else if (dateFacet != null && dateFacet.getStartDate() != null - && dateFacet.getEndDate() != null) - { + } else if (dateFacet != null && dateFacet.getStartDate() != null + && dateFacet.getEndDate() != null) { StatisticsSolrDateFilter dateFilter = new StatisticsSolrDateFilter(); dateFilter.setStartStr(dateFacet.getStartDate()); dateFilter.setEndStr(dateFacet.getEndDate()); @@ -186,8 +181,7 @@ public class StatisticsDataVisits extends StatisticsData StatisticsFilter filter = getFilters().get(i); filterQuery += "(" + filter.toQuery() + ")"; - if (i != (getFilters().size() -1)) - { + if (i != (getFilters().size() - 1)) { filterQuery += " AND "; } } @@ -196,7 +190,8 @@ public class StatisticsDataVisits extends StatisticsData } //Only use the view type and make sure old data (where no view type is present) is also supported //Solr doesn't explicitly apply boolean logic, so this query cannot be simplified to an OR query - filterQuery += "-(statistics_type:[* TO *] AND -statistics_type:" + SolrLoggerServiceImpl.StatisticsType.VIEW.text() + ")"; + filterQuery += "-(statistics_type:[* TO *] AND -statistics_type:" + SolrLoggerServiceImpl.StatisticsType.VIEW + .text() + ")"; // System.out.println("FILTERQUERY: " + filterQuery); @@ -216,7 +211,9 @@ public class StatisticsDataVisits extends StatisticsData String query = dataSetQuery.getQueries().get(0).getQuery(); if (dataSetQuery.getMax() == -1) { // We are asking from our current query all the visits faceted by date - ObjectCount[] results = solrLoggerService.queryFacetDate(query, filterQuery, dataSetQuery.getMax(), dateFacet.getDateType(), dateFacet.getStartDate(), dateFacet.getEndDate(), showTotal, context); + ObjectCount[] results = solrLoggerService + .queryFacetDate(query, filterQuery, dataSetQuery.getMax(), dateFacet.getDateType(), + dateFacet.getStartDate(), dateFacet.getEndDate(), showTotal, context); dataset = new Dataset(1, results.length); // Now that we have our results put em in a matrix for (int j = 0; j < results.length; j++) { @@ -228,17 +225,22 @@ public class StatisticsDataVisits extends StatisticsData dataset.setRowLabel(0, getResultName(dataSetQuery.getName(), dataSetQuery, context)); dataset.setRowLabelAttr(0, getAttributes(dataSetQuery.getName(), dataSetQuery, context)); } else { - // We need to get the max objects and the next part of the query on them (next part beeing the datasettimequery - ObjectCount[] maxObjectCounts = solrLoggerService.queryFacetField(query, filterQuery, dataSetQuery.getFacetField(), dataSetQuery.getMax(), false, null); + // We need to get the max objects and the next part of the query on them (next part beeing + // the datasettimequery + ObjectCount[] maxObjectCounts = solrLoggerService + .queryFacetField(query, filterQuery, dataSetQuery.getFacetField(), dataSetQuery.getMax(), + false, null); for (int j = 0; j < maxObjectCounts.length; j++) { ObjectCount firstCount = maxObjectCounts[j]; - String newQuery = dataSetQuery.getFacetField() + ": " + ClientUtils.escapeQueryChars(firstCount.getValue()) + " AND " + query; - ObjectCount[] maxDateFacetCounts = solrLoggerService.queryFacetDate(newQuery, filterQuery, dataSetQuery.getMax(), dateFacet.getDateType(), dateFacet.getStartDate(), dateFacet.getEndDate(), showTotal, context); + String newQuery = dataSetQuery.getFacetField() + ": " + ClientUtils + .escapeQueryChars(firstCount.getValue()) + " AND " + query; + ObjectCount[] maxDateFacetCounts = solrLoggerService + .queryFacetDate(newQuery, filterQuery, dataSetQuery.getMax(), dateFacet.getDateType(), + dateFacet.getStartDate(), dateFacet.getEndDate(), showTotal, context); // Make sure we have a dataSet - if (dataset == null) - { + if (dataset == null) { dataset = new Dataset(maxObjectCounts.length, maxDateFacetCounts.length); } @@ -249,8 +251,7 @@ public class StatisticsDataVisits extends StatisticsData for (int k = 0; k < maxDateFacetCounts.length; k++) { ObjectCount objectCount = maxDateFacetCounts[k]; // No need to add this many times - if (j == 0) - { + if (j == 0) { dataset.setColLabel(k, objectCount.getValue()); } dataset.addValueToMatrix(j, k, objectCount.getCount()); @@ -289,14 +290,16 @@ public class StatisticsDataVisits extends StatisticsData if (datasetQueries.size() == 2) { DatasetQuery secondDataSet = datasetQueries.get(1); // Now do the second one - ObjectCount[] topCounts2 = queryFacetField(secondDataSet, secondDataSet.getQueries().get(0).getQuery(), filterQuery); + ObjectCount[] topCounts2 = queryFacetField(secondDataSet, secondDataSet.getQueries().get(0).getQuery(), + filterQuery); // Now that have results for both of them lets do x.y queries List facetQueries = new ArrayList(); for (ObjectCount count2 : topCounts2) { - String facetQuery = secondDataSet.getFacetField() + ":" + ClientUtils.escapeQueryChars(count2.getValue()); + String facetQuery = secondDataSet.getFacetField() + ":" + ClientUtils + .escapeQueryChars(count2.getValue()); // Check if we also have a type present (if so this should be put into the query) - if ("id".equals(secondDataSet.getFacetField()) && secondDataSet.getQueries().get(0).getDsoType() != -1) - { + if ("id".equals(secondDataSet.getFacetField()) && secondDataSet.getQueries().get(0) + .getDsoType() != -1) { facetQuery += " AND type:" + secondDataSet.getQueries().get(0).getDsoType(); } @@ -307,8 +310,7 @@ public class StatisticsDataVisits extends StatisticsData ObjectCount[] currentResult = new ObjectCount[topCounts2.length]; // Make sure we have a dataSet - if (dataset == null) - { + if (dataset == null) { dataset = new Dataset(topCounts2.length, topCounts1.length); } dataset.setColLabel(i, getResultName(count1.getValue(), firsDataset, context)); @@ -316,14 +318,15 @@ public class StatisticsDataVisits extends StatisticsData String query = firsDataset.getFacetField() + ":" + ClientUtils.escapeQueryChars(count1.getValue()); // Check if we also have a type present (if so this should be put into the query) - if ("id".equals(firsDataset.getFacetField()) && firsDataset.getQueries().get(0).getDsoType() != -1) - { + if ("id".equals(firsDataset.getFacetField()) && firsDataset.getQueries().get(0) + .getDsoType() != -1) { query += " AND type:" + firsDataset.getQueries().get(0).getDsoType(); } - Map facetResult = solrLoggerService.queryFacetQuery(query, filterQuery, facetQueries); - - + Map facetResult = solrLoggerService + .queryFacetQuery(query, filterQuery, facetQueries); + + // TODO: the show total // No need to add this many times // TODO: dit vervangen door te displayen value @@ -335,10 +338,11 @@ public class StatisticsDataVisits extends StatisticsData } // Get our value the value is the same as the query - String facetQuery = secondDataSet.getFacetField() + ":" + ClientUtils.escapeQueryChars(count2.getValue()); + String facetQuery = secondDataSet.getFacetField() + ":" + ClientUtils + .escapeQueryChars(count2.getValue()); // Check if we also have a type present (if so this should be put into the query - if ("id".equals(secondDataSet.getFacetField()) && secondDataSet.getQueries().get(0).getDsoType() != -1) - { + if ("id".equals(secondDataSet.getFacetField()) && secondDataSet.getQueries().get(0) + .getDsoType() != -1) { facetQuery += " AND type:" + secondDataSet.getQueries().get(0).getDsoType(); } @@ -351,12 +355,14 @@ public class StatisticsDataVisits extends StatisticsData ObjectCount count2 = topCounts2[j]; String query = firsDataset.getFacetField() + ":" + count1.getValue(); // Check if we also have a type present (if so this should be put into the query - if ("id".equals(firsDataset.getFacetField()) && firsDataset.getQueries().get(0).getDsoType() != -1) + if ("id".equals(firsDataset.getFacetField()) && firsDataset.getQueries().get(0).getDsoType() + != -1) query += " AND type:" + firsDataset.getQueries().get(0).getDsoType(); query += " AND " + secondDataSet.getFacetField() + ":" + count2.getValue(); // Check if we also have a type present (if so this should be put into the query - if ("id".equals(secondDataSet.getFacetField()) && secondDataSet.getQueries().get(0).getDsoType() != -1) + if ("id".equals(secondDataSet.getFacetField()) && secondDataSet.getQueries().get(0) + .getDsoType() != -1) query += " AND type:" + secondDataSet.getQueries().get(0).getDsoType(); long count = SolrLogger.queryFacetQuery(query, filterQuery); @@ -392,14 +398,14 @@ public class StatisticsDataVisits extends StatisticsData if (dataset != null) { dataset.setRowTitle("Dataset 1"); dataset.setColTitle("Dataset 2"); - } else - { + } else { dataset = new Dataset(0, 0); } return dataset; } - protected void processAxis(Context context, DatasetGenerator datasetGenerator, List queries) throws SQLException { + protected void processAxis(Context context, DatasetGenerator datasetGenerator, List queries) + throws SQLException { if (datasetGenerator instanceof DatasetDSpaceObjectGenerator) { DatasetDSpaceObjectGenerator dspaceObjAxis = (DatasetDSpaceObjectGenerator) datasetGenerator; // Get the types involved @@ -451,6 +457,8 @@ public class StatisticsDataVisits extends StatisticsData case Constants.COMMUNITY: title = "Communities"; break; + default: + break; } datasetQuery.setName(title); // Put the type in so we only get the children of the type specified @@ -463,15 +471,13 @@ public class StatisticsDataVisits extends StatisticsData queries.add(datasetQuery); } - } else - if (datasetGenerator instanceof DatasetTypeGenerator) { + } else if (datasetGenerator instanceof DatasetTypeGenerator) { DatasetTypeGenerator typeAxis = (DatasetTypeGenerator) datasetGenerator; DatasetQuery datasetQuery = new DatasetQuery(); // First make sure our query is in order Query query = new Query(); - if (currentDso != null) - { + if (currentDso != null) { query.setDso(currentDso, currentDso.getType()); } datasetQuery.addQuery(query); @@ -488,30 +494,28 @@ public class StatisticsDataVisits extends StatisticsData /** * Gets the name of the DSO (example for collection: ((Collection) dso).getname(); * - * @param value - * UUID (or legacy record ID) of the DSO in question. - * @param datasetQuery - * FIXME: PLEASE DOCUMENT. - * @param context - * The relevant DSpace Context. + * @param value UUID (or legacy record ID) of the DSO in question. + * @param datasetQuery FIXME: PLEASE DOCUMENT. + * @param context The relevant DSpace Context. * @return the name of the given DSO - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ protected String getResultName(String value, DatasetQuery datasetQuery, - Context context) throws SQLException - { + Context context) throws SQLException { if ("continent".equals(datasetQuery.getName())) { value = LocationUtils.getContinentName(value, context - .getCurrentLocale()); + .getCurrentLocale()); } else if ("countryCode".equals(datasetQuery.getName())) { value = LocationUtils.getCountryName(value, context - .getCurrentLocale()); + .getCurrentLocale()); } else { Query query = datasetQuery.getQueries().get(0); //TODO: CHANGE & THROW AWAY THIS ENTIRE METHOD //Check if int String dsoId; + //DS 3602: Until all legacy stats records have been upgraded to using UUID, + //duplicate reports may be presented for each DSO. A note will be appended when reporting legacy counts. + String legacyNote = ""; int dsoLength = query.getDsoLength(); try { dsoId = UUID.fromString(value).toString(); @@ -519,12 +523,12 @@ public class StatisticsDataVisits extends StatisticsData try { //Legacy identifier support dsoId = String.valueOf(Integer.parseInt(value)); + legacyNote = "(legacy)"; } catch (NumberFormatException e1) { dsoId = null; } } - if (dsoId == null && query.getDso() != null && value == null) - { + if (dsoId == null && query.getDso() != null && value == null) { dsoId = query.getDso().getID().toString(); } @@ -532,21 +536,18 @@ public class StatisticsDataVisits extends StatisticsData switch (query.getDsoType()) { case Constants.BITSTREAM: Bitstream bit = bitstreamService.findByIdOrLegacyId(context, dsoId); - if (bit == null) - { + if (bit == null) { break; } - return value; + return bit.getName() + legacyNote; case Constants.ITEM: Item item = itemService.findByIdOrLegacyId(context, dsoId); - if (item == null) - { + if (item == null) { break; } String name = "untitled"; List vals = itemService.getMetadata(item, "dc", "title", null, Item.ANY); - if (vals != null && 0 < vals.size()) - { + if (vals != null && 0 < vals.size()) { name = vals.get(0).getValue(); } if (dsoLength != -1 && name.length() > dsoLength) { @@ -557,12 +558,11 @@ public class StatisticsDataVisits extends StatisticsData } } - return name; + return name + legacyNote; case Constants.COLLECTION: Collection coll = collectionService.findByIdOrLegacyId(context, dsoId); - if (coll == null) - { + if (coll == null) { break; } name = coll.getName(); @@ -574,12 +574,11 @@ public class StatisticsDataVisits extends StatisticsData name = name.substring(0, firstSpace) + " ..."; } } - return name; + return name + legacyNote; case Constants.COMMUNITY: Community comm = communityService.findByIdOrLegacyId(context, dsoId); - if (comm == null) - { + if (comm == null) { break; } name = comm.getName(); @@ -591,7 +590,9 @@ public class StatisticsDataVisits extends StatisticsData name = name.substring(0, firstSpace) + " ..."; } } - return name; + return name + legacyNote; + default: + break; } } } @@ -599,8 +600,7 @@ public class StatisticsDataVisits extends StatisticsData } protected Map getAttributes(String value, - DatasetQuery datasetQuery, Context context) throws SQLException - { + DatasetQuery datasetQuery, Context context) throws SQLException { HashMap attrs = new HashMap(); Query query = datasetQuery.getQueries().get(0); //TODO: CHANGE & THROW AWAY THIS ENTIRE METHOD @@ -608,7 +608,7 @@ public class StatisticsDataVisits extends StatisticsData String dsoId; try { dsoId = UUID.fromString(value).toString(); - }catch (Exception e) { + } catch (Exception e) { try { //Legacy identifier support dsoId = String.valueOf(Integer.parseInt(value)); @@ -616,8 +616,7 @@ public class StatisticsDataVisits extends StatisticsData dsoId = null; } } - if (dsoId == null && query.getDso() != null && value == null) - { + if (dsoId == null && query.getDso() != null && value == null) { dsoId = query.getDso().getID().toString(); } @@ -625,16 +624,14 @@ public class StatisticsDataVisits extends StatisticsData switch (query.dsoType) { case Constants.BITSTREAM: Bitstream bit = bitstreamService.findByIdOrLegacyId(context, dsoId); - if (bit == null) - { + if (bit == null) { break; } //Get our owning item Item owningItem = null; List bunds = bit.getBundles(); - if (0 < bunds.size() && 0 < bunds.get(0).getItems().size()) - { + if (0 < bunds.size() && 0 < bunds.get(0).getItems().size()) { owningItem = bunds.get(0).getItems().get(0); } @@ -643,47 +640,37 @@ public class StatisticsDataVisits extends StatisticsData // item its internal id. In the last case where the bitstream is not associated // with an item (such as a community logo) then reference the bitstreamID directly. String identifier = null; - if (owningItem != null && owningItem.getHandle() != null) - { + if (owningItem != null && owningItem.getHandle() != null) { identifier = "handle/" + owningItem.getHandle(); - } - else if (owningItem != null) - { + } else if (owningItem != null) { identifier = "item/" + owningItem.getID(); - } - else - { + } else { identifier = "id/" + bit.getID(); } - String url = ConfigurationManager.getProperty("dspace.url") + "/bitstream/"+identifier+"/"; + String url = ConfigurationManager.getProperty("dspace.url") + "/bitstream/" + identifier + "/"; // If we can put the pretty name of the bitstream on the end of the URL - try - { - if (bit.getName() != null) - { + try { + if (bit.getName() != null) { url += Util.encodeBitstreamName(bit.getName(), "UTF-8"); } - } - catch (UnsupportedEncodingException uee) - { + } catch (UnsupportedEncodingException uee) { // Just ignore it: we don't have to have a pretty // name on the end of the URL because the sequence id will // locate it. However it means that links in this file might // not work.... } - url += "?sequence="+bit.getSequenceID(); + url += "?sequence=" + bit.getSequenceID(); attrs.put("url", url); break; case Constants.ITEM: Item item = itemService.findByIdOrLegacyId(context, dsoId); - if (item == null) - { + if (item == null) { break; } @@ -692,8 +679,7 @@ public class StatisticsDataVisits extends StatisticsData case Constants.COLLECTION: Collection coll = collectionService.findByIdOrLegacyId(context, dsoId); - if (coll == null) - { + if (coll == null) { break; } @@ -702,13 +688,14 @@ public class StatisticsDataVisits extends StatisticsData case Constants.COMMUNITY: Community comm = communityService.findByIdOrLegacyId(context, dsoId); - if (comm == null) - { + if (comm == null) { break; } attrs.put("url", handleService.resolveToURL(context, comm.getHandle())); break; + default: + break; } } return attrs; @@ -716,12 +703,11 @@ public class StatisticsDataVisits extends StatisticsData protected ObjectCount[] queryFacetField(DatasetQuery dataset, String query, - String filterQuery) throws SolrServerException - { + String filterQuery) throws SolrServerException { String facetType = dataset.getFacetField() == null ? "id" : dataset - .getFacetField(); + .getFacetField(); return solrLoggerService.queryFacetField(query, filterQuery, facetType, - dataset.getMax(), false, null); + dataset.getMax(), false, null); } public static class DatasetQuery { @@ -768,102 +754,110 @@ public class StatisticsDataVisits extends StatisticsData } public class Query { - private int dsoType; - private DSpaceObject dso; - private int dsoLength; - private DSpaceObject owningDso; + private int dsoType; + private DSpaceObject dso; + private int dsoLength; + private DSpaceObject owningDso; - public Query() { - dso = null; - dsoType = -1; - dso = null; - owningDso = null; - } - - public void setOwningDso(DSpaceObject owningDso) { - this.owningDso = owningDso; - } - - public void setDso(DSpaceObject dso, int dsoType) { - this.dso = dso; - this.dsoType = dsoType; - } - - public void setDso(DSpaceObject dso, int dsoType, int length) { - this.dsoType = dsoType; - this.dso = dso; - } - - public void setDsoType(int dsoType) { - this.dsoType = dsoType; - } - - - public int getDsoLength() { - return dsoLength; - } - - - public void setDsoLength(int dsoLength) { - this.dsoLength = dsoLength; - } - - public int getDsoType() { - return dsoType; - } - - public DSpaceObject getDso() { - return dso; - } - - public String getQuery() { - //Time to construct our query - String query = ""; - //Check (& add if needed) the dsoType - if (dsoType != -1) - { - query += "type: " + dsoType; - } - - //Check (& add if needed) the dsoId - if (dso != null) - { - query += (query.equals("") ? "" : " AND "); - if (dso instanceof DSpaceObjectLegacySupport) { - query += " (id:" + dso.getID() + " OR " + ((DSpaceObjectLegacySupport) dso).getLegacyId() + ")"; - } else { - query += "id:" + dso.getID(); - } - } - - - if (owningDso != null && currentDso != null) { - query += (query.equals("") ? "" : " AND " ); - - String owningStr = ""; - switch (currentDso.getType()) { - case Constants.ITEM: - owningStr = "owningItem"; - break; - case Constants.COLLECTION: - owningStr = "owningColl"; - break; - case Constants.COMMUNITY: - owningStr = "owningComm"; - break; - } - owningStr += ":" + currentDso.getID(); - query += owningStr; - } - - if (query.equals("")) - { - query = "*:*"; - } - - return query; - } + public Query() { + dso = null; + dsoType = -1; + dso = null; + owningDso = null; } + public void setOwningDso(DSpaceObject owningDso) { + this.owningDso = owningDso; + } + + public void setDso(DSpaceObject dso, int dsoType) { + this.dso = dso; + this.dsoType = dsoType; + } + + public void setDso(DSpaceObject dso, int dsoType, int length) { + this.dsoType = dsoType; + this.dso = dso; + } + + public void setDsoType(int dsoType) { + this.dsoType = dsoType; + } + + + public int getDsoLength() { + return dsoLength; + } + + + public void setDsoLength(int dsoLength) { + this.dsoLength = dsoLength; + } + + public int getDsoType() { + return dsoType; + } + + public DSpaceObject getDso() { + return dso; + } + + public String getQuery() { + //Time to construct our query + String query = ""; + //Check (& add if needed) the dsoType + if (dsoType != -1) { + query += "type: " + dsoType; + } + + //Check (& add if needed) the dsoId + if (dso != null) { + query += (query.equals("") ? "" : " AND "); + + //DS-3602: For clarity, adding "id:" to the right hand side of the search + //In the solr schema, "id" has been declared as the defaultSearchField so the field name is optional + if (dso instanceof DSpaceObjectLegacySupport) { + query += " (id:" + dso.getID() + " OR id:" + ((DSpaceObjectLegacySupport) dso).getLegacyId() + ")"; + } else { + query += "id:" + dso.getID(); + } + } + + + if (owningDso != null && currentDso != null) { + query += (query.equals("") ? "" : " AND "); + + String owningStr = ""; + switch (currentDso.getType()) { + case Constants.ITEM: + owningStr = "owningItem"; + break; + case Constants.COLLECTION: + owningStr = "owningColl"; + break; + case Constants.COMMUNITY: + owningStr = "owningComm"; + break; + default: + break; + } + if (currentDso instanceof DSpaceObjectLegacySupport) { + owningStr = "(" + owningStr + ":" + currentDso.getID() + " OR " + + owningStr + ":" + ((DSpaceObjectLegacySupport) currentDso).getLegacyId() + ")"; + } else { + owningStr += ":" + currentDso.getID(); + } + + query += owningStr; + } + + if (query.equals("")) { + query = "*:*"; + } + + return query; + } + } + } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataWorkflow.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataWorkflow.java index 7986df7a31..3d2719faa7 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataWorkflow.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataWorkflow.java @@ -7,6 +7,16 @@ */ package org.dspace.statistics.content; +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.lang.StringUtils; @@ -25,12 +35,6 @@ import org.dspace.statistics.ObjectCount; import org.dspace.statistics.SolrLoggerServiceImpl; import org.dspace.statistics.content.filter.StatisticsFilter; -import java.io.File; -import java.io.IOException; -import java.sql.SQLException; -import java.text.ParseException; -import java.util.*; - /** * A workflow data implementation that will query the statistics backend for workflow information * @@ -42,9 +46,13 @@ public class StatisticsDataWorkflow extends StatisticsData { private static final Logger log = Logger.getLogger(StatisticsDataWorkflow.class); - /** Current DSpaceObject for which to generate the statistics. */ + /** + * Current DSpaceObject for which to generate the statistics. + */ private DSpaceObject currentDso; - /** Variable used to indicate of how many months an average is required (-1 is inactive) **/ + /** + * Variable used to indicate of how many months an average is required (-1 is inactive) + **/ private int averageMonths = -1; public StatisticsDataWorkflow(DSpaceObject dso, int averageMonths) { @@ -55,11 +63,11 @@ public class StatisticsDataWorkflow extends StatisticsData { @Override - public Dataset createDataset(Context context) throws SQLException, SolrServerException, IOException, ParseException { - // Check if we already have one. + public Dataset createDataset(Context context) + throws SQLException, SolrServerException, IOException, ParseException { + // Check if we already have one. // If we do then give it back. - if(getDataset() != null) - { + if (getDataset() != null) { return getDataset(); } @@ -73,29 +81,31 @@ public class StatisticsDataWorkflow extends StatisticsData { String query = getQuery(); - Dataset dataset = new Dataset(0,0); + Dataset dataset = new Dataset(0, 0); List datasetGenerators = getDatasetGenerators(); - if(0 < datasetGenerators.size()){ + if (0 < datasetGenerators.size()) { //At the moment we can only have one dataset generator DatasetGenerator datasetGenerator = datasetGenerators.get(0); - if(datasetGenerator instanceof DatasetTypeGenerator){ + if (datasetGenerator instanceof DatasetTypeGenerator) { DatasetTypeGenerator typeGenerator = (DatasetTypeGenerator) datasetGenerator; - ObjectCount[] topCounts = solrLoggerService.queryFacetField(query, defaultFilterQuery, typeGenerator.getType(), typeGenerator.getMax(), typeGenerator.isIncludeTotal(), null); + ObjectCount[] topCounts = solrLoggerService + .queryFacetField(query, defaultFilterQuery, typeGenerator.getType(), typeGenerator.getMax(), + typeGenerator.isIncludeTotal(), null); //Retrieve our total field counts Map totalFieldCounts = new HashMap(); - if(averageMonths != -1){ + if (averageMonths != -1) { totalFieldCounts = getTotalFacetCounts(typeGenerator); } long monthDifference = 1; - if(getOldestWorkflowItemDate() != null){ + if (getOldestWorkflowItemDate() != null) { monthDifference = getMonthsDifference(new Date(), getOldestWorkflowItemDate()); } dataset = new Dataset(topCounts.length, (averageMonths != -1 ? 3 : 2)); dataset.setColLabel(0, "step"); dataset.setColLabel(1, "performed"); - if(averageMonths != -1){ + if (averageMonths != -1) { dataset.setColLabel(2, "average"); } for (int i = 0; i < topCounts.length; i++) { @@ -103,10 +113,10 @@ public class StatisticsDataWorkflow extends StatisticsData { dataset.setRowLabel(i, String.valueOf(i + 1)); dataset.addValueToMatrix(i, 0, topCount.getValue()); dataset.addValueToMatrix(i, 1, topCount.getCount()); - if(averageMonths != -1){ + if (averageMonths != -1) { //Calculate the average of one month long monthlyAverage = 0; - if(totalFieldCounts.get(topCount.getValue()) != null){ + if (totalFieldCounts.get(topCount.getValue()) != null) { monthlyAverage = totalFieldCounts.get(topCount.getValue()) / monthDifference; } //We multiple our average for one month by the number of @@ -123,17 +133,17 @@ public class StatisticsDataWorkflow extends StatisticsData { /** * Returns the query to be used in solr * in case of a dso a scopeDso query will be returned otherwise the default *:* query will be used + * * @return the query as a string */ protected String getQuery() { String query = "statistics_type:" + SolrLoggerServiceImpl.StatisticsType.WORKFLOW.text(); query += " AND NOT(previousWorkflowStep: SUBMIT)"; - if(currentDso != null){ - if(currentDso.getType() == Constants.COMMUNITY){ + if (currentDso != null) { + if (currentDso.getType() == Constants.COMMUNITY) { query += " AND owningComm:"; - }else - if(currentDso.getType() == Constants.COLLECTION){ + } else if (currentDso.getType() == Constants.COLLECTION) { query += " AND owningColl:"; } query += currentDso.getID(); @@ -150,12 +160,14 @@ public class StatisticsDataWorkflow extends StatisticsData { /** * Retrieve the total counts for the facets (total count is same query but none of the filter queries). + * * @param typeGenerator the type generator * @return counts for each facet by name. * @throws org.apache.solr.client.solrj.SolrServerException passed through. */ protected Map getTotalFacetCounts(DatasetTypeGenerator typeGenerator) throws SolrServerException { - ObjectCount[] objectCounts = solrLoggerService.queryFacetField(getQuery(), null, typeGenerator.getType(), -1, false, null); + ObjectCount[] objectCounts = solrLoggerService + .queryFacetField(getQuery(), null, typeGenerator.getType(), -1, false, null); Map result = new HashMap(); for (ObjectCount objectCount : objectCounts) { result.put(objectCount.getValue(), objectCount.getCount()); @@ -164,22 +176,24 @@ public class StatisticsDataWorkflow extends StatisticsData { } - protected Date getOldestWorkflowItemDate() throws SolrServerException { ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); String workflowStartDate = configurationService.getProperty("usage-statistics.workflow-start-date"); - if(workflowStartDate == null){ + if (workflowStartDate == null) { //Query our solr for it ! - QueryResponse oldestRecord = solrLoggerService.query(getQuery(), null, null, 1, 0, null, null, null, null, "time", true); - if(0 < oldestRecord.getResults().getNumFound()){ + QueryResponse oldestRecord = solrLoggerService + .query(getQuery(), null, null, 1, 0, null, null, null, null, "time", true); + if (0 < oldestRecord.getResults().getNumFound()) { SolrDocument solrDocument = oldestRecord.getResults().get(0); Date oldestDate = (Date) solrDocument.getFieldValue("time"); //Store the date, we only need to retrieve this once ! try { - //Also store it in the solr-statics configuration file, the reason for this being that the sort query - //can be very time consuming & we do not want this delay each time we want to see workflow statistics + //Also store it in the solr-statics configuration file, the reason for this being that the sort + // query + //can be very time consuming & we do not want this delay each time we want to see workflow + // statistics String solrConfigDir = configurationService.getProperty("dspace.dir") + File.separator + "config" - + File.separator + "modules" + File.separator + "usage-statistics.cfg"; + + File.separator + "modules" + File.separator + "usage-statistics.cfg"; PropertiesConfiguration config = new PropertiesConfiguration(solrConfigDir); config.setProperty("workflow-start-date", new DCDate(oldestDate)); config.save(); @@ -187,15 +201,16 @@ public class StatisticsDataWorkflow extends StatisticsData { log.error("Error while storing workflow start date", e); } //Also store it in our local config ! - configurationService.setProperty("usage-statistics.workflow-start-date", new DCDate(oldestDate).toString()); + configurationService + .setProperty("usage-statistics.workflow-start-date", new DCDate(oldestDate).toString()); //Write to file return oldestDate; - }else{ + } else { return null; } - }else{ + } else { return new DCDate(workflowStartDate).toDate(); } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDisplay.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDisplay.java index 586916d2e3..9bd54c189f 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDisplay.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDisplay.java @@ -24,18 +24,18 @@ import org.dspace.statistics.content.filter.StatisticsFilter; * @author kevinvandevelde at atmire.com * Date: 23-dec-2008 * Time: 9:27:09 - * */ public abstract class StatisticsDisplay { private String id; private StatisticsData statisticsData; private String title; - /** css information used to position the display object in a html page**/ + /** + * css information used to position the display object in a html page + **/ private List css; - public void setTitle(String title) { this.title = title; } @@ -44,25 +44,24 @@ public abstract class StatisticsDisplay { return title; } - protected StatisticsDisplay(StatisticsData statisticsData){ + protected StatisticsDisplay(StatisticsData statisticsData) { this.statisticsData = statisticsData; } - public List getDatasetGenerators() { return statisticsData.getDatasetGenerators(); } - public void addDatasetGenerator(DatasetGenerator set){ + public void addDatasetGenerator(DatasetGenerator set) { statisticsData.addDatasetGenerator(set); } - public void addFilter(StatisticsFilter filter){ + public void addFilter(StatisticsFilter filter) { statisticsData.addFilters(filter); } - public List getFilters(){ + public List getFilters() { return statisticsData.getFilters(); } @@ -79,7 +78,7 @@ public abstract class StatisticsDisplay { } public abstract String getType(); - + public Dataset getDataset() { return statisticsData.getDataset(); } @@ -88,10 +87,9 @@ public abstract class StatisticsDisplay { return statisticsData.createDataset(context); } - public void addCss(String style){ + public void addCss(String style) { if (style != null) { - if (css == null) - { + if (css == null) { css = new ArrayList(); } css.add(style.trim()); @@ -103,8 +101,7 @@ public abstract class StatisticsDisplay { StringBuilder result = new StringBuilder(); for (String s : css) { result.append(s); - if (!s.endsWith(";")) - { + if (!s.endsWith(";")) { result.append(";"); } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsListing.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsListing.java index 794fcaebcf..a0a3a8e429 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsListing.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsListing.java @@ -10,20 +10,19 @@ package org.dspace.statistics.content; /** * Encapsulates all data to render the statistics as a list - * + * * @author kevinvandevelde at atmire.com * Date: 23-dec-2008 * Time: 12:38:58 - * */ public class StatisticsListing extends StatisticsDisplay { - public StatisticsListing(StatisticsData statisticsData){ + public StatisticsListing(StatisticsData statisticsData) { super(statisticsData); } @Override - public String getType() { - return "listing"; - } + public String getType() { + return "listing"; + } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsTable.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsTable.java index 1573630bfb..1161ac29e6 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsTable.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsTable.java @@ -14,16 +14,15 @@ package org.dspace.statistics.content; * @author kevinvandevelde at atmire.com * Date: 23-dec-2008 * Time: 9:27:52 - * */ -public class StatisticsTable extends StatisticsDisplay{ +public class StatisticsTable extends StatisticsDisplay { - public StatisticsTable(StatisticsData statisticsData){ + public StatisticsTable(StatisticsData statisticsData) { super(statisticsData); } - + @Override - public String getType() { - return "table"; - } + public String getType() { + return "table"; + } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/filter/StatisticsFilter.java b/dspace-api/src/main/java/org/dspace/statistics/content/filter/StatisticsFilter.java index 848e7b3d86..c4cbb4e3a4 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/filter/StatisticsFilter.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/filter/StatisticsFilter.java @@ -9,13 +9,16 @@ package org.dspace.statistics.content.filter; /** * A wrapper for some kind of Solr filter expression. + * * @author kevinvandevelde at atmire.com * Date: 12-mrt-2009 * Time: 10:36:03 */ public interface StatisticsFilter { - /** Convert this filter's configuration to a query string fragment. + /** + * Convert this filter's configuration to a query string fragment. + * * @return a query fragment. */ public String toQuery(); diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/filter/StatisticsSolrDateFilter.java b/dspace-api/src/main/java/org/dspace/statistics/content/filter/StatisticsSolrDateFilter.java index a8ded06e62..b25cbd358c 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/filter/StatisticsSolrDateFilter.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/filter/StatisticsSolrDateFilter.java @@ -7,15 +7,15 @@ */ package org.dspace.statistics.content.filter; -import org.dspace.statistics.SolrLoggerServiceImpl; - import java.text.SimpleDateFormat; -import java.util.Date; import java.util.Calendar; +import java.util.Date; + +import org.dspace.statistics.SolrLoggerServiceImpl; /** * Encapsulate a range of dates for Solr query filtering. - * + * * @author Kevin Van de Velde (kevin at atmire dot com) */ public class StatisticsSolrDateFilter implements StatisticsFilter { @@ -30,12 +30,11 @@ public class StatisticsSolrDateFilter implements StatisticsFilter { } /** - * Set the start date as a string expression. - * - * @param startStr - * statistics start date as a string + * Set the start date as a string expression. * - * Must be paired with {@link #setEndStr(String)}. + * @param startStr statistics start date as a string + * + * Must be paired with {@link #setEndStr(String)}. */ public void setStartStr(String startStr) { this.startStr = startStr; @@ -43,11 +42,10 @@ public class StatisticsSolrDateFilter implements StatisticsFilter { /** * Set the end date as a string expression. - * - * @param endStr - * statistics end date as a string * - * Must be paired with {@link #setStartStr(String)}. + * @param endStr statistics end date as a string + * + * Must be paired with {@link #setStartStr(String)}. */ public void setEndStr(String endStr) { this.endStr = endStr; @@ -56,8 +54,7 @@ public class StatisticsSolrDateFilter implements StatisticsFilter { /** * Set the range granularity: DAY, MONTH, or YEAR. * - * @param typeStr - * which granularity (case insensitive string: "day" / "month" / "year") + * @param typeStr which granularity (case insensitive string: "day" / "month" / "year") */ public void setTypeStr(String typeStr) { this.typeStr = typeStr; @@ -65,11 +62,10 @@ public class StatisticsSolrDateFilter implements StatisticsFilter { /** * Set the start date as a Date object. - * - * @param startDate - * statistics start date object * - * Must be paired with {@link #setEndDate(Date)}. + * @param startDate statistics start date object + * + * Must be paired with {@link #setEndDate(Date)}. */ public void setStartDate(Date startDate) { this.startDate = (startDate == null ? null : new Date(startDate.getTime())); @@ -77,11 +73,10 @@ public class StatisticsSolrDateFilter implements StatisticsFilter { /** * Set the end date as a Date object. - * - * @param endDate - * statistics end date object * - * Must be paired with {@link #setStartDate(Date)}. + * @param endDate statistics end date object + * + * Must be paired with {@link #setStartDate(Date)}. */ public void setEndDate(Date endDate) { this.endDate = (endDate == null ? null : new Date(endDate.getTime())); @@ -89,6 +84,7 @@ public class StatisticsSolrDateFilter implements StatisticsFilter { /** * Convert the date range to a filter expression. + * * @return Solr date filter expression */ @Override @@ -113,17 +109,14 @@ public class StatisticsSolrDateFilter implements StatisticsFilter { startCal.clear(Calendar.MONTH); startCal.set(Calendar.DATE, 1); dateType = Calendar.YEAR; - } else - { + } else { return ""; } Calendar endCal = (Calendar) startCal.clone(); - if (startDate == null) - { - if (startStr.startsWith("+")) - { + if (startDate == null) { + if (startStr.startsWith("+")) { startStr = startStr.substring(startStr.indexOf('+') + 1); } @@ -131,10 +124,8 @@ public class StatisticsSolrDateFilter implements StatisticsFilter { startDate = startCal.getTime(); } - if (endDate == null) - { - if (endStr.startsWith("+")) - { + if (endDate == null) { + if (endStr.startsWith("+")) { endStr = endStr.substring(endStr.indexOf('+') + 1); } diff --git a/dspace-api/src/main/java/org/dspace/statistics/factory/StatisticsServiceFactory.java b/dspace-api/src/main/java/org/dspace/statistics/factory/StatisticsServiceFactory.java index d5ab29ddb2..13f0dd7132 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/factory/StatisticsServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/statistics/factory/StatisticsServiceFactory.java @@ -8,12 +8,12 @@ package org.dspace.statistics.factory; import org.dspace.services.factory.DSpaceServicesFactory; -import org.dspace.statistics.service.ElasticSearchLoggerService; import org.dspace.statistics.service.SolrLoggerService; import org.dspace.statistics.util.SpiderDetectorService; /** - * Abstract factory to get services for the statistics package, use StatisticsServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the statistics package, use StatisticsServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -21,12 +21,10 @@ public abstract class StatisticsServiceFactory { public abstract SolrLoggerService getSolrLoggerService(); - public abstract ElasticSearchLoggerService getElasticSearchLoggerService(); - public abstract SpiderDetectorService getSpiderDetectorService(); - public static StatisticsServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("statisticsServiceFactory", StatisticsServiceFactory.class); + public static StatisticsServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("statisticsServiceFactory", StatisticsServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/factory/StatisticsServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/statistics/factory/StatisticsServiceFactoryImpl.java index 6970795974..dbb31160f3 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/factory/StatisticsServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/statistics/factory/StatisticsServiceFactoryImpl.java @@ -8,12 +8,12 @@ package org.dspace.statistics.factory; import org.dspace.services.factory.DSpaceServicesFactory; -import org.dspace.statistics.service.ElasticSearchLoggerService; import org.dspace.statistics.service.SolrLoggerService; import org.dspace.statistics.util.SpiderDetectorService; /** - * Factory implementation to get services for the statistics package, use StatisticsServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the statistics package, use StatisticsServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -22,17 +22,13 @@ public class StatisticsServiceFactoryImpl extends StatisticsServiceFactory { @Override public SolrLoggerService getSolrLoggerService() { // In order to lazy load, we cannot autowire it and instead load it by name - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("solrLoggerService", SolrLoggerService.class); - } - - @Override - public ElasticSearchLoggerService getElasticSearchLoggerService() { - // In order to lazy load, we cannot autowire it and instead load it by name - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("elasticSearchLoggerService", ElasticSearchLoggerService.class); + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("solrLoggerService", SolrLoggerService.class); } @Override public SpiderDetectorService getSpiderDetectorService() { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("spiderDetectorService", SpiderDetectorService.class); + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("spiderDetectorService", SpiderDetectorService.class); } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/service/ElasticSearchLoggerService.java b/dspace-api/src/main/java/org/dspace/statistics/service/ElasticSearchLoggerService.java deleted file mode 100644 index c64e4566af..0000000000 --- a/dspace-api/src/main/java/org/dspace/statistics/service/ElasticSearchLoggerService.java +++ /dev/null @@ -1,80 +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.statistics.service; - -import org.dspace.content.DSpaceObject; -import org.dspace.eperson.EPerson; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.xcontent.XContentBuilder; - -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; - -/** - * Service interface class for the Elastic Search logging. - * The implementation of this class is responsible for all business logic calls for the Elastic Search logging and is autowired by Spring. - * - * @deprecated As of DSpace 6.0, ElasticSearch statistics are replaced by Solr statistics. - * @see org.dspace.statistics.service.SolrLoggerService - * - * @author kevinvandevelde at atmire.com - */ -public interface ElasticSearchLoggerService { - - public static enum ClientType { - NODE, LOCAL, TRANSPORT - } - - - public void post(DSpaceObject dspaceObject, HttpServletRequest request, EPerson currentUser); - - public void post(DSpaceObject dspaceObject, String ip, String userAgent, String xforwardedfor, EPerson currentUser); - - public void buildParents(DSpaceObject dso, HashMap> parents) throws SQLException; - - public HashMap> getParents(DSpaceObject dso) - throws SQLException; - - public String getClusterName(); - - public void setClusterName(String clusterName); - - public String getIndexName(); - - public void setIndexName(String indexName); - - public String getIndexType(); - - public void setIndexType(String indexType); - - public String getAddress(); - - public void setAddress(String address); - - public int getPort(); - - public void setPort(int port); - - public void storeParents(XContentBuilder docBuilder, HashMap> parents) throws IOException; - - public boolean isUseProxies(); - - public void createTransportClient(); - - public Client getClient(); - - public Client getClient(ClientType clientType); - - // Node Client will discover other ES nodes running in local JVM - public Client createNodeClient(ClientType clientType); - - public String getConfigurationStringWithFallBack(String module, String configurationKey, String defaultFallbackValue); -} diff --git a/dspace-api/src/main/java/org/dspace/statistics/service/SolrLoggerService.java b/dspace-api/src/main/java/org/dspace/statistics/service/SolrLoggerService.java index 2244fb3cd0..c4120b629c 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/service/SolrLoggerService.java +++ b/dspace-api/src/main/java/org/dspace/statistics/service/SolrLoggerService.java @@ -7,6 +7,12 @@ */ package org.dspace.statistics.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; + import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrInputDocument; @@ -16,12 +22,6 @@ import org.dspace.eperson.EPerson; import org.dspace.statistics.ObjectCount; import org.dspace.usage.UsageWorkflowEvent; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; - /** * Static holder for a HttpSolrClient connection pool to issue * usage logging events to Solr from DSpace libraries, and some static query @@ -36,50 +36,48 @@ public interface SolrLoggerService { /** * Old post method, use the new postview method instead ! * - * @deprecated * @param dspaceObject the object used. - * @param request the current request context. - * @param currentUser the current session's user. + * @param request the current request context. + * @param currentUser the current session's user. + * @deprecated */ public void post(DSpaceObject dspaceObject, HttpServletRequest request, - EPerson currentUser); + EPerson currentUser); /** * Store a usage event into Solr. * * @param dspaceObject the object used. - * @param request the current request context. - * @param currentUser the current session's user. + * @param request the current request context. + * @param currentUser the current session's user. */ public void postView(DSpaceObject dspaceObject, HttpServletRequest request, - EPerson currentUser); + EPerson currentUser); public void postView(DSpaceObject dspaceObject, - String ip, String userAgent, String xforwardedfor, EPerson currentUser); + String ip, String userAgent, String xforwardedfor, EPerson currentUser); public void postSearch(DSpaceObject resultObject, HttpServletRequest request, EPerson currentUser, - List queries, int rpp, String sortBy, String order, int page, DSpaceObject scope); + List queries, int rpp, String sortBy, String order, int page, DSpaceObject scope); public void postWorkflow(UsageWorkflowEvent usageWorkflowEvent) throws SQLException; /** * Method just used to log the parents. *
      - *
    • Community log: owning comms.
    • - *
    • Collection log: owning comms and their comms.
    • - *
    • Item log: owning colls/comms.
    • - *
    • Bitstream log: owning item/colls/comms.
    • + *
    • Community log: owning comms.
    • + *
    • Collection log: owning comms and their comms.
    • + *
    • Item log: owning colls/comms.
    • + *
    • Bitstream log: owning item/colls/comms.
    • *
    * - * @param doc1 - * the current SolrInputDocument - * @param dso - * the current dspace object we want to log + * @param doc1 the current SolrInputDocument + * @param dso the current dspace object we want to log * @throws SQLException if database error - * ignore it + * ignore it */ public void storeParents(SolrInputDocument doc1, DSpaceObject dso) - throws SQLException; + throws SQLException; public boolean isUseProxies(); @@ -87,16 +85,14 @@ public interface SolrLoggerService { * Delete data from the index, as described by a query. * * @param query description of the records to be deleted. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SolrServerException - * Exception from the Solr server to the solrj Java client. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SolrServerException Exception from the Solr server to the solrj Java client. */ public void removeIndex(String query) throws IOException, - SolrServerException; + SolrServerException; public Map> queryField(String query, - List oldFieldVals, String field); + List oldFieldVals, String field); public void markRobotsByIP(); @@ -116,78 +112,62 @@ public interface SolrLoggerService { * update(query, addField, fieldName, vals, oldvals); } */ public void update(String query, String action, - List fieldNames, List> fieldValuesList) - throws SolrServerException, IOException; + List fieldNames, List> fieldValuesList) + throws SolrServerException, IOException; public void query(String query, int max) throws SolrServerException; /** * Query used to get values grouped by the given facet field. * - * @param query - * the query to be used - * @param filterQuery - * filter query - * @param facetField - * the facet field on which to group our values - * @param max - * the max number of values given back (in case of 10 the top 10 - * will be given) - * @param showTotal - * a boolean determining whether the total amount should be given - * back as the last element of the array - * @param facetQueries - * list of facet queries + * @param query the query to be used + * @param filterQuery filter query + * @param facetField the facet field on which to group our values + * @param max the max number of values given back (in case of 10 the top 10 + * will be given) + * @param showTotal a boolean determining whether the total amount should be given + * back as the last element of the array + * @param facetQueries list of facet queries * @return an array containing our results - * @throws SolrServerException - * Exception from the Solr server to the solrj Java client. + * @throws SolrServerException Exception from the Solr server to the solrj Java client. */ public ObjectCount[] queryFacetField(String query, - String filterQuery, String facetField, int max, boolean showTotal, - List facetQueries) throws SolrServerException; + String filterQuery, String facetField, int max, boolean showTotal, + List facetQueries) throws SolrServerException; /** * Query used to get values grouped by the date. * - * @param query - * the query to be used - * @param filterQuery - * filter query - * @param max - * the max number of values given back (in case of 10 the top 10 - * will be given) - * @param dateType - * the type to be used (example: DAY, MONTH, YEAR) - * @param dateStart - * the start date Format:(-3, -2, ..) the date is calculated - * relatively on today - * @param dateEnd - * the end date stop Format (-2, +1, ..) the date is calculated - * relatively on today - * @param showTotal - * a boolean determining whether the total amount should be given - * back as the last element of the array - * @param context - * The relevant DSpace Context. + * @param query the query to be used + * @param filterQuery filter query + * @param max the max number of values given back (in case of 10 the top 10 + * will be given) + * @param dateType the type to be used (example: DAY, MONTH, YEAR) + * @param dateStart the start date Format:(-3, -2, ..) the date is calculated + * relatively on today + * @param dateEnd the end date stop Format (-2, +1, ..) the date is calculated + * relatively on today + * @param showTotal a boolean determining whether the total amount should be given + * back as the last element of the array + * @param context The relevant DSpace Context. * @return and array containing our results - * @throws SolrServerException - * Exception from the Solr server to the solrj Java client. + * @throws SolrServerException Exception from the Solr server to the solrj Java client. */ public ObjectCount[] queryFacetDate(String query, - String filterQuery, int max, String dateType, String dateStart, - String dateEnd, boolean showTotal, Context context) throws SolrServerException; + String filterQuery, int max, String dateType, String dateStart, + String dateEnd, boolean showTotal, Context context) throws SolrServerException; public Map queryFacetQuery(String query, - String filterQuery, List facetQueries) - throws SolrServerException; + String filterQuery, List facetQueries) + throws SolrServerException; public ObjectCount queryTotal(String query, String filterQuery) - throws SolrServerException; + throws SolrServerException; public QueryResponse query(String query, String filterQuery, - String facetField, int rows, int max, String dateType, String dateStart, - String dateEnd, List facetQueries, String sort, boolean ascending) - throws SolrServerException; + String facetField, int rows, int max, String dateType, String dateStart, + String dateEnd, List facetQueries, String sort, boolean ascending) + throws SolrServerException; /** * Returns in a filterQuery string all the ip addresses that should be ignored diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/ApacheLogRobotsProcessor.java b/dspace-api/src/main/java/org/dspace/statistics/util/ApacheLogRobotsProcessor.java index f80c2b5f1d..0b742199ce 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/ApacheLogRobotsProcessor.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/ApacheLogRobotsProcessor.java @@ -7,25 +7,36 @@ */ package org.dspace.statistics.util; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.HashSet; +import java.util.Set; + 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 java.io.*; -import java.util.HashSet; -import java.util.Set; - /** * Commandline utility to create a file of spider addresses from an Apache * log file. - * + * * @author Mark Diggory (mdiggory at atmire.com) * @author kevinvandevelde at atmire.com * @author ben at atmire.com */ public class ApacheLogRobotsProcessor { + /** + * Default constructor + */ + private ApacheLogRobotsProcessor() { } /** * Creates a file containing spiders based on an Apache logfile @@ -47,21 +58,17 @@ public class ApacheLogRobotsProcessor { // Log source String logFileLoc; - if (line.hasOption("l")) - { + if (line.hasOption("l")) { logFileLoc = line.getOptionValue("l"); - } - else { + } else { logFileLoc = "-"; } // Spider IP list String spiderIpPath; - if (line.hasOption("s")) - { + if (line.hasOption("s")) { spiderIpPath = line.getOptionValue("s"); - } - else { + } else { spiderIpPath = "-"; } @@ -69,21 +76,15 @@ public class ApacheLogRobotsProcessor { Set logSpiders; Writer output; - if ("-".equals(spiderIpPath)) - { + if ("-".equals(spiderIpPath)) { logSpiders = new HashSet(); output = new BufferedWriter(new OutputStreamWriter(System.out)); - } - else - { + } else { File spiderIpFile = new File(spiderIpPath); - if (spiderIpFile.exists()) - { + if (spiderIpFile.exists()) { logSpiders = SpiderDetector.readPatterns(spiderIpFile); - } - else - { + } else { logSpiders = new HashSet(); } output = new BufferedWriter(new FileWriter(spiderIpFile)); @@ -91,10 +92,11 @@ public class ApacheLogRobotsProcessor { //First read in our log file line per line BufferedReader in; - if ("-".equals(logFileLoc)) + if ("-".equals(logFileLoc)) { in = new BufferedReader(new InputStreamReader(System.in)); - else + } else { in = new BufferedReader(new FileReader(logFileLoc)); + } String logLine; while ((logLine = in.readLine()) != null) { diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/ClassicDSpaceLogConverter.java b/dspace-api/src/main/java/org/dspace/statistics/util/ClassicDSpaceLogConverter.java index b226b2e6fc..b26f747aca 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/ClassicDSpaceLogConverter.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/ClassicDSpaceLogConverter.java @@ -7,67 +7,94 @@ */ package org.dspace.statistics.util; -import org.apache.commons.cli.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.dspace.app.statistics.LogAnalyser; import org.dspace.app.statistics.LogLine; -import org.dspace.content.*; +import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; -import java.io.*; -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import java.text.SimpleDateFormat; -import java.text.ParsePosition; - /** * A utility class to convert the classic dspace.log (as generated * by log4j) files into an intermediate format for ingestion into * the new solr stats. * - * @see StatisticsImporter - * @see StatisticsImporterElasticSearch - * * @author Stuart Lewis + * @see StatisticsImporter */ public class ClassicDSpaceLogConverter { private final Logger log = Logger.getLogger(ClassicDSpaceLogConverter.class); - /** A DSpace context */ + /** + * A DSpace context + */ private final Context context; - /** Whether or not to provide verbose output */ + /** + * Whether or not to provide verbose output + */ private boolean verbose = false; - /** Whether to include actions logged by org.dspace.usage.LoggerUsageEventListener */ + /** + * Whether to include actions logged by org.dspace.usage.LoggerUsageEventListener + */ private boolean newEvents = false; - /** A regular expression for extracting the IP address from a log line */ + /** + * A regular expression for extracting the IP address from a log line + */ private final Pattern ipaddrPattern = Pattern.compile("ip_addr=(\\d*\\.\\d*\\.\\d*\\.\\d*):"); - /** Date format (in) from the log line */ + /** + * Date format (in) from the log line + */ private final SimpleDateFormat dateFormatIn = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - /** Date format out (for solr) */ + /** + * Date format out (for solr) + */ private final SimpleDateFormat dateFormatOut = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - /** Date format (in) from the log line for the UID */ + /** + * Date format (in) from the log line for the UID + */ private final SimpleDateFormat dateFormatInUID = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS"); - /** Date format out (for uid) */ + /** + * Date format out (for uid) + */ private final SimpleDateFormat dateFormatOutUID = new SimpleDateFormat("yyyyMMddHHmmssSSS"); /** * Create an instance of the converter utility * - * @param c The context - * @param v Whether or not to provide verbose output + * @param c The context + * @param v Whether or not to provide verbose output * @param nE Whether to include actions logged by org.dspace.usage.LoggerUsageEventListener */ - public ClassicDSpaceLogConverter(Context c, boolean v, boolean nE) - { + public ClassicDSpaceLogConverter(Context c, boolean v, boolean nE) { // Set up some variables context = c; verbose = v; @@ -77,35 +104,32 @@ public class ClassicDSpaceLogConverter { /** * Convert a classic log file * - * @param in The filename to read from + * @param in The filename to read from * @param out The filename to write to * @return The number of lines processed */ - public int convert(String in, String out) - { + public int convert(String in, String out) { // Line counter int counter = 0; int lines = 0; - + // Figure out input, output BufferedReader input; Writer output; try { - if (null == in || in.isEmpty() || "-".equals(in)) - { + if (null == in || in.isEmpty() || "-".equals(in)) { input = new BufferedReader(new InputStreamReader(System.in)); in = "standard input"; - } - else + } else { input = new BufferedReader(new FileReader(in)); + } - if (null == out || out.isEmpty() || "-".equals(out)) - { + if (null == out || out.isEmpty() || "-".equals(out)) { output = new BufferedWriter(new OutputStreamWriter(System.out)); out = "standard output"; - } - else + } else { output = new BufferedWriter(new FileWriter(out)); + } } catch (IOException ie) { log.error("File access problem", ie); return 0; @@ -130,21 +154,17 @@ public class ClassicDSpaceLogConverter { String uid; String lastLine = ""; - while ((line = input.readLine()) != null) - { + while ((line = input.readLine()) != null) { // Read in the line and convert it to a LogLine lines++; - if (verbose) - { + if (verbose) { System.out.println(" - IN: " + line); } lline = LogAnalyser.getLogLine(line); // Get rid of any lines that aren't INFO - if ((lline == null) || (!lline.isLevel("INFO"))) - { - if (verbose) - { + if ((lline == null) || (!lline.isLevel("INFO"))) { + if (verbose) { System.out.println(" - IGNORED!"); } continue; @@ -152,107 +172,96 @@ public class ClassicDSpaceLogConverter { // Get the IP address of the user Matcher matcher = ipaddrPattern.matcher(line); - if (matcher.find()) - { + if (matcher.find()) { ip = matcher.group(1); - } - else - { + } else { ip = "unknown"; } // Get and format the date // We can use lline.getDate() as this strips the time element date = dateFormatOut.format( - dateFormatIn.parse(line.substring(0, line.indexOf(',')), - new ParsePosition(0))); + dateFormatIn.parse(line.substring(0, line.indexOf(',')), + new ParsePosition(0))); // Generate a UID for the log line // - based on the date/time uid = dateFormatOutUID.format( - dateFormatInUID.parse(line.substring(0, line.indexOf(' ', line.indexOf(' ') + 1)), - new ParsePosition(0))); + dateFormatInUID.parse(line.substring(0, line.indexOf(' ', line.indexOf(' ') + 1)), + new ParsePosition(0))); - try - { + try { // What sort of view is it? // (ignore lines from org.dspace.usage.LoggerUsageEventListener which is 1.6 code) if ((lline.getAction().equals("view_bitstream")) && (!lline.getParams().contains("invalid_bitstream_id")) && (!lline.getParams().contains("withdrawn")) && - ((!line.contains("org.dspace.usage.LoggerUsageEventListener")) || newEvents)) - { + ((!line.contains("org.dspace.usage.LoggerUsageEventListener")) || newEvents)) { id = lline.getParams().substring(13); - } - else if ((lline.getAction().equals("view_item")) && - ((!line.contains("org.dspace.usage.LoggerUsageEventListener")) || newEvents)) - { + } else if ((lline.getAction().equals("view_item")) && + ((!line.contains("org.dspace.usage.LoggerUsageEventListener")) || newEvents)) { handle = lline.getParams().substring(7); dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, handle); id = "" + dso.getID(); - } - else if ((lline.getAction().equals("view_collection")) && - ((!line.contains("org.dspace.usage.LoggerUsageEventListener")) || newEvents)) - { + } else if ((lline.getAction().equals("view_collection")) && + ((!line.contains("org.dspace.usage.LoggerUsageEventListener")) || newEvents)) { id = lline.getParams().substring(14); - } - else if ((lline.getAction().equals("view_community")) && - ((!line.contains("org.dspace.usage.LoggerUsageEventListener")) || newEvents)) - { + } else if ((lline.getAction().equals("view_community")) && + ((!line.contains("org.dspace.usage.LoggerUsageEventListener")) || newEvents)) { id = lline.getParams().substring(13); - } - else - { + } else { //if (verbose) System.out.println(" - IGNORED!"); continue; } // Construct the log line lout = uid + "," + - lline.getAction() + "," + - id + "," + - date + "," + - lline.getUser() + "," + - ip + "\n"; - } - catch (Exception e) - { - if (verbose) - { + lline.getAction() + "," + + id + "," + + date + "," + + lline.getUser() + "," + + ip + "\n"; + } catch (Exception e) { + if (verbose) { System.out.println(" - IN: " + line); } - if (verbose) - { + if (verbose) { System.err.println("Error with log line! " + e.getMessage()); } continue; } - if ((verbose) && (!"".equals(lout))) - { + if ((verbose) && (!"".equals(lout))) { System.out.println(" - IN: " + line); System.out.println(" - OUT: " + lout); } // Write the output line - if ((!"".equals(lout)) && (!lout.equals(lastLine))) - { + if ((!"".equals(lout)) && (!lout.equals(lastLine))) { output.write(lout); counter++; lastLine = lout; } } - } - catch (IOException e) - { + } catch (IOException e) { log.error("File access problem", e); - } - finally - { + } finally { // Clean up the input and output streams - try { input.close(); } catch (IOException e) { log.error(e.getMessage(), e); } - try { output.flush(); } catch (IOException e) { log.error(e.getMessage(), e); } - try { output.close(); } catch (IOException e) { log.error(e.getMessage(), e); } + try { + input.close(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + try { + output.flush(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + try { + output.close(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } } // Tell the user what we have done @@ -263,11 +272,10 @@ public class ClassicDSpaceLogConverter { /** * Print the help message * - * @param options The command line options the user gave + * @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) - { + private static void printHelp(Options options, int exitCode) { // print the help message HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("ClassicDSpaceLogConverter\n", options); @@ -280,41 +288,36 @@ public class ClassicDSpaceLogConverter { * * @param args the command line arguments given */ - public static void main(String[] args) - { + public static void main(String[] args) { CommandLineParser parser = new PosixParser(); Options options = new Options(); options.addOption("i", "in", true, - "source file ('-' or omit for standard input)"); + "source file ('-' or omit for standard input)"); options.addOption("o", "out", true, - "destination file or directory ('-' or omit for standard output)"); + "destination file or directory ('-' or omit for standard output)"); options.addOption("m", "multiple", false, - "treat the input file as having a wildcard ending"); + "treat the input file as having a wildcard ending"); options.addOption("n", "newformat", false, - "process new format log lines (1.6+)"); + "process new format log lines (1.6+)"); options.addOption("v", "verbose", false, - "display verbose output (useful for debugging)"); + "display verbose output (useful for debugging)"); options.addOption("h", "help", false, - "help"); + "help"); // Parse the command line arguments CommandLine line; - try - { + try { line = parser.parse(options, args); - } - catch (ParseException pe) - { + } catch (ParseException pe) { System.err.println("Error parsing command line arguments: " + pe.getMessage()); System.exit(1); return; } // Did the user ask to see the help? - if (line.hasOption('h')) - { + if (line.hasOption('h')) { printHelp(options, 0); } @@ -330,54 +333,41 @@ public class ClassicDSpaceLogConverter { newEvents); // Set up the log analyser - try - { + try { LogAnalyser.readConfig(); - } - catch (IOException ioe) - { + } catch (IOException ioe) { System.err.println("Unable to read config file: " + LogAnalyser.getConfigFile()); System.exit(1); } // Are we converting multiple files? - if (line.hasOption('m')) - { + if (line.hasOption('m')) { // Convert all the files final File sample = new File(line.getOptionValue('i')); File dir = sample.getAbsoluteFile().getParentFile(); - FilenameFilter filter = new FilenameFilter() - { + FilenameFilter filter = new FilenameFilter() { @Override - public boolean accept(File dir, String name) - { + public boolean accept(File dir, String name) { return name.startsWith(sample.getName()); } }; String[] children = dir.list(filter); - if (null == children) - { + if (null == children) { System.err.println(sample + " could not be used to find a directory of log files."); System.exit(1); - } - else if (children.length <= 0) { + } else if (children.length <= 0) { System.err.println(sample + " matched no files."); - } - else - { - for (String in : children) - { + } else { + for (String in : children) { System.err.println(in); String out = line.getOptionValue('o') + (dir.getAbsolutePath() + - System.getProperty("file.separator") + in).substring(line.getOptionValue('i').length()); + System.getProperty("file.separator") + in).substring(line.getOptionValue('i').length()); converter.convert(dir.getAbsolutePath() + System.getProperty("file.separator") + in, out); } } - } - else - { + } else { // Just convert the one file converter.convert(line.getOptionValue('i'), line.getOptionValue('o')); } diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/DnsLookup.java b/dspace-api/src/main/java/org/dspace/statistics/util/DnsLookup.java index de941a3eb4..90444be936 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/DnsLookup.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/DnsLookup.java @@ -7,20 +7,33 @@ */ package org.dspace.statistics.util; -import org.dspace.core.ConfigurationManager; -import org.xbill.DNS.*; - import java.io.IOException; +import org.dspace.core.ConfigurationManager; +import org.xbill.DNS.DClass; +import org.xbill.DNS.ExtendedResolver; +import org.xbill.DNS.Message; +import org.xbill.DNS.Name; +import org.xbill.DNS.Record; +import org.xbill.DNS.Resolver; +import org.xbill.DNS.ReverseMap; +import org.xbill.DNS.Section; +import org.xbill.DNS.Type; + /** * XBill DNS resolver to retrieve hostnames for client IP addresses. * TODO: deal with IPv6 addresses. - * + * * @author kevinvandevelde at atmire.com * @author ben at atmire.com */ public class DnsLookup { + /** + * Default constructor + */ + private DnsLookup() { } + /** * Resolve an IP address to a host name. * @@ -29,44 +42,39 @@ public class DnsLookup { * @throws IOException from infrastructure. */ public static String reverseDns(String hostIp) throws IOException { - Resolver res = new ExtendedResolver(); - - // set the timeout, defaults to 200 milliseconds - int timeout = ConfigurationManager.getIntProperty("usage-statistics", "resolver.timeout", 200); - res.setTimeout(0, timeout); + Resolver res = new ExtendedResolver(); - Name name = ReverseMap.fromAddress(hostIp); - int type = Type.PTR; - int dclass = DClass.IN; - Record rec = Record.newRecord(name, type, dclass); - Message query = Message.newQuery(rec); - Message response = res.send(query); + // set the timeout, defaults to 200 milliseconds + int timeout = ConfigurationManager.getIntProperty("usage-statistics", "resolver.timeout", 200); + res.setTimeout(0, timeout); - Record[] answers = response.getSectionArray(Section.ANSWER); - if (answers.length == 0) - { - return hostIp; - } - else - { - return answers[0].rdataToString(); - } - } + Name name = ReverseMap.fromAddress(hostIp); + int type = Type.PTR; + int dclass = DClass.IN; + Record rec = Record.newRecord(name, type, dclass); + Message query = Message.newQuery(rec); + Message response = res.send(query); + + Record[] answers = response.getSectionArray(Section.ANSWER); + if (answers.length == 0) { + return hostIp; + } else { + return answers[0].rdataToString(); + } + } /** * Resolve a host name to an IPv4 address. * - * @param hostname - * hostname to resolve to IP + * @param hostname hostname to resolve to IP * @return IPv4 address * @throws IOException from infrastructure or no resolution. */ public static String forward(String hostname) - throws IOException - { + throws IOException { Resolver res = new ExtendedResolver(); int timeout = ConfigurationManager.getIntProperty("usage-statistics", - "resolver.timeout", 200); + "resolver.timeout", 200); res.setTimeout(0, timeout); Name name = Name.fromString(hostname, Name.root); @@ -75,23 +83,19 @@ public class DnsLookup { Message response = res.send(query); Record[] answers = response.getSectionArray(Section.ANSWER); - if (answers.length == 0) - { + if (answers.length == 0) { throw new IOException("Unresolvable host name (empty response)"); } String resolution = null; - for (Record answer : answers) - { - if (answer.getType() == Type.A) - { + for (Record answer : answers) { + if (answer.getType() == Type.A) { resolution = answer.rdataToString(); break; } } - if (null == resolution) - { + if (null == resolution) { throw new IOException("Unresolvable host name (no A record)"); } diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/IPTable.java b/dspace-api/src/main/java/org/dspace/statistics/util/IPTable.java index 597932c893..6833fd1792 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/IPTable.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/IPTable.java @@ -22,15 +22,13 @@ public class IPTable { /* A lookup tree for IP addresses and SubnetRanges */ private Map>>> map = - new HashMap>>>(); + new HashMap>>>(); /** * Can be full v4 IP, subnet or range string * - * @param ip - * IP address(es) - * @throws IPFormatException - * Exception Class to deal with IPFormat errors. + * @param ip IP address(es) + * @throws IPFormatException Exception Class to deal with IPFormat errors. */ public void add(String ip) throws IPFormatException { @@ -45,8 +43,7 @@ public class IPTable { start = range[0].trim().split("/")[0].split("\\."); end = range[1].trim().split("/")[0].split("\\."); - if (start.length != 4 || end.length != 4) - { + if (start.length != 4 || end.length != 4) { throw new IPFormatException(ip + " - Ranges need to be full IPv4 Addresses"); } @@ -114,40 +111,36 @@ public class IPTable { } } - /** Check whether a given address is contained in this netblock. - * + /** + * Check whether a given address is contained in this netblock. + * * @param ip the address to be tested * @return true if {@code ip} is within this table's limits - * @throws IPFormatException - * Exception Class to deal with IPFormat errors. + * @throws IPFormatException Exception Class to deal with IPFormat errors. */ public boolean contains(String ip) throws IPFormatException { String[] subnets = ip.split("\\."); - if (subnets.length != 4) - { + if (subnets.length != 4) { throw new IPFormatException("needs to be a single IP address"); } Map>> first = map.get(subnets[0]); - if (first == null) - { + if (first == null) { return false; } Map> second = first.get(subnets[1]); - if (second == null) - { + if (second == null) { return false; } Set third = second.get(subnets[2]); - if (third == null) - { + if (third == null) { return false; } @@ -155,7 +148,9 @@ public class IPTable { } - /** Convert to a Set. + /** + * Convert to a Set. + * * @return this table's content as a Set */ public Set toSet() { diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/LocationUtils.java b/dspace-api/src/main/java/org/dspace/statistics/util/LocationUtils.java index 71cad7789e..693454a2cb 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/LocationUtils.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/LocationUtils.java @@ -17,152 +17,143 @@ import org.apache.log4j.Logger; import org.dspace.core.I18nUtil; /** - * Mapping between Country codes, English Country names, + * Mapping between Country codes, English Country names, * Continent Codes, and English Continent names * * @author kevinvandevelde at atmire.com * @author ben at atmire.com */ -public class LocationUtils -{ +public class LocationUtils { private static final Logger logger = Logger.getLogger(LocationUtils.class); private static final Properties countryToContinent = new Properties(); - + private static final String CONTINENT_NAMES_BUNDLE - = LocationUtils.class.getPackage().getName() + ".continent-names"; - + = LocationUtils.class.getPackage().getName() + ".continent-names"; + + /** + * Default constructor + */ + private LocationUtils() { } + /** * Map DSpace continent codes onto ISO country codes. - * + * * @param countryCode ISO 3166-1 alpha-2 country code. * @return DSpace 2-character code for continent containing that country, or * an error message string. */ - static public String getContinentCode(String countryCode) - { - if (null == countryCode) - { + static public String getContinentCode(String countryCode) { + if (null == countryCode) { logger.info("Null country code"); return I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); } - if (countryToContinent.isEmpty()) - try - { + if (countryToContinent.isEmpty()) { + try { countryToContinent.load(LocationUtils.class - .getResourceAsStream("country-continent-codes.properties")); - } - catch (IOException e) - { + .getResourceAsStream("country-continent-codes.properties")); + } catch (IOException e) { logger.error("Could not load country/continent map file", e); } + } String continent = countryToContinent.getProperty(countryCode); - if (null == continent) - { + if (null == continent) { logger.info("Unknown country code " + countryCode); return I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); - } - else + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); + } else { return continent; + } } /** * Map DSpace continent codes onto default continent names. - * + * * @param continentCode DSpace 2-character code for a continent. * @return Name of the continent in the default locale, or an error message * string. */ @Deprecated - static public String getContinentName(String continentCode) - { + static public String getContinentName(String continentCode) { return getContinentName(continentCode, Locale.getDefault()); } /** * Map DSpace continent codes onto localized continent names. - * + * * @param continentCode DSpace 2-character code for a continent. - * @param locale The desired localization. + * @param locale The desired localization. * @return Localized name of the continent, or an error message string. */ - static public String getContinentName(String continentCode, Locale locale) - { + static public String getContinentName(String continentCode, Locale locale) { ResourceBundle names; - if (null == locale) + if (null == locale) { locale = Locale.US; + } - if (null == continentCode) - { + if (null == continentCode) { logger.info("Null continentCode"); return I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); } - try - { + try { names = ResourceBundle.getBundle(CONTINENT_NAMES_BUNDLE, locale); - } - catch (MissingResourceException e) - { + } catch (MissingResourceException e) { logger.error("Could not load continent code/name resource bundle", - e); + e); return I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); } String name; - try - { + try { name = names.getString(continentCode); - } - catch (MissingResourceException e) - { + } catch (MissingResourceException e) { logger.info("No continent code " + continentCode + " in bundle " - + names.getLocale().getDisplayName()); + + names.getLocale().getDisplayName()); return I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); } return name; } /** * Map ISO country codes onto default country names. - * + * * @param countryCode ISO 3166-1 alpha-2 country code. * @return Name of the country in the default locale, or an error message * string. */ @Deprecated - static public String getCountryName(String countryCode) - { + static public String getCountryName(String countryCode) { return getCountryName(countryCode, Locale.getDefault()); } /** * Map ISO country codes onto localized country names. - * + * * @param countryCode ISO 3166-1 alpha-2 country code. - * @param locale Desired localization. + * @param locale Desired localization. * @return Localized name of the country, or an error message string. */ - static public String getCountryName(String countryCode, Locale locale) - { - if (null == countryCode) + static public String getCountryName(String countryCode, Locale locale) { + if (null == countryCode) { return I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-country"); + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-country"); + } Locale country = new Locale("EN", countryCode); String name = country.getDisplayCountry(locale); - if (name.isEmpty()) + if (name.isEmpty()) { return I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-country"); - else + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-country"); + } else { return name; + } } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetector.java b/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetector.java index 2ef92e31be..c4c5765e08 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetector.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetector.java @@ -29,7 +29,13 @@ public class SpiderDetector { private static final Logger log = LoggerFactory.getLogger(SpiderDetector.class); //Service where all methods get delegated to, this is instantiated by a spring-bean defined in core-services.xml - private static SpiderDetectorService spiderDetectorService = StatisticsServiceFactory.getInstance().getSpiderDetectorService(); + private static SpiderDetectorService spiderDetectorService = StatisticsServiceFactory.getInstance() + .getSpiderDetectorService(); + + /** + * Default constructor + */ + private SpiderDetector() { } /** * Get an immutable Set representing all the Spider Addresses here @@ -50,8 +56,7 @@ public class SpiderDetector { * @throws IOException could not happen since we check the file be4 we use it */ public static Set readPatterns(File patternFile) - throws IOException - { + throws IOException { return spiderDetectorService.readPatterns(patternFile); } @@ -64,12 +69,11 @@ public class SpiderDetector { * @param clientIP address of the client. * @param proxyIPs comma-list of X-Forwarded-For addresses, or null. * @param hostname domain name of host, or null. - * @param agent User-Agent header value, or null. + * @param agent User-Agent header value, or null. * @return true if the client matches any spider characteristics list. */ public static boolean isSpider(String clientIP, String proxyIPs, - String hostname, String agent) - { + String hostname, String agent) { return spiderDetectorService.isSpider(clientIP, proxyIPs, hostname, agent); } @@ -79,8 +83,7 @@ public class SpiderDetector { * @param request * @return true|false if the request was detected to be from a spider. */ - public static boolean isSpider(HttpServletRequest request) - { + public static boolean isSpider(HttpServletRequest request) { return spiderDetectorService.isSpider(request); } @@ -94,4 +97,4 @@ public class SpiderDetector { return spiderDetectorService.isSpider(ip); } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetectorService.java b/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetectorService.java index 75bb2fbe01..710e8472d2 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetectorService.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetectorService.java @@ -7,13 +7,14 @@ */ package org.dspace.statistics.util; -import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.util.Set; +import javax.servlet.http.HttpServletRequest; /** * Interface to implement a SpiderDetectorService + * * @author frederic at atmire.com */ public interface SpiderDetectorService { @@ -27,8 +28,8 @@ public interface SpiderDetectorService { public void loadSpiderIpAddresses(); public Set readPatterns(File patternFile) - throws IOException; + throws IOException; public IPTable getTable(); -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetectorServiceImpl.java b/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetectorServiceImpl.java index 69b41a1948..7939db3a12 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetectorServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/SpiderDetectorServiceImpl.java @@ -7,21 +7,24 @@ */ package org.dspace.statistics.util; -import org.apache.commons.configuration.ConversionException; -import org.apache.commons.lang.StringUtils; -import org.dspace.services.ConfigurationService; -import org.dspace.services.factory.DSpaceServicesFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.configuration.ConversionException; +import org.apache.commons.lang.StringUtils; +import org.dspace.services.ConfigurationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; /** * SpiderDetectorServiceImpl is used to find IP's that are spiders... @@ -42,10 +45,10 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { private Boolean useCaseInsensitiveMatching; private final List agents - = Collections.synchronizedList(new ArrayList()); + = Collections.synchronizedList(new ArrayList()); private final List domains - = Collections.synchronizedList(new ArrayList()); + = Collections.synchronizedList(new ArrayList()); private ConfigurationService configurationService; @@ -72,20 +75,19 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { * @param clientIP address of the client. * @param proxyIPs comma-list of X-Forwarded-For addresses, or null. * @param hostname domain name of host, or null. - * @param agent User-Agent header value, or null. + * @param agent User-Agent header value, or null. * @return true if the client matches any spider characteristics list. */ public boolean isSpider(String clientIP, String proxyIPs, String hostname, String agent) { // See if any agent patterns match - if (null != agent) - { - synchronized(agents) - { - if (agents.isEmpty()) + if (null != agent) { + synchronized (agents) { + if (agents.isEmpty()) { loadPatterns("agents", agents); + } } - if(isUseCaseInsensitiveMatching()) { + if (isUseCaseInsensitiveMatching()) { agent = StringUtils.lowerCase(agent); hostname = StringUtils.lowerCase(hostname); } @@ -105,29 +107,26 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { if (isUseProxies() && proxyIPs != null) { /* This header is a comma delimited list */ for (String xfip : proxyIPs.split(",")) { - if (isSpider(xfip)) - { + if (isSpider(xfip)) { return true; } } } - if (isSpider(clientIP)) + if (isSpider(clientIP)) { return true; + } // No. See if any DNS names match - if (null != hostname) - { - synchronized(domains) - { - if (domains.isEmpty()) + if (null != hostname) { + synchronized (domains) { + if (domains.isEmpty()) { loadPatterns("domains", domains); + } } - for (Pattern candidate : domains) - { + for (Pattern candidate : domains) { // prevent matcher() invocation from a null Pattern object - if (null != candidate && candidate.matcher(hostname).find()) - { + if (null != candidate && candidate.matcher(hostname).find()) { return true; } } @@ -145,18 +144,15 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { * @throws IOException could not happen since we check the file be4 we use it */ public Set readPatterns(File patternFile) - throws IOException - { + throws IOException { Set patterns = new HashSet<>(); - if (!patternFile.exists() || !patternFile.isFile()) - { + if (!patternFile.exists() || !patternFile.isFile()) { return patterns; } //Read our file & get all them patterns. - try (BufferedReader in = new BufferedReader(new FileReader(patternFile))) - { + try (BufferedReader in = new BufferedReader(new FileReader(patternFile))) { String line; while ((line = in.readLine()) != null) { if (!line.startsWith("#")) { @@ -177,34 +173,29 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { /** * Load agent name patterns from all files in a single subdirectory of config/spiders. * - * @param directory simple directory name (e.g. "agents"). - * "${dspace.dir}/config/spiders" will be prepended to yield the path to - * the directory of pattern files. + * @param directory simple directory name (e.g. "agents"). + * "${dspace.dir}/config/spiders" will be prepended to yield the path to + * the directory of pattern files. * @param patternList patterns read from the files in {@code directory} will - * be added to this List. + * be added to this List. */ - private void loadPatterns(String directory, List patternList) - { + private void loadPatterns(String directory, List patternList) { String dspaceHome = configurationService.getProperty("dspace.dir"); File spidersDir = new File(dspaceHome, "config/spiders"); File patternsDir = new File(spidersDir, directory); - if (patternsDir.exists() && patternsDir.isDirectory()) - { - for (File file : patternsDir.listFiles()) - { + if (patternsDir.exists() && patternsDir.isDirectory()) { + for (File file : patternsDir.listFiles()) { Set patterns; - try - { + try { patterns = readPatterns(file); - } catch (IOException ex) - { + } catch (IOException ex) { log.error("Patterns not read from {}: {}", - file.getPath(), ex.getMessage()); + file.getPath(), ex.getMessage()); continue; } //If case insensitive matching is enabled, lowercase the patterns so they can be lowercase matched for (String pattern : patterns) { - if(isUseCaseInsensitiveMatching()) { + if (isUseCaseInsensitiveMatching()) { pattern = StringUtils.lowerCase(pattern); } patternList.add(Pattern.compile(pattern)); @@ -213,9 +204,7 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { log.info("Loaded pattern file: {}", file.getPath()); } - } - else - { + } else { log.info("No patterns loaded from {}", patternsDir.getPath()); } } @@ -228,9 +217,9 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { */ public boolean isSpider(HttpServletRequest request) { return isSpider(request.getRemoteAddr(), - request.getHeader("X-Forwarded-For"), - request.getRemoteHost(), - request.getHeader("User-Agent")); + request.getHeader("X-Forwarded-For"), + request.getRemoteHost(), + request.getHeader("User-Agent")); } /** @@ -270,12 +259,10 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { if (spidersDir.exists() && spidersDir.isDirectory()) { for (File file : spidersDir.listFiles()) { - if (file.isFile()) - { + if (file.isFile()) { for (String ip : readPatterns(file)) { log.debug("Loading {}", ip); - if (!Character.isDigit(ip.charAt(0))) - { + if (!Character.isDigit(ip.charAt(0))) { try { ip = DnsLookup.forward(ip); log.debug("Resolved to {}", ip); @@ -292,8 +279,7 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { } else { log.info("No spider file loaded"); } - } - catch (IOException | IPTable.IPFormatException e) { + } catch (IOException | IPTable.IPFormatException e) { log.error("Error Loading Spiders:" + e.getMessage(), e); } @@ -303,12 +289,14 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { /** * checks if case insensitive matching is enabled + * * @return true if it's enabled, false if not */ private boolean isUseCaseInsensitiveMatching() { if (useCaseInsensitiveMatching == null) { try { - useCaseInsensitiveMatching = configurationService.getBooleanProperty("usage-statistics.bots.case-insensitive"); + useCaseInsensitiveMatching = configurationService + .getBooleanProperty("usage-statistics.bots.case-insensitive"); } catch (ConversionException e) { useCaseInsensitiveMatching = false; log.warn("Please use a boolean value for usage-statistics.bots.case-insensitive"); @@ -319,11 +307,11 @@ public class SpiderDetectorServiceImpl implements SpiderDetectorService { } private boolean isUseProxies() { - if(useProxies == null) { + if (useProxies == null) { useProxies = configurationService.getBooleanProperty("useProxies"); } return useProxies; } -} \ No newline at end of file +} diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsClient.java b/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsClient.java index 1ada3bcf54..9662a3f7d9 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsClient.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsClient.java @@ -7,33 +7,40 @@ */ package org.dspace.statistics.util; -import org.apache.commons.cli.*; +import java.io.File; +import java.net.URL; + +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.log4j.Logger; import org.apache.tools.ant.taskdefs.Get; +import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.statistics.factory.StatisticsServiceFactory; import org.dspace.statistics.service.SolrLoggerService; -import java.io.*; -import java.net.URL; -import org.dspace.services.factory.DSpaceServicesFactory; - /** * Class to load intermediate statistics files into solr * * @author Stuart Lewis */ -public class StatisticsClient -{ +public class StatisticsClient { private static final Logger log = Logger.getLogger(StatisticsClient.class); + /** + * Default constructor + */ + private StatisticsClient() { } + /** * Print the help message * - * @param options The command line options the user gave + * @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) - { + private static void printHelp(Options options, int exitCode) { // print the help message HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("StatisticsClient\n", options); @@ -46,69 +53,54 @@ public class StatisticsClient * @param args The command line arguments * @throws Exception If something goes wrong */ - public static void main(String[] args) throws Exception - { - CommandLineParser parser = new PosixParser(); + public static void main(String[] args) throws Exception { + CommandLineParser parser = new PosixParser(); - Options options = new Options(); + Options options = new Options(); options.addOption("u", "update-spider-files", false, - "Update Spider IP Files from internet into " + - DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") + "/config/spiders"); + "Update Spider IP Files from internet into " + + DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("dspace.dir") + "/config/spiders"); options.addOption("m", "mark-spiders", false, "Update isBot Flag in Solr"); options.addOption("f", "delete-spiders-by-flag", false, "Delete Spiders in Solr By isBot Flag"); options.addOption("i", "delete-spiders-by-ip", false, "Delete Spiders in Solr By IP Address"); options.addOption("o", "optimize", false, "Run maintenance on the SOLR index"); options.addOption("b", "reindex-bitstreams", false, "Reindex the bitstreams to ensure we have the bundle name"); - options.addOption("e", "export", false, "Export SOLR view statistics data to usage-statistics-intermediate-format"); - options.addOption("r", "remove-deleted-bitstreams", false, "While indexing the bundle names remove the statistics about deleted bitstreams"); - options.addOption("s", "shard-solr-index", false, "Split the data from the main Solr core into separate Solr cores per year"); + options.addOption("e", "export", false, + "Export SOLR view statistics data to usage-statistics-intermediate-format"); + options.addOption("r", "remove-deleted-bitstreams", false, + "While indexing the bundle names remove the statistics about deleted bitstreams"); + options.addOption("s", "shard-solr-index", false, + "Split the data from the main Solr core into separate Solr cores per year"); options.addOption("h", "help", false, "help"); - CommandLine line = parser.parse(options, args); + CommandLine line = parser.parse(options, args); // Did the user ask to see the help? - if (line.hasOption('h')) - { + if (line.hasOption('h')) { printHelp(options, 0); } SolrLoggerService solrLoggerService = StatisticsServiceFactory.getInstance().getSolrLoggerService(); - if(line.hasOption("u")) - { + if (line.hasOption("u")) { StatisticsClient.updateSpiderFiles(); - } - else if (line.hasOption('m')) - { + } else if (line.hasOption('m')) { solrLoggerService.markRobotsByIP(); - } - else if(line.hasOption('f')) - { + } else if (line.hasOption('f')) { solrLoggerService.deleteRobotsByIsBotFlag(); - } - else if(line.hasOption('i')) - { + } else if (line.hasOption('i')) { solrLoggerService.deleteRobotsByIP(); - } - else if(line.hasOption('o')) - { + } else if (line.hasOption('o')) { solrLoggerService.optimizeSOLR(); - } - else if(line.hasOption('b')) - { + } else if (line.hasOption('b')) { solrLoggerService.reindexBitstreamHits(line.hasOption('r')); - } - else if(line.hasOption('e')) - { + } else if (line.hasOption('e')) { solrLoggerService.exportHits(); - } - else if(line.hasOption('s')) - { + } else if (line.hasOption('s')) { solrLoggerService.shardSolrIndex(); - } - else - { + } else { printHelp(options, 0); } } @@ -116,37 +108,35 @@ public class StatisticsClient /** * Method to update Spiders in config directory. */ - private static void updateSpiderFiles() - { - try - { + private static void updateSpiderFiles() { + try { System.out.println("Downloading latest spider IP addresses:"); // Get the list URLs to download from - String[] urls = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("solr-statistics.spiderips.urls"); - if((urls == null) || (urls.length==0)) - { + String[] urls = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("solr-statistics.spiderips.urls"); + if ((urls == null) || (urls.length == 0)) { System.err.println(" - Missing setting from dspace.cfg: solr.spiderips.urls"); System.exit(0); } // Get the location of spiders directory - File spiders = new File(DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir"),"config/spiders"); + File spiders = new File( + DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir"), + "config/spiders"); - if (!spiders.exists() && !spiders.mkdirs()) - { + if (!spiders.exists() && !spiders.mkdirs()) { log.error("Unable to create spiders directory"); } - for (String value : urls) - { + for (String value : urls) { value = value.trim(); System.out.println(" Downloading: " + value); URL url = new URL(value); Get get = new Get(); - get.setDest(new File(spiders, url.getHost() + url.getPath().replace("/","-"))); + get.setDest(new File(spiders, url.getHost() + url.getPath().replace("/", "-"))); get.setSrc(url); get.setUseTimestamp(true); get.execute(); @@ -154,8 +144,7 @@ public class StatisticsClient } - } catch (Exception e) - { + } catch (Exception e) { System.err.println(" - Error: " + e.getMessage()); e.printStackTrace(); System.exit(1); diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsImporter.java b/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsImporter.java index bb0b3397d5..8588b381ce 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsImporter.java +++ b/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsImporter.java @@ -7,43 +7,68 @@ */ package org.dspace.statistics.util; -import org.apache.commons.cli.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Random; +import java.util.UUID; + +import com.maxmind.geoip2.DatabaseReader; +import com.maxmind.geoip2.model.CityResponse; +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.lang.time.DateFormatUtils; import org.apache.log4j.Logger; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.SolrServerException; -import org.dspace.content.*; +import org.apache.solr.client.solrj.impl.HttpSolrServer; +import org.apache.solr.common.SolrInputDocument; +import org.dspace.content.Bitstream; 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.*; -import org.dspace.core.Context; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.DSpaceObjectLegacySupportService; +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.statistics.SolrLoggerServiceImpl; - -import java.text.*; -import java.io.*; -import java.util.*; - -import com.maxmind.geoip.LookupService; -import com.maxmind.geoip.Location; import org.dspace.statistics.factory.StatisticsServiceFactory; import org.dspace.statistics.service.SolrLoggerService; /** * Class to load intermediate statistics files (produced from log files by {@link ClassicDSpaceLogConverter}) into Solr. * - * @see ClassicDSpaceLogConverter - * * @author Stuart Lewis + * @see ClassicDSpaceLogConverter */ -public class StatisticsImporter -{ +public class StatisticsImporter { private static final Logger log = Logger.getLogger(StatisticsImporter.class); - /** Date format (for solr) */ + /** + * Date format (for solr) + */ private static final ThreadLocal dateFormat = new ThreadLocal() { @Override protected DateFormat initialValue() { @@ -52,28 +77,44 @@ public class StatisticsImporter }; protected final SolrLoggerService solrLoggerService = StatisticsServiceFactory.getInstance().getSolrLoggerService(); - /** Solr server connection */ + /** + * Solr server connection + */ private static HttpSolrServer solr; - /** GEOIP lookup service */ - private static LookupService geoipLookup; + /** + * GEOIP lookup service + */ + private static DatabaseReader geoipLookup; - /** Whether to skip the DNS reverse lookup or not */ + /** + * Whether to skip the DNS reverse lookup or not + */ private static boolean skipReverseDNS = false; - /** Local items */ + /** + * Local items + */ private List localItems; - /** Local collections */ + /** + * Local collections + */ private List localCollections; - /** Local communities */ + /** + * Local communities + */ private List localCommunities; - /** Local bitstreams */ + /** + * Local bitstreams + */ private List localBitstreams; - /** Whether or not to replace item IDs with local values (for testing) */ + /** + * Whether or not to replace item IDs with local values (for testing) + */ private final boolean useLocal; protected final BitstreamService bitstreamService; @@ -87,26 +128,22 @@ public class StatisticsImporter * * @param local Whether to use local data */ - public StatisticsImporter(boolean local) - { + public StatisticsImporter(boolean local) { bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); collectionService = ContentServiceFactory.getInstance().getCollectionService(); communityService = ContentServiceFactory.getInstance().getCommunityService(); itemService = ContentServiceFactory.getInstance().getItemService(); // Setup the lists of communities, collections, items & bitstreams if required useLocal = local; - if (local) - { - try - { + if (local) { + try { ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance(); System.out.print("Loading local communities... "); Context c = new Context(); List communities = communityService.findAll(c); localCommunities = new ArrayList<>(); - for (Community community : communities) - { + for (Community community : communities) { localCommunities.add(community.getID()); } System.out.println("Found " + localCommunities.size()); @@ -114,8 +151,7 @@ public class StatisticsImporter System.out.print("Loading local collections... "); List collections = collectionService.findAll(c); localCollections = new ArrayList<>(); - for (Collection collection : collections) - { + for (Collection collection : collections) { localCollections.add(collection.getID()); } System.out.println("Found " + localCollections.size()); @@ -124,8 +160,7 @@ public class StatisticsImporter Iterator items = itemService.findAll(c); localItems = new ArrayList<>(); Item i; - while (items.hasNext()) - { + while (items.hasNext()) { i = items.next(); localItems.add(i.getID()); } @@ -134,17 +169,14 @@ public class StatisticsImporter System.out.print("Loading local bitstreams... "); List bitstreams = bitstreamService.findAll(c); localBitstreams = new ArrayList<>(); - for (Bitstream bitstream : bitstreams) - { - if (bitstream.getName() != null) - { + for (Bitstream bitstream : bitstreams) { + if (bitstream.getName() != null) { localBitstreams.add(bitstream.getID()); } } System.out.println("Found " + localBitstreams.size()); - } catch (Exception e) - { + } catch (Exception e) { System.err.println("Error retrieving items from DSpace database:"); e.printStackTrace(); System.exit(1); @@ -156,26 +188,23 @@ public class StatisticsImporter * Read lines from the statistics file and load their data into solr. * * @param filename The filename of the file to load - * @param context The DSpace Context - * @param verbose Whether to display verbose output + * @param context The DSpace Context + * @param verbose Whether to display verbose output */ - protected void load(String filename, Context context, boolean verbose) - { + protected void load(String filename, Context context, boolean verbose) { // Item counter int counter = 0; int errors = 0; int searchengines = 0; - try - { + try { BufferedReader input; - if (null == filename || "-".equals(filename)) - { + if (null == filename || "-".equals(filename)) { input = new BufferedReader(new InputStreamReader(System.in)); filename = "standard input"; - } - else + } else { input = new BufferedReader(new FileReader(new File(filename))); + } // Print out the filename for confirmation System.out.println("Processing file: " + filename); @@ -191,8 +220,8 @@ public class StatisticsImporter String continent = ""; String country = ""; String countryCode = ""; - float longitude = 0f; - float latitude = 0f; + double longitude = 0f; + double latitude = 0f; String city = ""; String dns; @@ -200,14 +229,12 @@ public class StatisticsImporter Object fromCache; Random rand = new Random(); - while ((line = input.readLine()) != null) - { + while ((line = input.readLine()) != null) { // Tokenise the line String data = ""; counter++; errors++; - if (verbose) - { + if (verbose) { System.out.println("Line:" + line); } String[] parts = line.split(","); @@ -220,22 +247,16 @@ public class StatisticsImporter // Resolve the dns (if applicable) to get rid of search engine bots early on in the processing chain dns = ""; - if (!skipReverseDNS) - { + if (!skipReverseDNS) { // Is the IP address in the cache? fromCache = dnsCache.get(ip); - if (fromCache != null) - { - dns = (String)fromCache; - } - else - { - try - { + if (fromCache != null) { + dns = (String) fromCache; + } else { + try { dns = DnsLookup.reverseDns(ip); dnsCache.put(ip, dns); - } catch (Exception e) - { + } catch (Exception e) { dns = ""; } } @@ -245,10 +266,8 @@ public class StatisticsImporter data += (", dns name = " + dns); if ((dns.endsWith(".googlebot.com.")) || (dns.endsWith(".crawl.yahoo.net.")) || - (dns.endsWith(".search.msn.com."))) - { - if (verbose) - { + (dns.endsWith(".search.msn.com."))) { + if (verbose) { System.out.println(data + ", IGNORE (search engine)"); } errors--; @@ -257,15 +276,15 @@ public class StatisticsImporter } // Get the geo information for the user - Location location; try { - location = geoipLookup.getLocation(ip); - city = location.city; - country = location.countryName; - countryCode = location.countryCode; - longitude = location.longitude; - latitude = location.latitude; - if(verbose) { + InetAddress ipAddress = InetAddress.getByName(ip); + CityResponse cityResponse = geoipLookup.city(ipAddress); + city = cityResponse.getCity().getName(); + country = cityResponse.getCountry().getName(); + countryCode = cityResponse.getCountry().getIsoCode(); + longitude = cityResponse.getLocation().getLongitude(); + latitude = cityResponse.getLocation().getLatitude(); + if (verbose) { data += (", country = " + country); data += (", city = " + city); System.out.println(data); @@ -273,8 +292,7 @@ public class StatisticsImporter try { continent = LocationUtils.getContinentCode(countryCode); } catch (Exception e) { - if (verbose) - { + if (verbose) { System.out.println("Unknown country code: " + countryCode); } continue; @@ -286,48 +304,34 @@ public class StatisticsImporter // Now find our dso ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance(); DSpaceObjectLegacySupportService legacySupportService = null; - if ("view_bitstream".equals(action)) - { + if ("view_bitstream".equals(action)) { legacySupportService = contentServiceFactory.getBitstreamService(); - if (useLocal) - { + if (useLocal) { id = "" + localBitstreams.get(rand.nextInt(localBitstreams.size())); } - } - else if ("view_item".equals(action)) - { + } else if ("view_item".equals(action)) { legacySupportService = contentServiceFactory.getItemService(); - if (useLocal) - { + if (useLocal) { id = "" + localItems.get(rand.nextInt(localItems.size())); } - } - else if ("view_collection".equals(action)) - { + } else if ("view_collection".equals(action)) { legacySupportService = contentServiceFactory.getCollectionService(); - if (useLocal) - { + if (useLocal) { id = "" + localCollections.get(rand.nextInt(localCollections.size())); } - } - else if ("view_community".equals(action)) - { + } else if ("view_community".equals(action)) { legacySupportService = contentServiceFactory.getCommunityService(); - if (useLocal) - { + if (useLocal) { id = "" + localCommunities.get(rand.nextInt(localCommunities.size())); } } - if(legacySupportService == null) - { + if (legacySupportService == null) { continue; } DSpaceObject dso = legacySupportService.findByIdOrLegacyId(context, id); - if (dso == null) - { - if (verbose) - { + if (dso == null) { + if (verbose) { System.err.println(" - DSO with ID '" + id + "' is no longer in the system"); } continue; @@ -336,8 +340,7 @@ public class StatisticsImporter // Get the eperson details EPerson eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, user); int epersonId = 0; - if (eperson != null) - { + if (eperson != null) { eperson.getID(); } @@ -353,12 +356,10 @@ public class StatisticsImporter sid.addField("city", city); sid.addField("latitude", latitude); sid.addField("longitude", longitude); - if (epersonId > 0) - { + if (epersonId > 0) { sid.addField("epersonid", epersonId); } - if (dns != null) - { + if (dns != null) { sid.addField("dns", dns.toLowerCase()); } @@ -367,13 +368,9 @@ public class StatisticsImporter errors--; } - } - catch (RuntimeException re) - { + } catch (RuntimeException re) { throw re; - } - catch (Exception e) - { + } catch (Exception e) { System.err.println(e.getMessage()); log.error(e.getMessage(), e); } @@ -381,29 +378,25 @@ public class StatisticsImporter DecimalFormat percentage = new DecimalFormat("##.###"); int committed = counter - errors - searchengines; System.out.println("Processed " + counter + " log lines"); - if (counter > 0) - { + if (counter > 0) { Double committedpercentage = 100d * committed / counter; - System.out.println(" - " + committed + " entries added to solr: " + percentage.format(committedpercentage) + "%"); + System.out + .println(" - " + committed + " entries added to solr: " + percentage.format(committedpercentage) + "%"); Double errorpercentage = 100d * errors / counter; System.out.println(" - " + errors + " errors: " + percentage.format(errorpercentage) + "%"); Double sepercentage = 100d * searchengines / counter; - System.out.println(" - " + searchengines + " search engine activity skipped: " + percentage.format(sepercentage) + "%"); + System.out.println( + " - " + searchengines + " search engine activity skipped: " + percentage.format(sepercentage) + "%"); System.out.print("About to commit data to solr..."); // Commit at the end because it takes a while - try - { + try { solr.commit(); - } - catch (SolrServerException sse) - { + } catch (SolrServerException sse) { System.err.println("Error committing statistics to solr server!"); sse.printStackTrace(); System.exit(1); - } - catch (IOException ioe) - { + } catch (IOException ioe) { System.err.println("Error writing to solr server!"); ioe.printStackTrace(); System.exit(1); @@ -415,11 +408,10 @@ public class StatisticsImporter /** * Print the help message * - * @param options The command line options the user gave + * @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) - { + private static void printHelp(Options options, int exitCode) { // print the help message HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("StatisticsImporter\n", options); @@ -432,35 +424,32 @@ public class StatisticsImporter * @param args the command line arguments given * @throws Exception If something goes wrong */ - public static void main(String[] args) throws Exception - { + public static void main(String[] args) throws Exception { CommandLineParser parser = new PosixParser(); Options options = new Options(); options.addOption("i", "in", true, - "the input file ('-' or omit for standard input)"); + "the input file ('-' or omit for standard input)"); options.addOption("l", "local", false, - "developers tool - map external log file to local handles"); + "developers tool - map external log file to local handles"); options.addOption("m", "multiple", false, - "treat the input file as having a wildcard ending"); + "treat the input file as having a wildcard ending"); options.addOption("s", "skipdns", false, - "skip performing reverse DNS lookups on IP addresses"); + "skip performing reverse DNS lookups on IP addresses"); options.addOption("v", "verbose", false, - "display verbose output (useful for debugging)"); + "display verbose output (useful for debugging)"); options.addOption("h", "help", false, - "help"); + "help"); CommandLine line = parser.parse(options, args); // Did the user ask to see the help? - if (line.hasOption('h')) - { + if (line.hasOption('h')) { printHelp(options, 0); } - if (line.hasOption('s')) - { + if (line.hasOption('s')) { skipReverseDNS = true; } @@ -476,50 +465,46 @@ public class StatisticsImporter // Find our solr server String sserver = ConfigurationManager.getProperty("solr-statistics", "server"); - if (verbose) - { + if (verbose) { System.out.println("Writing to solr server at: " + sserver); } solr = new HttpSolrServer(sserver); - String dbfile = ConfigurationManager.getProperty("usage-statistics", "dbfile"); - try - { - geoipLookup = new LookupService(dbfile, LookupService.GEOIP_STANDARD); - } - catch (FileNotFoundException fe) - { - log.error("The GeoLite Database file is missing (" + dbfile + ")! Solr Statistics cannot generate location based reports! Please see the DSpace installation instructions for instructions to install this file.", fe); - } - catch (IOException e) - { - log.error("Unable to load GeoLite Database file (" + dbfile + ")! You may need to reinstall it. See the DSpace installation instructions for more details.", e); + String dbPath = ConfigurationManager.getProperty("usage-statistics", "dbfile"); + try { + File dbFile = new File(dbPath); + geoipLookup = new DatabaseReader.Builder(dbFile).build(); + } catch (FileNotFoundException fe) { + log.error( + "The GeoLite Database file is missing (" + dbPath + ")! Solr Statistics cannot generate location " + + "based reports! Please see the DSpace installation instructions for instructions to install this " + + "file.", + fe); + } catch (IOException e) { + log.error( + "Unable to load GeoLite Database file (" + dbPath + ")! You may need to reinstall it. See the DSpace " + + "installation instructions for more details.", + e); } StatisticsImporter si = new StatisticsImporter(local); - if (line.hasOption('m')) - { + if (line.hasOption('m')) { // Convert all the files final File sample = new File(line.getOptionValue('i')); File dir = sample.getParentFile(); - FilenameFilter filter = new FilenameFilter() - { + FilenameFilter filter = new FilenameFilter() { @Override - public boolean accept(File dir, String name) - { + public boolean accept(File dir, String name) { return name.startsWith(sample.getName()); } }; String[] children = dir.list(filter); - for (String in : children) - { + for (String in : children) { System.out.println(in); si.load(dir.getAbsolutePath() + System.getProperty("file.separator") + in, context, verbose); } - } - else - { + } else { // Just convert the one file si.load(line.getOptionValue('i'), context, verbose); } @@ -528,22 +513,20 @@ public class StatisticsImporter /** * Inner class to hold a cache of reverse lookups of IP addresses + * * @param key type. * @param value type. */ - static class DNSCache extends LinkedHashMap - { + static class DNSCache extends LinkedHashMap { private final int maxCapacity; - public DNSCache(int initialCapacity, float loadFactor, int maxCapacity) - { + public DNSCache(int initialCapacity, float loadFactor, int maxCapacity) { super(initialCapacity, loadFactor, true); this.maxCapacity = maxCapacity; } @Override - protected boolean removeEldestEntry(java.util.Map.Entry eldest) - { + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { return size() >= this.maxCapacity; } } diff --git a/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsImporterElasticSearch.java b/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsImporterElasticSearch.java deleted file mode 100644 index 52969c9030..0000000000 --- a/dspace-api/src/main/java/org/dspace/statistics/util/StatisticsImporterElasticSearch.java +++ /dev/null @@ -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.statistics.util; - -import com.maxmind.geoip.Location; -import com.maxmind.geoip.LookupService; -import org.apache.commons.cli.*; -import org.apache.commons.lang.time.DateFormatUtils; -import org.apache.log4j.Logger; -import org.dspace.content.Bitstream; -import org.dspace.content.Bundle; -import org.dspace.content.DSpaceObject; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.DSpaceObjectLegacySupportService; -import org.dspace.core.ConfigurationManager; -import org.dspace.core.Constants; -import org.dspace.core.Context; -import org.dspace.eperson.EPerson; -import org.dspace.eperson.factory.EPersonServiceFactory; -import org.dspace.statistics.SolrLoggerServiceImpl; -import org.dspace.statistics.factory.StatisticsServiceFactory; -import org.dspace.statistics.service.ElasticSearchLoggerService; -import org.elasticsearch.action.bulk.BulkRequestBuilder; -import org.elasticsearch.action.bulk.BulkResponse; -import org.elasticsearch.client.Client; - -import org.elasticsearch.common.geo.GeoPoint; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; - - -import java.io.*; -import java.text.DateFormat; -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.*; - - -/** - * Class to load intermediate statistics files (produced from log files by ClassicDSpaceLogConverter) into Elastic Search - * - * @see ClassicDSpaceLogConverter - * - * @author Peter Dietz (pdietz84@gmail.com) - */ -public class StatisticsImporterElasticSearch { - private static final Logger log = Logger.getLogger(StatisticsImporterElasticSearch.class); - - /** Date format */ - private static ThreadLocal dateFormat = new ThreadLocal() { - @Override - protected DateFormat initialValue() { - return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - } - }; - - //TODO ES Client - - /** GEOIP lookup service */ - private static LookupService geoipLookup; - - /** Metadata storage information */ - private static Map metadataStorageInfo; - - /** Whether to skip the DNS reverse lookup or not */ - private static boolean skipReverseDNS = false; - - private static ElasticSearchLoggerService elasticSearchLoggerInstance = StatisticsServiceFactory.getInstance().getElasticSearchLoggerService(); - ; - private static Client client; - private static BulkRequestBuilder bulkRequest; - - /** - * Read lines from the statistics file and load their data into Elastic Search. - * - * @param filename The filename of the file to load - * @param context The DSpace Context - * @param verbose Whether to display verbose output - */ - private void load(String filename, Context context, boolean verbose) - { - // Item counter - int counter = 0; - int errors = 0; - int searchengines = 0; - - try - { - BufferedReader input; - if (null == filename || "-".equals(filename)) - { - input = new BufferedReader(new InputStreamReader(System.in)); - filename = "standard input"; - } - else - input = new BufferedReader(new FileReader(new File(filename))); - - // Print out the filename for confirmation - System.out.println("Processing file: " + filename); - - String line; -// String uuid; - String action; - String id; - Date date; - String user; - String ip; - - String continent = ""; - String country = ""; - String countryCode = ""; - float longitude = 0f; - float latitude = 0f; - String city = ""; - String dns; - - DNSCache dnsCache = new DNSCache(2500, 0.75f, 2500); - Object fromCache; - - ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance(); - while ((line = input.readLine()) != null) - { - // Tokenise the line - counter++; - errors++; - if (verbose) - { - System.out.println("Line:" + line); - } - String[] parts = line.split(","); -// uuid = parts[0]; - action = parts[1]; - id = parts[2]; - date = dateFormat.get().parse(parts[3]); - user = parts[4]; - ip = parts[5]; - - // Resolve the dns (if applicable) to get rid of search engine bots early on in the processing chain - dns = ""; - if (!skipReverseDNS) - { - // Is the IP address in the cache? - fromCache = dnsCache.get(ip); - if (fromCache != null) - { - dns = (String)fromCache; - } - else - { - try - { - dns = DnsLookup.reverseDns(ip); - dnsCache.put(ip, dns); - } catch (Exception e) - { - dns = ""; - } - } - } - - - - - String data = ""; - data += ("ip addr = " + ip); - data += (", dns name = " + dns); - if ((dns.endsWith(".googlebot.com.")) || - (dns.endsWith(".crawl.yahoo.net.")) || - (dns.endsWith(".search.msn.com."))) - { - if (verbose) - { - System.out.println(data + ", IGNORE (search engine)"); - } - errors--; - searchengines++; - continue; - } - - // Get the geo information for the user - Location location; - try { - location = geoipLookup.getLocation(ip); - city = location.city; - country = location.countryName; - countryCode = location.countryCode; - longitude = location.longitude; - latitude = location.latitude; - if(verbose) { - data += (", country = " + country); - data += (", city = " + city); - System.out.println(data); - } - try { - continent = LocationUtils.getContinentCode(countryCode); - } catch (Exception e) { - if (verbose) - { - System.out.println("Unknown country code: " + countryCode); - } - continue; - } - } catch (Exception e) { - // No problem - just can't look them up - } - - // Now find our dso - DSpaceObjectLegacySupportService legacySupportService = null; - int type = 0; - if ("view_bitstream".equals(action)) - { - legacySupportService = contentServiceFactory.getBitstreamService(); - type = Constants.BITSTREAM; - } - else if ("view_item".equals(action)) - { - legacySupportService = contentServiceFactory.getItemService(); - type = Constants.ITEM; - } - else if ("view_collection".equals(action)) - { - legacySupportService = contentServiceFactory.getCollectionService(); - type = Constants.COLLECTION; - } - else if ("view_community".equals(action)) - { - legacySupportService = contentServiceFactory.getCommunityService(); - type = Constants.COMMUNITY; - } - if(legacySupportService == null) - { - continue; - } - - - DSpaceObject dso = legacySupportService.findByIdOrLegacyId(context, id); - if (dso == null) - { - if (verbose) - { - System.err.println(" - DSO with ID '" + id + "' is no longer in the system"); - } - continue; - } - - // Get the eperson details - EPerson eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, user); - int epersonId = 0; - if (eperson != null) - { - eperson.getID(); - } - - //TODO Is there any way to reuse ElasticSearchLogger.post() ? - - // Save it in our server - XContentBuilder postBuilder = XContentFactory.jsonBuilder().startObject() - .field("id", dso.getID()) - .field("typeIndex", dso.getType()) - .field("type", contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso)) - - .field("geo", new GeoPoint(latitude, longitude)) - .field("continent", continent) - .field("countryCode", countryCode) - .field("country", country) - .field("city", city) - - .field("ip", ip) - - .field("time", DateFormatUtils.format(date, SolrLoggerServiceImpl.DATE_FORMAT_8601)); - - // Unable to get UserAgent from logs. .field("userAgent") - - if (dso instanceof Bitstream) { - Bitstream bit = (Bitstream) dso; - List bundles = bit.getBundles(); - postBuilder = postBuilder.field("bundleName").startArray(); - for (Bundle bundle : bundles) { - postBuilder = postBuilder.value(bundle.getName()); - } - postBuilder = postBuilder.endArray(); - } - - if (epersonId > 0) - { - postBuilder = postBuilder.field("epersonid", epersonId); - } - if (dns != null) - { - postBuilder = postBuilder.field("dns", dns.toLowerCase()); - } - - - //Save for later: .field("isBot") - - elasticSearchLoggerInstance.storeParents(postBuilder, elasticSearchLoggerInstance.getParents(dso)); - - bulkRequest.add(client.prepareIndex(elasticSearchLoggerInstance.getIndexName(), elasticSearchLoggerInstance.getIndexType()) - .setSource(postBuilder.endObject())); - - - errors--; - } - - if(bulkRequest.numberOfActions() > 0) { - BulkResponse bulkResponse = bulkRequest.execute().actionGet(); - if(bulkResponse.hasFailures()) { - log.error("Bulk Request Failed due to: " + bulkResponse.buildFailureMessage()); - } - } - } - catch (RuntimeException re) - { - throw re; - } - catch (Exception e) - { - System.err.println(e.getMessage()); - log.error(e.getMessage(), e); - } - - DecimalFormat percentage = new DecimalFormat("##.###"); - int committed = counter - errors - searchengines; - System.out.println("Processed " + counter + " log lines"); - if (counter > 0) - { - Double committedpercentage = 100d * committed / counter; - System.out.println(" - " + committed + " entries added to ElasticSearch: " + percentage.format(committedpercentage) + "%"); - Double errorpercentage = 100d * errors / counter; - System.out.println(" - " + errors + " errors: " + percentage.format(errorpercentage) + "%"); - Double sepercentage = 100d * searchengines / counter; - System.out.println(" - " + searchengines + " search engine activity skipped: " + percentage.format(sepercentage) + "%"); - } - System.out.println(" done!"); - } - - - /** - * 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("StatisticsImporterElasticSearch\n", options); - System.exit(exitCode); - } - - - /** - * Main method to run the statistics importer. - * - * @param args the command line arguments given - * @throws Exception If something goes wrong - */ - public static void main(String[] args) throws Exception - { - CommandLineParser parser = new PosixParser(); - - Options options = new Options(); - - options.addOption("i", "in", true, "the input file ('-' or omit for standard input)"); - options.addOption("m", "multiple", false, "treat the input file as having a wildcard ending"); - options.addOption("s", "skipdns", false, "skip performing reverse DNS lookups on IP addresses"); - options.addOption("v", "verbose", false, "display verbose output (useful for debugging)"); - options.addOption("h", "help", false, "help"); - - CommandLine line = parser.parse(options, args); - - // Did the user ask to see the help? - if (line.hasOption('h')) - { - printHelp(options, 0); - } - - if (line.hasOption('s')) - { - skipReverseDNS = true; - } - - log.info("Getting ElasticSearch Transport Client for StatisticsImporterElasticSearch..."); - - // This is only invoked via terminal, do not use _this_ node as that data storing node. - // Need to get a NodeClient or TransportClient, but definitely do not want to get a local data storing client. - client = elasticSearchLoggerInstance.getClient(ElasticSearchLoggerService.ClientType.TRANSPORT); - - client.admin().indices().prepareRefresh(StatisticsServiceFactory.getInstance().getElasticSearchLoggerService().getIndexName()).execute().actionGet(); - bulkRequest = client.prepareBulk(); - - // We got all our parameters now get the rest - Context context = new Context(); - - // Verbose option - boolean verbose = line.hasOption('v'); - - String dbfile = ConfigurationManager.getProperty("usage-statistics", "dbfile"); - try - { - geoipLookup = new LookupService(dbfile, LookupService.GEOIP_STANDARD); - } - catch (FileNotFoundException fe) - { - log.error("The GeoLite Database file is missing (" + dbfile + ")! Elastic Search Statistics cannot generate location based reports! Please see the DSpace installation instructions for instructions to install this file.", fe); - } - catch (IOException e) - { - log.error("Unable to load GeoLite Database file (" + dbfile + ")! You may need to reinstall it. See the DSpace installation instructions for more details.", e); - } - - - StatisticsImporterElasticSearch elasticSearchImporter = new StatisticsImporterElasticSearch(); - if (line.hasOption('m')) - { - // Convert all the files - final File sample = new File(line.getOptionValue('i')); - File dir = sample.getParentFile(); - FilenameFilter filter = new FilenameFilter() - { - @Override - public boolean accept(File dir, String name) - { - return name.startsWith(sample.getName()); - } - }; - String[] children = dir.list(filter); - for (String in : children) - { - System.out.println(in); - elasticSearchImporter.load(dir.getAbsolutePath() + System.getProperty("file.separator") + in, context, verbose); - } - } - else - { - // Just convert the one file - elasticSearchImporter.load(line.getOptionValue('i'), context, verbose); - } - } - - - /** - * Inner class to hold a cache of reverse lookups of IP addresses - * @param IP address - * @param hostname looked up via DNS - */ - static class DNSCache extends LinkedHashMap - { - private int maxCapacity; - - public DNSCache(int initialCapacity, float loadFactor, int maxCapacity) - { - super(initialCapacity, loadFactor, true); - this.maxCapacity = maxCapacity; - } - - @Override - protected boolean removeEldestEntry(java.util.Map.Entry eldest) - { - return size() >= this.maxCapacity; - } - } -} diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitStoreMigrate.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitStoreMigrate.java index b852814a41..9aab7c4346 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitStoreMigrate.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitStoreMigrate.java @@ -7,7 +7,12 @@ */ package org.dspace.storage.bitstore; -import org.apache.commons.cli.*; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; @@ -20,21 +25,27 @@ import org.dspace.storage.bitstore.service.BitstreamStorageService; */ public class BitStoreMigrate { - /** log4j log */ + /** + * log4j log + */ private static Logger log = Logger.getLogger(BitStoreMigrate.class); private static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - private static final BitstreamStorageService bitstreamStorageService = StorageServiceFactory.getInstance().getBitstreamStorageService(); + private static final BitstreamStorageService bitstreamStorageService = + StorageServiceFactory.getInstance().getBitstreamStorageService(); + + /** + * Default constructor + */ + private BitStoreMigrate() { } /** * Migrates asset store. * * @param argv the command line arguments given */ - public static void main(String[] argv) - { - try - { + public static void main(String[] argv) { + try { log.info("Migrate Assetstore"); // set up command line parser @@ -44,26 +55,26 @@ public class BitStoreMigrate { // create an options object and populate it Options options = new Options(); - options.addOption("a", "source", true, "Source assetstore store_number (to lose content). This is a number such as 0 or 1"); - options.addOption("b", "destination", true, "Destination assetstore store_number (to gain content). This is a number such as 0 or 1."); - options.addOption("d", "delete", false, "Delete file from losing assetstore. (Default: Keep bitstream in old assetstore)"); + options.addOption("a", "source", true, + "Source assetstore store_number (to lose content). This is a number such as 0 or 1"); + options.addOption("b", "destination", true, + "Destination assetstore store_number (to gain content). This is a number such as 0 or " + + "1."); + options.addOption("d", "delete", false, + "Delete file from losing assetstore. (Default: Keep bitstream in old assetstore)"); options.addOption("p", "print", false, "Print out current assetstore information"); options.addOption("s", "size", true, "Batch commit size. (Default: 1, commit after each file transfer)"); options.addOption("h", "help", false, "Help"); - try - { + try { line = parser.parse(options, argv); - } - catch (ParseException e) - { + } catch (ParseException e) { log.fatal(e); System.exit(1); } // user asks for help - if (line.hasOption('h')) - { + if (line.hasOption('h')) { printHelp(options); System.exit(0); } @@ -71,31 +82,31 @@ public class BitStoreMigrate { Context context = new Context(Context.Mode.BATCH_EDIT); context.turnOffAuthorisationSystem(); - if(line.hasOption('p')) { + if (line.hasOption('p')) { bitstreamStorageService.printStores(context); System.exit(0); } boolean deleteOld = false; - if (line.hasOption('d')) - { + if (line.hasOption('d')) { log.debug("DELETE flag set to remove bitstream from old assetstore"); deleteOld = true; } log.debug("deleteOldAssets = " + deleteOld); - if(line.hasOption('a') && line.hasOption('b')) { + if (line.hasOption('a') && line.hasOption('b')) { Integer sourceAssetstore = Integer.valueOf(line.getOptionValue('a')); Integer destinationAssetstore = Integer.valueOf(line.getOptionValue('b')); //Safe default, commit every time. TODO Performance Profile Integer batchCommitSize = 1; - if(line.hasOption('s')) { + if (line.hasOption('s')) { batchCommitSize = Integer.parseInt(line.getOptionValue('s')); } - bitstreamStorageService.migrate(context, sourceAssetstore, destinationAssetstore, deleteOld, batchCommitSize); + bitstreamStorageService + .migrate(context, sourceAssetstore, destinationAssetstore, deleteOld, batchCommitSize); } else { printHelp(options); System.exit(0); @@ -104,17 +115,14 @@ public class BitStoreMigrate { context.complete(); System.exit(0); - } - catch (Exception e) - { + } catch (Exception e) { log.fatal("Caught exception:", e); System.out.println("Exception during BitStoreMigrate: " + e.getMessage()); System.exit(1); } } - private static void printHelp(Options options) - { + private static void printHelp(Options options) { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("BitstoreMigrate\n", options); } diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitStoreService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitStoreService.java index fdd2f75d5f..b33867f0e2 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitStoreService.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitStoreService.java @@ -7,45 +7,40 @@ */ package org.dspace.storage.bitstore; -import org.dspace.content.Bitstream; - import java.io.IOException; import java.io.InputStream; import java.util.Map; +import org.dspace.content.Bitstream; + /** * A low-level asset store interface - * + * * @author Richard Rodgers, Peter Dietz */ -public interface BitStoreService -{ +public interface BitStoreService { /** * Initialize the asset store * - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ public void init() throws IOException; /** * Return an identifier unique to this asset store instance - * + * * @return a unique ID */ public String generateId(); - + /** * Retrieve the bits for bitstream - * - * @param bitstream - * DSpace Bitstream object - * @throws java.io.IOException - * If a problem occurs while retrieving the bits, or if no - * asset with ID exists in the store * + * @param bitstream DSpace Bitstream object * @return The stream of bits + * @throws java.io.IOException If a problem occurs while retrieving the bits, or if no + * asset with ID exists in the store */ public InputStream get(Bitstream bitstream) throws IOException; @@ -57,38 +52,29 @@ public interface BitStoreService * If an exception is thrown, the bits have not been stored. *

    * - * @param bitstream - * The bitstream object - * @param inputStream - * The stream of bits - * @throws java.io.IOException - * If a problem occurs while storing the bits + * @param bitstream The bitstream object + * @param inputStream The stream of bits + * @throws java.io.IOException If a problem occurs while storing the bits */ public void put(Bitstream bitstream, InputStream inputStream) throws IOException; /** * Obtain technical metadata about an asset in the asset store. * - * @param bitstream - * The bitstream to describe - * @param attrs - * A Map whose keys consist of desired metadata fields - * - * @throws java.io.IOException - * If a problem occurs while obtaining metadata + * @param bitstream The bitstream to describe + * @param attrs A Map whose keys consist of desired metadata fields * @return attrs - * A Map with key/value pairs of desired metadata - * If file not found, then return null + * A Map with key/value pairs of desired metadata + * If file not found, then return null + * @throws java.io.IOException If a problem occurs while obtaining metadata */ public Map about(Bitstream bitstream, Map attrs) throws IOException; /** * Remove an asset from the asset store. * - * @param bitstream - * The bitstream of the asset to delete - * @throws java.io.IOException - * If a problem occurs while removing the asset + * @param bitstream The bitstream of the asset to delete + * @throws java.io.IOException If a problem occurs while removing the asset */ public void remove(Bitstream bitstream) throws IOException; } diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java index 5dacbf9545..18e1f33388 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java @@ -7,7 +7,16 @@ */ package org.dspace.storage.bitstore; -import org.apache.commons.collections.MapUtils; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.collections4.MapUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.checker.service.ChecksumHistoryService; @@ -21,16 +30,11 @@ import org.dspace.storage.bitstore.service.BitstreamStorageService; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.*; - /** *

    * Stores, retrieves and deletes bitstreams. *

    - * + * *

    * Presently, asset stores are specified in dspace.cfg. Since * Java does not offer a way of detecting free disk space, the asset store to @@ -39,24 +43,25 @@ import java.util.*; * available space in the asset stores, and DSpace (Tomcat) has to be restarted * when the asset store for new ('incoming') bitstreams is changed. *

    - * + * *

    * Mods by David Little, UCSD Libraries 12/21/04 to allow the registration of * files (bitstreams) into DSpace. *

    - * - *

    Cleanup integration with checker package by Nate Sarr 2006-01. N.B. The - * dependency on the checker package isn't ideal - a Listener pattern would be + * + *

    Cleanup integration with checker package by Nate Sarr 2006-01. N.B. The + * dependency on the checker package isn't ideal - a Listener pattern would be * better but was considered overkill for the purposes of integrating the checker. - * It would be worth re-considering a Listener pattern if another package needs to - * be notified of BitstreamStorageManager actions.

    + * It would be worth re-considering a Listener pattern if another package needs to + * be notified of BitstreamStorageManager actions.

    * * @author Peter Breton, Robert Tansley, David Little, Nathan Sarr * @version $Revision$ */ -public class BitstreamStorageServiceImpl implements BitstreamStorageService, InitializingBean -{ - /** log4j log */ +public class BitstreamStorageServiceImpl implements BitstreamStorageService, InitializingBean { + /** + * log4j log + */ private static Logger log = Logger.getLogger(BitstreamStorageServiceImpl.class); @Autowired(required = true) @@ -64,32 +69,34 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini @Autowired(required = true) protected ChecksumHistoryService checksumHistoryService; - /** asset stores */ + /** + * asset stores + */ private Map stores = new HashMap(); - /** The index of the asset store to use for new bitstreams */ + /** + * The index of the asset store to use for new bitstreams + */ private int incoming; - /** - * This prefix string marks registered bitstreams in internal_id - */ - protected final String REGISTERED_FLAG = "-R"; + /** + * This prefix string marks registered bitstreams in internal_id + */ + protected final String REGISTERED_FLAG = "-R"; - protected BitstreamStorageServiceImpl() - { + protected BitstreamStorageServiceImpl() { } @Override public void afterPropertiesSet() throws Exception { - for(Map.Entry storeEntry : stores.entrySet()) { + for (Map.Entry storeEntry : stores.entrySet()) { storeEntry.getValue().init(); } } @Override - public UUID store(Context context, Bitstream bitstream, InputStream is) throws SQLException, IOException - { + public UUID store(Context context, Bitstream bitstream, InputStream is) throws SQLException, IOException { // Create internal ID String id = Utils.generateKey(); @@ -108,10 +115,11 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini //bitstream.setSizeBytes(file.length()); //bitstream.setChecksum(Utils.toHex(dis.getMessageDigest().digest())); //bitstream.setChecksumAlgorithm("MD5"); - + bitstream.setDeleted(false); try { - //Update our bitstream but turn off the authorization system since permissions haven't been set at this point in time. + //Update our bitstream but turn off the authorization system since permissions haven't been set at this + // point in time. context.turnOffAuthorisationSystem(); bitstreamService.update(context, bitstream); } catch (AuthorizeException e) { @@ -123,36 +131,33 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini UUID bitstreamId = bitstream.getID(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug("Stored bitstreamID " + bitstreamId); } return bitstreamId; } - /** - * Register a bitstream already in storage. - * - * @param context - * The current context - * @param assetstore The assetstore number for the bitstream to be - * registered - * @param bitstreamPath The relative path of the bitstream to be registered. - * The path is relative to the path of ths assetstore. - * @return The ID of the registered bitstream - * @throws SQLException - * If a problem occurs accessing the RDBMS - * @throws IOException if IO error - */ - @Override + /** + * Register a bitstream already in storage. + * + * @param context The current context + * @param assetstore The assetstore number for the bitstream to be + * registered + * @param bitstreamPath The relative path of the bitstream to be registered. + * The path is relative to the path of ths assetstore. + * @return The ID of the registered bitstream + * @throws SQLException If a problem occurs accessing the RDBMS + * @throws IOException if IO error + */ + @Override public UUID register(Context context, Bitstream bitstream, int assetstore, - String bitstreamPath) throws SQLException, IOException, AuthorizeException { + String bitstreamPath) throws SQLException, IOException, AuthorizeException { - // mark this bitstream as a registered bitstream - String sInternalId = REGISTERED_FLAG + bitstreamPath; + // mark this bitstream as a registered bitstream + String sInternalId = REGISTERED_FLAG + bitstreamPath; - // Create a deleted bitstream row, using a separate DB connection + // Create a deleted bitstream row, using a separate DB connection bitstream.setDeleted(true); bitstream.setInternalId(sInternalId); bitstream.setStoreNumber(assetstore); @@ -164,34 +169,33 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini wantedMetadata.put("checksum_algorithm", null); Map receivedMetadata = stores.get(assetstore).about(bitstream, wantedMetadata); - if(MapUtils.isEmpty(receivedMetadata)) { + if (MapUtils.isEmpty(receivedMetadata)) { String message = "Not able to register bitstream:" + bitstream.getID() + " at path: " + bitstreamPath; log.error(message); throw new IOException(message); } else { - if(receivedMetadata.containsKey("checksum_algorithm")) { + if (receivedMetadata.containsKey("checksum_algorithm")) { bitstream.setChecksumAlgorithm(receivedMetadata.get("checksum_algorithm").toString()); } - if(receivedMetadata.containsKey("checksum")) { + if (receivedMetadata.containsKey("checksum")) { bitstream.setChecksum(receivedMetadata.get("checksum").toString()); } - if(receivedMetadata.containsKey("size_bytes")) { + if (receivedMetadata.containsKey("size_bytes")) { bitstream.setSizeBytes(Long.valueOf(receivedMetadata.get("size_bytes").toString())); } } - bitstream.setDeleted(false); + bitstream.setDeleted(false); bitstreamService.update(context, bitstream); - UUID bitstreamId = bitstream.getID(); - if (log.isDebugEnabled()) - { - log.debug("Registered bitstream " + bitstreamId + " at location " + bitstreamPath); - } - return bitstreamId; - } + UUID bitstreamId = bitstream.getID(); + if (log.isDebugEnabled()) { + log.debug("Registered bitstream " + bitstreamId + " at location " + bitstreamPath); + } + return bitstreamId; + } @Override public Map computeChecksum(Context context, Bitstream bitstream) throws IOException { @@ -206,12 +210,11 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini @Override public boolean isRegisteredBitstream(String internalId) { return internalId.startsWith(REGISTERED_FLAG); - } + } @Override public InputStream retrieve(Context context, Bitstream bitstream) - throws SQLException, IOException - { + throws SQLException, IOException { Integer storeNumber = bitstream.getStoreNumber(); return stores.get(storeNumber).get(bitstream); } @@ -221,14 +224,12 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini Context context = null; int commitCounter = 0; - try - { + try { context = new Context(Context.Mode.BATCH_EDIT); context.turnOffAuthorisationSystem(); List storage = bitstreamService.findDeletedBitstreams(context); - for (Bitstream bitstream : storage) - { + for (Bitstream bitstream : storage) { UUID bid = bitstream.getID(); Map wantedMetadata = new HashMap(); wantedMetadata.put("size_bytes", null); @@ -237,19 +238,15 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini // Make sure entries which do not exist are removed - if (MapUtils.isEmpty(receivedMetadata)) - { + if (MapUtils.isEmpty(receivedMetadata)) { log.debug("bitstore.about is empty, so file is not present"); - if (deleteDbRecords) - { + if (deleteDbRecords) { log.debug("deleting record"); - if (verbose) - { + if (verbose) { System.out.println(" - Deleting bitstream information (ID: " + bid + ")"); } checksumHistoryService.deleteByBitstream(context, bitstream); - if (verbose) - { + if (verbose) { System.out.println(" - Deleting bitstream record from database (ID: " + bid + ")"); } bitstreamService.expunge(context, bitstream); @@ -260,46 +257,40 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini // This is a small chance that this is a file which is // being stored -- get it next time. - if (isRecent(Long.valueOf(receivedMetadata.get("modified").toString()))) - { - log.debug("file is recent"); + if (isRecent(Long.valueOf(receivedMetadata.get("modified").toString()))) { + log.debug("file is recent"); context.uncacheEntity(bitstream); - continue; + continue; } - if (deleteDbRecords) - { + if (deleteDbRecords) { log.debug("deleting db record"); - if (verbose) - { + if (verbose) { System.out.println(" - Deleting bitstream information (ID: " + bid + ")"); } checksumHistoryService.deleteByBitstream(context, bitstream); - if (verbose) - { + if (verbose) { System.out.println(" - Deleting bitstream record from database (ID: " + bid + ")"); } bitstreamService.expunge(context, bitstream); } - if (isRegisteredBitstream(bitstream.getInternalId())) { + if (isRegisteredBitstream(bitstream.getInternalId())) { context.uncacheEntity(bitstream); - continue; // do not delete registered bitstreams - } + continue; // do not delete registered bitstreams + } - // Since versioning allows for multiple bitstreams, check if the internal identifier isn't used on another place - if(0 < bitstreamService.findDuplicateInternalIdentifier(context, bitstream).size()) - { + // Since versioning allows for multiple bitstreams, check if the internal identifier isn't used on + // another place + if (bitstreamService.findDuplicateInternalIdentifier(context, bitstream).isEmpty()) { stores.get(bitstream.getStoreNumber()).remove(bitstream); String message = ("Deleted bitstreamID " + bid + ", internalID " + bitstream.getInternalId()); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(message); } - if (verbose) - { + if (verbose) { System.out.println(message); } } @@ -309,8 +300,7 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini // if we hit an exception, which isn't useful at all for large // amounts of bitstreams. commitCounter++; - if (commitCounter % 100 == 0) - { + if (commitCounter % 100 == 0) { context.dispatchEvents(); } @@ -320,72 +310,82 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini System.out.print("Committing changes to the database..."); context.complete(); System.out.println(" Done!"); - } - // Aborting will leave the DB objects around, even if the - // bitstreams are deleted. This is OK; deleting them next - // time around will be a no-op. - catch (SQLException | IOException sqle) - { - if (verbose) - { + } catch (SQLException | IOException sqle) { + // Aborting will leave the DB objects around, even if the + // bitstreams are deleted. This is OK; deleting them next + // time around will be a no-op. + if (verbose) { System.err.println("Error: " + sqle.getMessage()); } context.abort(); throw sqle; } finally { - if(context != null){ + if (context != null) { context.restoreAuthSystemState(); } } } - /** - * - * @param context - * The relevant DSpace Context. - * @param bitstream - * the bitstream to be cloned - * @return id of the clone bitstream. - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - @Override - public Bitstream clone(Context context, Bitstream bitstream) throws SQLException, IOException, AuthorizeException { - Bitstream clonedBitstream = bitstreamService.create(context, bitstreamService.retrieve(context, bitstream)); - List metadataValues = bitstreamService.getMetadata(bitstream, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue metadataValue : metadataValues) { - bitstreamService.addMetadata(context, clonedBitstream, metadataValue.getMetadataField(), metadataValue.getLanguage(), metadataValue.getValue(), metadataValue.getAuthority(), metadataValue.getConfidence()); - } - return clonedBitstream; + public Long getLastModified(Bitstream bitstream) { + Map wantedMetadata = new HashMap(); + wantedMetadata.put("modified", null); + try { + wantedMetadata = stores.get(incoming).about(bitstream, wantedMetadata); + } catch (IOException e) { + log.error(e); + } + return Long.valueOf(wantedMetadata.get("modified").toString()); + } - } + /** + * @param context The relevant DSpace Context. + * @param bitstream the bitstream to be cloned + * @return id of the clone bitstream. + * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + */ + @Override + public Bitstream clone(Context context, Bitstream bitstream) throws SQLException, IOException, AuthorizeException { + Bitstream clonedBitstream = bitstreamService.clone(context, bitstream); + clonedBitstream.setStoreNumber(bitstream.getStoreNumber()); + + List metadataValues = bitstreamService + .getMetadata(bitstream, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + + for (MetadataValue metadataValue : metadataValues) { + bitstreamService.addMetadata(context, clonedBitstream, metadataValue.getMetadataField(), + metadataValue.getLanguage(), metadataValue.getValue(), metadataValue.getAuthority(), + metadataValue.getConfidence()); + } + bitstreamService.update(context, clonedBitstream); + return clonedBitstream; + + } /** * Migrates all assets off of one assetstore to another - * @param assetstoreSource - * source assetstore - * @param assetstoreDestination - * destination assetstore - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * + * @param assetstoreSource source assetstore + * @param assetstoreDestination destination assetstore + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ - public void migrate(Context context, Integer assetstoreSource, Integer assetstoreDestination, boolean deleteOld, Integer batchCommitSize) throws IOException, SQLException, AuthorizeException { + public void migrate(Context context, Integer assetstoreSource, Integer assetstoreDestination, boolean deleteOld, + Integer batchCommitSize) throws IOException, SQLException, AuthorizeException { //Find all the bitstreams on the old source, copy it to new destination, update store_number, save, remove old Iterator allBitstreamsInSource = bitstreamService.findByStoreNumber(context, assetstoreSource); Integer processedCounter = 0; while (allBitstreamsInSource.hasNext()) { Bitstream bitstream = allBitstreamsInSource.next(); - log.info("Copying bitstream:" + bitstream.getID() + " from assetstore[" + assetstoreSource + "] to assetstore[" + assetstoreDestination + "] Name:" + bitstream.getName() + ", SizeBytes:" + bitstream.getSize()); + log.info("Copying bitstream:" + bitstream + .getID() + " from assetstore[" + assetstoreSource + "] to assetstore[" + assetstoreDestination + "] " + + "Name:" + bitstream + .getName() + ", SizeBytes:" + bitstream.getSizeBytes()); InputStream inputStream = retrieve(context, bitstream); stores.get(assetstoreDestination).put(bitstream, inputStream); @@ -407,15 +407,19 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini } } - log.info("Assetstore Migration from assetstore[" + assetstoreSource + "] to assetstore[" + assetstoreDestination + "] completed. " + processedCounter + " objects were transferred."); + log.info( + "Assetstore Migration from assetstore[" + assetstoreSource + "] to assetstore[" + assetstoreDestination + + "] completed. " + processedCounter + " objects were transferred."); } public void printStores(Context context) { try { - for(Integer storeNumber : stores.keySet()) { + for (Integer storeNumber : stores.keySet()) { long countBitstreams = bitstreamService.countByStoreNumber(context, storeNumber); - System.out.println("store[" + storeNumber + "] == " + stores.get(storeNumber).getClass().getSimpleName() + ", which has " + countBitstreams + " bitstreams."); + System.out.println("store[" + storeNumber + "] == " + stores.get(storeNumber).getClass() + .getSimpleName() + ", which has " + + countBitstreams + " bitstreams."); } System.out.println("Incoming assetstore is store[" + incoming + "]"); } catch (SQLException e) { @@ -445,17 +449,14 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini /** * Return true if this file is too recent to be deleted, false otherwise. - * - * @param lastModified - * The time asset was last modified + * + * @param lastModified The time asset was last modified * @return True if this file is too recent to be deleted */ - protected boolean isRecent(Long lastModified) - { + protected boolean isRecent(Long lastModified) { long now = new java.util.Date().getTime(); - if (lastModified >= now) - { + if (lastModified >= now) { return true; } diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/Cleanup.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/Cleanup.java index c62d6cb342..97c2a512b7 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/Cleanup.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/Cleanup.java @@ -13,32 +13,35 @@ import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; - import org.apache.log4j.Logger; import org.dspace.storage.bitstore.factory.StorageServiceFactory; /** * Cleans up asset store. - * + * * @author Peter Breton * @version $Revision$ */ -public class Cleanup -{ - /** log4j log */ +public class Cleanup { + /** + * log4j log + */ private static Logger log = Logger.getLogger(Cleanup.class); + /** + * Default constructor + */ + private Cleanup() { } + /** * Cleans up asset store. - * + * * @param argv the command line arguments given */ - public static void main(String[] argv) - { - try - { + public static void main(String[] argv) { + try { log.info("Cleaning up asset store"); - + // set up command line parser CommandLineParser parser = new PosixParser(); CommandLine line = null; @@ -49,45 +52,38 @@ public class Cleanup options.addOption("l", "leave", false, "Leave database records but delete file from assetstore"); options.addOption("v", "verbose", false, "Provide verbose output"); options.addOption("h", "help", false, "Help"); - - try - { + + try { line = parser.parse(options, argv); - } - catch (ParseException e) - { + } catch (ParseException e) { log.fatal(e); System.exit(1); } - + // user asks for help - if (line.hasOption('h')) - { + if (line.hasOption('h')) { printHelp(options); System.exit(0); } boolean deleteDbRecords = true; // Prune stage - if (line.hasOption('l')) - { + if (line.hasOption('l')) { log.debug("option l used setting flag to leave db records"); - deleteDbRecords = false; + deleteDbRecords = false; } log.debug("leave db records = " + deleteDbRecords); - StorageServiceFactory.getInstance().getBitstreamStorageService().cleanup(deleteDbRecords, line.hasOption('v')); - + StorageServiceFactory.getInstance().getBitstreamStorageService() + .cleanup(deleteDbRecords, line.hasOption('v')); + System.exit(0); - } - catch (Exception e) - { + } catch (Exception e) { log.fatal("Caught exception:", e); System.exit(1); } } - - private static void printHelp(Options options) - { + + private static void printHelp(Options options) { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("Cleanup\n", options); } diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/DSBitStoreService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/DSBitStoreService.java index 6d5e3fc166..31901c7f34 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/DSBitStoreService.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/DSBitStoreService.java @@ -7,29 +7,34 @@ */ package org.dspace.storage.bitstore; -import org.apache.log4j.Logger; -import org.dspace.content.Bitstream; -import org.dspace.core.Utils; - -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Map; +import org.apache.log4j.Logger; +import org.dspace.content.Bitstream; +import org.dspace.core.Utils; + /** * Native DSpace (or "Directory Scatter" if you prefer) asset store. * Implements a directory 'scatter' algorithm to avoid OS limits on * files per directory. - * + * * @author Peter Breton, Robert Tansley, Richard Rodgers, Peter Dietz */ -public class DSBitStoreService implements BitStoreService -{ - /** log4j log */ +public class DSBitStoreService implements BitStoreService { + /** + * log4j log + */ private static Logger log = Logger.getLogger(DSBitStoreService.class); - + // These settings control the way an identifier is hashed into // directory and file names // @@ -43,58 +48,51 @@ public class DSBitStoreService implements BitStoreService private static final int digitsPerLevel = 2; private static final int directoryLevels = 3; - + // Checksum algorithm private static final String CSA = "MD5"; - /** the asset directory */ - private File baseDir; - - public DSBitStoreService() - { - } - - /** - * Initialize the asset store - * + /** + * the asset directory */ - public void init() - { - // the config string contains just the asset store directory path - //set baseDir? - } + private File baseDir; - /** + public DSBitStoreService() { + } + + /** + * Initialize the asset store + */ + public void init() { + // the config string contains just the asset store directory path + //set baseDir? + } + + /** * Return an identifier unique to this asset store instance - * + * * @return a unique ID */ - public String generateId() - { + public String generateId() { return Utils.generateKey(); - } + } - /** + /** * Retrieve the bits for the asset with ID. If the asset does not * exist, returns null. - * - * @param bitstream - * The ID of the asset to retrieve - * @throws java.io.IOException - * If a problem occurs while retrieving the bits * + * @param bitstream The ID of the asset to retrieve * @return The stream of bits, or null + * @throws java.io.IOException If a problem occurs while retrieving the bits */ - public InputStream get(Bitstream bitstream) throws IOException - { + public InputStream get(Bitstream bitstream) throws IOException { try { return new FileInputStream(getFile(bitstream)); - } catch (Exception e) - { + } catch (Exception e) { log.error("get(" + bitstream.getInternalId() + ")", e); throw new IOException(e); } - } + } /** * Store a stream of bits. @@ -104,13 +102,10 @@ public class DSBitStoreService implements BitStoreService * If an exception is thrown, the bits have not been stored. *

    * - * @param in - * The stream of bits to store - * @throws java.io.IOException - * If a problem occurs while storing the bits + * @param in The stream of bits to store + * @throws java.io.IOException If a problem occurs while storing the bits */ - public void put(Bitstream bitstream, InputStream in) throws IOException - { + public void put(Bitstream bitstream, InputStream in) throws IOException { try { File file = getFile(bitstream); @@ -122,47 +117,37 @@ public class DSBitStoreService implements BitStoreService //Create the corresponding file and open it file.createNewFile(); - FileOutputStream fos = new FileOutputStream(file); + try ( + FileOutputStream fos = new FileOutputStream(file); + // Read through a digest input stream that will work out the MD5 + DigestInputStream dis = new DigestInputStream(in, MessageDigest.getInstance(CSA)); + ) { + Utils.bufferedCopy(dis, fos); + in.close(); - // Read through a digest input stream that will work out the MD5 - DigestInputStream dis = null; - - try { - dis = new DigestInputStream(in, MessageDigest.getInstance(CSA)); - } - // Should never happen - catch (NoSuchAlgorithmException nsae) { + bitstream.setSizeBytes(file.length()); + bitstream.setChecksum(Utils.toHex(dis.getMessageDigest().digest())); + bitstream.setChecksumAlgorithm(CSA); + } catch (NoSuchAlgorithmException nsae) { + // Should never happen log.warn("Caught NoSuchAlgorithmException", nsae); } - - Utils.bufferedCopy(dis, fos); - fos.close(); - in.close(); - - bitstream.setSizeBytes(file.length()); - bitstream.setChecksum(Utils.toHex(dis.getMessageDigest().digest())); - bitstream.setChecksumAlgorithm(CSA); } catch (Exception e) { log.error("put(" + bitstream.getInternalId() + ", inputstream)", e); throw new IOException(e); } - } - + } + /** * Obtain technical metadata about an asset in the asset store. * - * @param bitstream - * The asset to describe - * @param attrs - * A Map whose keys consist of desired metadata fields - * - * @throws java.io.IOException - * If a problem occurs while obtaining metadata + * @param bitstream The asset to describe + * @param attrs A Map whose keys consist of desired metadata fields * @return attrs - * A Map with key/value pairs of desired metadata + * A Map with key/value pairs of desired metadata + * @throws java.io.IOException If a problem occurs while obtaining metadata */ - public Map about(Bitstream bitstream, Map attrs) throws IOException - { + public Map about(Bitstream bitstream, Map attrs) throws IOException { try { // potentially expensive, since it may calculate the checksum File file = getFile(bitstream); @@ -202,18 +187,15 @@ public class DSBitStoreService implements BitStoreService log.error("about(" + bitstream.getInternalId() + ")", e); throw new IOException(e); } - } + } /** * Remove an asset from the asset store. An irreversible operation. * - * @param bitstream - * The asset to delete - * @throws java.io.IOException - * If a problem occurs while removing the asset + * @param bitstream The asset to delete + * @throws java.io.IOException If a problem occurs while removing the asset */ - public void remove(Bitstream bitstream) throws IOException - { + public void remove(Bitstream bitstream) throws IOException { try { File file = getFile(bitstream); if (file != null) { @@ -227,35 +209,30 @@ public class DSBitStoreService implements BitStoreService log.error("remove(" + bitstream.getInternalId() + ")", e); throw new IOException(e); } - } - + } + //////////////////////////////////////// // Internal methods //////////////////////////////////////// - - /** + + /** * Delete empty parent directories. - * - * @param file - * The file with parent directories to delete + * + * @param file The file with parent directories to delete */ - private synchronized static void deleteParents(File file) - { - if (file == null) - { + private synchronized static void deleteParents(File file) { + if (file == null) { return; } - - File tmp = file; - for (int i = 0; i < directoryLevels; i++) - { - File directory = tmp.getParentFile(); - File[] files = directory.listFiles(); + File tmp = file; + + for (int i = 0; i < directoryLevels; i++) { + File directory = tmp.getParentFile(); + File[] files = directory.listFiles(); // Only delete empty directories - if (files.length != 0) - { + if (files.length != 0) { break; } @@ -268,20 +245,14 @@ public class DSBitStoreService implements BitStoreService * Return the file corresponding to a bitstream. It's safe to pass in * null. * - * @param bitstream - * the database table row for the bitstream. Can be - * null - * + * @param bitstream the database table row for the bitstream. Can be + * null * @return The corresponding file in the file system, or null - * - * @throws IOException - * If a problem occurs while determining the file + * @throws IOException If a problem occurs while determining the file */ - protected File getFile(Bitstream bitstream) throws IOException - { + protected File getFile(Bitstream bitstream) throws IOException { // Check that bitstream is not null - if (bitstream == null) - { + if (bitstream == null) { return null; } @@ -307,8 +278,7 @@ public class DSBitStoreService implements BitStoreService // make a path traversal attack, so ignore the path // prefix. The internal-ID is supposed to be just a // filename, so this will not affect normal operation. - if (sInternalId.contains(File.separator)) - { + if (sInternalId.contains(File.separator)) { sInternalId = sInternalId.substring(sInternalId.lastIndexOf(File.separator) + 1); } @@ -322,7 +292,7 @@ public class DSBitStoreService implements BitStoreService bufFilename.append(sInternalId); if (log.isDebugEnabled()) { log.debug("Local filename for " + sInternalId + " is " - + bufFilename.toString()); + + bufFilename.toString()); } return new File(bufFilename.toString()); } @@ -331,8 +301,7 @@ public class DSBitStoreService implements BitStoreService * Return the intermediate path derived from the internal_id. This method * splits the id into groups which become subdirectories. * - * @param iInternalId - * The internal_id + * @param iInternalId The internal_id * @return The path based on the id without leading or trailing separators */ protected String getIntermediatePath(String iInternalId) { @@ -343,13 +312,14 @@ public class DSBitStoreService implements BitStoreService buf.append(File.separator); } buf.append(iInternalId.substring(digits, digits - + digitsPerLevel)); + + digitsPerLevel)); } buf.append(File.separator); return buf.toString(); } protected final String REGISTERED_FLAG = "-R"; + public boolean isRegisteredBitstream(String internalId) { return internalId.startsWith(REGISTERED_FLAG); } diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java index 200f2ff1c8..51072d2259 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java @@ -7,13 +7,23 @@ */ package org.dspace.storage.bitstore; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.regions.Region; import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; -import com.amazonaws.services.s3.model.*; +import com.amazonaws.services.s3.model.AmazonS3Exception; +import com.amazonaws.services.s3.model.GetObjectRequest; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; +import com.amazonaws.services.s3.model.PutObjectResult; +import com.amazonaws.services.s3.model.S3Object; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; @@ -23,50 +33,53 @@ import org.dspace.core.ConfigurationManager; import org.dspace.core.Utils; import org.springframework.beans.factory.annotation.Required; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; - /** * Asset store using Amazon's Simple Storage Service (S3). * S3 is a commercial, web-service accessible, remote storage facility. * NB: you must have obtained an account with Amazon to use this store - * + * * @author Richard Rodgers, Peter Dietz - */ + */ -public class S3BitStoreService implements BitStoreService -{ - /** log4j log */ +public class S3BitStoreService implements BitStoreService { + /** + * log4j log + */ private static Logger log = Logger.getLogger(S3BitStoreService.class); - - /** Checksum algorithm */ + + /** + * Checksum algorithm + */ private static final String CSA = "MD5"; private String awsAccessKey; private String awsSecretKey; private String awsRegionName; - /** container for all the assets */ + /** + * container for all the assets + */ private String bucketName = null; - /** (Optional) subfolder within bucket where objects are stored */ + /** + * (Optional) subfolder within bucket where objects are stored + */ private String subfolder = null; - - /** S3 service */ + + /** + * S3 service + */ private AmazonS3 s3Service = null; - public S3BitStoreService() - { + public S3BitStoreService() { } /** * Initialize the asset store * S3 Requires: - * - access key - * - secret key - * - bucket name + * - access key + * - secret key + * - bucket name */ public void init() throws IOException { if (StringUtils.isBlank(getAwsAccessKey()) || StringUtils.isBlank(getAwsSecretKey())) { @@ -84,13 +97,11 @@ public class S3BitStoreService implements BitStoreService } try { - if (! s3Service.doesBucketExist(bucketName)) { + if (!s3Service.doesBucketExist(bucketName)) { s3Service.createBucket(bucketName); log.info("Creating new S3 Bucket: " + bucketName); } - } - catch (Exception e) - { + } catch (Exception e) { log.error(e); throw new IOException(e); } @@ -107,43 +118,34 @@ public class S3BitStoreService implements BitStoreService } } - log.info("AWS S3 Assetstore ready to go! bucket:"+bucketName); + log.info("AWS S3 Assetstore ready to go! bucket:" + bucketName); } - - + /** * Return an identifier unique to this asset store instance - * + * * @return a unique ID */ - public String generateId() - { + public String generateId() { return Utils.generateKey(); } /** * Retrieve the bits for the asset with ID. If the asset does not * exist, returns null. - * - * @param bitstream - * The ID of the asset to retrieve - * @throws java.io.IOException - * If a problem occurs while retrieving the bits * + * @param bitstream The ID of the asset to retrieve * @return The stream of bits, or null + * @throws java.io.IOException If a problem occurs while retrieving the bits */ - public InputStream get(Bitstream bitstream) throws IOException - { + public InputStream get(Bitstream bitstream) throws IOException { String key = getFullKey(bitstream.getInternalId()); - try - { + try { S3Object object = s3Service.getObject(new GetObjectRequest(bucketName, key)); return (object != null) ? object.getObjectContent() : null; - } - catch (Exception e) - { - log.error("get("+key+")", e); + } catch (Exception e) { + log.error("get(" + key + ")", e); throw new IOException(e); } } @@ -156,13 +158,10 @@ public class S3BitStoreService implements BitStoreService * If an exception is thrown, the bits have not been stored. *

    * - * @param in - * The stream of bits to store - * @throws java.io.IOException - * If a problem occurs while storing the bits + * @param in The stream of bits to store + * @throws java.io.IOException If a problem occurs while storing the bits */ - public void put(Bitstream bitstream, InputStream in) throws IOException - { + public void put(Bitstream bitstream, InputStream in) throws IOException { String key = getFullKey(bitstream.getInternalId()); //Copy istream to temp file, and send the file, with some metadata File scratchFile = File.createTempFile(bitstream.getInternalId(), "s3bs"); @@ -179,8 +178,8 @@ public class S3BitStoreService implements BitStoreService scratchFile.delete(); - } catch(Exception e) { - log.error("put(" + bitstream.getInternalId() +", is)", e); + } catch (Exception e) { + log.error("put(" + bitstream.getInternalId() + ", is)", e); throw new IOException(e); } finally { if (scratchFile.exists()) { @@ -195,19 +194,14 @@ public class S3BitStoreService implements BitStoreService * Checksum used is (ETag) hex encoded 128-bit MD5 digest of an object's content as calculated by Amazon S3 * (Does not use getContentMD5, as that is 128-bit MD5 digest calculated on caller's side) * - * @param bitstream - * The asset to describe - * @param attrs - * A Map whose keys consist of desired metadata fields - * - * @throws java.io.IOException - * If a problem occurs while obtaining metadata + * @param bitstream The asset to describe + * @param attrs A Map whose keys consist of desired metadata fields * @return attrs - * A Map with key/value pairs of desired metadata - * If file not found, then return null + * A Map with key/value pairs of desired metadata + * If file not found, then return null + * @throws java.io.IOException If a problem occurs while obtaining metadata */ - public Map about(Bitstream bitstream, Map attrs) throws IOException - { + public Map about(Bitstream bitstream, Map attrs) throws IOException { String key = getFullKey(bitstream.getInternalId()); try { ObjectMetadata objectMetadata = s3Service.getObjectMetadata(bucketName, key); @@ -230,7 +224,7 @@ public class S3BitStoreService implements BitStoreService return null; } } catch (Exception e) { - log.error("about("+key+", attrs)", e); + log.error("about(" + key + ", attrs)", e); throw new IOException(e); } return null; @@ -239,26 +233,23 @@ public class S3BitStoreService implements BitStoreService /** * Remove an asset from the asset store. An irreversible operation. * - * @param bitstream - * The asset to delete - * @throws java.io.IOException - * If a problem occurs while removing the asset + * @param bitstream The asset to delete + * @throws java.io.IOException If a problem occurs while removing the asset */ - public void remove(Bitstream bitstream) throws IOException - { + public void remove(Bitstream bitstream) throws IOException { String key = getFullKey(bitstream.getInternalId()); try { s3Service.deleteObject(bucketName, key); } catch (Exception e) { - log.error("remove("+key+")", e); + log.error("remove(" + key + ")", e); throw new IOException(e); } } /** * Utility Method: Prefix the key with a subfolder, if this instance assets are stored within subfolder - * @param id - * DSpace bitstream internal ID + * + * @param id DSpace bitstream internal ID * @return full key prefixed with a subfolder, if applicable */ public String getFullKey(String id) { @@ -314,14 +305,12 @@ public class S3BitStoreService implements BitStoreService /** * Contains a command-line testing tool. Expects arguments: - * -a accessKey -s secretKey -f assetFileName + * -a accessKey -s secretKey -f assetFileName * * @param args the command line arguments given - * @throws Exception - * generic exception + * @throws Exception generic exception */ - public static void main(String[] args) throws Exception - { + public static void main(String[] args) throws Exception { //TODO use proper CLI, or refactor to be a unit test. Can't mock this without keys though. // parse command line @@ -329,24 +318,17 @@ public class S3BitStoreService implements BitStoreService String accessKey = null; String secretKey = null; - for (int i = 0; i < args.length; i+= 2) - { - if (args[i].startsWith("-a")) - { - accessKey = args[i+1]; - } - else if (args[i].startsWith("-s")) - { - secretKey = args[i+1]; - } - else if (args[i].startsWith("-f")) - { - assetFile = args[i+1]; + for (int i = 0; i < args.length; i += 2) { + if (args[i].startsWith("-a")) { + accessKey = args[i + 1]; + } else if (args[i].startsWith("-s")) { + secretKey = args[i + 1]; + } else if (args[i].startsWith("-f")) { + assetFile = args[i + 1]; } } - if (accessKey == null || secretKey == null ||assetFile == null) - { + if (accessKey == null || secretKey == null || assetFile == null) { System.out.println("Missing arguments - exiting"); return; } diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/factory/StorageServiceFactory.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/factory/StorageServiceFactory.java index b310d97a2b..be954557fc 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/factory/StorageServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/factory/StorageServiceFactory.java @@ -11,7 +11,8 @@ import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.storage.bitstore.service.BitstreamStorageService; /** - * Abstract factory to get services for the storage package, use StorageServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the storage package, use StorageServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -19,8 +20,8 @@ public abstract class StorageServiceFactory { public abstract BitstreamStorageService getBitstreamStorageService(); - public static StorageServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("storageServiceFactory", StorageServiceFactory.class); + public static StorageServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("storageServiceFactory", StorageServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/factory/StorageServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/factory/StorageServiceFactoryImpl.java index 88f1d4e0e0..0dc67223d8 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/factory/StorageServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/factory/StorageServiceFactoryImpl.java @@ -11,7 +11,8 @@ import org.dspace.storage.bitstore.service.BitstreamStorageService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the storage package, use StorageServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the storage package, use StorageServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java index 5258e1cc81..95963b14ca 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java @@ -7,16 +7,16 @@ */ package org.dspace.storage.bitstore.service; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Bitstream; -import org.dspace.core.Context; - import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import java.util.Map; import java.util.UUID; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.core.Context; + /** *

    * Stores, retrieves and deletes bitstreams. @@ -73,18 +73,12 @@ public interface BitstreamStorageService { * and some or all of the bits have also been stored. * * - * @param context - * The current context - * @param bitstream - * The bitstream to store - * @param is - * The stream of bits to store - * @throws java.io.IOException - * If a problem occurs while storing the bits - * @throws java.sql.SQLException - * If a problem occurs accessing the RDBMS - * + * @param context The current context + * @param bitstream The bitstream to store + * @param is The stream of bits to store * @return The ID of the stored bitstream + * @throws java.io.IOException If a problem occurs while storing the bits + * @throws java.sql.SQLException If a problem occurs accessing the RDBMS */ public UUID store(Context context, Bitstream bitstream, InputStream is) throws SQLException, IOException; @@ -92,24 +86,20 @@ public interface BitstreamStorageService { /** * Register a bitstream already in storage. * - * @param context - * The current context - * @param bitstream - * The bitstream to register - * @param assetstore The assetstore number for the bitstream to be - * registered + * @param context The current context + * @param bitstream The bitstream to register + * @param assetstore The assetstore number for the bitstream to be + * registered * @param bitstreamPath The relative path of the bitstream to be registered. - * The path is relative to the path of ths assetstore. + * The path is relative to the path of ths assetstore. * @return The ID of the registered bitstream - * @throws SQLException - * If a problem occurs accessing the RDBMS - * @throws IOException if IO error - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException If a problem occurs accessing the RDBMS + * @throws IOException if IO error + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public UUID register(Context context, Bitstream bitstream, int assetstore, String bitstreamPath) - throws SQLException, IOException, AuthorizeException; + throws SQLException, IOException, AuthorizeException; public Map computeChecksum(Context context, Bitstream bitstream) throws IOException; @@ -126,18 +116,14 @@ public interface BitstreamStorageService { * Retrieve the bits for the bitstream with ID. If the bitstream does not * exist, or is marked deleted, returns null. * - * @param context - * The current context - * @param bitstream - * The bitstream to retrieve + * @param context The current context + * @param bitstream The bitstream to retrieve * @return The stream of bits, or null - * @throws IOException - * If a problem occurs while retrieving the bits - * @throws SQLException - * If a problem occurs accessing the RDBMS + * @throws IOException If a problem occurs while retrieving the bits + * @throws SQLException If a problem occurs accessing the RDBMS */ public InputStream retrieve(Context context, Bitstream bitstream) - throws SQLException, IOException; + throws SQLException, IOException; /** * Clean up the bitstream storage area. This method deletes any bitstreams @@ -145,49 +131,61 @@ public interface BitstreamStorageService { * be undone. * * @param deleteDbRecords if true deletes the database records otherwise it - * only deletes the files and directories in the assetstore - * @param verbose - * verbosity flag - * @throws IOException - * If a problem occurs while cleaning up - * @throws SQLException - * If a problem occurs accessing the RDBMS - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * only deletes the files and directories in the assetstore + * @param verbose verbosity flag + * @throws IOException If a problem occurs while cleaning up + * @throws SQLException If a problem occurs accessing the RDBMS + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void cleanup(boolean deleteDbRecords, boolean verbose) throws SQLException, IOException, AuthorizeException; + /** + * Clone the given bitstream to a new bitstream with a new ID. + * Metadata of the given bitstream are also copied to the new bitstream. + * + * @param context + * DSpace context object + * @param bitstream + * the bitstream to be cloned + * @return id of the clone bitstream. + * @throws SQLException if database error + * @throws IOException if IO error + * @throws AuthorizeException if authorization error + */ public Bitstream clone(Context context, Bitstream bitstream) throws SQLException, IOException, AuthorizeException; /** * Print out (log/out) a listing of the assetstores configured, and how many assets they contain - * @param context - * The relevant DSpace Context. + * + * @param context The relevant DSpace Context. * @throws SQLException if database error */ public void printStores(Context context) throws SQLException; /** * Migrate all the assets from assetstoreSource to assetstoreDestination - * @param context - * The relevant DSpace Context. - * @param assetstoreSource - * source assetstore - * @param assetstoreDestination - * destination assetstore - * @param deleteOld - * whether to delete files from the source assetstore after migration - * @param batchCommitSize - * batch size - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * + * @param context The relevant DSpace Context. + * @param assetstoreSource source assetstore + * @param assetstoreDestination destination assetstore + * @param deleteOld whether to delete files from the source assetstore after migration + * @param batchCommitSize batch size + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ - public void migrate(Context context, Integer assetstoreSource, Integer assetstoreDestination, boolean deleteOld, Integer batchCommitSize) throws IOException, SQLException, AuthorizeException; + public void migrate(Context context, Integer assetstoreSource, Integer assetstoreDestination, boolean deleteOld, + Integer batchCommitSize) throws IOException, SQLException, AuthorizeException; + + + /** + * Get the last modified timestamp of the file linked to the given bitstream + * + * @param bitstream The bitstream for which to get the last modified timestamp + * @return The last modified timestamp in milliseconds + */ + public Long getLastModified(Bitstream bitstream); } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseConfigVO.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseConfigVO.java index f230e8f5d4..c883780909 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseConfigVO.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseConfigVO.java @@ -8,9 +8,11 @@ package org.dspace.storage.rdbms; /** - * Value object for the Database configuration, can be used to get the database configuration parameters. - * The config parameters are retrieved by the implementation of the org.dspace.core.DBConnection object. - * This class should never be used to store configuration, it is just used to export and can be used for display purposes + * Get database configuration parameters. The parameter values are retrieved by + * the configured implementation of the {@link DBConnection} interface. + * + *

    This class cannot be used to alter configuration; + * it is just used to export and can be used for display purposes * * @author kevinvandevelde at atmire.com */ @@ -26,47 +28,102 @@ public class DatabaseConfigVO { private int maxConnections; - public DatabaseConfigVO() - { + public DatabaseConfigVO() { } + /** + * Get the JDBC URL which identifies the DBMS instance and database. This + * is set in the DSpace configuration. + * + * @return URL pointing to the configured database. + */ public String getDatabaseUrl() { return databaseUrl; } + /** + * DO NOT USE unless you are writing a DBConnection implementation. This + * method does not set the URL that will be used to connect to the database. + * + * @param databaseUrl JDBC URL being used by the DBConnection for creating connections. + */ public void setDatabaseUrl(String databaseUrl) { this.databaseUrl = databaseUrl; } + /** + * Get the name of the DBMS driver, which should indicate what DBMS is in use. + * + * @return the driver's notion of its "name". + */ public String getDatabaseDriver() { return databaseDriver; } + /** + * DO NOT USE unless you are writing an implementation of DBConnection. + * This method does not select the DBMS driver. + * + * @param databaseDriver the driver's name. + */ public void setDatabaseDriver(String databaseDriver) { this.databaseDriver = databaseDriver; } + /** + * Get the name of the database role used to authenticate connections to the DBMS. + * + * @return DBMS user name, from DSpace configuration. + */ public String getUserName() { return userName; } + /** + * DO NOT USE unless you are writing an implementation of DBConnection. + * This method does not alter the user name. + * + * @param userName the configured DBMS username. + */ public void setUserName(String userName) { this.userName = userName; } + /** + * Get the name of the database schema. + * + * @return name of the schema. + */ public String getSchema() { return schema; } + /** + * DO NOT USE unless you are writing an implementation of DBConnection. + * This method does not set the schema that will be used. + * + * @param schema name of the database schema, from configuration. + */ public void setSchema(String schema) { this.schema = schema; } + /** + * Get the maximum number of concurrent DBMS connections that will be opened (if possible). + * + * @return configured maximum DBMS connection count. + */ public int getMaxConnections() { return maxConnections; } + /** + * DO NOT USE unless you are writing an implementation of DBConnection. + * This method does not set the connection maximum. + * + * @param maxConnections configured maximum number of concurrent DBMS connections. + */ public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseRegistryUpdater.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseRegistryUpdater.java index 392c159510..209dec554b 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseRegistryUpdater.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseRegistryUpdater.java @@ -42,26 +42,25 @@ import org.slf4j.LoggerFactory; * * @author Tim Donohue */ -public class DatabaseRegistryUpdater implements FlywayCallback -{ - /** logging category */ +public class DatabaseRegistryUpdater implements FlywayCallback { + /** + * logging category + */ private static final Logger log = LoggerFactory.getLogger(DatabaseRegistryUpdater.class); /** * Method to actually update our registries from latest configs */ - private void updateRegistries() - { + private void updateRegistries() { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); Context context = null; - try - { + try { context = new Context(); context.turnOffAuthorisationSystem(); String base = config.getProperty("dspace.dir") - + File.separator + "config" + File.separator - + "registries" + File.separator; + + File.separator + "config" + File.separator + + "registries" + File.separator; // Load updates to Bitstream format registry (if any) log.info("Updating Bitstream Format Registry based on " + base + "bitstream-formats.xml"); @@ -76,8 +75,7 @@ public class DatabaseRegistryUpdater implements FlywayCallback MetadataImporter.loadRegistry(base + "sword-metadata.xml", true); // Check if XML Workflow is enabled in workflow.cfg - if (WorkflowServiceFactory.getInstance().getWorkflowService() instanceof XmlWorkflowService) - { + if (WorkflowServiceFactory.getInstance().getWorkflowService() instanceof XmlWorkflowService) { // If so, load in the workflow metadata types as well MetadataImporter.loadRegistry(base + "workflow-types.xml", true); } @@ -86,17 +84,14 @@ public class DatabaseRegistryUpdater implements FlywayCallback // Commit changes and close context context.complete(); log.info("All Bitstream Format Regitry and Metadata Registry updates were completed."); - } - catch(Exception e) - { + } catch (Exception e) { log.error("Error attempting to update Bitstream Format and/or Metadata Registries", e); throw new RuntimeException("Error attempting to update Bitstream Format and/or Metadata Registries", e); - } - finally - { + } finally { // Clean up our context, if it still exists & it was never completed - if(context!=null && context.isValid()) + if (context != null && context.isValid()) { context.abort(); + } } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java index 28dbe88cf8..13944f8de7 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java @@ -23,7 +23,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.sql.DataSource; -import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.core.Context; @@ -49,12 +48,12 @@ import org.flywaydb.core.internal.info.MigrationInfoDumper; *

    * Currently, we use Flyway DB (http://flywaydb.org/) for database management. * - * @see org.dspace.storage.rdbms.DatabaseUtils * @author Tim Donohue */ -public class DatabaseUtils -{ - /** log4j category */ +public class DatabaseUtils { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(DatabaseUtils.class); // Our Flyway DB object (initialized by setupFlyway()) @@ -63,34 +62,38 @@ public class DatabaseUtils // When this temp file exists, the "checkReindexDiscovery()" method will auto-reindex Discovery // Reindex flag file is at [dspace]/solr/search/conf/reindex.flag // See also setReindexDiscovery()/getReindexDiscover() - private static final String reindexDiscoveryFilePath = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.dir") + - File.separator + "solr" + - File.separator + "search" + - File.separator + "conf" + - File.separator + "reindex.flag"; + private static final String reindexDiscoveryFilePath = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("dspace.dir") + + File.separator + "solr" + + File.separator + "search" + + File.separator + "conf" + + File.separator + "reindex.flag"; // Types of databases supported by DSpace. See getDbType() - public static final String DBMS_POSTGRES="postgres"; - public static final String DBMS_ORACLE="oracle"; - public static final String DBMS_H2="h2"; + public static final String DBMS_POSTGRES = "postgres"; + public static final String DBMS_ORACLE = "oracle"; + public static final String DBMS_H2 = "h2"; + + /** + * Default constructor + */ + private DatabaseUtils() { } /** * Commandline tools for managing database changes, etc. + * * @param argv the command line arguments given */ - public static void main(String[] argv) - { + public static void main(String[] argv) { // Usage checks - if (argv.length < 1) - { + if (argv.length < 1) { System.out.println("\nDatabase action argument is missing."); System.out.println("Valid actions: 'test', 'info', 'migrate', 'repair', 'validate' or 'clean'"); System.out.println("\nOr, type 'database help' for more information.\n"); System.exit(1); } - try - { + try { // Get a reference to our configured DataSource DataSource dataSource = getDataSource(); @@ -98,12 +101,10 @@ public class DatabaseUtils Flyway flyway = setupFlyway(dataSource); // "test" = Test Database Connection - if (argv[0].equalsIgnoreCase("test")) - { + if (argv[0].equalsIgnoreCase("test")) { // Try to connect to the database System.out.println("\nAttempting to connect to database"); - try(Connection connection = dataSource.getConnection()) - { + try (Connection connection = dataSource.getConnection()) { System.out.println("Connected successfully!"); // Print basic database connection information @@ -113,24 +114,20 @@ public class DatabaseUtils boolean issueFound = printDBIssues(connection); // If issues found, exit with an error status (even if connection succeeded). - if (issueFound) + if (issueFound) { System.exit(1); - else + } else { System.exit(0); - } - catch (SQLException sqle) - { + } + } catch (SQLException sqle) { System.err.println("\nError running 'test': "); System.err.println(" - " + sqle); System.err.println("\nPlease see the DSpace documentation for assistance.\n"); sqle.printStackTrace(); System.exit(1); } - } - else if (argv[0].equalsIgnoreCase("info") || argv[0].equalsIgnoreCase("status")) - { - try(Connection connection = dataSource.getConnection()) - { + } else if (argv[0].equalsIgnoreCase("info") || argv[0].equalsIgnoreCase("status")) { + try (Connection connection = dataSource.getConnection()) { // Print basic Database info printDBInfo(connection); @@ -140,15 +137,17 @@ public class DatabaseUtils // If Flyway is NOT yet initialized, also print the determined version information // NOTE: search is case sensitive, as flyway table name is ALWAYS lowercase, // See: http://flywaydb.org/documentation/faq.html#case-sensitive - if (!tableExists(connection, flyway.getTable(), true)) - { - System.out.println("\nNOTE: This database is NOT yet initialized for auto-migrations (via Flyway)."); + if (!tableExists(connection, flyway.getTable(), true)) { + System.out + .println("\nNOTE: This database is NOT yet initialized for auto-migrations (via Flyway)."); // Determine which version of DSpace this looks like String dbVersion = determineDBVersion(connection); - if (dbVersion!=null) - { - System.out.println("\nYour database looks to be compatible with DSpace version " + dbVersion); - System.out.println("All upgrades *after* version " + dbVersion + " will be run during the next migration."); + if (dbVersion != null) { + System.out + .println("\nYour database looks to be compatible with DSpace version " + dbVersion); + System.out.println( + "All upgrades *after* version " + dbVersion + " will be run during the next migration" + + "."); System.out.println("\nIf you'd like to upgrade now, simply run 'dspace database migrate'."); } } @@ -157,144 +156,144 @@ public class DatabaseUtils boolean issueFound = printDBIssues(connection); // If issues found, exit with an error status - if (issueFound) + if (issueFound) { System.exit(1); - else + } else { System.exit(0); - } - catch (SQLException e) - { + } + } catch (SQLException e) { System.err.println("Info exception:"); e.printStackTrace(); System.exit(1); } - } - else if (argv[0].equalsIgnoreCase("migrate")) - { - try (Connection connection = dataSource.getConnection()) - { + } else if (argv[0].equalsIgnoreCase("migrate")) { + try (Connection connection = dataSource.getConnection()) { System.out.println("\nDatabase URL: " + connection.getMetaData().getURL()); // "migrate" allows for an OPTIONAL second argument: // - "ignored" = Also run any previously "ignored" migrations during the migration // - [version] = ONLY run migrations up to a specific DSpace version (ONLY FOR TESTING) - if (argv.length==2) - { - if (argv[1].equalsIgnoreCase("ignored")) - { - System.out.println("Migrating database to latest version AND running previously \"Ignored\" migrations... (Check logs for details)"); + if (argv.length == 2) { + if (argv[1].equalsIgnoreCase("ignored")) { + System.out.println( + "Migrating database to latest version AND running previously \"Ignored\" " + + "migrations... (Check logs for details)"); // Update the database to latest version, but set "outOfOrder=true" // This will ensure any old migrations in the "ignored" state are now run updateDatabase(dataSource, connection, null, true); - } - else - { + } else { // Otherwise, we assume "argv[1]" is a valid migration version number // This is only for testing! Never specify for Production! String migrationVersion = argv[1]; BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); - System.out.println("You've specified to migrate your database ONLY to version " + migrationVersion + " ..."); - System.out.println("\nWARNING: It is highly likely you will see errors in your logs when the Metadata"); - System.out.println("or Bitstream Format Registry auto-update. This is because you are attempting to"); - System.out.println("use an OLD version " + migrationVersion + " Database with a newer DSpace API. NEVER do this in a"); - System.out.println("PRODUCTION scenario. The resulting old DB is only useful for migration testing.\n"); + System.out.println( + "You've specified to migrate your database ONLY to version " + migrationVersion + " " + + "..."); + System.out.println( + "\nWARNING: It is highly likely you will see errors in your logs when the Metadata"); + System.out.println( + "or Bitstream Format Registry auto-update. This is because you are attempting to"); + System.out.println( + "use an OLD version " + migrationVersion + " Database with a newer DSpace API. NEVER " + + "do this in a"); + System.out.println( + "PRODUCTION scenario. The resulting old DB is only useful for migration testing.\n"); - System.out.print("Are you SURE you only want to migrate your database to version " + migrationVersion + "? [y/n]: "); + System.out.print( + "Are you SURE you only want to migrate your database to version " + migrationVersion + + "? [y/n]: "); String choiceString = input.readLine(); input.close(); - if (choiceString.equalsIgnoreCase("y")) - { - System.out.println("Migrating database ONLY to version " + migrationVersion + " ... (Check logs for details)"); + if (choiceString.equalsIgnoreCase("y")) { + System.out.println( + "Migrating database ONLY to version " + migrationVersion + " ... (Check logs for " + + "details)"); // Update the database, to the version specified. updateDatabase(dataSource, connection, migrationVersion, false); - } - else - { + } else { System.out.println("No action performed."); } } - } - else - { + } else { System.out.println("Migrating database to latest version... (Check dspace logs for details)"); updateDatabase(dataSource, connection); } System.out.println("Done."); System.exit(0); - } - catch(SQLException e) - { + } catch (SQLException e) { System.err.println("Migration exception:"); e.printStackTrace(); System.exit(1); } - } - // "repair" = Run Flyway repair script - else if (argv[0].equalsIgnoreCase("repair")) - { - try (Connection connection = dataSource.getConnection();) - { + } else if (argv[0].equalsIgnoreCase("repair")) { + // "repair" = Run Flyway repair script + + try (Connection connection = dataSource.getConnection();) { System.out.println("\nDatabase URL: " + connection.getMetaData().getURL()); - System.out.println("Attempting to repair any previously failed migrations (or mismatched checksums) via FlywayDB... (Check dspace logs for details)"); + System.out.println( + "Attempting to repair any previously failed migrations (or mismatched checksums) via " + + "FlywayDB... (Check dspace logs for details)"); flyway.repair(); System.out.println("Done."); System.exit(0); - } - catch(SQLException|FlywayException e) - { + } catch (SQLException | FlywayException e) { System.err.println("Repair exception:"); e.printStackTrace(); System.exit(1); } - } - // "validate" = Run Flyway validation to check for database errors/issues - else if (argv[0].equalsIgnoreCase("validate")) - { - try (Connection connection = dataSource.getConnection();) - { + } else if (argv[0].equalsIgnoreCase("validate")) { + // "validate" = Run Flyway validation to check for database errors/issues + + try (Connection connection = dataSource.getConnection();) { System.out.println("\nDatabase URL: " + connection.getMetaData().getURL()); - System.out.println("Attempting to validate database status (and migration checksums) via FlywayDB..."); + System.out + .println("Attempting to validate database status (and migration checksums) via FlywayDB..."); flyway.validate(); System.out.println("No errors thrown. Validation succeeded. (Check dspace logs for more details)"); System.exit(0); - } - catch(SQLException|FlywayException e) - { + } catch (SQLException | FlywayException e) { System.err.println("Validation exception:"); e.printStackTrace(); System.exit(1); } - } - // "clean" = Run Flyway clean script - else if (argv[0].equalsIgnoreCase("clean")) - { + } else if (argv[0].equalsIgnoreCase("clean")) { + // "clean" = Run Flyway clean script + // If clean is disabled, return immediately - if (flyway.isCleanDisabled()) - { - System.out.println("\nWARNING: 'clean' command is currently disabled, as it is dangerous to run in Production scenarios!"); - System.out.println("\nIn order to run a 'clean' you first must enable it in your DSpace config by specifying 'db.cleanDisabled=false'.\n"); + if (flyway.isCleanDisabled()) { + System.out.println( + "\nWARNING: 'clean' command is currently disabled, as it is dangerous to run in Production " + + "scenarios!"); + System.out.println( + "\nIn order to run a 'clean' you first must enable it in your DSpace config by specifying 'db" + + ".cleanDisabled=false'.\n"); System.exit(1); } - try (Connection connection = dataSource.getConnection()) - { + try (Connection connection = dataSource.getConnection()) { String dbType = getDbType(connection); // Not all Postgres user accounts will be able to run a 'clean', // as only 'superuser' accounts can remove the 'pgcrypto' extension. - if (dbType.equals(DBMS_POSTGRES)) - { + if (dbType.equals(DBMS_POSTGRES)) { // Check if database user has permissions suitable to run a clean - if (!PostgresUtils.checkCleanPermissions(connection)) - { + if (!PostgresUtils.checkCleanPermissions(connection)) { String username = connection.getMetaData().getUserName(); // Exit immediately, providing a descriptive error message - System.out.println("\nERROR: The database user '" + username + "' does not have sufficient privileges to run a 'database clean' (via Flyway)."); - System.out.println("\nIn order to run a 'clean', the database user MUST have 'superuser' privileges"); - System.out.println("OR the '" + PostgresUtils.PGCRYPTO + "' extension must be installed in a separate schema (see documentation)."); - System.out.println("\nOptionally, you could also manually remove the '" + PostgresUtils.PGCRYPTO + "' extension first (DROP EXTENSION " + PostgresUtils.PGCRYPTO + " CASCADE;), then rerun the 'clean'"); + System.out.println( + "\nERROR: The database user '" + username + "' does not have sufficient privileges to" + + " run a 'database clean' (via Flyway)."); + System.out.println( + "\nIn order to run a 'clean', the database user MUST have 'superuser' privileges"); + System.out.println( + "OR the '" + PostgresUtils.PGCRYPTO + "' extension must be installed in a separate " + + "schema (see documentation)."); + System.out.println( + "\nOptionally, you could also manually remove the '" + PostgresUtils.PGCRYPTO + "' " + + "extension first (DROP EXTENSION " + PostgresUtils.PGCRYPTO + " CASCADE;), then " + + "rerun the 'clean'"); System.exit(1); } } @@ -302,56 +301,56 @@ public class DatabaseUtils BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); System.out.println("\nDatabase URL: " + connection.getMetaData().getURL()); - System.out.println("\nWARNING: ALL DATA AND TABLES IN YOUR DATABASE WILL BE PERMANENTLY DELETED.\n"); + System.out + .println("\nWARNING: ALL DATA AND TABLES IN YOUR DATABASE WILL BE PERMANENTLY DELETED.\n"); System.out.println("There is NO turning back from this action. Backup your DB before continuing."); - if (dbType.equals(DBMS_ORACLE)) - { + if (dbType.equals(DBMS_ORACLE)) { System.out.println("\nORACLE WARNING: your RECYCLEBIN will also be PURGED.\n"); - } - else if (dbType.equals(DBMS_POSTGRES)) - { - System.out.println("\nPOSTGRES WARNING: the '" + PostgresUtils.PGCRYPTO + "' extension will be dropped if it is in the same schema as the DSpace database.\n"); + } else if (dbType.equals(DBMS_POSTGRES)) { + System.out.println( + "\nPOSTGRES WARNING: the '" + PostgresUtils.PGCRYPTO + "' extension will be dropped if it" + + " is in the same schema as the DSpace database.\n"); } System.out.print("Do you want to PERMANENTLY DELETE everything from your database? [y/n]: "); String choiceString = input.readLine(); input.close(); - if (choiceString.equalsIgnoreCase("y")) - { + if (choiceString.equalsIgnoreCase("y")) { System.out.println("Scrubbing database clean... (Check dspace logs for details)"); cleanDatabase(flyway, dataSource); System.out.println("Done."); System.exit(0); - } - else - { + } else { System.out.println("No action performed."); } - } - catch(SQLException e) - { + } catch (SQLException e) { System.err.println("Clean exception:"); e.printStackTrace(); System.exit(1); } - } - else - { + } else { System.out.println("\nUsage: database [action]"); System.out.println("Valid actions: 'test', 'info', 'migrate', 'repair' or 'clean'"); - System.out.println(" - test = Performs a test connection to database to validate connection settings"); - System.out.println(" - info / status = Describe basic info/status about database, including validating the compatibility of this database"); + System.out.println( + " - test = Performs a test connection to database to validate connection settings"); + System.out.println( + " - info / status = Describe basic info/status about database, including validating the " + + "compatibility of this database"); System.out.println(" - migrate = Migrate the database to the latest version"); - System.out.println(" - repair = Attempt to repair any previously failed database migrations or checksum mismatches (via Flyway repair)"); - System.out.println(" - validate = Validate current database's migration status (via Flyway validate), validating all migration checksums."); - System.out.println(" - clean = DESTROY all data and tables in database (WARNING there is no going back!). Requires 'db.cleanDisabled=false' setting in config."); + System.out.println( + " - repair = Attempt to repair any previously failed database migrations or checksum " + + "mismatches (via Flyway repair)"); + System.out.println( + " - validate = Validate current database's migration status (via Flyway validate), " + + "validating all migration checksums."); + System.out.println( + " - clean = DESTROY all data and tables in database (WARNING there is no going back!). " + + "Requires 'db.cleanDisabled=false' setting in config."); System.out.println(""); System.exit(0); } - } - catch (Exception e) - { + } catch (Exception e) { System.err.println("Caught exception:"); e.printStackTrace(); System.exit(1); @@ -361,11 +360,11 @@ public class DatabaseUtils /** * Print basic information about the current database to System.out. * This is utilized by both the 'test' and 'info' commandline options. + * * @param connection current database connection * @throws SQLException if database error occurs */ - private static void printDBInfo(Connection connection) throws SQLException - { + private static void printDBInfo(Connection connection) throws SQLException { // Get basic Database info from connection DatabaseMetaData meta = connection.getMetaData(); String dbType = getDbType(connection); @@ -373,28 +372,30 @@ public class DatabaseUtils System.out.println("Database URL: " + meta.getURL()); System.out.println("Database Schema: " + getSchemaName(connection)); System.out.println("Database Username: " + meta.getUserName()); - System.out.println("Database Software: " + meta.getDatabaseProductName() + " version " + meta.getDatabaseProductVersion()); + System.out.println( + "Database Software: " + meta.getDatabaseProductName() + " version " + meta.getDatabaseProductVersion()); System.out.println("Database Driver: " + meta.getDriverName() + " version " + meta.getDriverVersion()); // For Postgres, report whether pgcrypto is installed // (If it isn't, we'll also write out warnings...see below) - if (dbType.equals(DBMS_POSTGRES)) - { + if (dbType.equals(DBMS_POSTGRES)) { boolean pgcryptoUpToDate = PostgresUtils.isPgcryptoUpToDate(); Double pgcryptoVersion = PostgresUtils.getPgcryptoInstalledVersion(connection); - System.out.println("PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension installed/up-to-date? " + pgcryptoUpToDate + " " + ((pgcryptoVersion!=null) ? "(version=" + pgcryptoVersion + ")" : "(not installed)")); + System.out.println( + "PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension installed/up-to-date? " + pgcryptoUpToDate + "" + + " " + ((pgcryptoVersion != null) ? "(version=" + pgcryptoVersion + ")" : "(not installed)")); } } /** * Print any warnings about current database setup to System.err (if any). * This is utilized by both the 'test' and 'info' commandline options. + * * @param connection current database connection * @return boolean true if database issues found, false otherwise * @throws SQLException if database error occurs */ - private static boolean printDBIssues(Connection connection) throws SQLException - { + private static boolean printDBIssues(Connection connection) throws SQLException { boolean issueFound = false; // Get the DB Type @@ -402,53 +403,72 @@ public class DatabaseUtils // For PostgreSQL databases, we need to check for the 'pgcrypto' extension. // If it is NOT properly installed, we'll need to warn the user, as DSpace will be unable to proceed. - if (dbType.equals(DBMS_POSTGRES)) - { + if (dbType.equals(DBMS_POSTGRES)) { // Get version of pgcrypto available in this postgres instance Double pgcryptoAvailable = PostgresUtils.getPgcryptoAvailableVersion(connection); // Generic requirements message - String requirementsMsg = "\n** DSpace REQUIRES PostgreSQL >= " + PostgresUtils.POSTGRES_VERSION + " AND " + PostgresUtils.PGCRYPTO + " extension >= " + PostgresUtils.PGCRYPTO_VERSION + " **\n"; + String requirementsMsg = "\n** DSpace REQUIRES PostgreSQL >= " + PostgresUtils.POSTGRES_VERSION + " AND " + + PostgresUtils.PGCRYPTO + " extension >= " + PostgresUtils.PGCRYPTO_VERSION + " **\n"; // Check if installed in PostgreSQL & a supported version - if (pgcryptoAvailable!=null && pgcryptoAvailable.compareTo(PostgresUtils.PGCRYPTO_VERSION)>=0) - { + if (pgcryptoAvailable != null && pgcryptoAvailable.compareTo(PostgresUtils.PGCRYPTO_VERSION) >= 0) { // We now know it's available in this Postgres. Let's see if it is installed in this database. Double pgcryptoInstalled = PostgresUtils.getPgcryptoInstalledVersion(connection); // Check if installed in database, but outdated version - if (pgcryptoInstalled!=null && pgcryptoInstalled.compareTo(PostgresUtils.PGCRYPTO_VERSION)<0) - { - System.out.println("\nWARNING: Required PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is OUTDATED (installed version=" + pgcryptoInstalled + ", available version = " + pgcryptoAvailable + ")."); + if (pgcryptoInstalled != null && pgcryptoInstalled.compareTo(PostgresUtils.PGCRYPTO_VERSION) < 0) { + System.out.println( + "\nWARNING: Required PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is OUTDATED " + + "(installed version=" + pgcryptoInstalled + ", available version = " + pgcryptoAvailable + + ")."); System.out.println(requirementsMsg); - System.out.println("To update it, please connect to your DSpace database as a 'superuser' and manually run the following command: "); - System.out.println("\n ALTER EXTENSION " + PostgresUtils.PGCRYPTO + " UPDATE TO '" + pgcryptoAvailable + "';\n"); + System.out.println( + "To update it, please connect to your DSpace database as a 'superuser' and manually run the " + + "following command: "); + System.out.println( + "\n ALTER EXTENSION " + PostgresUtils.PGCRYPTO + " UPDATE TO '" + pgcryptoAvailable + "';\n"); issueFound = true; - } - else if (pgcryptoInstalled==null) // If it's not installed in database - { - System.out.println("\nWARNING: Required PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is NOT INSTALLED on this database."); + } else if (pgcryptoInstalled == null) { + // If it's not installed in database + + System.out.println( + "\nWARNING: Required PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is NOT INSTALLED " + + "on this database."); System.out.println(requirementsMsg); - System.out.println("To install it, please connect to your DSpace database as a 'superuser' and manually run the following command: "); + System.out.println( + "To install it, please connect to your DSpace database as a 'superuser' and manually run the " + + "following command: "); System.out.println("\n CREATE EXTENSION " + PostgresUtils.PGCRYPTO + ";\n"); issueFound = true; } - } - // Check if installed in Postgres, but an unsupported version - else if (pgcryptoAvailable!=null && pgcryptoAvailable.compareTo(PostgresUtils.PGCRYPTO_VERSION)<0) - { - System.out.println("\nWARNING: UNSUPPORTED version of PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension found (version=" + pgcryptoAvailable + ")."); + } else if (pgcryptoAvailable != null && pgcryptoAvailable.compareTo(PostgresUtils.PGCRYPTO_VERSION) < 0) { + // If installed in Postgres, but an unsupported version + + System.out.println( + "\nWARNING: UNSUPPORTED version of PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension found " + + "(version=" + pgcryptoAvailable + ")."); System.out.println(requirementsMsg); - System.out.println("Make sure you are running a supported version of PostgreSQL, and then install " + PostgresUtils.PGCRYPTO + " version >= " + PostgresUtils.PGCRYPTO_VERSION); - System.out.println("The '" + PostgresUtils.PGCRYPTO + "' extension is often provided in the 'postgresql-contrib' package for your operating system."); + System.out.println( + "Make sure you are running a supported version of PostgreSQL, and then install " + PostgresUtils + .PGCRYPTO + " version >= " + PostgresUtils.PGCRYPTO_VERSION); + System.out.println( + "The '" + PostgresUtils.PGCRYPTO + "' extension is often provided in the 'postgresql-contrib' " + + "package for your operating system."); issueFound = true; - } - else if (pgcryptoAvailable==null) // If it's not installed in Postgres - { - System.out.println("\nWARNING: PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is NOT AVAILABLE. Please install it into this PostgreSQL instance."); + } else if (pgcryptoAvailable == null) { + // If it's not installed in Postgres + + System.out.println( + "\nWARNING: PostgreSQL '" + PostgresUtils.PGCRYPTO + "' extension is NOT AVAILABLE. Please " + + "install it into this PostgreSQL instance."); System.out.println(requirementsMsg); - System.out.println("The '" + PostgresUtils.PGCRYPTO + "' extension is often provided in the 'postgresql-contrib' package for your operating system."); - System.out.println("Once the extension is installed globally, please connect to your DSpace database as a 'superuser' and manually run the following command: "); + System.out.println( + "The '" + PostgresUtils.PGCRYPTO + "' extension is often provided in the 'postgresql-contrib' " + + "package for your operating system."); + System.out.println( + "Once the extension is installed globally, please connect to your DSpace database as a " + + "'superuser' and manually run the following command: "); System.out.println("\n CREATE EXTENSION " + PostgresUtils.PGCRYPTO + ";\n"); issueFound = true; } @@ -460,18 +480,14 @@ public class DatabaseUtils * Setup/Initialize the Flyway API to run against our DSpace database * and point at our migration scripts. * - * @param datasource - * DataSource object initialized by DatabaseManager + * @param datasource DataSource object initialized by DatabaseManager * @return initialized Flyway object */ - private synchronized static Flyway setupFlyway(DataSource datasource) - { + private synchronized static Flyway setupFlyway(DataSource datasource) { ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); - if (flywaydb==null) - { - try(Connection connection = datasource.getConnection()) - { + if (flywaydb == null) { + try (Connection connection = datasource.getConnection()) { // Initialize Flyway DB API (http://flywaydb.org/), used to perform DB migrations flywaydb = new Flyway(); flywaydb.setDataSource(datasource); @@ -490,10 +506,9 @@ public class DatabaseUtils // First, add location for custom SQL migrations, if any (based on DB Type) // e.g. [dspace.dir]/etc/[dbtype]/ // (We skip this for H2 as it's only used for unit testing) - if (!dbType.equals(DBMS_H2)) - { + if (!dbType.equals(DBMS_H2)) { scriptLocations.add("filesystem:" + config.getProperty("dspace.dir") + - "/etc/" + dbType); + "/etc/" + dbType); } // Also add the Java package where Flyway will load SQL migrations from (based on DB Type) @@ -504,7 +519,9 @@ public class DatabaseUtils scriptLocations.add("classpath:org.dspace.storage.rdbms.migration"); //Add all potential workflow migration paths - List workflowFlywayMigrationLocations = WorkflowServiceFactory.getInstance().getWorkflowService().getFlywayMigrationLocations(); + List workflowFlywayMigrationLocations = WorkflowServiceFactory.getInstance() + .getWorkflowService() + .getFlywayMigrationLocations(); scriptLocations.addAll(workflowFlywayMigrationLocations); // Now tell Flyway which locations to load SQL / Java migrations from @@ -513,12 +530,12 @@ public class DatabaseUtils // Set flyway callbacks (i.e. classes which are called post-DB migration and similar) // In this situation, we have a Registry Updater that runs PRE-migration - // NOTE: DatabaseLegacyReindexer only indexes in Legacy Lucene & RDBMS indexes. It can be removed once those are obsolete. - List flywayCallbacks = DSpaceServicesFactory.getInstance().getServiceManager().getServicesByType(FlywayCallback.class); + // NOTE: DatabaseLegacyReindexer only indexes in Legacy Lucene & RDBMS indexes. It can be removed + // once those are obsolete. + List flywayCallbacks = DSpaceServicesFactory.getInstance().getServiceManager() + .getServicesByType(FlywayCallback.class); flywaydb.setCallbacks(flywayCallbacks.toArray(new FlywayCallback[flywayCallbacks.size()])); - } - catch(SQLException e) - { + } catch (SQLException e) { log.error("Unable to setup Flyway against DSpace database", e); } } @@ -536,16 +553,17 @@ public class DatabaseUtils * successful migration, and any errors will be logged. * * @throws SQLException if database error - * If database cannot be upgraded. + * If database cannot be upgraded. */ public static synchronized void updateDatabase() - throws SQLException - { + throws SQLException { // Get our configured dataSource DataSource dataSource = getDataSource(); + if (null == dataSource) { + throw new SQLException("The DataSource is a null reference -- cannot continue."); + } - try(Connection connection = dataSource.getConnection()) - { + try (Connection connection = dataSource.getConnection()) { // Upgrade database to the latest version of our schema updateDatabase(dataSource, connection); } @@ -560,16 +578,13 @@ public class DatabaseUtils * If a Flyway DB migration fails it will be rolled back to the last * successful migration, and any errors will be logged. * - * @param datasource - * DataSource object (retrieved from DatabaseManager()) - * @param connection - * Database connection + * @param datasource DataSource object (retrieved from DatabaseManager()) + * @param connection Database connection * @throws SQLException if database error - * If database cannot be upgraded. + * If database cannot be upgraded. */ protected static synchronized void updateDatabase(DataSource datasource, Connection connection) - throws SQLException - { + throws SQLException { // By default, upgrade to the *latest* version and never run migrations out-of-order updateDatabase(datasource, connection, null, false); } @@ -583,24 +598,24 @@ public class DatabaseUtils * If a Flyway DB migration fails it will be rolled back to the last * successful migration, and any errors will be logged. * - * @param datasource - * DataSource object (retrieved from DatabaseManager()) - * @param connection - * Database connection - * @param targetVersion - * If specified, only migrate the database to a particular *version* of DSpace. This is mostly just useful for testing. - * If null, the database is migrated to the latest version. - * @param outOfOrder - * If true, Flyway will run any lower version migrations that were previously "ignored". - * If false, Flyway will only run new migrations with a higher version number. + * @param datasource DataSource object (retrieved from DatabaseManager()) + * @param connection Database connection + * @param targetVersion If specified, only migrate the database to a particular *version* of DSpace. This is + * mostly just useful for testing. + * If null, the database is migrated to the latest version. + * @param outOfOrder If true, Flyway will run any lower version migrations that were previously "ignored". + * If false, Flyway will only run new migrations with a higher version number. * @throws SQLException if database error - * If database cannot be upgraded. + * If database cannot be upgraded. */ - protected static synchronized void updateDatabase(DataSource datasource, Connection connection, String targetVersion, boolean outOfOrder) - throws SQLException - { - try - { + protected static synchronized void updateDatabase(DataSource datasource, + Connection connection, String targetVersion, boolean outOfOrder) + throws SQLException { + if (null == datasource) { + throw new SQLException("The datasource is a null reference -- cannot continue."); + } + + try { // Setup Flyway API against our database Flyway flyway = setupFlyway(datasource); @@ -610,8 +625,7 @@ public class DatabaseUtils // If a target version was specified, tell Flyway to ONLY migrate to that version // (i.e. all later migrations are left as "pending"). By default we always migrate to latest version. - if (!StringUtils.isBlank(targetVersion)) - { + if (!StringUtils.isBlank(targetVersion)) { flyway.setTargetAsString(targetVersion); } @@ -619,19 +633,15 @@ public class DatabaseUtils // If not, then this is the first time Flyway has run, and we need to initialize // NOTE: search is case sensitive, as flyway table name is ALWAYS lowercase, // See: http://flywaydb.org/documentation/faq.html#case-sensitive - if (!tableExists(connection, flyway.getTable(), true)) - { + if (!tableExists(connection, flyway.getTable(), true)) { // Try to determine our DSpace database version, so we know what to tell Flyway to do String dbVersion = determineDBVersion(connection); // If this is a fresh install, dbVersion will be null - if (dbVersion==null) - { + if (dbVersion == null) { // Initialize the Flyway database table with defaults (version=1) flyway.baseline(); - } - else - { + } else { // Otherwise, pass our determined DB version to Flyway to initialize database table flyway.setBaselineVersionAsString(dbVersion); flyway.setBaselineDescription("Initializing from DSpace " + dbVersion + " database schema"); @@ -643,12 +653,11 @@ public class DatabaseUtils MigrationInfo[] pending = flyway.info().pending(); // As long as there are pending migrations, log them and run migrate() - if (pending!=null && pending.length>0) - { + if (pending != null && pending.length > 0) { log.info("Pending DSpace database schema migrations:"); - for (MigrationInfo info : pending) - { - log.info("\t" + info.getVersion() + " " + info.getDescription() + " " + info.getType() + " " + info.getState()); + for (MigrationInfo info : pending) { + log.info("\t" + info.getVersion() + " " + info.getDescription() + " " + info.getType() + " " + info + .getState()); } // Run all pending Flyway migrations to ensure the DSpace Database is up to date @@ -656,12 +665,10 @@ public class DatabaseUtils // Flag that Discovery will need reindexing, since database was updated setReindexDiscovery(true); - } - else + } else { log.info("DSpace database schema is up to date"); - } - catch(FlywayException fe) - { + } + } catch (FlywayException fe) { // If any FlywayException (Runtime) is thrown, change it to a SQLException throw new SQLException("Flyway migration error occurred", fe); } @@ -672,48 +679,38 @@ public class DatabaseUtils *

    * FlywayDB (http://flywaydb.org/) is used to clean the database * - * @param flyway - * Initialized Flyway object - * @param dataSource - * Initialized DataSource + * @param flyway Initialized Flyway object + * @param dataSource Initialized DataSource * @throws SQLException if database error - * If database cannot be cleaned. + * If database cannot be cleaned. */ private static synchronized void cleanDatabase(Flyway flyway, DataSource dataSource) - throws SQLException - { - try - { + throws SQLException { + try { // First, run Flyway's clean command on database. // For MOST database types, this takes care of everything flyway.clean(); - try(Connection connection = dataSource.getConnection()) - { + try (Connection connection = dataSource.getConnection()) { // Get info about which database type we are using String dbType = getDbType(connection); // If this is Oracle, the only way to entirely clean the database // is to also purge the "Recyclebin". See: // http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9018.htm - if (dbType.equals(DBMS_ORACLE)) - { + if (dbType.equals(DBMS_ORACLE)) { PreparedStatement statement = null; - try - { + try { statement = connection.prepareStatement("PURGE RECYCLEBIN"); statement.executeQuery(); - } - finally - { - if (statement!=null && !statement.isClosed()) + } finally { + if (statement != null && !statement.isClosed()) { statement.close(); + } } } } - } - catch(FlywayException fe) - { + } catch (FlywayException fe) { // If any FlywayException (Runtime) is thrown, change it to a SQLException throw new SQLException("Flyway clean error occurred", fe); } @@ -728,17 +725,14 @@ public class DatabaseUtils * your database and matching them up with known tables that existed in * different versions of DSpace. * - * @param connection - * Current Database Connection - * @throws SQLException if DB status cannot be determined + * @param connection Current Database Connection * @return DSpace version as a String (e.g. "4.0"), or null if database is empty + * @throws SQLException if DB status cannot be determined */ private static String determineDBVersion(Connection connection) - throws SQLException - { + throws SQLException { // First, is this a "fresh_install"? Check for an "item" table. - if (!tableExists(connection, "Item")) - { + if (!tableExists(connection, "Item")) { // Item table doesn't exist. This database must be a fresh install return null; } @@ -746,94 +740,82 @@ public class DatabaseUtils // We will now check prior versions in reverse chronological order, looking // for specific tables or columns that were newly created in each version. - // Is this pre-DSpace 5.0 (with Metadata 4 All changes)? Look for the "resource_id" column in the "metadatavalue" table - if (tableColumnExists(connection, "metadatavalue", "resource_id")) - { + // Is this pre-DSpace 5.0 (with Metadata 4 All changes)? Look for the "resource_id" column in the + // "metadatavalue" table + if (tableColumnExists(connection, "metadatavalue", "resource_id")) { return "5.0.2014.09.26"; // This version matches the version in the SQL migration for this feature } - // Is this pre-DSpace 5.0 (with Helpdesk plugin)? Look for the "request_message" column in the "requestitem" table - if (tableColumnExists(connection, "requestitem", "request_message")) - { + // Is this pre-DSpace 5.0 (with Helpdesk plugin)? Look for the "request_message" column in the "requestitem" + // table + if (tableColumnExists(connection, "requestitem", "request_message")) { return "5.0.2014.08.08"; // This version matches the version in the SQL migration for this feature } // Is this DSpace 4.x? Look for the "Webapp" table created in that version. - if (tableExists(connection, "Webapp")) - { + if (tableExists(connection, "Webapp")) { return "4.0"; } // Is this DSpace 3.x? Look for the "versionitem" table created in that version. - if (tableExists(connection, "versionitem")) - { + if (tableExists(connection, "versionitem")) { return "3.0"; } // Is this DSpace 1.8.x? Look for the "bitstream_order" column in the "bundle2bitstream" table - if (tableColumnExists(connection, "bundle2bitstream", "bitstream_order")) - { + if (tableColumnExists(connection, "bundle2bitstream", "bitstream_order")) { return "1.8"; } // Is this DSpace 1.7.x? Look for the "dctyperegistry_seq" to NOT exist (it was deleted in 1.7) // NOTE: DSPACE 1.7.x only differs from 1.6 in a deleted sequence. - if (!sequenceExists(connection, "dctyperegistry_seq")) - { + if (!sequenceExists(connection, "dctyperegistry_seq")) { return "1.7"; } // Is this DSpace 1.6.x? Look for the "harvested_collection" table created in that version. - if (tableExists(connection, "harvested_collection")) - { + if (tableExists(connection, "harvested_collection")) { return "1.6"; } // Is this DSpace 1.5.x? Look for the "collection_item_count" table created in that version. - if (tableExists(connection, "collection_item_count")) - { + if (tableExists(connection, "collection_item_count")) { return "1.5"; } // Is this DSpace 1.4.x? Look for the "Group2Group" table created in that version. - if (tableExists(connection, "Group2Group")) - { + if (tableExists(connection, "Group2Group")) { return "1.4"; } // Is this DSpace 1.3.x? Look for the "epersongroup2workspaceitem" table created in that version. - if (tableExists(connection, "epersongroup2workspaceitem")) - { + if (tableExists(connection, "epersongroup2workspaceitem")) { return "1.3"; } // Is this DSpace 1.2.x? Look for the "Community2Community" table created in that version. - if (tableExists(connection, "Community2Community")) - { + if (tableExists(connection, "Community2Community")) { return "1.2"; } // Is this DSpace 1.1.x? Look for the "Community" table created in that version. - if (tableExists(connection, "Community")) - { + if (tableExists(connection, "Community")) { return "1.1"; } // IF we get here, something went wrong! This database is missing a LOT of DSpace tables - throw new SQLException("CANNOT AUTOUPGRADE DSPACE DATABASE, AS IT DOES NOT LOOK TO BE A VALID DSPACE DATABASE."); + throw new SQLException("CANNOT AUTOUPGRADE DSPACE DATABASE, AS IT DOES NOT LOOK TO BE A VALID DSPACE DATABASE" + + "."); } /** * Determine if a particular database table exists in our database * - * @param connection - * Current Database Connection - * @param tableName - * The name of the table + * @param connection Current Database Connection + * @param tableName The name of the table * @return true if table of that name exists, false otherwise */ - public static boolean tableExists(Connection connection, String tableName) - { + public static boolean tableExists(Connection connection, String tableName) { //By default, do a case-insensitive search return tableExists(connection, tableName, false); } @@ -841,22 +823,17 @@ public class DatabaseUtils /** * Determine if a particular database table exists in our database * - * @param connection - * Current Database Connection - * @param tableName - * The name of the table - * @param caseSensitive - * When "true", the case of the tableName will not be changed. - * When "false, the name may be uppercased or lowercased based on DB type. + * @param connection Current Database Connection + * @param tableName The name of the table + * @param caseSensitive When "true", the case of the tableName will not be changed. + * When "false, the name may be uppercased or lowercased based on DB type. * @return true if table of that name exists, false otherwise */ - public static boolean tableExists(Connection connection, String tableName, boolean caseSensitive) - { + public static boolean tableExists(Connection connection, String tableName, boolean caseSensitive) { boolean exists = false; ResultSet results = null; - try - { + try { // Get the name of the Schema that the DSpace Database is using // (That way we can search the right schema) String schema = getSchemaName(connection); @@ -865,8 +842,7 @@ public class DatabaseUtils DatabaseMetaData meta = connection.getMetaData(); // If this is not a case sensitive search - if (!caseSensitive) - { + if (!caseSensitive) { // Canonicalize everything to the proper case based on DB type schema = canonicalize(connection, schema); tableName = canonicalize(connection, tableName); @@ -874,25 +850,18 @@ public class DatabaseUtils // Search for a table of the given name in our current schema results = meta.getTables(null, schema, tableName, null); - if (results!=null && results.next()) - { + if (results != null && results.next()) { exists = true; } - } - catch(SQLException e) - { + } catch (SQLException e) { log.error("Error attempting to determine if table " + tableName + " exists", e); - } - finally - { - try - { + } finally { + try { // ensure the ResultSet gets closed - if (results!=null && !results.isClosed()) + if (results != null && !results.isClosed()) { results.close(); - } - catch(SQLException e) - { + } + } catch (SQLException e) { // ignore it } } @@ -903,21 +872,16 @@ public class DatabaseUtils /** * Determine if a particular database column exists in our database * - * @param connection - * Current Database Connection - * @param tableName - * The name of the table - * @param columnName - * The name of the column in the table + * @param connection Current Database Connection + * @param tableName The name of the table + * @param columnName The name of the column in the table * @return true if column of that name exists, false otherwise */ - public static boolean tableColumnExists(Connection connection, String tableName, String columnName) - { + public static boolean tableColumnExists(Connection connection, String tableName, String columnName) { boolean exists = false; ResultSet results = null; - try - { + try { // Get the name of the Schema that the DSpace Database is using // (That way we can search the right schema) String schema = getSchemaName(connection); @@ -932,25 +896,18 @@ public class DatabaseUtils // Search for a column of that name in the specified table & schema results = meta.getColumns(null, schema, tableName, columnName); - if (results!=null && results.next()) - { + if (results != null && results.next()) { exists = true; } - } - catch(SQLException e) - { + } catch (SQLException e) { log.error("Error attempting to determine if column " + columnName + " exists", e); - } - finally - { - try - { + } finally { + try { // ensure the ResultSet gets closed - if (results!=null && !results.isClosed()) + if (results != null && !results.isClosed()) { results.close(); - } - catch(SQLException e) - { + } + } catch (SQLException e) { // ignore it } } @@ -967,16 +924,14 @@ public class DatabaseUtils * The name of the table * @return true if sequence of that name exists, false otherwise */ - public static boolean sequenceExists(Connection connection, String sequenceName) - { + public static boolean sequenceExists(Connection connection, String sequenceName) { boolean exists = false; PreparedStatement statement = null; ResultSet results = null; // Whether or not to filter query based on schema (this is DB Type specific) boolean schemaFilter = false; - try - { + try { // Get the name of the Schema that the DSpace Database is using // (That way we can search the right schema) String schema = getSchemaName(connection); @@ -988,20 +943,18 @@ public class DatabaseUtils // Different database types store sequence information in different tables String dbtype = getDbType(connection); String sequenceSQL = null; - switch(dbtype) - { + switch (dbtype) { case DBMS_POSTGRES: // Default schema in PostgreSQL is "public" - if (schema == null) - { + if (schema == null) { schema = "public"; } // PostgreSQL specific query for a sequence in a particular schema sequenceSQL = "SELECT COUNT(1) FROM pg_class, pg_namespace " + - "WHERE pg_class.relnamespace=pg_namespace.oid " + - "AND pg_class.relkind='S' " + - "AND pg_class.relname=? " + - "AND pg_namespace.nspname=?"; + "WHERE pg_class.relnamespace=pg_namespace.oid " + + "AND pg_class.relkind='S' " + + "AND pg_class.relname=? " + + "AND pg_namespace.nspname=?"; // We need to filter by schema in PostgreSQL schemaFilter = true; break; @@ -1014,49 +967,41 @@ public class DatabaseUtils // In H2, sequences are listed in the "information_schema.sequences" table // SEE: http://www.h2database.com/html/grammar.html#information_schema sequenceSQL = "SELECT COUNT(1) " + - "FROM INFORMATION_SCHEMA.SEQUENCES " + - "WHERE SEQUENCE_NAME = ?"; + "FROM INFORMATION_SCHEMA.SEQUENCES " + + "WHERE SEQUENCE_NAME = ?"; break; default: throw new SQLException("DBMS " + dbtype + " is unsupported."); } // If we have a SQL query to run for the sequence, then run it - if (sequenceSQL!=null) - { + if (sequenceSQL != null) { // Run the query, passing it our parameters statement = connection.prepareStatement(sequenceSQL); statement.setString(1, sequenceName); - if (schemaFilter) - { + if (schemaFilter) { statement.setString(2, schema); } results = statement.executeQuery(); // If results are non-zero, then this sequence exists! - if (results!=null && results.next() && results.getInt(1)>0) - { + if (results != null && results.next() && results.getInt(1) > 0) { exists = true; } } - } - catch(SQLException e) - { + } catch (SQLException e) { log.error("Error attempting to determine if sequence " + sequenceName + " exists", e); - } - finally - { - try - { + } finally { + try { // Ensure statement gets closed - if (statement!=null && !statement.isClosed()) + if (statement != null && !statement.isClosed()) { statement.close(); + } // Ensure ResultSet gets closed - if (results!=null && !results.isClosed()) + if (results != null && !results.isClosed()) { results.close(); - } - catch(SQLException e) - { + } + } catch (SQLException e) { // ignore it } } @@ -1069,17 +1014,13 @@ public class DatabaseUtils *

    * The SQL is executed using the Flyway SQL parser. * - * @param connection - * Current Database Connection - * @param sqlToExecute - * The actual SQL to execute as a String + * @param connection Current Database Connection + * @param sqlToExecute The actual SQL to execute as a String * @throws SQLException if database error - * If a database error occurs + * If a database error occurs */ - public static void executeSql(Connection connection, String sqlToExecute) throws SQLException - { - try - { + public static void executeSql(Connection connection, String sqlToExecute) throws SQLException { + try { // Create a Flyway DbSupport object (based on our connection) // This is how Flyway determines the database *type* (e.g. Postgres vs Oracle) DbSupport dbSupport = DbSupportFactory.createDbSupport(connection, false); @@ -1087,9 +1028,7 @@ public class DatabaseUtils // Load our SQL string & execute via Flyway's SQL parser SqlScript script = new SqlScript(sqlToExecute, dbSupport); script.execute(dbSupport.getJdbcTemplate()); - } - catch(FlywayException fe) - { + } catch (FlywayException fe) { // If any FlywayException (Runtime) is thrown, change it to a SQLException throw new SQLException("Flyway executeSql() error occurred", fe); } @@ -1099,54 +1038,46 @@ public class DatabaseUtils * Get the Database Schema Name in use by this Connection, so that it can * be used to limit queries in other methods (e.g. tableExists()). * - * @param connection - * Current Database Connection + * @param connection Current Database Connection * @return Schema name as a string, or "null" if cannot be determined or unspecified - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public static String getSchemaName(Connection connection) - throws SQLException - { + throws SQLException { String schema = null; - + // Try to get the schema from the DB connection itself. // As long as the Database driver supports JDBC4.1, there should be a getSchema() method // If this method is unimplemented or doesn't exist, it will throw an exception (likely an AbstractMethodError) - try - { + try { schema = connection.getSchema(); - } - catch (Exception|AbstractMethodError e) - { + } catch (Exception | AbstractMethodError e) { + // ignore } // If we don't know our schema, let's try the schema in the DSpace configuration - if (StringUtils.isBlank(schema)) - { - schema = canonicalize(connection, DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("db.schema")); + if (StringUtils.isBlank(schema)) { + schema = canonicalize(connection, DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("db.schema")); } - + // Still blank? Ok, we'll find a "sane" default based on the DB type - if (StringUtils.isBlank(schema)) - { + if (StringUtils.isBlank(schema)) { String dbType = getDbType(connection); - if (dbType.equals(DBMS_POSTGRES)) - { + if (dbType.equals(DBMS_POSTGRES)) { // For PostgreSQL, the default schema is named "public" // See: http://www.postgresql.org/docs/9.0/static/ddl-schemas.html schema = "public"; - } - else if (dbType.equals(DBMS_ORACLE)) - { + } else if (dbType.equals(DBMS_ORACLE)) { // For Oracle, default schema is actually the user account // See: http://stackoverflow.com/a/13341390 DatabaseMetaData meta = connection.getMetaData(); schema = meta.getUserName(); - } - else // For H2 (in memory), there is no such thing as a schema + } else { + // For H2 (in memory), there is no such thing as a schema schema = null; + } } return schema; @@ -1156,40 +1087,33 @@ public class DatabaseUtils * Return the canonical name for a database identifier based on whether this * database defaults to storing identifiers in uppercase or lowercase. * - * @param connection - * Current Database Connection - * @param dbIdentifier - * Identifier to canonicalize (may be a table name, column name, etc) + * @param connection Current Database Connection + * @param dbIdentifier Identifier to canonicalize (may be a table name, column name, etc) * @return The canonical name of the identifier. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public static String canonicalize(Connection connection, String dbIdentifier) - throws SQLException - { + throws SQLException { // Avoid any null pointers - if (dbIdentifier==null) + if (dbIdentifier == null) { return null; - + } + DatabaseMetaData meta = connection.getMetaData(); // Check how this database stores its identifiers, etc. // i.e. lowercase vs uppercase (by default we assume mixed case) - if (meta.storesLowerCaseIdentifiers()) - { + if (meta.storesLowerCaseIdentifiers()) { return StringUtils.lowerCase(dbIdentifier); - - } - else if (meta.storesUpperCaseIdentifiers()) - { + + } else if (meta.storesUpperCaseIdentifiers()) { return StringUtils.upperCase(dbIdentifier); - } - else // Otherwise DB doesn't care about case - { + } else { + // Otherwise DB doesn't care about case return dbIdentifier; } } - + /** * Whether or not to tell Discovery to reindex itself based on the updated * database. @@ -1201,37 +1125,34 @@ public class DatabaseUtils * Because the DB migration may be initialized by commandline or any one of * the many DSpace webapps, setting this to "true" actually writes a temporary * file which lets Solr know when reindex is needed. + * * @param reindex true or false */ - public static synchronized void setReindexDiscovery(boolean reindex) - { + public static synchronized void setReindexDiscovery(boolean reindex) { File reindexFlag = new File(reindexDiscoveryFilePath); // If we need to flag Discovery to reindex, we'll create a temporary file to do so. - if (reindex) - { - try - { + if (reindex) { + try { //If our flag file doesn't exist, create it as writeable to all - if (!reindexFlag.exists()) - { + if (!reindexFlag.exists()) { reindexFlag.createNewFile(); reindexFlag.setWritable(true, false); } + } catch (IOException io) { + log.error("Unable to create Discovery reindex flag file " + reindexFlag + .getAbsolutePath() + ". You may need to reindex manually.", io); } - catch(IOException io) - { - log.error("Unable to create Discovery reindex flag file " + reindexFlag.getAbsolutePath() + ". You may need to reindex manually.", io); - } - } - else // Otherwise, Discovery doesn't need to reindex. Delete the temporary file if it exists - { + } else { + // Otherwise, Discovery doesn't need to reindex. Delete the temporary file if it exists + //If our flag file exists, delete it - if (reindexFlag.exists()) - { + if (reindexFlag.exists()) { boolean deleted = reindexFlag.delete(); - if (!deleted) - log.error("Unable to delete Discovery reindex flag file " + reindexFlag.getAbsolutePath() + ". You may need to delete it manually."); + if (!deleted) { + log.error("Unable to delete Discovery reindex flag file " + reindexFlag + .getAbsolutePath() + ". You may need to delete it manually."); + } } } } @@ -1242,10 +1163,10 @@ public class DatabaseUtils * Because the DB migration may be initialized by commandline or any one of * the many DSpace webapps, this checks for the existence of a temporary * file to know when Discovery/Solr needs reindexing. + * * @return whether reindex flag is true/false */ - public static boolean getReindexDiscovery() - { + public static boolean getReindexDiscovery() { // Simply check if the flag file exists File reindexFlag = new File(reindexDiscoveryFilePath); return reindexFlag.exists(); @@ -1258,15 +1179,12 @@ public class DatabaseUtils * This method is called by Discovery whenever it initializes a connection * to Solr. * - * @param indexer - * The actual indexer to use to reindex Discovery, if needed + * @param indexer The actual indexer to use to reindex Discovery, if needed * @see org.dspace.discovery.SolrServiceImpl */ - public static synchronized void checkReindexDiscovery(IndexingService indexer) - { + public static synchronized void checkReindexDiscovery(IndexingService indexer) { // We only do something if the reindexDiscovery flag has been triggered - if (getReindexDiscovery()) - { + if (getReindexDiscovery()) { // Kick off a custom thread to perform the reindexing in Discovery // (See ReindexerThread nested class below) ReindexerThread go = new ReindexerThread(indexer); @@ -1278,16 +1196,15 @@ public class DatabaseUtils * Internal class to actually perform re-indexing in a separate thread. * (See checkReindexDiscovery() method)> */ - private static class ReindexerThread extends Thread - { + private static class ReindexerThread extends Thread { private final IndexingService indexer; /** * Constructor. Pass it an existing IndexingService + * * @param is */ - ReindexerThread(IndexingService is) - { + ReindexerThread(IndexingService is) { this.indexer = is; } @@ -1296,20 +1213,17 @@ public class DatabaseUtils * This is synchronized so that only one thread can get in at a time. */ @Override - public void run() - { - synchronized(this.indexer) - { + public void run() { + synchronized (this.indexer) { // Make sure reindexDiscovery flag is still true // If multiple threads get here we only want to reindex ONCE - if (DatabaseUtils.getReindexDiscovery()) - { + if (DatabaseUtils.getReindexDiscovery()) { Context context = null; - try - { + try { context = new Context(); context.turnOffAuthorisationSystem(); - log.info("Post database migration, reindexing all content in Discovery search and browse engine"); + log.info( + "Post database migration, reindexing all content in Discovery search and browse engine"); // Reindex Discovery completely // Force clean all content @@ -1320,24 +1234,22 @@ public class DatabaseUtils this.indexer.buildSpellCheck(); log.info("Reindexing is complete"); - } - catch(SearchServiceException sse) - { - log.warn("Unable to reindex content in Discovery search and browse engine. You may need to reindex manually.", sse); - } - catch(SQLException | IOException e) - { + } catch (SearchServiceException sse) { + log.warn( + "Unable to reindex content in Discovery search and browse engine. You may need to reindex" + + " manually.", + sse); + } catch (SQLException | IOException e) { log.error("Error attempting to reindex all contents for search/browse", e); - } - finally - { + } finally { // Reset our indexing flag. Indexing is done or it threw an error, // Either way, we shouldn't try again. DatabaseUtils.setReindexDiscovery(false); // Clean up our context, if it still exists - if (context!=null && context.isValid()) + if (context != null && context.isValid()) { context.abort(); + } } } } @@ -1346,31 +1258,24 @@ public class DatabaseUtils /** * Determine the type of Database, based on the DB connection. - * + * * @param connection current DB Connection * @return a DB keyword/type (see DatabaseUtils.DBMS_* constants) * @throws SQLException if database error */ public static String getDbType(Connection connection) - throws SQLException - { + throws SQLException { DatabaseMetaData meta = connection.getMetaData(); String prodName = meta.getDatabaseProductName(); String dbms_lc = prodName.toLowerCase(Locale.ROOT); - if (dbms_lc.contains("postgresql")) - { + if (dbms_lc.contains("postgresql")) { return DBMS_POSTGRES; - } - else if (dbms_lc.contains("oracle")) - { + } else if (dbms_lc.contains("oracle")) { return DBMS_ORACLE; - } - else if (dbms_lc.contains("h2")) // Used for unit testing only - { + } else if (dbms_lc.contains("h2")) { + // Used for unit testing only return DBMS_H2; - } - else - { + } else { return dbms_lc; } } @@ -1378,34 +1283,41 @@ public class DatabaseUtils /** * Get a reference to the configured DataSource (which can be used to * initialize the database using Flyway). + * The DataSource is configured via our ServiceManager (i.e. via Spring). *

    * This is NOT public, as we discourage direct connections to the database * which bypass Hibernate. Only Flyway should be allowed a direct connection. + * * @return DataSource */ - protected static DataSource getDataSource() - { - // DataSource is configured via our ServiceManager (i.e. via Spring). - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("dataSource", BasicDataSource.class); + protected static DataSource getDataSource() { + DataSource dataSource = DSpaceServicesFactory.getInstance() + .getServiceManager() + .getServiceByName("dataSource", DataSource.class); + if (null == dataSource) { + log.error("The service manager could not find the DataSource."); + } + return dataSource; } /** * In case of a unit test the flyway db is cached to long leading to exceptions, we need to clear the object */ - public static void clearFlywayDBCache() - { + public static void clearFlywayDBCache() { flywaydb = null; } /** * Returns the current Flyway schema_version being used by the given database. * (i.e. the version of the highest numbered migration that this database has run) + * * @param connection current DB Connection * @return version as string * @throws SQLException if database error occurs */ public static String getCurrentFlywayState(Connection connection) throws SQLException { - PreparedStatement statement = connection.prepareStatement("SELECT \"version\" FROM \"schema_version\" ORDER BY \"version\" desc"); + PreparedStatement statement = connection + .prepareStatement("SELECT \"version\" FROM \"schema_version\" ORDER BY \"version\" desc"); ResultSet resultSet = statement.executeQuery(); resultSet.next(); return resultSet.getString("version"); @@ -1415,16 +1327,15 @@ public class DatabaseUtils * Return the DSpace version that this Flyway-enabled database reports to be compatible with. * The version is retrieved from Flyway, and parsed into a Double to represent an actual * DSpace version number (e.g. 5.0, 6.0, etc) + * * @param connection current DB Connection * @return reported DSpace version as a Double * @throws SQLException if database error occurs */ - public static Double getCurrentFlywayDSpaceState(Connection connection) throws SQLException - { + public static Double getCurrentFlywayDSpaceState(Connection connection) throws SQLException { String flywayState = getCurrentFlywayState(connection); Matcher matcher = Pattern.compile("^([0-9]*\\.[0-9]*)(\\.)?.*").matcher(flywayState); - if (matcher.matches()) - { + if (matcher.matches()) { return Double.parseDouble(matcher.group(1)); } return null; diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/GroupServiceInitializer.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/GroupServiceInitializer.java index c6179bfc53..1517b29a31 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/GroupServiceInitializer.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/GroupServiceInitializer.java @@ -7,6 +7,8 @@ */ package org.dspace.storage.rdbms; +import java.sql.Connection; + import org.apache.log4j.Logger; import org.dspace.core.Context; import org.dspace.eperson.service.GroupService; @@ -14,8 +16,6 @@ import org.flywaydb.core.api.MigrationInfo; import org.flywaydb.core.api.callback.FlywayCallback; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.Connection; - /** * Callback method to ensure that the default groups are created in the database * AFTER the database migration completes. @@ -32,8 +32,7 @@ public class GroupServiceInitializer implements FlywayCallback { public void initGroups() { // After every migrate, ensure default Groups are setup correctly. Context context = null; - try - { + try { context = new Context(); context.turnOffAuthorisationSystem(); // While it's not really a formal "registry", we need to ensure the @@ -42,17 +41,14 @@ public class GroupServiceInitializer implements FlywayCallback { context.restoreAuthSystemState(); // Commit changes and close context context.complete(); - } - catch(Exception e) - { + } catch (Exception e) { log.error("Error attempting to add/update default DSpace Groups", e); throw new RuntimeException(e); - } - finally - { + } finally { // Clean up our context, if it still exists & it was never completed - if(context!=null && context.isValid()) + if (context != null && context.isValid()) { context.abort(); + } } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgreSQLCryptoChecker.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgreSQLCryptoChecker.java index 3b50c89ed9..410e922e0c 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgreSQLCryptoChecker.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgreSQLCryptoChecker.java @@ -10,6 +10,7 @@ package org.dspace.storage.rdbms; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; + import org.apache.log4j.Logger; import org.flywaydb.core.api.FlywayException; import org.flywaydb.core.api.MigrationInfo; @@ -27,38 +28,34 @@ import org.flywaydb.core.api.callback.FlywayCallback; * * @author Tim Donohue */ -public class PostgreSQLCryptoChecker implements FlywayCallback -{ +public class PostgreSQLCryptoChecker implements FlywayCallback { private Logger log = Logger.getLogger(PostgreSQLCryptoChecker.class); /** * Check for pgcrypto (if needed). Throws an exception if pgcrypto is * not installed or needs an upgrade. + * * @param connection database connection */ - public void checkPgCrypto(Connection connection) - { + public void checkPgCrypto(Connection connection) { String dbType; - try - { + try { dbType = DatabaseUtils.getDbType(connection); - } - catch(SQLException se) - { + } catch (SQLException se) { throw new FlywayException("Unable to determine database type.", se); } // ONLY Check if this is a PostgreSQL database - if(dbType!=null && dbType.equals(DatabaseUtils.DBMS_POSTGRES)) - { + if (dbType != null && dbType.equals(DatabaseUtils.DBMS_POSTGRES)) { // If this is a PostgreSQL database, then a supported version // of the 'pgcrypto' extension MUST be installed to continue. - + // Check if pgcrypto is both installed & a supported version - if(!PostgresUtils.isPgcryptoUpToDate()) - { - throw new FlywayException("This PostgreSQL Database is INCOMPATIBLE with DSpace. The upgrade will NOT proceed. " + - "A supported version (>=" + PostgresUtils.PGCRYPTO_VERSION + ") of the '" + PostgresUtils.PGCRYPTO + "' extension must be installed! " + + if (!PostgresUtils.isPgcryptoUpToDate()) { + throw new FlywayException( + "This PostgreSQL Database is INCOMPATIBLE with DSpace. The upgrade will NOT proceed. " + + "A supported version (>=" + PostgresUtils.PGCRYPTO_VERSION + ") of the '" + PostgresUtils + .PGCRYPTO + "' extension must be installed! " + "Please run 'dspace database info' for additional info/tips."); } } @@ -69,27 +66,23 @@ public class PostgreSQLCryptoChecker implements FlywayCallback *

    * The pgcrypto extension MUST be removed before a clean or else errors occur. * This method checks if it needs to be removed and, if so, removes it. + * * @param connection database connection */ - public void removePgCrypto(Connection connection) - { - try - { + public void removePgCrypto(Connection connection) { + try { String dbType = DatabaseUtils.getDbType(connection); // ONLY remove if this is a PostgreSQL database - if(dbType!=null && dbType.equals(DatabaseUtils.DBMS_POSTGRES)) - { + if (dbType != null && dbType.equals(DatabaseUtils.DBMS_POSTGRES)) { // Get current schema String schema = DatabaseUtils.getSchemaName(connection); // Check if pgcrypto is in this schema // If so, it MUST be removed before a 'clean' - if(PostgresUtils.isPgcryptoInSchema(schema)) - { + if (PostgresUtils.isPgcryptoInSchema(schema)) { // remove the extension - try(Statement statement = connection.createStatement()) - { + try (Statement statement = connection.createStatement()) { // WARNING: ONLY superusers can remove pgcrypto. However, at this point, // we have already verified user acct permissions via PostgresUtils.checkCleanPermissions() // (which is called prior to a 'clean' being triggered). @@ -97,10 +90,9 @@ public class PostgreSQLCryptoChecker implements FlywayCallback } } } - } - catch(SQLException e) - { - throw new FlywayException("Failed to check for and/or remove '" + PostgresUtils.PGCRYPTO + "' extension", e); + } catch (SQLException e) { + throw new FlywayException("Failed to check for and/or remove '" + PostgresUtils.PGCRYPTO + "' extension", + e); } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgresUtils.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgresUtils.java index f53f6f0795..0d049bb6ac 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgresUtils.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/PostgresUtils.java @@ -7,12 +7,14 @@ */ package org.dspace.storage.rdbms; +import static org.dspace.storage.rdbms.DatabaseUtils.getSchemaName; + import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.sql.DataSource; -import static org.dspace.storage.rdbms.DatabaseUtils.getSchemaName; + import org.flywaydb.core.api.FlywayException; /** @@ -23,12 +25,16 @@ import org.flywaydb.core.api.FlywayException; * * @author Tim Donohue */ -public class PostgresUtils -{ +public class PostgresUtils { // PostgreSQL pgcrypto extention name, and required versions of Postgres & pgcrypto - public static final String PGCRYPTO="pgcrypto"; - public static final Double PGCRYPTO_VERSION=1.1; - public static final Double POSTGRES_VERSION=9.4; + public static final String PGCRYPTO = "pgcrypto"; + public static final Double PGCRYPTO_VERSION = 1.1; + public static final Double POSTGRES_VERSION = 9.4; + + /** + * Default constructor + */ + private PostgresUtils() { } /** * Get version of pgcrypto extension available. The extension is "available" @@ -36,29 +42,24 @@ public class PostgresUtils * MUST be installed in the DSpace database (see getPgcryptoInstalled()). *

    * The pgcrypto extension is required for Postgres databases + * * @param connection database connection * @return version number or null if not available */ - protected static Double getPgcryptoAvailableVersion(Connection connection) - { + protected static Double getPgcryptoAvailableVersion(Connection connection) { Double version = null; String checkPgCryptoAvailable = "SELECT default_version AS version FROM pg_available_extensions WHERE name=?"; // Run the query to obtain the version of 'pgcrypto' available - try (PreparedStatement statement = connection.prepareStatement(checkPgCryptoAvailable)) - { - statement.setString(1,PGCRYPTO); - try(ResultSet results = statement.executeQuery()) - { - if(results.next()) - { + try (PreparedStatement statement = connection.prepareStatement(checkPgCryptoAvailable)) { + statement.setString(1, PGCRYPTO); + try (ResultSet results = statement.executeQuery()) { + if (results.next()) { version = results.getDouble("version"); } } - } - catch(SQLException e) - { + } catch (SQLException e) { throw new FlywayException("Unable to determine whether 'pgcrypto' extension is available.", e); } @@ -70,29 +71,24 @@ public class PostgresUtils *

    * The pgcrypto extension is required for Postgres databases to support * UUIDs. + * * @param connection database connection * @return version number or null if not installed */ - protected static Double getPgcryptoInstalledVersion(Connection connection) - { + protected static Double getPgcryptoInstalledVersion(Connection connection) { Double version = null; String checkPgCryptoInstalled = "SELECT extversion AS version FROM pg_extension WHERE extname=?"; // Run the query to obtain the version of 'pgcrypto' installed on this database - try (PreparedStatement statement = connection.prepareStatement(checkPgCryptoInstalled)) - { - statement.setString(1,PGCRYPTO); - try(ResultSet results = statement.executeQuery()) - { - if(results.next()) - { + try (PreparedStatement statement = connection.prepareStatement(checkPgCryptoInstalled)) { + statement.setString(1, PGCRYPTO); + try (ResultSet results = statement.executeQuery()) { + if (results.next()) { version = results.getDouble("version"); } } - } - catch(SQLException e) - { + } catch (SQLException e) { throw new FlywayException("Unable to determine whether 'pgcrypto' extension is installed.", e); } @@ -104,27 +100,23 @@ public class PostgresUtils *

    * This requirement is only needed for PostgreSQL databases. * It doesn't matter what schema pgcrypto is installed in, as long as it exists. + * * @return true if everything is installed and up-to-date. False otherwise. */ - public static boolean isPgcryptoUpToDate() - { + public static boolean isPgcryptoUpToDate() { // Get our configured dataSource DataSource dataSource = DatabaseUtils.getDataSource(); - try(Connection connection = dataSource.getConnection()) - { + try (Connection connection = dataSource.getConnection()) { Double pgcryptoInstalled = getPgcryptoInstalledVersion(connection); // Check if installed & up-to-date in this DSpace database - if(pgcryptoInstalled!=null && pgcryptoInstalled.compareTo(PGCRYPTO_VERSION)>=0) - { + if (pgcryptoInstalled != null && pgcryptoInstalled.compareTo(PGCRYPTO_VERSION) >= 0) { return true; } return false; - } - catch(SQLException e) - { + } catch (SQLException e) { throw new FlywayException("Unable to determine whether 'pgcrypto' extension is up-to-date.", e); } } @@ -139,41 +131,36 @@ public class PostgresUtils * @param schema name of schema * @return true if pgcrypto is in this schema. False otherwise. */ - public static boolean isPgcryptoInSchema(String schema) - { + public static boolean isPgcryptoInSchema(String schema) { // Get our configured dataSource DataSource dataSource = DatabaseUtils.getDataSource(); - try(Connection connection = dataSource.getConnection()) - { + try (Connection connection = dataSource.getConnection()) { // Check if pgcrypto is installed in the current database schema. String pgcryptoInstalledInSchema = "SELECT extversion FROM pg_extension,pg_namespace " + - "WHERE pg_extension.extnamespace=pg_namespace.oid " + - "AND extname=? " + - "AND nspname=?;"; + "WHERE pg_extension.extnamespace=pg_namespace.oid " + + "AND extname=? " + + "AND nspname=?;"; Double pgcryptoVersion = null; - try (PreparedStatement statement = connection.prepareStatement(pgcryptoInstalledInSchema)) - { - statement.setString(1,PGCRYPTO); + try (PreparedStatement statement = connection.prepareStatement(pgcryptoInstalledInSchema)) { + statement.setString(1, PGCRYPTO); statement.setString(2, schema); - try(ResultSet results = statement.executeQuery()) - { - if(results.next()) - { + try (ResultSet results = statement.executeQuery()) { + if (results.next()) { pgcryptoVersion = results.getDouble("extversion"); } } } // If a pgcrypto version returns, it's installed in this schema - if(pgcryptoVersion!=null) + if (pgcryptoVersion != null) { return true; - else + } else { return false; - } - catch(SQLException e) - { - throw new FlywayException("Unable to determine whether 'pgcrypto' extension is installed in schema '" + schema + "'.", e); + } + } catch (SQLException e) { + throw new FlywayException( + "Unable to determine whether 'pgcrypto' extension is installed in schema '" + schema + "'.", e); } } @@ -188,51 +175,43 @@ public class PostgresUtils * @param connection database connection * @return true if permissions valid, false otherwise */ - protected static boolean checkCleanPermissions(Connection connection) - { - try - { + protected static boolean checkCleanPermissions(Connection connection) { + try { // get username of our db user String username = connection.getMetaData().getUserName(); // Check their permissions. Are they a 'superuser'? String checkSuperuser = "SELECT rolsuper FROM pg_roles WHERE rolname=?;"; boolean superuser = false; - try (PreparedStatement statement = connection.prepareStatement(checkSuperuser)) - { - statement.setString(1,username); - try(ResultSet results = statement.executeQuery()) - { - if(results.next()) - { + try (PreparedStatement statement = connection.prepareStatement(checkSuperuser)) { + statement.setString(1, username); + try (ResultSet results = statement.executeQuery()) { + if (results.next()) { superuser = results.getBoolean("rolsuper"); } } - } - catch(SQLException e) - { + } catch (SQLException e) { throw new FlywayException("Unable to determine if user '" + username + "' is a superuser.", e); } // If user is a superuser, then "clean" can be run successfully - if(superuser) - { + if (superuser) { return true; - } - else // Otherwise, we'll need to see which schema 'pgcrypto' is installed in - { + } else { + // Otherwise, we'll need to see which schema 'pgcrypto' is installed in + // Get current schema name String schema = getSchemaName(connection); // If pgcrypto is installed in this schema, then superuser privileges are needed to remove it - if(isPgcryptoInSchema(schema)) + if (isPgcryptoInSchema(schema)) { return false; - else // otherwise, a 'clean' can be run by anyone + } else { + // otherwise, a 'clean' can be run by anyone return true; + } } - } - catch(SQLException e) - { + } catch (SQLException e) { throw new FlywayException("Unable to determine if DB user has 'clean' privileges.", e); } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/SiteServiceInitializer.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/SiteServiceInitializer.java index 243cc50d53..68f671c951 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/SiteServiceInitializer.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/SiteServiceInitializer.java @@ -7,6 +7,8 @@ */ package org.dspace.storage.rdbms; +import java.sql.Connection; + import org.apache.log4j.Logger; import org.dspace.content.service.SiteService; import org.dspace.core.Context; @@ -14,8 +16,6 @@ import org.flywaydb.core.api.MigrationInfo; import org.flywaydb.core.api.callback.FlywayCallback; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.Connection; - /** * Callback method to ensure that the Site object is created (if no site exists) * after the database migration completes. @@ -32,29 +32,24 @@ public class SiteServiceInitializer implements FlywayCallback { public void initializeSiteObject() { // After every migrate, ensure default Site is setup correctly. Context context = null; - try - { + try { context = new Context(); context.turnOffAuthorisationSystem(); // While it's not really a formal "registry", we need to ensure the // default, required Groups exist in the DSpace database - if(siteService.findSite(context) == null) - { + if (siteService.findSite(context) == null) { siteService.createSite(context); } context.restoreAuthSystemState(); // Commit changes and close context context.complete(); - } - catch(Exception e) - { + } catch (Exception e) { log.error("Error attempting to add/update default DSpace Groups", e); - } - finally - { + } finally { // Clean up our context, if it still exists & it was never completed - if(context!=null && context.isValid()) + if (context != null && context.isValid()) { context.abort(); + } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/hibernate/postgres/DSpacePostgreSQL82Dialect.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/hibernate/postgres/DSpacePostgreSQL82Dialect.java index 8b5d5a8e17..2701c22fd2 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/hibernate/postgres/DSpacePostgreSQL82Dialect.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/hibernate/postgres/DSpacePostgreSQL82Dialect.java @@ -16,15 +16,16 @@ import org.hibernate.type.descriptor.sql.LongVarcharTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; /** - * UUID's are not supported by default in hibernate due to differences in the database in order to fix this a custom sql dialect is needed. + * UUID's are not supported by default in hibernate due to differences in the database in order to fix this a custom + * sql dialect is needed. * Source: https://forum.hibernate.org/viewtopic.php?f=1&t=1014157 * * @author kevinvandevelde at atmire.com */ -public class DSpacePostgreSQL82Dialect extends PostgreSQL82Dialect -{ +public class DSpacePostgreSQL82Dialect extends PostgreSQL82Dialect { @Override - public void contributeTypes(final org.hibernate.boot.model.TypeContributions typeContributions, final ServiceRegistry serviceRegistry) { + public void contributeTypes(final org.hibernate.boot.model.TypeContributions typeContributions, + final ServiceRegistry serviceRegistry) { super.contributeTypes(typeContributions, serviceRegistry); typeContributions.contributeType(new InternalPostgresUUIDType()); } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/MigrationUtils.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/MigrationUtils.java index 36d6e5e78c..4c4dcb2896 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/MigrationUtils.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/MigrationUtils.java @@ -11,6 +11,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; + import org.apache.commons.lang.StringUtils; /** @@ -21,26 +22,32 @@ import org.apache.commons.lang.StringUtils; * used for database migrations which take place PRIOR to Hibernate loading. * However, as you'll see below, all methods are protected to ensure the rest * of the API cannot bypass Hibernate. - * + * * @author Tim Donohue */ -public class MigrationUtils -{ +public class MigrationUtils { + + /** + * Default constructor + */ + private MigrationUtils() { } + /** * Drop a given Database Constraint (based on the current database type). * Returns a "checksum" for this migration which can be used as part of * a Flyway Java migration * - * @param connection the current Database connection - * @param tableName the name of the table the constraint applies to - * @param columnName the name of the column the constraint applies to - * @param constraintSuffix Only used for PostgreSQL, whose constraint naming convention depends on a suffix (key, fkey, etc) + * @param connection the current Database connection + * @param tableName the name of the table the constraint applies to + * @param columnName the name of the column the constraint applies to + * @param constraintSuffix Only used for PostgreSQL, whose constraint naming convention depends on a suffix (key, + * fkey, etc) * @return migration checksum as an Integer * @throws SQLException if a database error occurs */ - protected static Integer dropDBConstraint(Connection connection, String tableName, String columnName, String constraintSuffix) - throws SQLException - { + protected static Integer dropDBConstraint(Connection connection, String tableName, String columnName, + String constraintSuffix) + throws SQLException { Integer checksum = -1; // First, in order to drop the appropriate Database constraint, we @@ -50,16 +57,14 @@ public class MigrationUtils String constraintName = null; String constraintNameSQL = null; boolean cascade = false; - switch(dbtype.toLowerCase()) - { + switch (dbtype.toLowerCase()) { case "postgres": case "postgresql": // In Postgres, constraints are always named: // {tablename}_{columnname(s)}_{suffix} // see: http://stackoverflow.com/a/4108266/3750035 constraintName = StringUtils.lowerCase(tableName); - if(!StringUtils.equals(constraintSuffix, "pkey")) - { + if (!StringUtils.equals(constraintSuffix, "pkey")) { constraintName += "_" + StringUtils.lowerCase(columnName); } @@ -69,53 +74,46 @@ public class MigrationUtils case "oracle": // In Oracle, constraints are listed in the USER_CONS_COLUMNS table constraintNameSQL = "SELECT CONSTRAINT_NAME " + - "FROM USER_CONS_COLUMNS " + - "WHERE TABLE_NAME = ? AND COLUMN_NAME = ?"; + "FROM USER_CONS_COLUMNS " + + "WHERE TABLE_NAME = ? AND COLUMN_NAME = ?"; cascade = true; break; case "h2": // In H2, constraints are listed in the "information_schema.constraints" table constraintNameSQL = "SELECT DISTINCT CONSTRAINT_NAME " + - "FROM information_schema.constraints " + - "WHERE table_name = ? AND column_list = ?"; + "FROM information_schema.constraints " + + "WHERE table_name = ? AND column_list = ?"; break; default: throw new SQLException("DBMS " + dbtype + " is unsupported in this migration."); } // If we have a SQL query to run for the constraint name, then run it - if (constraintNameSQL!=null) - { + if (constraintNameSQL != null) { // Run the query to obtain the constraint name, passing it the parameters PreparedStatement statement = connection.prepareStatement(constraintNameSQL); statement.setString(1, StringUtils.upperCase(tableName)); statement.setString(2, StringUtils.upperCase(columnName)); - try - { + try { ResultSet results = statement.executeQuery(); - if(results.next()) - { + if (results.next()) { constraintName = results.getString("CONSTRAINT_NAME"); } results.close(); - } - finally - { + } finally { statement.close(); } } // As long as we have a constraint name, drop it - if (constraintName!=null && !constraintName.isEmpty()) - { + if (constraintName != null && !constraintName.isEmpty()) { // This drop constaint SQL should be the same in all databases String dropConstraintSQL = "ALTER TABLE " + tableName + " DROP CONSTRAINT " + constraintName; - if(cascade){ + if (cascade) { dropConstraintSQL += " CASCADE"; } - try(PreparedStatement statement = connection.prepareStatement(dropConstraintSQL)) - { + try (PreparedStatement statement = connection.prepareStatement(dropConstraintSQL)) { statement.execute(); } // Return the size of the query we just ran @@ -125,8 +123,8 @@ public class MigrationUtils return checksum; } - - + + /** * Drop a given Database Table (based on the current database type). * Returns a "checksum" for this migration which can be used as part of @@ -137,21 +135,19 @@ public class MigrationUtils * needs to be dynamically determined via Java. * * @param connection the current Database connection - * @param tableName the name of the table to drop + * @param tableName the name of the table to drop * @return migration checksum as an Integer * @throws SQLException if a database error occurs */ protected static Integer dropDBTable(Connection connection, String tableName) - throws SQLException - { + throws SQLException { String dropTableSQL = null; Integer checksum = -1; - // First, in order to drop the appropriate Database table, we must + // First, in order to drop the appropriate Database table, we must // determine the query based on DB type String dbtype = connection.getMetaData().getDatabaseProductName(); - switch(dbtype.toLowerCase()) - { + switch (dbtype.toLowerCase()) { case "postgres": case "postgresql": dropTableSQL = "DROP TABLE IF EXISTS " + tableName + " CASCADE"; @@ -165,22 +161,20 @@ public class MigrationUtils default: throw new SQLException("DBMS " + dbtype + " is unsupported in this migration."); } - + // If we have a SQL query to run, then run it - if (dropTableSQL!=null) - { - try(PreparedStatement statement = connection.prepareStatement(dropTableSQL)) - { + if (dropTableSQL != null) { + try (PreparedStatement statement = connection.prepareStatement(dropTableSQL)) { statement.execute(); } // Return the size of the query we just ran // This will be our "checksum" for this Flyway migration (see getChecksum()) checksum = dropTableSQL.length(); } - + return checksum; } - + /** * Drop a given Database Sequence (based on the current database type). * Returns a "checksum" for this migration which can be used as part of @@ -190,26 +184,24 @@ public class MigrationUtils * a Flyway SQL migration. This method should ONLY be used if the sequence name * needs to be dynamically determined via Java. * - * @param connection the current Database connection + * @param connection the current Database connection * @param sequenceName the name of the sequence to drop * @return migration checksum as an Integer * @throws SQLException if a database error occurs */ protected static Integer dropDBSequence(Connection connection, String sequenceName) - throws SQLException - { + throws SQLException { String dropSequenceSQL = null; Integer checksum = -1; String dbtype = connection.getMetaData().getDatabaseProductName(); - switch(dbtype.toLowerCase()) - { + switch (dbtype.toLowerCase()) { case "postgres": case "postgresql": dropSequenceSQL = "DROP SEQUENCE IF EXISTS " + sequenceName; break; case "oracle": - dropSequenceSQL = "DROP SEQUENCE " + sequenceName ; + dropSequenceSQL = "DROP SEQUENCE " + sequenceName; break; case "h2": dropSequenceSQL = "DROP SEQUENCE IF EXISTS " + sequenceName; @@ -219,20 +211,18 @@ public class MigrationUtils } // If we have a SQL query to run, then run it - if (dropSequenceSQL!=null) - { - try(PreparedStatement statement = connection.prepareStatement(dropSequenceSQL)) - { + if (dropSequenceSQL != null) { + try (PreparedStatement statement = connection.prepareStatement(dropSequenceSQL)) { statement.execute(); } // Return the size of the query we just ran // This will be our "checksum" for this Flyway migration (see getChecksum()) checksum = dropSequenceSQL.length(); } - + return checksum; } - + /** * Drop a given Database View (based on the current database type). * Returns a "checksum" for this migration which can be used as part of @@ -243,19 +233,17 @@ public class MigrationUtils * needs to be dynamically determined via Java. * * @param connection the current Database connection - * @param viewName the name of the view to drop + * @param viewName the name of the view to drop * @return migration checksum as an Integer * @throws SQLException if a database error occurs */ protected static Integer dropDBView(Connection connection, String viewName) - throws SQLException - { + throws SQLException { String dropViewSQL = null; Integer checksum = -1; String dbtype = connection.getMetaData().getDatabaseProductName(); - switch(dbtype.toLowerCase()) - { + switch (dbtype.toLowerCase()) { case "postgres": case "postgresql": dropViewSQL = "DROP VIEW IF EXISTS " + viewName + " CASCADE"; @@ -271,17 +259,15 @@ public class MigrationUtils } // If we have a SQL query to run, then run it - if (dropViewSQL!=null) - { - try(PreparedStatement statement = connection.prepareStatement(dropViewSQL)) - { + if (dropViewSQL != null) { + try (PreparedStatement statement = connection.prepareStatement(dropViewSQL)) { statement.execute(); } // Return the size of the query we just ran // This will be our "checksum" for this Flyway migration (see getChecksum()) checksum = dropViewSQL.length(); } - + return checksum; } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V1_3_9__Drop_constraint_for_DSpace_1_4_schema.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V1_3_9__Drop_constraint_for_DSpace_1_4_schema.java index cba74cb9cf..c3a79783ad 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V1_3_9__Drop_constraint_for_DSpace_1_4_schema.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V1_3_9__Drop_constraint_for_DSpace_1_4_schema.java @@ -10,6 +10,7 @@ package org.dspace.storage.rdbms.migration; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; + import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; @@ -37,24 +38,20 @@ import org.flywaydb.core.api.migration.jdbc.JdbcMigration; * @author Tim Donohue */ public class V1_3_9__Drop_constraint_for_DSpace_1_4_schema - implements JdbcMigration, MigrationChecksumProvider -{ + implements JdbcMigration, MigrationChecksumProvider { /* The checksum to report for this migration (when successful) */ private int checksum = -1; /** * Actually migrate the existing database - * @param connection - * SQL Connection object - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * + * @param connection SQL Connection object + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. */ @Override public void migrate(Connection connection) - throws IOException, SQLException - { + throws IOException, SQLException { // Drop the constraint associated with "name" column of "community" checksum = MigrationUtils.dropDBConstraint(connection, "community", "name", "key"); } @@ -62,11 +59,11 @@ public class V1_3_9__Drop_constraint_for_DSpace_1_4_schema /** * Return the checksum to be associated with this Migration * in the Flyway database table (schema_version). + * * @return checksum as an Integer */ @Override - public Integer getChecksum() - { + public Integer getChecksum() { return checksum; } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V1_5_9__Drop_constraint_for_DSpace_1_6_schema.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V1_5_9__Drop_constraint_for_DSpace_1_6_schema.java index 13ab900600..77eb7a070d 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V1_5_9__Drop_constraint_for_DSpace_1_6_schema.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V1_5_9__Drop_constraint_for_DSpace_1_6_schema.java @@ -10,6 +10,7 @@ package org.dspace.storage.rdbms.migration; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; + import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; @@ -37,24 +38,20 @@ import org.flywaydb.core.api.migration.jdbc.JdbcMigration; * @author Tim Donohue */ public class V1_5_9__Drop_constraint_for_DSpace_1_6_schema - implements JdbcMigration, MigrationChecksumProvider -{ + implements JdbcMigration, MigrationChecksumProvider { /* The checksum to report for this migration (when successful) */ private int checksum = -1; /** * Actually migrate the existing database - * @param connection - * SQL Connection object - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * + * @param connection SQL Connection object + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. */ @Override public void migrate(Connection connection) - throws IOException, SQLException - { + throws IOException, SQLException { // Drop the constraint associated with "collection_id" column of "community2collection" table int return1 = MigrationUtils.dropDBConstraint(connection, "community2collection", "collection_id", "pkey"); // Drop the constraint associated with "child_comm_id" column of "community2community" table @@ -62,18 +59,18 @@ public class V1_5_9__Drop_constraint_for_DSpace_1_6_schema // Drop the constraint associated with "item_id" column of "collection2item" table int return3 = MigrationUtils.dropDBConstraint(connection, "collection2item", "item_id", "pkey"); - // Checksum will just be the sum of those three return values - checksum = return1 + return2 + return3; + // Checksum will just be the sum of those three return values + checksum = return1 + return2 + return3; } /** * Return the checksum to be associated with this Migration * in the Flyway database table (schema_version). + * * @return checksum as an Integer */ @Override - public Integer getChecksum() - { + public Integer getChecksum() { return checksum; } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V5_0_2014_09_25__DS_1582_Metadata_For_All_Objects_drop_constraint.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V5_0_2014_09_25__DS_1582_Metadata_For_All_Objects_drop_constraint.java index 8d524b416f..17598ade6c 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V5_0_2014_09_25__DS_1582_Metadata_For_All_Objects_drop_constraint.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V5_0_2014_09_25__DS_1582_Metadata_For_All_Objects_drop_constraint.java @@ -10,6 +10,7 @@ package org.dspace.storage.rdbms.migration; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; + import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; @@ -38,24 +39,20 @@ import org.flywaydb.core.api.migration.jdbc.JdbcMigration; * @author Tim Donohue */ public class V5_0_2014_09_25__DS_1582_Metadata_For_All_Objects_drop_constraint - implements JdbcMigration, MigrationChecksumProvider -{ + implements JdbcMigration, MigrationChecksumProvider { /* The checksum to report for this migration (when successful) */ private int checksum = -1; /** * Actually migrate the existing database - * @param connection - * SQL Connection object - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * + * @param connection SQL Connection object + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. */ @Override public void migrate(Connection connection) - throws IOException, SQLException - { + throws IOException, SQLException { // Drop the constraint associated with "item_id" column of "metadatavalue" checksum = MigrationUtils.dropDBConstraint(connection, "metadatavalue", "item_id", "fkey"); } @@ -63,11 +60,11 @@ public class V5_0_2014_09_25__DS_1582_Metadata_For_All_Objects_drop_constraint /** * Return the checksum to be associated with this Migration * in the Flyway database table (schema_version). + * * @return checksum as an Integer */ @Override - public Integer getChecksum() - { + public Integer getChecksum() { return checksum; } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V5_7_2017_05_05__DS_3431_Add_Policies_for_BasicWorkflow.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V5_7_2017_05_05__DS_3431_Add_Policies_for_BasicWorkflow.java index 2d6fdad3d2..3b8e551b12 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V5_7_2017_05_05__DS_3431_Add_Policies_for_BasicWorkflow.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V5_7_2017_05_05__DS_3431_Add_Policies_for_BasicWorkflow.java @@ -7,41 +7,40 @@ */ package org.dspace.storage.rdbms.migration; +import java.sql.Connection; + import org.dspace.core.Constants; import org.dspace.storage.rdbms.DatabaseUtils; import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; import org.flywaydb.core.internal.util.scanner.classpath.ClassPathResource; -import java.sql.Connection; - public class V5_7_2017_05_05__DS_3431_Add_Policies_for_BasicWorkflow - implements JdbcMigration, MigrationChecksumProvider -{ + implements JdbcMigration, MigrationChecksumProvider { // Size of migration script run Integer migration_file_size = -1; @Override - public void migrate(Connection connection) throws Exception - { + public void migrate(Connection connection) throws Exception { // Based on type of DB, get path to SQL migration script String dbtype = DatabaseUtils.getDbType(connection); String dataMigrateSQL; - String sqlMigrationPath = "org/dspace/storage/rdbms/sqlmigration/workflow/" + dbtype +"/"; + String sqlMigrationPath = "org/dspace/storage/rdbms/sqlmigration/workflow/" + dbtype + "/"; // Now, check if the XMLWorkflow table (cwf_workflowitem) already exists in this database // If XMLWorkflow Table does NOT exist in this database, then lets do the migration! - // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql scripts - if (DatabaseUtils.tableExists(connection, "cwf_workflowitem")) - { + // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql + // scripts + if (DatabaseUtils.tableExists(connection, "cwf_workflowitem")) { return; - }else{ + } else { //Migrate the basic workflow // Get the contents of our data migration script, based on path & DB type dataMigrateSQL = new ClassPathResource(sqlMigrationPath + "basicWorkflow" + "/V5.7_2017.05.05__DS-3431.sql", - getClass().getClassLoader()).loadAsString(Constants.DEFAULT_ENCODING); + getClass().getClassLoader()) + .loadAsString(Constants.DEFAULT_ENCODING); } // Actually execute the Data migration SQL diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2015_03_06__DS_2701_Dso_Uuid_Migration.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2015_03_06__DS_2701_Dso_Uuid_Migration.java index e491d18f81..98ac8752be 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2015_03_06__DS_2701_Dso_Uuid_Migration.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2015_03_06__DS_2701_Dso_Uuid_Migration.java @@ -7,11 +7,11 @@ */ package org.dspace.storage.rdbms.migration; +import java.sql.Connection; + import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; -import java.sql.Connection; - /** * Migration class that will drop the public key for the dspace objects, the integer based key will be moved to a UUID * diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2015_08_31__DS_2701_Hibernate_Workflow_Migration.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2015_08_31__DS_2701_Hibernate_Workflow_Migration.java index ad07319afb..62f4b126ba 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2015_08_31__DS_2701_Hibernate_Workflow_Migration.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2015_08_31__DS_2701_Hibernate_Workflow_Migration.java @@ -7,47 +7,49 @@ */ package org.dspace.storage.rdbms.migration; +import java.sql.Connection; + import org.dspace.core.Constants; import org.dspace.storage.rdbms.DatabaseUtils; import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; import org.flywaydb.core.internal.util.scanner.classpath.ClassPathResource; -import java.sql.Connection; - /** * User: kevin (kevin at atmire.com) * Date: 1/09/15 * Time: 12:08 */ -public class V6_0_2015_08_31__DS_2701_Hibernate_Workflow_Migration implements JdbcMigration, MigrationChecksumProvider -{ +public class V6_0_2015_08_31__DS_2701_Hibernate_Workflow_Migration implements JdbcMigration, MigrationChecksumProvider { // Size of migration script run Integer migration_file_size = -1; @Override - public void migrate(Connection connection) throws Exception - { + public void migrate(Connection connection) throws Exception { // Based on type of DB, get path to SQL migration script String dbtype = DatabaseUtils.getDbType(connection); String dataMigrateSQL; - String sqlMigrationPath = "org/dspace/storage/rdbms/sqlmigration/workflow/" + dbtype +"/"; + String sqlMigrationPath = "org/dspace/storage/rdbms/sqlmigration/workflow/" + dbtype + "/"; // Now, check if the XMLWorkflow table (cwf_workflowitem) already exists in this database // If XMLWorkflow Table does NOT exist in this database, then lets do the migration! - // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql scripts - if (DatabaseUtils.tableExists(connection, "cwf_workflowitem")) - { + // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql + // scripts + if (DatabaseUtils.tableExists(connection, "cwf_workflowitem")) { // Get the contents of our data migration script, based on path & DB type - dataMigrateSQL = new ClassPathResource(sqlMigrationPath + "xmlworkflow"+ - "/V6.0_2015.08.11__DS-2701_Xml_Workflow_Migration.sql", getClass().getClassLoader()).loadAsString(Constants.DEFAULT_ENCODING); - }else{ + dataMigrateSQL = new ClassPathResource(sqlMigrationPath + "xmlworkflow" + + "/V6.0_2015.08.11__DS-2701_Xml_Workflow_Migration.sql", + getClass().getClassLoader()) + .loadAsString(Constants.DEFAULT_ENCODING); + } else { //Migrate the basic workflow - // Get the contents of our data migration script, based on path & DB type - dataMigrateSQL = new ClassPathResource(sqlMigrationPath + "basicWorkflow"+ - "/V6.0_2015.08.11__DS-2701_Basic_Workflow_Migration.sql", getClass().getClassLoader()).loadAsString(Constants.DEFAULT_ENCODING); + // Get the contents of our data migration script, based on path & DB type + dataMigrateSQL = new ClassPathResource(sqlMigrationPath + "basicWorkflow" + + "/V6.0_2015.08.11__DS-2701_Basic_Workflow_Migration.sql", + getClass().getClassLoader()) + .loadAsString(Constants.DEFAULT_ENCODING); } // Actually execute the Data migration SQL diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables.java index 16e2f567fd..366fc76b89 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables.java @@ -9,6 +9,7 @@ package org.dspace.storage.rdbms.migration; import java.sql.Connection; import java.sql.SQLException; + import org.apache.log4j.Logger; import org.dspace.browse.BrowseException; import org.dspace.browse.BrowseIndex; @@ -19,51 +20,49 @@ import org.flywaydb.core.api.migration.jdbc.JdbcMigration; /** * This Flyway Java migration deletes any legacy DBMS browse tables found in * the database. See https://jira.duraspace.org/browse/DS-2188. - * + * * @author Tim Donohue */ -public class V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables implements JdbcMigration, MigrationChecksumProvider -{ - /** log4j category */ +public class V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables implements JdbcMigration, MigrationChecksumProvider { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables.class); - + /* The checksum to report for this migration (when successful) */ private int checksum = -1; - + @Override - public void migrate(Connection connection) throws Exception, SQLException - { + public void migrate(Connection connection) throws Exception, SQLException { removeDBMSBrowseTables(connection); } - /** - * Delete all the existing DBMS browse tables. The DBMS browse system - * has been replaced by Discovery / Solr. - *

    - * NOTE: This method was based on the "clearDatabase()" method of the old - * DSpace 5.x `IndexBrowse` class. As such, it is essentially performing - * the same as the old "./dspace index-db-browse -f -d" command. But, it - * also removes old, obsolete item_count tables and communities2item table - * - * @param connection Database Connection - * @throws BrowseException - */ + /** + * Delete all the existing DBMS browse tables. The DBMS browse system + * has been replaced by Discovery / Solr. + *

    + * NOTE: This method was based on the "clearDatabase()" method of the old + * DSpace 5.x `IndexBrowse` class. As such, it is essentially performing + * the same as the old "./dspace index-db-browse -f -d" command. But, it + * also removes old, obsolete item_count tables and communities2item table + * + * @param connection Database Connection + * @throws BrowseException + */ private void removeDBMSBrowseTables(Connection connection) - throws BrowseException - { + throws BrowseException { // Browse index tables start at index=1 int i = 1; - + // Keep looping (incrementing our index by 1) until we've hit three index // tables that have not been found. // We don't actually know how many index tables will be in each database, - // and there are no guarrantees it'll match the highest index of the site's + // and there are no guarrantees it'll match the highest index of the site's // existing "webui.browse.index.#" settings. // Since that's the case, we'll just keep searching for index tables, // until we encounter a total of three that are not found. int countTablesNotFound = 0; - while(countTablesNotFound < 3) - { + while (countTablesNotFound < 3) { String tableName = BrowseIndex.getTableName(i, false, false, false, false); String distinctTableName = BrowseIndex.getTableName(i, false, false, true, false); String distinctMapName = BrowseIndex.getTableName(i, false, false, false, true); @@ -78,52 +77,48 @@ public class V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables implements JdbcM String distinctColViewName = BrowseIndex.getTableName(i, false, true, false, true); String distinctComViewName = BrowseIndex.getTableName(i, true, false, false, true); - if(DatabaseUtils.tableExists(connection, tableName, false)) - { + if (DatabaseUtils.tableExists(connection, tableName, false)) { // Found an index table. Deleting it & everything related to it // Drop table dropTable(connection, tableName); - + // Drop Sequence dropSequence(connection, sequence); - + // Drop Collection View dropView(connection, colViewName); - + // Drop Community View - dropView(connection, comViewName); + dropView(connection, comViewName); } - + // Check for existence of "distinct table" - if (DatabaseUtils.tableExists(connection, distinctTableName, false)) - { + if (DatabaseUtils.tableExists(connection, distinctTableName, false)) { // Found. Need to delete all its resources // Drop table dropTable(connection, distinctTableName); - + // Drop Map table dropTable(connection, distinctMapName); - + // Drop sequence dropSequence(connection, distinctSequence); - + // Drop Map Sequence dropSequence(connection, mapSequence); - + // Drop Collection View dropView(connection, distinctColViewName); - + // Drop Community View dropView(connection, distinctComViewName); - } - else - { + } else { // increment our "not found" count countTablesNotFound++; } - + // increment our table index i++; } @@ -132,111 +127,107 @@ public class V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables implements JdbcM dropItemTables(connection, BrowseIndex.getItemBrowseIndex()); dropItemTables(connection, BrowseIndex.getWithdrawnBrowseIndex()); dropItemTables(connection, BrowseIndex.getPrivateBrowseIndex()); - + // Check for existence of "communities2item" table // This is no longer used, see DS-2578 - if (DatabaseUtils.tableExists(connection, "communities2item", false)) - { + if (DatabaseUtils.tableExists(connection, "communities2item", false)) { dropTable(connection, "communities2item"); dropSequence(connection, "communities2item_seq"); } - + // Check for existence of "community_item_count" table // This is no longer used, as item counts are now in Solr - if (DatabaseUtils.tableExists(connection, "community_item_count", false)) - { + if (DatabaseUtils.tableExists(connection, "community_item_count", false)) { dropTable(connection, "community_item_count"); } - + // Check for existence of "collection_item_count" table // This is no longer used, as item counts are now in Solr - if (DatabaseUtils.tableExists(connection, "collection_item_count", false)) - { + if (DatabaseUtils.tableExists(connection, "collection_item_count", false)) { dropTable(connection, "collection_item_count"); } - + // NOTE: the old "community2item" View was already dropped by // V6.0_2015.03.07__DS-2701_Hibernate_migration.sql } - - + + /** * Drop a table by name. If an error occurs, just log a warning, as its possible * some sites may have deleted the table manually. - * + * * @param connection Database Connection - * @param tableName Table Name + * @param tableName Table Name */ - private void dropTable(Connection connection, String tableName) - { - try - { + private void dropTable(Connection connection, String tableName) { + try { // Drop table & increment our flyway checksum this.checksum += MigrationUtils.dropDBTable(connection, tableName); - } - catch(SQLException sqe){ + } catch (SQLException sqe) { // Ignore any errors (don't cause migration to fail), but log as warning - log.warn("Database Table '" + tableName + " could not be dropped during migration. This warning may be ignored, if this table was already deleted.", sqe); + log.warn( + "Database Table '" + tableName + " could not be dropped during migration. This warning may be " + + "ignored, if this table was already deleted.", + sqe); } } - + /** * Drop a sequence by name. If an error occurs, just log a warning, as its possible * some sites may have deleted it manually. - * - * @param connection Database Connection + * + * @param connection Database Connection * @param sequenceName Sequence Name */ - private void dropSequence(Connection connection, String sequenceName) - { - try - { + private void dropSequence(Connection connection, String sequenceName) { + try { // Drop sequence & increment our flyway checksum - this.checksum += MigrationUtils.dropDBSequence(connection, sequenceName); - } - catch(SQLException sqe){ + this.checksum += MigrationUtils.dropDBSequence(connection, sequenceName); + } catch (SQLException sqe) { // Ignore any errors (don't cause migration to fail), but log as warning - log.warn("Database Sequence '" + sequenceName + " could not be dropped during migration. This warning may be ignored, if this sequence was already deleted.", sqe); + log.warn( + "Database Sequence '" + sequenceName + " could not be dropped during migration. This warning may be " + + "ignored, if this sequence was already deleted.", + sqe); } } - + /** * Drop a view by name. If an error occurs, just log a warning, as its possible * some sites may have deleted the view manually. - * + * * @param connection Database Connection - * @param viewName View Name + * @param viewName View Name */ - private void dropView(Connection connection, String viewName) - { - try - { + private void dropView(Connection connection, String viewName) { + try { // Drop view & increment our flyway checksum - this.checksum += MigrationUtils.dropDBView(connection, viewName); - } - catch(SQLException sqe){ + this.checksum += MigrationUtils.dropDBView(connection, viewName); + } catch (SQLException sqe) { // Ignore any errors (don't cause migration to fail), but log as warning - log.warn("Database View '" + viewName + " could not be dropped during migration. This warning may be ignored, if this view was already deleted.", sqe); + log.warn( + "Database View '" + viewName + " could not be dropped during migration. This warning may be ignored, " + + "if this view was already deleted.", + sqe); } } - + /** * drop the tables and related database entries for the internal * 'item' tables + * * @param connection Database Connection - * @param bix BrowseIndex + * @param bix BrowseIndex * @throws BrowseException */ - private void dropItemTables(Connection connection, BrowseIndex bix) throws BrowseException - { - if(DatabaseUtils.tableExists(connection, bix.getTableName())) - { + private void dropItemTables(Connection connection, BrowseIndex bix) throws BrowseException { + if (DatabaseUtils.tableExists(connection, bix.getTableName())) { String tableName = bix.getTableName(); String sequence = bix.getSequenceName(false, false); - + // Drop table dropTable(connection, tableName); - + // Drop sequence dropSequence(connection, sequence); @@ -244,15 +235,15 @@ public class V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables implements JdbcM // they may exist and need to be removed String colViewName = bix.getTableName(false, true, false, false); String comViewName = bix.getTableName(true, false, false, false); - + // Drop Collection View dropView(connection, colViewName); - + // Drop Community View dropView(connection, comViewName); } } - + @Override public Integer getChecksum() { return checksum; diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_1_2017_01_03__DS_3431_Add_Policies_for_BasicWorkflow.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_1_2017_01_03__DS_3431_Add_Policies_for_BasicWorkflow.java index 728cef10cb..51e401b400 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_1_2017_01_03__DS_3431_Add_Policies_for_BasicWorkflow.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/migration/V6_1_2017_01_03__DS_3431_Add_Policies_for_BasicWorkflow.java @@ -7,41 +7,40 @@ */ package org.dspace.storage.rdbms.migration; +import java.sql.Connection; + import org.dspace.core.Constants; import org.dspace.storage.rdbms.DatabaseUtils; import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; import org.flywaydb.core.internal.util.scanner.classpath.ClassPathResource; -import java.sql.Connection; - public class V6_1_2017_01_03__DS_3431_Add_Policies_for_BasicWorkflow - implements JdbcMigration, MigrationChecksumProvider -{ + implements JdbcMigration, MigrationChecksumProvider { // Size of migration script run Integer migration_file_size = -1; @Override - public void migrate(Connection connection) throws Exception - { + public void migrate(Connection connection) throws Exception { // Based on type of DB, get path to SQL migration script String dbtype = DatabaseUtils.getDbType(connection); String dataMigrateSQL; - String sqlMigrationPath = "org/dspace/storage/rdbms/sqlmigration/workflow/" + dbtype +"/"; + String sqlMigrationPath = "org/dspace/storage/rdbms/sqlmigration/workflow/" + dbtype + "/"; // Now, check if the XMLWorkflow table (cwf_workflowitem) already exists in this database // If XMLWorkflow Table does NOT exist in this database, then lets do the migration! - // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql scripts - if (DatabaseUtils.tableExists(connection, "cwf_workflowitem")) - { + // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql + // scripts + if (DatabaseUtils.tableExists(connection, "cwf_workflowitem")) { return; - }else{ + } else { //Migrate the basic workflow - // Get the contents of our data migration script, based on path & DB type + // Get the contents of our data migration script, based on path & DB type dataMigrateSQL = new ClassPathResource(sqlMigrationPath + "basicWorkflow" + "/V6.1_2017.01.03__DS-3431.sql", - getClass().getClassLoader()).loadAsString(Constants.DEFAULT_ENCODING); + getClass().getClassLoader()) + .loadAsString(Constants.DEFAULT_ENCODING); } // Actually execute the Data migration SQL diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/xmlworkflow/V5_0_2014_11_04__Enable_XMLWorkflow_Migration.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/xmlworkflow/V5_0_2014_11_04__Enable_XMLWorkflow_Migration.java index 74da8f34c6..f3fe4418c6 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/xmlworkflow/V5_0_2014_11_04__Enable_XMLWorkflow_Migration.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/xmlworkflow/V5_0_2014_11_04__Enable_XMLWorkflow_Migration.java @@ -10,6 +10,7 @@ package org.dspace.storage.rdbms.xmlworkflow; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; + import org.dspace.core.Constants; import org.dspace.storage.rdbms.DatabaseUtils; import org.dspace.workflow.factory.WorkflowServiceFactory; @@ -33,62 +34,63 @@ import org.slf4j.LoggerFactory; * http://flywaydb.org/documentation/migration/java.html *

    * It can upgrade a 5.0 version of DSpace to use the XMLWorkflow. - * + * * @author Tim Donohue */ public class V5_0_2014_11_04__Enable_XMLWorkflow_Migration - implements JdbcMigration, MigrationChecksumProvider -{ - /** logging category */ + implements JdbcMigration, MigrationChecksumProvider { + /** + * logging category + */ private static final Logger log = LoggerFactory.getLogger(V5_0_2014_11_04__Enable_XMLWorkflow_Migration.class); - + // Size of migration script run Integer migration_file_size = -1; - + /** * Actually migrate the existing database - * @param connection - * SQL Connection object - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * + * @param connection SQL Connection object + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. */ @Override public void migrate(Connection connection) - throws IOException, SQLException - { - // Make sure XML Workflow is enabled, shouldn't even be needed since this class is only loaded if the service is enabled. + throws IOException, SQLException { + // Make sure XML Workflow is enabled, shouldn't even be needed since this class is only loaded if the service + // is enabled. if (WorkflowServiceFactory.getInstance().getWorkflowService() instanceof XmlWorkflowService - // If your database was upgraded to DSpace 6 prior to enabling XML Workflow, we MUST skip this 5.x migration, as it is incompatible - // with a 6.x database. In that scenario the corresponding 6.x XML Workflow migration will create necessary tables. - && DatabaseUtils.getCurrentFlywayDSpaceState(connection) < 6) - { + // If your database was upgraded to DSpace 6 prior to enabling XML Workflow, we MUST skip this 5.x + // migration, as it is incompatible + // with a 6.x database. In that scenario the corresponding 6.x XML Workflow migration will create + // necessary tables. + && DatabaseUtils.getCurrentFlywayDSpaceState(connection) < 6) { // Now, check if the XMLWorkflow table (cwf_workflowitem) already exists in this database // If XMLWorkflow Table does NOT exist in this database, then lets do the migration! - // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql scripts - if (!DatabaseUtils.tableExists(connection, "cwf_workflowitem")) - { + // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql + // scripts + if (!DatabaseUtils.tableExists(connection, "cwf_workflowitem")) { String dbtype = connection.getMetaData().getDatabaseProductName(); String dbFileLocation = null; - if(dbtype.toLowerCase().contains("postgres")) - { + if (dbtype.toLowerCase().contains("postgres")) { dbFileLocation = "postgres"; - }else - if(dbtype.toLowerCase().contains("oracle")){ + } else if (dbtype.toLowerCase().contains("oracle")) { dbFileLocation = "oracle"; } - // Determine path of this migration class (as the SQL scripts + // Determine path of this migration class (as the SQL scripts // we will run are based on this path under /src/main/resources) - String packagePath = V5_0_2014_11_04__Enable_XMLWorkflow_Migration.class.getPackage().getName().replace(".", "/"); + String packagePath = V5_0_2014_11_04__Enable_XMLWorkflow_Migration.class.getPackage().getName() + .replace(".", "/"); // Get the contents of our DB Schema migration script, based on path & DB type // (e.g. /src/main/resources/[path-to-this-class]/postgres/xml_workflow_migration.sql) String dbMigrateSQL = new ClassPathResource(packagePath + "/" + - dbFileLocation + - "/xml_workflow_migration.sql", getClass().getClassLoader()).loadAsString(Constants.DEFAULT_ENCODING); + dbFileLocation + + "/xml_workflow_migration.sql", + getClass().getClassLoader()) + .loadAsString(Constants.DEFAULT_ENCODING); // Actually execute the Database schema migration SQL // This will create the necessary tables for the XMLWorkflow feature @@ -97,8 +99,10 @@ public class V5_0_2014_11_04__Enable_XMLWorkflow_Migration // Get the contents of our data migration script, based on path & DB type // (e.g. /src/main/resources/[path-to-this-class]/postgres/data_workflow_migration.sql) String dataMigrateSQL = new ClassPathResource(packagePath + "/" + - dbFileLocation + - "/data_workflow_migration.sql", getClass().getClassLoader()).loadAsString(Constants.DEFAULT_ENCODING); + dbFileLocation + + "/data_workflow_migration.sql", + getClass().getClassLoader()) + .loadAsString(Constants.DEFAULT_ENCODING); // Actually execute the Data migration SQL // This will migrate all existing traditional workflows to the new XMLWorkflow system & tables @@ -109,15 +113,15 @@ public class V5_0_2014_11_04__Enable_XMLWorkflow_Migration } } } - + /** * Return the checksum to be associated with this Migration * in the Flyway database table (schema_version). + * * @return checksum as an Integer */ @Override - public Integer getChecksum() - { + public Integer getChecksum() { return migration_file_size; } } diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/xmlworkflow/V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/xmlworkflow/V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration.java index 6cc2fefec6..684f4d6b5c 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/xmlworkflow/V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/xmlworkflow/V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration.java @@ -7,6 +7,8 @@ */ package org.dspace.storage.rdbms.xmlworkflow; +import java.sql.Connection; + import org.dspace.core.Constants; import org.dspace.storage.rdbms.DatabaseUtils; import org.dspace.workflow.factory.WorkflowServiceFactory; @@ -15,8 +17,6 @@ import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; import org.flywaydb.core.internal.util.scanner.classpath.ClassPathResource; -import java.sql.Connection; - /** * This class automatically migrates your DSpace Database to use the * XML-based Configurable Workflow system whenever it is enabled. @@ -29,47 +29,47 @@ import java.sql.Connection; * http://flywaydb.org/documentation/migration/java.html *

    * It can upgrade a 6.0 version of DSpace to use the XMLWorkflow. - * + * * User: kevin (kevin at atmire.com) * Date: 1/09/15 * Time: 11:34 */ -public class V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration implements JdbcMigration, MigrationChecksumProvider -{ +public class V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration implements JdbcMigration, MigrationChecksumProvider { // Size of migration script run protected Integer migration_file_size = -1; @Override public void migrate(Connection connection) throws Exception { - // Make sure XML Workflow is enabled, shouldn't even be needed since this class is only loaded if the service is enabled. - if (WorkflowServiceFactory.getInstance().getWorkflowService() instanceof XmlWorkflowService) - { + // Make sure XML Workflow is enabled, shouldn't even be needed since this class is only loaded if the service + // is enabled. + if (WorkflowServiceFactory.getInstance().getWorkflowService() instanceof XmlWorkflowService) { // Now, check if the XMLWorkflow table (cwf_workflowitem) already exists in this database // If XMLWorkflow Table does NOT exist in this database, then lets do the migration! - // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql scripts - if (!DatabaseUtils.tableExists(connection, "cwf_workflowitem")) - { + // If XMLWorkflow Table ALREADY exists, then this migration is a noop, we assume you manually ran the sql + // scripts + if (!DatabaseUtils.tableExists(connection, "cwf_workflowitem")) { String dbtype = connection.getMetaData().getDatabaseProductName(); String dbFileLocation = null; - if(dbtype.toLowerCase().contains("postgres")) - { + if (dbtype.toLowerCase().contains("postgres")) { dbFileLocation = "postgres"; - }else - if(dbtype.toLowerCase().contains("oracle")){ + } else if (dbtype.toLowerCase().contains("oracle")) { dbFileLocation = "oracle"; } // Determine path of this migration class (as the SQL scripts // we will run are based on this path under /src/main/resources) - String packagePath = V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration.class.getPackage().getName().replace(".", "/"); + String packagePath = V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration.class.getPackage().getName() + .replace(".", "/"); // Get the contents of our DB Schema migration script, based on path & DB type // (e.g. /src/main/resources/[path-to-this-class]/postgres/xml_workflow_migration.sql) String dbMigrateSQL = new ClassPathResource(packagePath + "/" + - dbFileLocation + - "/v6.0__DS-2701_xml_workflow_migration.sql", getClass().getClassLoader()).loadAsString(Constants.DEFAULT_ENCODING); + dbFileLocation + + "/v6.0__DS-2701_xml_workflow_migration.sql", + getClass().getClassLoader()) + .loadAsString(Constants.DEFAULT_ENCODING); // Actually execute the Database schema migration SQL // This will create the necessary tables for the XMLWorkflow feature @@ -78,8 +78,10 @@ public class V6_0_2015_09_01__DS_2701_Enable_XMLWorkflow_Migration implements Jd // Get the contents of our data migration script, based on path & DB type // (e.g. /src/main/resources/[path-to-this-class]/postgres/data_workflow_migration.sql) String dataMigrateSQL = new ClassPathResource(packagePath + "/" + - dbFileLocation + - "/v6.0__DS-2701_data_workflow_migration.sql", getClass().getClassLoader()).loadAsString(Constants.DEFAULT_ENCODING); + dbFileLocation + + "/v6.0__DS-2701_data_workflow_migration.sql", + getClass().getClassLoader()) + .loadAsString(Constants.DEFAULT_ENCODING); // Actually execute the Data migration SQL // This will migrate all existing traditional workflows to the new XMLWorkflow system & tables diff --git a/dspace-api/src/main/java/org/dspace/submit/AbstractProcessingStep.java b/dspace-api/src/main/java/org/dspace/submit/AbstractProcessingStep.java index e155768070..17bd6423c0 100644 --- a/dspace-api/src/main/java/org/dspace/submit/AbstractProcessingStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/AbstractProcessingStep.java @@ -7,384 +7,42 @@ */ package org.dspace.submit; -import java.io.IOException; -import java.sql.SQLException; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.authorize.AuthorizeException; +import org.dspace.app.itemimport.BTEBatchImportService; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.InProgressSubmission; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +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.ItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; /** - * Abstract processing class for DSpace Submission Steps. This defines the base - * methods which are required for any Step processing class. - *

    - * This abstract class defines the base methods which are used by both the - * Manakin XML UI and the JSP UI to perform submission step processing. - *

    - * This includes the following methods: - *

      - *
    • doProcessing() method - called to perform any step processing
    • - *
    • getErrorFields() method - called to determine the fields which errored - * out during processing
    • - *
    • getErrorMessage() method - called to determine any error message - * returned after processing
    • - *
    - *

    - * If you are using the JSP UI (with the SubmissionController servlet) you - * should extend the org.dspace.submit.SubmissionStep class, which defines - * additional methods used to maintain the context of the submission within a - * JSP environment! - * - * @see org.dspace.app.webui.submit.JSPStepManager - * @see org.dspace.app.webui.servlet.SubmissionController - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * - * @author Tim Donohue - * @version $Revision$ + * Abstract processing class for DSpace Submission Steps. This defines the base methods which are required for any Step + * processing class. */ -public abstract class AbstractProcessingStep -{ - /*************************************************************************** - * Constant - Name of the "<-Previous" button - **************************************************************************/ - public static final String PREVIOUS_BUTTON = "submit_prev"; - - /*************************************************************************** - * Constant - Name of the "Next->" button - **************************************************************************/ - public static final String NEXT_BUTTON = "submit_next"; - - /*************************************************************************** - * Constant - Name of the "Select" list - **************************************************************************/ - public static final String SELECT_CHANGE = "submit_change"; - - /*************************************************************************** - * Constant - Name of the "Cancel/Save" button - **************************************************************************/ - public static final String CANCEL_BUTTON = "submit_cancel"; - - /*************************************************************************** - * Constant - Prefix of all buttons in the Progress Bar - **************************************************************************/ - public static final String PROGRESS_BAR_PREFIX = "submit_jump_"; - - /*************************************************************************** - * Flag which specifies that the LAST PAGE of a step has been reached. This - * flag is used when a Workflow Item is rejected (and returned to the - * workspace) to specify that the LAST PAGE of the LAST STEP has already - * been reached - **************************************************************************/ - public static final int LAST_PAGE_REACHED = Integer.MAX_VALUE; - - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - **************************************************************************/ - public static final int STATUS_COMPLETE = 0; - - /** Maps each status/error flag to a textual, human understandable message * */ - private Map errorMessages = null; - - private static final String ERROR_FIELDS_ATTRIBUTE = "dspace.submit.error_fields"; - +public abstract class AbstractProcessingStep { protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); + protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the doPostProcessing() method. - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * The relevant DSpace Context. - * @param request - * Servlet's HTTP request object. - * @param response - * Servlet's HTTP response object. - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - public abstract int doProcessing(Context context, - HttpServletRequest request, HttpServletResponse response, - SubmissionInfo subInfo) throws ServletException, IOException, - SQLException, AuthorizeException; + protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); + protected BTEBatchImportService bteBatchImportService = DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("org.dspace.app.itemimport" + ".BTEBatchImportService", BTEBatchImportService.class); - /** - * Return a list of all UI fields which had errors that occurred during the - * step processing. This list is for usage in generating the appropriate - * error message(s) in the UI. - *

    - * The list of fields which had errors should be set by the AbstractProcessingStep's - * doProcessing() method, so that it can be accessed later by whatever UI is - * generated. - * - * @param request - * current servlet request object - * @return List of error fields (as Strings) - */ - public static final List getErrorFields(HttpServletRequest request) - { - return (List) request.getAttribute(ERROR_FIELDS_ATTRIBUTE); - } - - /** - * Sets the list of all UI fields which had errors that occurred during the - * step processing. This list is for usage in generating the appropriate - * error message(s) in the UI. - *

    - * The list of fields which had errors should be set by the AbstractProcessingStep's - * doProcessing() method, so that it can be accessed later by whatever UI is - * generated. - * - * @param request - * current servlet request object - * @param errorFields - * List of all fields (as Strings) which had errors - */ - private static final void setErrorFields(HttpServletRequest request, List errorFields) - { - if(errorFields==null) - { - request.removeAttribute(ERROR_FIELDS_ATTRIBUTE); - } - else - { - request.setAttribute(ERROR_FIELDS_ATTRIBUTE, errorFields); - } - } + public abstract void doPreProcessing(Context context, InProgressSubmission wsi); - /** - * Add a single UI field to the list of all error fields (which can - * later be retrieved using getErrorFields()) - *

    - * The list of fields which had errors should be set by the AbstractProcessingStep's - * doProcessing() method, so that it can be accessed later by whatever UI is - * generated. - * - * @param request - * Servlet's HTTP request object. - * @param fieldName - * the name of the field which had an error - */ - protected static final void addErrorField(HttpServletRequest request, String fieldName) - { - //get current list - List errorFields = getErrorFields(request); - - if (errorFields == null) - { - errorFields = new ArrayList(); - } - - //add this field - errorFields.add(fieldName); - - //save updated list - setErrorFields(request, errorFields); - } - - /** - * Clears the list of all fields that errored out during the previous step's - * processing. - * - * @param request - * Servlet's HTTP request object. - * - */ - protected static final void clearErrorFields(HttpServletRequest request) - { - //get current list - List errorFields = getErrorFields(request); - - if (errorFields != null) - { - setErrorFields(request, null); - } - } - - /** - * Return the text of an error message based on the passed in error flag. - * These error messages are used for non-interactive steps (so that they can - * log something more specific than just an error flag) - *

    - * Since each step can define its own error messages and flags, this method - * depends on all the error messages being initialized by using the - * "addErrorMessage()" method within the constructor for the step class! - * - * @param errorFlag - * The error flag defined in this step which represents an error - * message. - * @return String which contains the text of the error message, or null if - * error message not found - */ - public final String getErrorMessage(int errorFlag) - { - if (this.errorMessages == null || this.errorMessages.size() == 0) - { - return null; - } - else - { - return this.errorMessages.get(Integer.valueOf(errorFlag)); - } - } - - /** - * Add an error message to the internal map for this step. - *

    - * This method associates a specific error message with an error flag - * defined in this step. - *

    - * This is extremely useful to define the error message which will be logged - * for a non-interactive step. - * - * @param errorFlag - * the status value indicating the type of error - * @param errorMessage - * text of the message to be added - */ - protected final void addErrorMessage(int errorFlag, String errorMessage) - { - if (this.errorMessages == null) - { - this.errorMessages = new HashMap(); - } - - errorMessages.put(Integer.valueOf(errorFlag), errorMessage); - } - - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used by the SubmissionController to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * Servlet's HTTP request object. - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - */ - public abstract int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException; - - /** - * Find out which page a user is currently viewing - * - * @param request - * Servlet's HTTP request object. - * - * @return current page - */ - public static final int getCurrentPage(HttpServletRequest request) - { - int pageNum = -1; - - // try to retrieve cached page from request attribute - Integer currentPage = (Integer) request.getAttribute("submission.page"); - - if (currentPage == null) - { - // try and get it as a 'page' parameter - String val = request.getParameter("page"); - - try - { - pageNum = Integer.parseInt(val.trim()); - } - catch (Exception e) - { - // Problem with parameter - pageNum = -1; - } - - // if couldn't find page in request parameter - if (pageNum < 0) - { - // default to page #1, since no other optionsc - pageNum = 1; - - setCurrentPage(request, pageNum); - } - else - { - // save to request attribute - setCurrentPage(request, pageNum); - } - } - else - { - pageNum = currentPage.intValue(); - } - - return pageNum; - } - - /** - * Set which page a user is currently viewing - * - * @param request - * Servlet's HTTP request object. - * @param pageNumber - * new current page - */ - public static final void setCurrentPage(HttpServletRequest request, - int pageNumber) - { - // set info to request - request.setAttribute("submission.page", Integer.valueOf(pageNumber)); - } + public abstract void doPostProcessing(Context context, InProgressSubmission wsi); } diff --git a/dspace-api/src/main/java/org/dspace/submit/extraction/MetadataExtractor.java b/dspace-api/src/main/java/org/dspace/submit/extraction/MetadataExtractor.java new file mode 100644 index 0000000000..0961a49d92 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/extraction/MetadataExtractor.java @@ -0,0 +1,54 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.submit.extraction; + +import java.util.List; + +import gr.ekt.bte.dataloader.FileDataLoader; +import org.dspace.services.ConfigurationService; + +/** + * Configuration bean to associate a BTE FileDataLoader with a specific list of format identified by the file + * extensions. See config/spring/api/metadata-extractor.xml + * + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + * @author Andrea Bollini (andrea.bollini at 4science.it) + */ +public class MetadataExtractor { + + private List extensions; + + private FileDataLoader dataLoader; + + private ConfigurationService configurationService; + + public List getExtensions() { + return extensions; + } + + public void setExtensions(List mime) { + this.extensions = mime; + } + + public FileDataLoader getDataLoader() { + return dataLoader; + } + + public void setDataLoader(FileDataLoader dataLoader) { + this.dataLoader = dataLoader; + } + + public ConfigurationService getConfigurationService() { + return configurationService; + } + + public void setConfigurationService(ConfigurationService configurationService) { + this.configurationService = configurationService; + } + +} diff --git a/dspace-api/src/main/java/org/dspace/submit/listener/MetadataListener.java b/dspace-api/src/main/java/org/dspace/submit/listener/MetadataListener.java new file mode 100644 index 0000000000..df3c78919e --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/listener/MetadataListener.java @@ -0,0 +1,61 @@ +/** + * 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.submit.listener; + +import java.util.Map; + +import gr.ekt.bte.core.DataLoader; +import org.dspace.services.ConfigurationService; + +/** + * Configuration bean to map metadata to identifiers (i.e dc.identifier.doi -> doi, dc.identifier.isbn -> isbn) and + * alias to BTE Data Loader. See config/spring/api/step-processing.xml + * + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + * @author Andrea Bollini (andrea.bollini at 4science.it) + * + */ +public class MetadataListener { + + /** + * Metadata to identifier map + */ + private Map metadata; + + private ConfigurationService configurationService; + + /** + * Alias to data loader map + */ + private Map dataloadersMap; + + public ConfigurationService getConfigurationService() { + return configurationService; + } + + public void setConfigurationService(ConfigurationService configurationService) { + this.configurationService = configurationService; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public Map getDataloadersMap() { + return dataloadersMap; + } + + public void setDataloadersMap(Map dataloadersMap) { + this.dataloadersMap = dataloadersMap; + } + +} diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivFileDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivFileDataLoader.java index 2a08ace18b..3711842fde 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivFileDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivFileDataLoader.java @@ -15,73 +15,64 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.dspace.app.util.XMLUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - import gr.ekt.bte.core.DataLoadingSpec; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.RecordSet; import gr.ekt.bte.core.Value; import gr.ekt.bte.dataloader.FileDataLoader; import gr.ekt.bte.exceptions.MalformedSourceException; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.dspace.app.util.XMLUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; /** * @author Andrea Bollini * @author Kostas Stamatis * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis - * */ -public class ArXivFileDataLoader extends FileDataLoader -{ +public class ArXivFileDataLoader extends FileDataLoader { private static Logger log = Logger.getLogger(ArXivFileDataLoader.class); Map fieldMap; // mapping between service fields and local - // intermediate fields + // intermediate fields /** * Empty constructor */ - public ArXivFileDataLoader() - { + public ArXivFileDataLoader() { } /** - * @param filename - * Name of file to load ArXiv data from. + * @param filename Name of file to load ArXiv data from. */ - public ArXivFileDataLoader(String filename) - { + public ArXivFileDataLoader(String filename) { super(filename); } /* * {@see gr.ekt.bte.core.DataLoader#getRecords()} * - * @throws MalformedSourceException + * @throws MalformedSourceException */ @Override - public RecordSet getRecords() throws MalformedSourceException - { + public RecordSet getRecords() throws MalformedSourceException { RecordSet recordSet = new RecordSet(); - try - { + try { InputStream inputStream = new FileInputStream(new File(filename)); DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -92,29 +83,19 @@ public class ArXivFileDataLoader extends FileDataLoader Element xmlRoot = inDoc.getDocumentElement(); List dataRoots = XMLUtils.getElementList(xmlRoot, "entry"); - for (Element dataRoot : dataRoots) - { + for (Element dataRoot : dataRoots) { Record record = ArxivUtils.convertArxixDomToRecord(dataRoot); - if (record != null) - { + if (record != null) { recordSet.addRecord(convertFields(record)); } } - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { log.error(e.getMessage(), e); - } - catch (ParserConfigurationException e) - { + } catch (ParserConfigurationException e) { log.error(e.getMessage(), e); - } - catch (SAXException e) - { + } catch (SAXException e) { log.error(e.getMessage(), e); - } - catch (IOException e) - { + } catch (IOException e) { log.error(e.getMessage(), e); } @@ -123,42 +104,33 @@ public class ArXivFileDataLoader extends FileDataLoader /* * (non-Javadoc) - * + * * @see * gr.ekt.bte.core.DataLoader#getRecords(gr.ekt.bte.core.DataLoadingSpec) */ @Override public RecordSet getRecords(DataLoadingSpec spec) - throws MalformedSourceException - { - if (spec.getOffset() > 0) - { + throws MalformedSourceException { + if (spec.getOffset() > 0) { return new RecordSet(); } return getRecords(); } - public Record convertFields(Record publication) - { - for (String fieldName : fieldMap.keySet()) - { + public Record convertFields(Record publication) { + for (String fieldName : fieldMap.keySet()) { String md = null; - if (fieldMap != null) - { + if (fieldMap != null) { md = this.fieldMap.get(fieldName); } - if (StringUtils.isBlank(md)) - { + if (StringUtils.isBlank(md)) { continue; - } - else - { + } else { md = md.trim(); } - if (publication.isMutable()) - { + if (publication.isMutable()) { List values = publication.getValues(fieldName); publication.makeMutable().removeField(fieldName); publication.makeMutable().addField(md, values); @@ -168,8 +140,7 @@ public class ArXivFileDataLoader extends FileDataLoader return publication; } - public void setFieldMap(Map fieldMap) - { + public void setFieldMap(Map fieldMap) { this.fieldMap = fieldMap; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivOnlineDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivOnlineDataLoader.java index 2589c83eaa..e477412621 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivOnlineDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivOnlineDataLoader.java @@ -7,16 +7,15 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; - import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.http.HttpException; +import gr.ekt.bte.core.Record; +import org.apache.http.HttpException; import org.dspace.core.Context; /** @@ -25,58 +24,47 @@ import org.dspace.core.Context; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class ArXivOnlineDataLoader extends NetworkSubmissionLookupDataLoader -{ +public class ArXivOnlineDataLoader extends NetworkSubmissionLookupDataLoader { protected ArXivService arXivService = new ArXivService(); protected boolean searchProvider = true; - public void setArXivService(ArXivService arXivService) - { + public void setArXivService(ArXivService arXivService) { this.arXivService = arXivService; } @Override - public List getSupportedIdentifiers() - { - return Arrays.asList(new String[] { ARXIV, DOI }); + public List getSupportedIdentifiers() { + return Arrays.asList(new String[] {ARXIV, DOI}); } - public void setSearchProvider(boolean searchProvider) - { + public void setSearchProvider(boolean searchProvider) { this.searchProvider = searchProvider; } @Override - public boolean isSearchProvider() - { + public boolean isSearchProvider() { return searchProvider; } @Override public List getByIdentifier(Context context, - Map> keys) throws HttpException, IOException - { + Map> keys) throws HttpException, IOException { List results = new ArrayList(); - if (keys != null) - { + if (keys != null) { Set dois = keys.get(DOI); Set arxivids = keys.get(ARXIV); List items = new ArrayList(); - if (dois != null && dois.size() > 0) - { + if (dois != null && dois.size() > 0) { items.addAll(arXivService.getByDOIs(dois)); } - if (arxivids != null && arxivids.size() > 0) - { - for (String arxivid : arxivids) - { + if (arxivids != null && arxivids.size() > 0) { + for (String arxivid : arxivids) { items.add(arXivService.getByArXivIDs(arxivid)); } } - for (Record item : items) - { + for (Record item : items) { results.add(convertFields(item)); } } @@ -85,12 +73,10 @@ public class ArXivOnlineDataLoader extends NetworkSubmissionLookupDataLoader @Override public List search(Context context, String title, String author, - int year) throws HttpException, IOException - { + int year) throws HttpException, IOException { List results = new ArrayList(); List items = arXivService.searchByTerm(title, author, year); - for (Record item : items) - { + for (Record item : items) { results.add(convertFields(item)); } return results; diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivService.java b/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivService.java index 0b97207855..44cd7ca541 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivService.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivService.java @@ -7,17 +7,15 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; - import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Set; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import gr.ekt.bte.core.Record; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpException; import org.apache.http.HttpResponse; @@ -39,8 +37,7 @@ import org.w3c.dom.Element; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class ArXivService -{ +public class ArXivService { private int timeout = 1000; /** @@ -48,16 +45,13 @@ public class ArXivService * * @param timeout milliseconds */ - public void setTimeout(int timeout) - { + public void setTimeout(int timeout) { this.timeout = timeout; } public List getByDOIs(Set dois) throws HttpException, - IOException - { - if (dois != null && dois.size() > 0) - { + IOException { + if (dois != null && dois.size() > 0) { String doisQuery = StringUtils.join(dois.iterator(), " OR "); return search(doisQuery, null, 100); } @@ -65,31 +59,27 @@ public class ArXivService } public List searchByTerm(String title, String author, int year) - throws HttpException, IOException - { + throws HttpException, IOException { StringBuffer query = new StringBuffer(); - if (StringUtils.isNotBlank(title)) - { + if (StringUtils.isNotBlank(title)) { query.append("ti:\"").append(title).append("\""); } - if (StringUtils.isNotBlank(author)) - { + if (StringUtils.isNotBlank(author)) { // [FAU] - if (query.length() > 0) + if (query.length() > 0) { query.append(" AND "); + } query.append("au:\"").append(author).append("\""); } return search(query.toString(), "", 10); } protected List search(String query, String arxivid, int max_result) - throws IOException, HttpException - { - List results = new ArrayList(); - HttpGet method = null; - try - { - HttpClient client = new DefaultHttpClient(); + throws IOException, HttpException { + List results = new ArrayList(); + HttpGet method = null; + try { + HttpClient client = new DefaultHttpClient(); HttpParams params = client.getParams(); params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout); @@ -99,83 +89,68 @@ public class ArXivService uriBuilder.addParameter("search_query", query); uriBuilder.addParameter("max_results", String.valueOf(max_result)); method = new HttpGet(uriBuilder.build()); - } catch (URISyntaxException ex) - { + } catch (URISyntaxException ex) { throw new HttpException(ex.getMessage()); } // Execute the method. - HttpResponse response = client.execute(method); + HttpResponse response = client.execute(method); StatusLine responseStatus = response.getStatusLine(); int statusCode = responseStatus.getStatusCode(); - if (statusCode != HttpStatus.SC_OK) - { - if (statusCode == HttpStatus.SC_BAD_REQUEST) - throw new RuntimeException("arXiv query is not valid"); - else - throw new RuntimeException("Http call failed: " - + responseStatus); - } - - try - { - DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); - factory.setValidating(false); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); - - DocumentBuilder db = factory.newDocumentBuilder(); - Document inDoc = db.parse(response.getEntity().getContent()); - - Element xmlRoot = inDoc.getDocumentElement(); - List dataRoots = XMLUtils.getElementList(xmlRoot, - "entry"); - - for (Element dataRoot : dataRoots) - { - Record crossitem = ArxivUtils - .convertArxixDomToRecord(dataRoot); - if (crossitem != null) - { - results.add(crossitem); - } - } - } - catch (Exception e) - { - throw new RuntimeException( - "ArXiv identifier is not valid or not exist"); - } - } - finally - { - if (method != null) - { - method.releaseConnection(); - } - } - - return results; - } - - public Record getByArXivIDs(String raw) throws HttpException, IOException - { - if (StringUtils.isNotBlank(raw)) - { - raw = raw.trim(); - if (raw.startsWith("http://arxiv.org/abs/")) - { - raw = raw.substring("http://arxiv.org/abs/".length()); + if (statusCode != HttpStatus.SC_OK) { + if (statusCode == HttpStatus.SC_BAD_REQUEST) { + throw new RuntimeException("arXiv query is not valid"); + } else { + throw new RuntimeException("Http call failed: " + + responseStatus); + } } - else if (raw.toLowerCase().startsWith("arxiv:")) - { + + try { + DocumentBuilderFactory factory = DocumentBuilderFactory + .newInstance(); + factory.setValidating(false); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + + DocumentBuilder db = factory.newDocumentBuilder(); + Document inDoc = db.parse(response.getEntity().getContent()); + + Element xmlRoot = inDoc.getDocumentElement(); + List dataRoots = XMLUtils.getElementList(xmlRoot, + "entry"); + + for (Element dataRoot : dataRoots) { + Record crossitem = ArxivUtils + .convertArxixDomToRecord(dataRoot); + if (crossitem != null) { + results.add(crossitem); + } + } + } catch (Exception e) { + throw new RuntimeException( + "ArXiv identifier is not valid or not exist"); + } + } finally { + if (method != null) { + method.releaseConnection(); + } + } + + return results; + } + + public Record getByArXivIDs(String raw) throws HttpException, IOException { + if (StringUtils.isNotBlank(raw)) { + raw = raw.trim(); + if (raw.startsWith("http://arxiv.org/abs/")) { + raw = raw.substring("http://arxiv.org/abs/".length()); + } else if (raw.toLowerCase().startsWith("arxiv:")) { raw = raw.substring("arxiv:".length()); } List result = search("", raw, 1); - if (result != null && result.size() > 0) - { + if (result != null && result.size() > 0) { return result.get(0); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/ArxivUtils.java b/dspace-api/src/main/java/org/dspace/submit/lookup/ArxivUtils.java index c7db15e302..4caa0a957b 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/ArxivUtils.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/ArxivUtils.java @@ -6,7 +6,7 @@ * http://www.dspace.org/license/ */ /** - * + * */ package org.dspace.submit.lookup; @@ -17,82 +17,83 @@ import gr.ekt.bte.core.MutableRecord; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.StringValue; import gr.ekt.bte.core.Value; - import org.dspace.app.util.XMLUtils; import org.dspace.submit.util.SubmissionLookupPublication; import org.w3c.dom.Element; /** - * * @author Andrea Bollini * @author Kostas Stamatis * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis - * */ -public class ArxivUtils -{ +public class ArxivUtils { - public static Record convertArxixDomToRecord(Element dataRoot) - { + /** + * Default constructor + */ + private ArxivUtils() { } + + public static Record convertArxixDomToRecord(Element dataRoot) { MutableRecord record = new SubmissionLookupPublication(""); String articleTitle = XMLUtils.getElementValue(dataRoot, "title"); - if (articleTitle != null) + if (articleTitle != null) { record.addValue("title", new StringValue(articleTitle)); + } String summary = XMLUtils.getElementValue(dataRoot, "summary"); - if (summary != null) + if (summary != null) { record.addValue("summary", new StringValue(summary)); + } String year = XMLUtils.getElementValue(dataRoot, "published"); - if (year != null) + if (year != null) { record.addValue("published", new StringValue(year)); + } String splashPageUrl = XMLUtils.getElementValue(dataRoot, "id"); - if (splashPageUrl != null) + if (splashPageUrl != null) { record.addValue("id", new StringValue(splashPageUrl)); + } String comment = XMLUtils.getElementValue(dataRoot, "arxiv:comment"); - if (comment != null) + if (comment != null) { record.addValue("comment", new StringValue(comment)); + } List links = XMLUtils.getElementList(dataRoot, "link"); - if (links != null) - { - for (Element link : links) - { + if (links != null) { + for (Element link : links) { if ("related".equals(link.getAttribute("rel")) - && "pdf".equals(link.getAttribute("title"))) - { + && "pdf".equals(link.getAttribute("title"))) { String pdfUrl = link.getAttribute("href"); - if (pdfUrl != null) + if (pdfUrl != null) { record.addValue("pdfUrl", new StringValue(pdfUrl)); + } } } } String doi = XMLUtils.getElementValue(dataRoot, "arxiv:doi"); - if (doi != null) + if (doi != null) { record.addValue("doi", new StringValue(doi)); + } String journalRef = XMLUtils.getElementValue(dataRoot, - "arxiv:journal_ref"); - if (journalRef != null) + "arxiv:journal_ref"); + if (journalRef != null) { record.addValue("journalRef", new StringValue(journalRef)); + } List primaryCategory = new LinkedList(); List primaryCategoryList = XMLUtils.getElementList(dataRoot, - "arxiv:primary_category"); - if (primaryCategoryList != null) - { - for (Element primaryCategoryElement : primaryCategoryList) - { + "arxiv:primary_category"); + if (primaryCategoryList != null) { + for (Element primaryCategoryElement : primaryCategoryList) { primaryCategory - .add(primaryCategoryElement.getAttribute("term")); + .add(primaryCategoryElement.getAttribute("term")); } } - if (primaryCategory.size() > 0) - { + if (primaryCategory.size() > 0) { List values = new LinkedList(); - for (String s : primaryCategory) - { + for (String s : primaryCategory) { values.add(new StringValue(s)); } record.addField("primaryCategory", values); @@ -100,20 +101,16 @@ public class ArxivUtils List category = new LinkedList(); List categoryList = XMLUtils.getElementList(dataRoot, - "category"); - if (categoryList != null) - { - for (Element categoryElement : categoryList) - { + "category"); + if (categoryList != null) { + for (Element categoryElement : categoryList) { category.add(categoryElement.getAttribute("term")); } } - if (category.size() > 0) - { + if (category.size() > 0) { List values = new LinkedList(); - for (String s : category) - { + for (String s : category) { values.add(new StringValue(s)); } record.addField("category", values); @@ -122,33 +119,27 @@ public class ArxivUtils List authors = new LinkedList(); List authorsWithAffiliations = new LinkedList(); List authorList = XMLUtils.getElementList(dataRoot, "author"); - if (authorList != null) - { - for (Element authorElement : authorList) - { - String authorName = XMLUtils.getElementValue(authorElement, "name"); - String authorAffiliation = XMLUtils.getElementValue(authorElement, "arxiv:affiliation"); - - authors.add(authorName); - authorsWithAffiliations.add(authorName +": " + authorAffiliation); + if (authorList != null) { + for (Element authorElement : authorList) { + String authorName = XMLUtils.getElementValue(authorElement, "name"); + String authorAffiliation = XMLUtils.getElementValue(authorElement, "arxiv:affiliation"); + + authors.add(authorName); + authorsWithAffiliations.add(authorName + ": " + authorAffiliation); } } - if (authors.size() > 0) - { + if (authors.size() > 0) { List values = new LinkedList(); - for (String sArray : authors) - { + for (String sArray : authors) { values.add(new StringValue(sArray)); } record.addField("author", values); } - - if (authorsWithAffiliations.size() > 0) - { + + if (authorsWithAffiliations.size() > 0) { List values = new LinkedList(); - for (String sArray : authorsWithAffiliations) - { + for (String sArray : authorsWithAffiliations) { values.add(new StringValue(sArray)); } record.addField("authorWithAffiliation", values); diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiFileDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiFileDataLoader.java index 53f7a0c29d..1ddc866568 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiFileDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiFileDataLoader.java @@ -15,71 +15,62 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - import gr.ekt.bte.core.DataLoadingSpec; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.RecordSet; import gr.ekt.bte.core.Value; import gr.ekt.bte.dataloader.FileDataLoader; import gr.ekt.bte.exceptions.MalformedSourceException; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; /** * Load metadata from CiNii formated file * * @author Keiji Suzuki - * */ -public class CiNiiFileDataLoader extends FileDataLoader -{ +public class CiNiiFileDataLoader extends FileDataLoader { private static Logger log = Logger.getLogger(CiNiiFileDataLoader.class); Map fieldMap; // mapping between service fields and local - // intermediate fields + // intermediate fields /** * Empty constructor */ - public CiNiiFileDataLoader() - { + public CiNiiFileDataLoader() { } /** - * @param filename - * Name of file to load CiNii data from. + * @param filename Name of file to load CiNii data from. */ - public CiNiiFileDataLoader(String filename) - { + public CiNiiFileDataLoader(String filename) { super(filename); } /* * {@see gr.ekt.bte.core.DataLoader#getRecords()} * - * @throws MalformedSourceException + * @throws MalformedSourceException */ @Override - public RecordSet getRecords() throws MalformedSourceException - { + public RecordSet getRecords() throws MalformedSourceException { RecordSet recordSet = new RecordSet(); - try - { + try { InputStream inputStream = new FileInputStream(new File(filename)); DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -89,28 +80,19 @@ public class CiNiiFileDataLoader extends FileDataLoader Element xmlRoot = inDoc.getDocumentElement(); - // There is no element to represent an record, so we can not process + // There is no element to represent an record, so we can not process // multi records at once. Record record = CiNiiUtils.convertCiNiiDomToRecord(xmlRoot); - if (record != null) - { + if (record != null) { recordSet.addRecord(convertFields(record)); } - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { log.error(e.getMessage(), e); - } - catch (ParserConfigurationException e) - { + } catch (ParserConfigurationException e) { log.error(e.getMessage(), e); - } - catch (SAXException e) - { + } catch (SAXException e) { log.error(e.getMessage(), e); - } - catch (IOException e) - { + } catch (IOException e) { log.error(e.getMessage(), e); } @@ -119,43 +101,34 @@ public class CiNiiFileDataLoader extends FileDataLoader /* * (non-Javadoc) - * + * * @see * gr.ekt.bte.core.DataLoader#getRecords(gr.ekt.bte.core.DataLoadingSpec) */ @Override public RecordSet getRecords(DataLoadingSpec spec) - throws MalformedSourceException - { - if (spec.getOffset() > 0) - { + throws MalformedSourceException { + if (spec.getOffset() > 0) { return new RecordSet(); } return getRecords(); } - public Record convertFields(Record publication) - { - for (String fieldName : fieldMap.keySet()) - { + public Record convertFields(Record publication) { + for (String fieldName : fieldMap.keySet()) { String md = null; - if (fieldMap != null) - { + if (fieldMap != null) { md = this.fieldMap.get(fieldName); } - if (StringUtils.isBlank(md)) - { + if (StringUtils.isBlank(md)) { continue; - } - else - { + } else { md = md.trim(); } - if (publication.isMutable()) - { + if (publication.isMutable()) { List values = publication.getValues(fieldName); publication.makeMutable().removeField(fieldName); publication.makeMutable().addField(md, values); @@ -165,8 +138,7 @@ public class CiNiiFileDataLoader extends FileDataLoader return publication; } - public void setFieldMap(Map fieldMap) - { + public void setFieldMap(Map fieldMap) { this.fieldMap = fieldMap; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiOnlineDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiOnlineDataLoader.java index 7919823001..93316ee137 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiOnlineDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiOnlineDataLoader.java @@ -7,76 +7,69 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; - import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.http.HttpException; +import gr.ekt.bte.core.Record; +import org.apache.http.HttpException; import org.dspace.core.Context; /** * Load metadata from CiNii RDF API + * * @author Keiji Suzuki */ -public class CiNiiOnlineDataLoader extends NetworkSubmissionLookupDataLoader -{ +public class CiNiiOnlineDataLoader extends NetworkSubmissionLookupDataLoader { protected CiNiiService ciniiService = new CiNiiService(); protected boolean searchProvider = true; - /** Application id to use CiNii */ + /** + * Application id to use CiNii + */ protected String appId = null; - /** max result number to return */ + /** + * max result number to return + */ protected int maxResults = 10; - public void setCiNiiService(CiNiiService ciniiService) - { + public void setCiNiiService(CiNiiService ciniiService) { this.ciniiService = ciniiService; } @Override - public List getSupportedIdentifiers() - { - return Arrays.asList(new String[] { CINII }); + public List getSupportedIdentifiers() { + return Arrays.asList(new String[] {CINII}); } - public void setSearchProvider(boolean searchProvider) - { + public void setSearchProvider(boolean searchProvider) { this.searchProvider = searchProvider; } @Override - public boolean isSearchProvider() - { + public boolean isSearchProvider() { return searchProvider; } @Override public List getByIdentifier(Context context, - Map> keys) throws HttpException, IOException - { - if (appId == null) - { + Map> keys) throws HttpException, IOException { + if (appId == null) { throw new RuntimeException("No CiNii Application ID is specified!"); } List results = new ArrayList(); - if (keys != null) - { + if (keys != null) { Set ciniiids = keys.get(CINII); - if (ciniiids != null && ciniiids.size() > 0) - { - for (String ciniiid : ciniiids) - { + if (ciniiids != null && ciniiids.size() > 0) { + for (String ciniiid : ciniiids) { Record record = ciniiService.getByCiNiiID(ciniiid, getAppId()); - if (record != null) - { + if (record != null) { results.add(convertFields(record)); } } @@ -87,34 +80,28 @@ public class CiNiiOnlineDataLoader extends NetworkSubmissionLookupDataLoader @Override public List search(Context context, String title, String author, int year) - throws HttpException, IOException - { - if (appId == null) - { + throws HttpException, IOException { + if (appId == null) { throw new RuntimeException("No CiNii Application ID is specified!"); } - return ciniiService.searchByTerm(title, author, year, - getMaxResults(), getAppId()); + return ciniiService.searchByTerm(title, author, year, + getMaxResults(), getAppId()); } - public String getAppId() - { + public String getAppId() { return appId; } - public void setAppId(String appId) - { + public void setAppId(String appId) { this.appId = appId; } - public int getMaxResults() - { + public int getMaxResults() { return maxResults; } - public void setMaxResults(int maxResults) - { + public void setMaxResults(int maxResults) { this.maxResults = maxResults; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiService.java b/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiService.java index dec88fc01c..db495906da 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiService.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiService.java @@ -7,15 +7,14 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; - import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; + +import gr.ekt.bte.core.Record; import org.apache.http.HttpException; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; @@ -24,7 +23,6 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreConnectionPNames; - import org.apache.log4j.Logger; import org.dspace.app.util.XMLUtils; import org.w3c.dom.Document; @@ -33,38 +31,33 @@ import org.w3c.dom.Element; /** * @author Keiji Suzuki */ -public class CiNiiService -{ - /** log4j category */ +public class CiNiiService { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(CiNiiService.class); protected int timeout = 1000; - public void setTimeout(int timeout) - { + public void setTimeout(int timeout) { this.timeout = timeout; } public Record getByCiNiiID(String id, String appId) throws HttpException, - IOException - { - return search(id, appId); + IOException { + return search(id, appId); } - public List searchByTerm(String title, String author, int year, - int maxResults, String appId) - throws HttpException, IOException - { + public List searchByTerm(String title, String author, int year, + int maxResults, String appId) + throws HttpException, IOException { List records = new ArrayList(); List ids = getCiNiiIDs(title, author, year, maxResults, appId); - if (ids != null && ids.size() > 0) - { - for (String id : ids) - { + if (ids != null && ids.size() > 0) { + for (String id : ids) { Record record = search(id, appId); - if (record != null) - { + if (record != null) { records.add(record); } } @@ -76,43 +69,36 @@ public class CiNiiService /** * Get metadata by searching CiNii RDF API with CiNii NAID * - * @param id - * CiNii NAID to search by - * @param appId - * registered application identifier for the API + * @param id CiNii NAID to search by + * @param appId registered application identifier for the API * @return record metadata - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws HttpException - * Represents a XML/HTTP fault and provides access to the HTTP status code. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws HttpException Represents a XML/HTTP fault and provides access to the HTTP status code. */ protected Record search(String id, String appId) - throws IOException, HttpException - { + throws IOException, HttpException { HttpGet method = null; - try - { + try { HttpClient client = new DefaultHttpClient(); client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout); - method = new HttpGet("http://ci.nii.ac.jp/naid/"+id+".rdf?appid="+appId); + method = new HttpGet("http://ci.nii.ac.jp/naid/" + id + ".rdf?appid=" + appId); // Execute the method. HttpResponse response = client.execute(method); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); - if (statusCode != HttpStatus.SC_OK) - { - if (statusCode == HttpStatus.SC_BAD_REQUEST) + if (statusCode != HttpStatus.SC_OK) { + if (statusCode == HttpStatus.SC_BAD_REQUEST) { throw new RuntimeException("CiNii RDF is not valid"); - else + } else { throw new RuntimeException("CiNii RDF Http call failed: " - + statusLine); + + statusLine); + } } - try - { + try { DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -123,17 +109,12 @@ public class CiNiiService Element xmlRoot = inDoc.getDocumentElement(); return CiNiiUtils.convertCiNiiDomToRecord(xmlRoot); - } - catch (Exception e) - { + } catch (Exception e) { throw new RuntimeException( - "CiNii RDF identifier is not valid or not exist"); + "CiNii RDF identifier is not valid or not exist"); } - } - finally - { - if (method != null) - { + } finally { + if (method != null) { method.releaseConnection(); } } @@ -142,72 +123,58 @@ public class CiNiiService /** * Get CiNii NAIDs by searching CiNii OpenURL API with title, author and year * - * @param title - * record title - * @param author - * record author - * @param year - * record year - * @param maxResults - * maximun number of results returned - * @param appId - * registered application identifier for the API + * @param title record title + * @param author record author + * @param year record year + * @param maxResults maximun number of results returned + * @param appId registered application identifier for the API * @return matching NAIDs - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws HttpException - * Represents a XML/HTTP fault and provides access to the HTTP status code. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws HttpException Represents a XML/HTTP fault and provides access to the HTTP status code. */ protected List getCiNiiIDs(String title, String author, int year, - int maxResults, String appId) - throws IOException, HttpException - { + int maxResults, String appId) + throws IOException, HttpException { // Need at least one query term - if (title == null && author == null && year == -1) - { + if (title == null && author == null && year == -1) { return null; } HttpGet method = null; List ids = new ArrayList(); - try - { + try { HttpClient client = new DefaultHttpClient(); client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout); StringBuilder query = new StringBuilder(); query.append("format=rss&appid=").append(appId) .append("&count=").append(maxResults); - if (title != null) - { + if (title != null) { query.append("&title=").append(URLEncoder.encode(title, "UTF-8")); } - if (author != null) - { + if (author != null) { query.append("&author=").append(URLEncoder.encode(author, "UTF-8")); } - if (year != -1) - { + if (year != -1) { query.append("&year_from=").append(String.valueOf(year)); query.append("&year_to=").append(String.valueOf(year)); } - method = new HttpGet("http://ci.nii.ac.jp/opensearch/search?"+query.toString()); + method = new HttpGet("http://ci.nii.ac.jp/opensearch/search?" + query.toString()); // Execute the method. HttpResponse response = client.execute(method); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); - if (statusCode != HttpStatus.SC_OK) - { - if (statusCode == HttpStatus.SC_BAD_REQUEST) + if (statusCode != HttpStatus.SC_OK) { + if (statusCode == HttpStatus.SC_BAD_REQUEST) { throw new RuntimeException("CiNii OpenSearch query is not valid"); - else + } else { throw new RuntimeException("CiNii OpenSearch call failed: " - + statusLine); + + statusLine); + } } - try - { + try { DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -219,27 +186,20 @@ public class CiNiiService List items = XMLUtils.getElementList(xmlRoot, "item"); int url_len = "http://ci.nii.ac.jp/naid/".length(); - for (Element item : items) - { + for (Element item : items) { String about = item.getAttribute("rdf:about"); - if (about.length() > url_len) - { + if (about.length() > url_len) { ids.add(about.substring(url_len)); } } return ids; - } - catch (Exception e) - { + } catch (Exception e) { throw new RuntimeException( - "CiNii OpenSearch results is not valid or not exist"); + "CiNii OpenSearch results is not valid or not exist"); } - } - finally - { - if (method != null) - { + } finally { + if (method != null) { method.releaseConnection(); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiUtils.java b/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiUtils.java index e134257e59..65cf2bf609 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiUtils.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/CiNiiUtils.java @@ -6,7 +6,7 @@ * http://www.dspace.org/license/ */ /** - * + * */ package org.dspace.submit.lookup; @@ -17,27 +17,27 @@ import gr.ekt.bte.core.MutableRecord; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.StringValue; import gr.ekt.bte.core.Value; - import org.apache.commons.lang.StringUtils; import org.dspace.app.util.XMLUtils; import org.dspace.submit.util.SubmissionLookupPublication; import org.w3c.dom.Element; /** - * * @author Keiji Suzuki - * */ -public class CiNiiUtils -{ - public static Record convertCiNiiDomToRecord(Element xmlRoot) - { +public class CiNiiUtils { + + /** + * Default constructor + */ + private CiNiiUtils() { } + + public static Record convertCiNiiDomToRecord(Element xmlRoot) { MutableRecord record = new SubmissionLookupPublication(""); List list = XMLUtils.getElementList(xmlRoot, "rdf:Description"); // Valid CiNii record should have three rdf:Description elements - if (list.size() < 3) - { + if (list.size() < 3) { return record; } @@ -49,197 +49,157 @@ public class CiNiiUtils language = language != null ? language.toLowerCase() : "ja"; record.addValue("language", new StringValue(language)); - if ("ja".equals(language) || "jpn".equals(language)) - { + if ("ja".equals(language) || "jpn".equals(language)) { String title = XMLUtils.getElementValue(description_ja, "dc:title"); - if (title != null) - { + if (title != null) { record.addValue("title", new StringValue(title)); } String titleAlternative = XMLUtils.getElementValue(description_en, "dc:title"); - if (titleAlternative != null) - { + if (titleAlternative != null) { record.addValue("titleAlternative", new StringValue(titleAlternative)); } List authors = getAuthors(description_ja); - if (authors.size() > 0) - { + if (authors.size() > 0) { record.addField("authors", authors); } List authorAlternative = getAuthors(description_en); - if (authorAlternative.size() > 0) - { + if (authorAlternative.size() > 0) { record.addField("auhtorAlternative", authorAlternative); } String publisher = XMLUtils.getElementValue(description_ja, "dc:publisher"); - if (publisher != null) - { + if (publisher != null) { record.addValue("publisher", new StringValue(publisher)); } - } - else - { + } else { String title = XMLUtils.getElementValue(description_en, "dc:title"); - if (title != null) - { + if (title != null) { record.addValue("title", new StringValue(title)); } String titleAlternative = XMLUtils.getElementValue(description_ja, "dc:title"); - if (titleAlternative != null) - { + if (titleAlternative != null) { record.addValue("titleAlternative", new StringValue(titleAlternative)); } List authors = getAuthors(description_en); - if (authors.size() > 0) - { + if (authors.size() > 0) { record.addField("authors", authors); } List authorAlternative = getAuthors(description_ja); - if (authorAlternative.size() > 0) - { + if (authorAlternative.size() > 0) { record.addField("authorAlternative", authorAlternative); } String publisher = XMLUtils.getElementValue(description_en, "dc:publisher"); - if (publisher != null) - { + if (publisher != null) { record.addValue("publisher", new StringValue(publisher)); } } String abstract_ja = XMLUtils.getElementValue(description_ja, "dc:description"); String abstract_en = XMLUtils.getElementValue(description_en, "dc:description"); - if (abstract_ja != null && abstract_en != null) - { + if (abstract_ja != null && abstract_en != null) { List description = new LinkedList(); description.add(new StringValue(abstract_ja)); description.add(new StringValue(abstract_en)); record.addField("description", description); - } - else if (abstract_ja != null) - { + } else if (abstract_ja != null) { record.addValue("description", new StringValue(abstract_ja)); - } - else if (abstract_en != null) - { + } else if (abstract_en != null) { record.addValue("description", new StringValue(abstract_en)); } List subjects = getSubjects(description_ja); subjects.addAll(getSubjects(description_en)); - if (subjects.size() > 0) - { + if (subjects.size() > 0) { record.addField("subjects", subjects); } String journal_j = XMLUtils.getElementValue(description_ja, "prism:publicationName"); String journal_e = XMLUtils.getElementValue(description_en, "prism:publicationName"); - if (journal_j != null && journal_e != null) - { - record.addValue("journal", new StringValue(journal_j+" = "+journal_e)); - } - else if (journal_j != null) - { - + if (journal_j != null && journal_e != null) { + record.addValue("journal", new StringValue(journal_j + " = " + journal_e)); + } else if (journal_j != null) { + record.addValue("journal", new StringValue(journal_j)); - } - else if (journal_e != null) - { - + } else if (journal_e != null) { + record.addValue("journal", new StringValue(journal_e)); } String volume = XMLUtils.getElementValue(description_ja, "prism:volume"); - if (volume != null) - { + if (volume != null) { record.addValue("volume", new StringValue(volume)); } String issue = XMLUtils.getElementValue(description_ja, "prism:number"); - if (issue != null) - { + if (issue != null) { record.addValue("issue", new StringValue(issue)); } String spage = XMLUtils.getElementValue(description_ja, "prism:startingPage"); - if (spage != null) - { + if (spage != null) { record.addValue("spage", new StringValue(spage)); } String epage = XMLUtils.getElementValue(description_ja, "prism:endingPage"); - if (epage != null) - { + if (epage != null) { record.addValue("epage", new StringValue(epage)); } String pages = XMLUtils.getElementValue(description_ja, "prism:pageRange"); - if (pages != null && spage == null) - { + if (pages != null && spage == null) { int pos = pages.indexOf("-"); - if (pos > -1) - { + if (pos > -1) { spage = pages.substring(0, pos); - epage = pages.substring(pos+1, pages.length() - pos); - if (!epage.equals("") && spage.length() > epage.length()) - { + epage = pages.substring(pos + 1, pages.length() - pos); + if (!epage.equals("") && spage.length() > epage.length()) { epage = spage.substring(0, spage.length() - epage.length()) + epage; } - } - else - { + } else { spage = pages; epage = ""; } record.addValue("spage", new StringValue(spage)); - if (!epage.equals("") && epage == null) - { + if (!epage.equals("") && epage == null) { record.addValue("epage", new StringValue(epage)); } } String issn = XMLUtils.getElementValue(description_ja, "prism:issn"); - if (issn != null) - { + if (issn != null) { record.addValue("issn", new StringValue(issn)); } String issued = XMLUtils.getElementValue(description_ja, "prism:publicationDate"); - if (issued != null) - { + if (issued != null) { record.addValue("issued", new StringValue(issued)); } String ncid = XMLUtils.getElementValue(description_ja, "cinii:ncid"); - if (ncid != null) - { + if (ncid != null) { record.addValue("ncid", new StringValue(ncid)); } String naid = XMLUtils.getElementValue(description_ja, "cinii:naid"); - if (naid != null) - { + if (naid != null) { record.addValue("naid", new StringValue(naid)); } return record; } - private static List getAuthors(Element element) - { + private static List getAuthors(Element element) { List authors = new LinkedList(); List authorList = XMLUtils.getElementValueList(element, "dc:creator"); - if (authorList != null && authorList.size() > 0) - { - for (String author : authorList) - { + if (authorList != null && authorList.size() > 0) { + for (String author : authorList) { int pos = author.indexOf(" "); - if (pos > -1) + if (pos > -1) { author = author.substring(0, pos) + "," + author.substring(pos); + } authors.add(new StringValue(author)); } } @@ -247,17 +207,14 @@ public class CiNiiUtils return authors; } - private static List getSubjects(Element element) - { + private static List getSubjects(Element element) { List subjects = new LinkedList(); List topicList = XMLUtils.getElementList(element, "foaf:topic"); String attrValue = null; - for (Element topic : topicList) - { + for (Element topic : topicList) { attrValue = topic.getAttribute("dc:title"); - if (StringUtils.isNotBlank(attrValue)) - { + if (StringUtils.isNotBlank(attrValue)) { subjects.add(new StringValue(attrValue.trim())); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefFileDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefFileDataLoader.java index 2f176c04ab..71b50e06dc 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefFileDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefFileDataLoader.java @@ -15,23 +15,21 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.apache.commons.lang.StringUtils; -import org.dspace.app.util.XMLUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - import gr.ekt.bte.core.DataLoadingSpec; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.RecordSet; import gr.ekt.bte.core.Value; import gr.ekt.bte.dataloader.FileDataLoader; import gr.ekt.bte.exceptions.MalformedSourceException; +import org.apache.commons.lang.StringUtils; +import org.dspace.app.util.XMLUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; /** * @author Andrea Bollini @@ -39,45 +37,39 @@ import gr.ekt.bte.exceptions.MalformedSourceException; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class CrossRefFileDataLoader extends FileDataLoader -{ +public class CrossRefFileDataLoader extends FileDataLoader { Map fieldMap; // mapping between service fields and local - // intermediate fields + // intermediate fields /** - * + * */ - public CrossRefFileDataLoader() - { + public CrossRefFileDataLoader() { } /** - * @param filename - * Name of file to load ArXiv data from. + * @param filename Name of file to load ArXiv data from. */ - public CrossRefFileDataLoader(String filename) - { + public CrossRefFileDataLoader(String filename) { super(filename); } /* * (non-Javadoc) - * + * * @see gr.ekt.bte.core.DataLoader#getRecords() */ @Override - public RecordSet getRecords() throws MalformedSourceException - { + public RecordSet getRecords() throws MalformedSourceException { RecordSet recordSet = new RecordSet(); - try - { + try { InputStream inputStream = new FileInputStream(new File(filename)); DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -87,26 +79,18 @@ public class CrossRefFileDataLoader extends FileDataLoader Element xmlRoot = inDoc.getDocumentElement(); Element queryResult = XMLUtils.getSingleElement(xmlRoot, "query_result"); - Element body = XMLUtils.getSingleElement(queryResult, "body"); - Element dataRoot = XMLUtils.getSingleElement(body, "query"); + Element body = XMLUtils.getSingleElement(queryResult, "body"); + Element dataRoot = XMLUtils.getSingleElement(body, "query"); Record record = CrossRefUtils.convertCrossRefDomToRecord(dataRoot); recordSet.addRecord(convertFields(record)); - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { e.printStackTrace(); - } - catch (ParserConfigurationException e) - { + } catch (ParserConfigurationException e) { e.printStackTrace(); - } - catch (SAXException e) - { + } catch (SAXException e) { e.printStackTrace(); - } - catch (IOException e) - { + } catch (IOException e) { e.printStackTrace(); } @@ -116,42 +100,33 @@ public class CrossRefFileDataLoader extends FileDataLoader /* * (non-Javadoc) - * + * * @see * gr.ekt.bte.core.DataLoader#getRecords(gr.ekt.bte.core.DataLoadingSpec) */ @Override public RecordSet getRecords(DataLoadingSpec spec) - throws MalformedSourceException - { - if (spec.getOffset() > 0) - { + throws MalformedSourceException { + if (spec.getOffset() > 0) { return new RecordSet(); } return getRecords(); } - public Record convertFields(Record publication) - { - for (String fieldName : fieldMap.keySet()) - { + public Record convertFields(Record publication) { + for (String fieldName : fieldMap.keySet()) { String md = null; - if (fieldMap != null) - { + if (fieldMap != null) { md = this.fieldMap.get(fieldName); } - if (StringUtils.isBlank(md)) - { + if (StringUtils.isBlank(md)) { continue; - } - else - { + } else { md = md.trim(); } - if (publication.isMutable()) - { + if (publication.isMutable()) { List values = publication.getValues(fieldName); publication.makeMutable().removeField(fieldName); publication.makeMutable().addField(md, values); @@ -161,8 +136,7 @@ public class CrossRefFileDataLoader extends FileDataLoader return publication; } - public void setFieldMap(Map fieldMap) - { + public void setFieldMap(Map fieldMap) { this.fieldMap = fieldMap; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefOnlineDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefOnlineDataLoader.java index bd74010f1b..36e4fb1989 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefOnlineDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefOnlineDataLoader.java @@ -7,17 +7,15 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; - import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; - import javax.xml.parsers.ParserConfigurationException; +import gr.ekt.bte.core.Record; import org.apache.http.HttpException; import org.dspace.core.Context; import org.jdom.JDOMException; @@ -29,63 +27,49 @@ import org.xml.sax.SAXException; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class CrossRefOnlineDataLoader extends NetworkSubmissionLookupDataLoader -{ +public class CrossRefOnlineDataLoader extends NetworkSubmissionLookupDataLoader { protected CrossRefService crossrefService = new CrossRefService(); protected boolean searchProvider = true; protected String apiKey = null; protected int maxResults = 10; - - public void setSearchProvider(boolean searchProvider) - { + + public void setSearchProvider(boolean searchProvider) { this.searchProvider = searchProvider; } - public void setCrossrefService(CrossRefService crossrefService) - { + public void setCrossrefService(CrossRefService crossrefService) { this.crossrefService = crossrefService; } @Override - public List getSupportedIdentifiers() - { - return Arrays.asList(new String[] { DOI }); + public List getSupportedIdentifiers() { + return Arrays.asList(new String[] {DOI}); } @Override public List getByIdentifier(Context context, - Map> keys) throws HttpException, IOException - { - if (keys != null && keys.containsKey(DOI)) - { + Map> keys) throws HttpException, IOException { + if (keys != null && keys.containsKey(DOI)) { Set dois = keys.get(DOI); List items = null; List results = new ArrayList(); - - if (getApiKey() == null){ - throw new RuntimeException("No CrossRef API key is specified!"); + + if (getApiKey() == null) { + throw new RuntimeException("No CrossRef API key is specified!"); } - - try - { + + try { items = crossrefService.search(context, dois, getApiKey()); - } - catch (JDOMException e) - { + } catch (JDOMException e) { + throw new RuntimeException(e.getMessage(), e); + } catch (ParserConfigurationException e) { + throw new RuntimeException(e.getMessage(), e); + } catch (SAXException e) { throw new RuntimeException(e.getMessage(), e); } - catch (ParserConfigurationException e) - { - throw new RuntimeException(e.getMessage(), e); - } - catch (SAXException e) - { - throw new RuntimeException(e.getMessage(), e); - } - for (Record record : items) - { + for (Record record : items) { results.add(convertFields(record)); } return results; @@ -95,36 +79,34 @@ public class CrossRefOnlineDataLoader extends NetworkSubmissionLookupDataLoader @Override public List search(Context context, String title, String author, - int year) throws HttpException, IOException - { - if (getApiKey() == null){ - throw new RuntimeException("No CrossRef API key is specified!"); + int year) throws HttpException, IOException { + if (getApiKey() == null) { + throw new RuntimeException("No CrossRef API key is specified!"); } - + List items = crossrefService.search(context, title, author, - year, getMaxResults(), getApiKey()); + year, getMaxResults(), getApiKey()); return items; } @Override - public boolean isSearchProvider() - { + public boolean isSearchProvider() { return searchProvider; } - public String getApiKey() { - return apiKey; - } + public String getApiKey() { + return apiKey; + } - public void setApiKey(String apiKey) { - this.apiKey = apiKey; - } + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } - public int getMaxResults() { - return maxResults; - } + public int getMaxResults() { + return maxResults; + } - public void setMaxResults(int maxResults) { - this.maxResults = maxResults; - } + public void setMaxResults(int maxResults) { + this.maxResults = maxResults; + } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefService.java b/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefService.java index 7942523923..d1c0fa2654 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefService.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefService.java @@ -7,35 +7,24 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; - import java.io.IOException; import java.lang.reflect.Type; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.dspace.app.util.XMLUtils; -import org.dspace.core.Context; -import org.dspace.core.LogManager; -import org.jdom.JDOMException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; +import gr.ekt.bte.core.Record; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; import org.apache.http.HttpException; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; @@ -45,6 +34,14 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreConnectionPNames; +import org.apache.log4j.Logger; +import org.dspace.app.util.XMLUtils; +import org.dspace.core.Context; +import org.dspace.core.LogManager; +import org.jdom.JDOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; /** * @author Andrea Bollini @@ -52,126 +49,106 @@ import org.apache.http.params.CoreConnectionPNames; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class CrossRefService -{ +public class CrossRefService { private static final Logger log = Logger.getLogger(CrossRefService.class); protected int timeout = 1000; - public void setTimeout(int timeout) - { + public void setTimeout(int timeout) { this.timeout = timeout; } public List search(Context context, Set dois, String apiKey) - throws HttpException, IOException, JDOMException, - ParserConfigurationException, SAXException - { + throws HttpException, IOException, JDOMException, + ParserConfigurationException, SAXException { List results = new ArrayList(); - if (dois != null && dois.size() > 0) - { - for (String record : dois) - { - try - { - HttpGet method = null; - try - { - HttpClient client = new DefaultHttpClient(); + if (dois != null && dois.size() > 0) { + for (String record : dois) { + try { + HttpGet method = null; + try { + HttpClient client = new DefaultHttpClient(); client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout); try { - URIBuilder uriBuilder = new URIBuilder( - "http://www.crossref.org/openurl/"); - uriBuilder.addParameter("pid", apiKey); - uriBuilder.addParameter("noredirect", "true"); - uriBuilder.addParameter("id", record); - method = new HttpGet(uriBuilder.build()); + URIBuilder uriBuilder = new URIBuilder( + "http://www.crossref.org/openurl/"); + uriBuilder.addParameter("pid", apiKey); + uriBuilder.addParameter("noredirect", "true"); + uriBuilder.addParameter("id", record); + method = new HttpGet(uriBuilder.build()); } catch (URISyntaxException ex) { throw new HttpException("Request not sent", ex); } // Execute the method. - HttpResponse response = client.execute(method); + HttpResponse response = client.execute(method); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); - if (statusCode != HttpStatus.SC_OK) - { - throw new RuntimeException("Http call failed: " - + statusLine); - } + if (statusCode != HttpStatus.SC_OK) { + throw new RuntimeException("Http call failed: " + + statusLine); + } - Record crossitem; - try - { - DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); - factory.setValidating(false); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); + Record crossitem; + try { + DocumentBuilderFactory factory = DocumentBuilderFactory + .newInstance(); + factory.setValidating(false); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); - DocumentBuilder db = factory - .newDocumentBuilder(); - Document inDoc = db.parse(response.getEntity().getContent()); + DocumentBuilder db = factory + .newDocumentBuilder(); + Document inDoc = db.parse(response.getEntity().getContent()); - Element xmlRoot = inDoc.getDocumentElement(); - Element queryResult = XMLUtils.getSingleElement(xmlRoot, "query_result"); - Element body = XMLUtils.getSingleElement(queryResult, "body"); - Element dataRoot = XMLUtils.getSingleElement(body, "query"); + Element xmlRoot = inDoc.getDocumentElement(); + Element queryResult = XMLUtils.getSingleElement(xmlRoot, "query_result"); + Element body = XMLUtils.getSingleElement(queryResult, "body"); + Element dataRoot = XMLUtils.getSingleElement(body, "query"); - crossitem = CrossRefUtils - .convertCrossRefDomToRecord(dataRoot); - results.add(crossitem); - } - catch (Exception e) - { - log.warn(LogManager - .getHeader( - context, - "retrieveRecordDOI", - record - + " DOI is not valid or not exist: " - + e.getMessage())); - } - } - finally - { - if (method != null) - { - method.releaseConnection(); - } - } - } - catch (RuntimeException rt) - { - log.error(rt.getMessage(), rt); - } + crossitem = CrossRefUtils + .convertCrossRefDomToRecord(dataRoot); + results.add(crossitem); + } catch (Exception e) { + log.warn(LogManager + .getHeader( + context, + "retrieveRecordDOI", + record + + " DOI is not valid or not exist: " + + e.getMessage())); + } + } finally { + if (method != null) { + method.releaseConnection(); + } + } + } catch (RuntimeException rt) { + log.error(rt.getMessage(), rt); + } } } return results; } public List search(Context context, String title, String authors, - int year, int count, String apiKey) throws IOException, HttpException - { + int year, int count, String apiKey) throws IOException, HttpException { HttpGet method = null; - try - { + try { HttpClient client = new DefaultHttpClient(); client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout); URIBuilder uriBuilder = new URIBuilder("http://search.labs.crossref.org/dois"); StringBuilder sb = new StringBuilder(); - if (StringUtils.isNotBlank(title)) - { + if (StringUtils.isNotBlank(title)) { sb.append(title); } sb.append(" "); - if (StringUtils.isNotBlank(authors)) - { + if (StringUtils.isNotBlank(authors)) { sb.append(authors); } String q = sb.toString().trim(); @@ -186,37 +163,29 @@ public class CrossRefService StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); - if (statusCode != HttpStatus.SC_OK) - { + if (statusCode != HttpStatus.SC_OK) { throw new RuntimeException("Http call failed:: " - + statusLine); + + statusLine); } Gson gson = new Gson(); - Type listType = new TypeToken>() - { + Type listType = new TypeToken>() { }.getType(); List json = gson.fromJson( - IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8), - listType); + IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8), + listType); Set dois = new HashSet(); - for (Map r : json) - { + for (Map r : json) { dois.add(SubmissionLookupUtils.normalizeDOI((String) r - .get("doi"))); + .get("doi"))); } method.releaseConnection(); return search(context, dois, apiKey); - } - catch (Exception e) - { + } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); - } - finally - { - if (method != null) - { + } finally { + if (method != null) { method.releaseConnection(); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefUtils.java b/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefUtils.java index e05d6d4577..c80af2b0a7 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefUtils.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/CrossRefUtils.java @@ -6,7 +6,7 @@ * http://www.dspace.org/license/ */ /** - * + * */ package org.dspace.submit.lookup; @@ -17,7 +17,6 @@ import gr.ekt.bte.core.MutableRecord; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.StringValue; import gr.ekt.bte.core.Value; - import org.apache.commons.lang.StringUtils; import org.dspace.app.util.XMLUtils; import org.dspace.submit.util.SubmissionLookupPublication; @@ -29,121 +28,124 @@ import org.w3c.dom.Element; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class CrossRefUtils -{ +public class CrossRefUtils { /** - * - */ - public CrossRefUtils() - { - // TODO Auto-generated constructor stub - } + * Default constructor + */ + private CrossRefUtils() { } - public static Record convertCrossRefDomToRecord(Element dataRoot) - { + public static Record convertCrossRefDomToRecord(Element dataRoot) { MutableRecord record = new SubmissionLookupPublication(""); String status = dataRoot.getAttribute("status"); - if (!"resolved".equals(status)) - { + if (!"resolved".equals(status)) { String msg = XMLUtils.getElementValue(dataRoot, "msg"); String exMsg = status + " - " + msg; throw new RuntimeException(exMsg); } String doi = XMLUtils.getElementValue(dataRoot, "doi"); - if (doi != null) + if (doi != null) { record.addValue("doi", new StringValue(doi)); + } String itemType = doi != null ? XMLUtils.getElementAttribute(dataRoot, - "doi", "type") : "unspecified"; - if (itemType != null) + "doi", "type") : "unspecified"; + if (itemType != null) { record.addValue("doiType", new StringValue(itemType)); + } List identifier = XMLUtils.getElementList(dataRoot, "issn"); - for (Element ident : identifier) - { + for (Element ident : identifier) { if ("print".equalsIgnoreCase(ident.getAttribute("type")) - || StringUtils.isNotBlank(ident.getAttribute("type"))) - { + || StringUtils.isNotBlank(ident.getAttribute("type"))) { String issn = ident.getTextContent().trim(); - if (issn != null) + if (issn != null) { record.addValue("printISSN", new StringValue(issn)); - } - else - { + } + } else { String eissn = ident.getTextContent().trim(); - if (eissn != null) + if (eissn != null) { record.addValue("electronicISSN", new StringValue(eissn)); + } } } - + List identifierisbn = XMLUtils.getElementList(dataRoot, "isbn"); - for (Element ident : identifierisbn) - { + for (Element ident : identifierisbn) { if ("print".equalsIgnoreCase(ident.getAttribute("type")) - || StringUtils.isNotBlank(ident.getAttribute("type"))) - { + || StringUtils.isNotBlank(ident.getAttribute("type"))) { String issn = ident.getTextContent().trim(); - if (issn != null) + if (issn != null) { record.addValue("printISBN", new StringValue(issn)); - } - else - { + } + } else { String eissn = ident.getTextContent().trim(); - if (eissn != null) + if (eissn != null) { record.addValue("electronicISBN", new StringValue(eissn)); + } } } String editionNumber = XMLUtils.getElementValue(dataRoot, - "editionNumber"); - if (editionNumber != null) + "editionNumber"); + if (editionNumber != null) { record.addValue("editionNumber", new StringValue(editionNumber)); + } String volume = XMLUtils.getElementValue(dataRoot, "volume"); - if (volume != null) + if (volume != null) { record.addValue("volume", new StringValue(volume)); + } String issue = XMLUtils.getElementValue(dataRoot, "issue"); - if (issue != null) + if (issue != null) { record.addValue("issue", new StringValue(issue)); + } String year = XMLUtils.getElementValue(dataRoot, "year"); - if (year != null) + if (year != null) { record.addValue("year", new StringValue(year)); + } String firstPage = XMLUtils.getElementValue(dataRoot, "first_page"); - if (firstPage != null) + if (firstPage != null) { record.addValue("firstPage", new StringValue(firstPage)); + } String lastPage = XMLUtils.getElementValue(dataRoot, "last_page"); - if (lastPage != null) + if (lastPage != null) { record.addValue("lastPage", new StringValue(lastPage)); + } String seriesTitle = XMLUtils.getElementValue(dataRoot, "series_title"); - if (seriesTitle != null) + if (seriesTitle != null) { record.addValue("seriesTitle", new StringValue(seriesTitle)); + } String journalTitle = XMLUtils.getElementValue(dataRoot, - "journal_title"); - if (journalTitle != null) + "journal_title"); + if (journalTitle != null) { record.addValue("journalTitle", new StringValue(journalTitle)); + } String volumeTitle = XMLUtils.getElementValue(dataRoot, "volume_title"); - if (volumeTitle != null) + if (volumeTitle != null) { record.addValue("volumeTitle", new StringValue(volumeTitle)); + } String articleTitle = XMLUtils.getElementValue(dataRoot, - "article_title"); - if (articleTitle != null) + "article_title"); + if (articleTitle != null) { record.addValue("articleTitle", new StringValue(articleTitle)); + } String publicationType = XMLUtils.getElementValue(dataRoot, - "pubblication_type"); - if (publicationType != null) + "pubblication_type"); + if (publicationType != null) { record.addValue("publicationType", new StringValue(publicationType)); + } List authors = new LinkedList(); List editors = new LinkedList(); @@ -151,77 +153,60 @@ public class CrossRefUtils List chairs = new LinkedList(); List contributors = XMLUtils.getElementList(dataRoot, - "contributors"); + "contributors"); List contributor = null; - if (contributors != null && contributors.size() > 0) - { + if (contributors != null && contributors.size() > 0) { contributor = XMLUtils.getElementList(contributors.get(0), - "contributor"); + "contributor"); - for (Element contrib : contributor) - { + for (Element contrib : contributor) { String givenName = XMLUtils.getElementValue(contrib, - "given_name"); + "given_name"); String surname = XMLUtils.getElementValue(contrib, "surname"); if ("editor".equalsIgnoreCase(contrib - .getAttribute("contributor_role"))) - { - editors.add(new String[] { givenName, surname }); - } - else if ("chair".equalsIgnoreCase(contrib - .getAttribute("contributor_role"))) - { - chairs.add(new String[] { givenName, surname }); - } - else if ("translator".equalsIgnoreCase(contrib - .getAttribute("contributor_role"))) - { - translators.add(new String[] { givenName, surname }); - } - else - { - authors.add(new String[] { givenName, surname }); + .getAttribute("contributor_role"))) { + editors.add(new String[] {givenName, surname}); + } else if ("chair".equalsIgnoreCase(contrib + .getAttribute("contributor_role"))) { + chairs.add(new String[] {givenName, surname}); + } else if ("translator".equalsIgnoreCase(contrib + .getAttribute("contributor_role"))) { + translators.add(new String[] {givenName, surname}); + } else { + authors.add(new String[] {givenName, surname}); } } } - if (authors.size() > 0) - { + if (authors.size() > 0) { List values = new LinkedList(); - for (String[] sArray : authors) - { + for (String[] sArray : authors) { values.add(new StringValue(sArray[1] + ", " + sArray[0])); } record.addField("authors", values); } - if (editors.size() > 0) - { + if (editors.size() > 0) { List values = new LinkedList(); - for (String[] sArray : editors) - { + for (String[] sArray : editors) { values.add(new StringValue(sArray[1] + ", " + sArray[0])); } record.addField("editors", values); } - if (translators.size() > 0) - { + if (translators.size() > 0) { List values = new LinkedList(); - for (String[] sArray : translators) - { + for (String[] sArray : translators) { values.add(new StringValue(sArray[1] + ", " + sArray[0])); } record.addField("translators", values); } - if (chairs.size() > 0) - { + if (chairs.size() > 0) { List values = new LinkedList(); - for (String[] sArray : chairs) - { + for (String[] sArray : chairs) { values.add(new StringValue(sArray[1] + ", " + sArray[0])); } record.addField("chairs", values); diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/DSpaceWorkspaceItemOutputGenerator.java b/dspace-api/src/main/java/org/dspace/submit/lookup/DSpaceWorkspaceItemOutputGenerator.java index 1c3f354596..13d57a303d 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/DSpaceWorkspaceItemOutputGenerator.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/DSpaceWorkspaceItemOutputGenerator.java @@ -7,12 +7,6 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.DataOutputSpec; -import gr.ekt.bte.core.OutputGenerator; -import gr.ekt.bte.core.Record; -import gr.ekt.bte.core.RecordSet; -import gr.ekt.bte.core.Value; - import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; @@ -22,6 +16,11 @@ import java.util.List; import java.util.Map; import java.util.Set; +import gr.ekt.bte.core.DataOutputSpec; +import gr.ekt.bte.core.OutputGenerator; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.RecordSet; +import gr.ekt.bte.core.Value; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.util.DCInput; @@ -48,11 +47,10 @@ import org.springframework.beans.factory.annotation.Autowired; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator -{ +public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator { private static Logger log = Logger - .getLogger(DSpaceWorkspaceItemOutputGenerator.class); + .getLogger(DSpaceWorkspaceItemOutputGenerator.class); protected Context context; @@ -78,40 +76,32 @@ public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator protected WorkspaceItemService workspaceItemService; @Override - public List generateOutput(RecordSet recordSet) - { + public List generateOutput(RecordSet recordSet) { log.info("BTE OutputGenerator started. Records to output: " - + recordSet.getRecords().size()); + + recordSet.getRecords().size()); // Printing debug message String totalString = ""; - for (Record record : recordSet.getRecords()) - { + for (Record record : recordSet.getRecords()) { totalString += SubmissionLookupUtils.getPrintableString(record) - + "\n"; + + "\n"; } log.debug("Records to output:\n" + totalString); witems = new ArrayList(); - for (Record rec : recordSet.getRecords()) - { - try - { + for (Record rec : recordSet.getRecords()) { + try { WorkspaceItem wi = workspaceItemService.create(context, collection, - true); + true); merge(formName, wi.getItem(), rec); witems.add(wi); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { log.error(e.getMessage(), e); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error(e.getMessage(), e); } @@ -121,111 +111,85 @@ public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator } @Override - public List generateOutput(RecordSet records, DataOutputSpec spec) - { + public List generateOutput(RecordSet records, DataOutputSpec spec) { return generateOutput(records); } - public List getWitems() - { + public List getWitems() { return witems; } - public void setContext(Context context) - { + public void setContext(Context context) { this.context = context; } - public void setFormName(String formName) - { + public void setFormName(String formName) { this.formName = formName; } - public void setDto(ItemSubmissionLookupDTO dto) - { + public void setDto(ItemSubmissionLookupDTO dto) { this.dto = dto; } - public void setOutputMap(Map outputMap) - { + public void setOutputMap(Map outputMap) { // Reverse the key-value pairs this.outputMap = new HashMap(); - for (String key : outputMap.keySet()) - { + for (String key : outputMap.keySet()) { this.outputMap.put(outputMap.get(key), key); } } - public void setCollection(Collection collection) - { + public void setCollection(Collection collection) { this.collection = collection; } - public void setExtraMetadataToKeep(List extraMetadataToKeep) - { + public void setExtraMetadataToKeep(List extraMetadataToKeep) { this.extraMetadataToKeep = extraMetadataToKeep; } // Methods - public void merge(String formName, Item item, Record record) - { - try - { + public void merge(String formName, Item item, Record record) { + try { Record itemLookup = record; Set addedMetadata = new HashSet(); - for (String field : itemLookup.getFields()) - { + for (String field : itemLookup.getFields()) { String metadata = getMetadata(formName, itemLookup, field); - if (StringUtils.isBlank(metadata)) - { + if (StringUtils.isBlank(metadata)) { continue; } if (itemService.getMetadataByMetadataString(item, metadata).size() == 0 - || addedMetadata.contains(metadata)) - { + || addedMetadata.contains(metadata)) { addedMetadata.add(metadata); String[] md = splitMetadata(metadata); - if (isValidMetadata(formName, md)) - { // if in extra metadata or in the spefific form + if (isValidMetadata(formName, md)) { // if in extra metadata or in the spefific form List values = itemLookup.getValues(field); - if (values != null && values.size() > 0) - { - if (isRepeatableMetadata(formName, md)) - { // if metadata is repeatable in form - for (Value value : values) - { + if (values != null && values.size() > 0) { + if (isRepeatableMetadata(formName, md)) { // if metadata is repeatable in form + for (Value value : values) { String[] splitValue = splitValue(value - .getAsString()); - if (splitValue[3] != null) - { + .getAsString()); + if (splitValue[3] != null) { itemService.addMetadata(context, item, md[0], md[1], md[2], - md[3], splitValue[0], - splitValue[1], - Integer.parseInt(splitValue[2])); - } - else - { + md[3], splitValue[0], + splitValue[1], + Integer.parseInt(splitValue[2])); + } else { itemService.addMetadata(context, item, md[0], md[1], md[2], - md[3], value.getAsString()); + md[3], value.getAsString()); } } - } - else - { + } else { String value = values.iterator().next() - .getAsString(); + .getAsString(); String[] splitValue = splitValue(value); - if (splitValue[3] != null) - { + if (splitValue[3] != null) { itemService.addMetadata(context, item, md[0], md[1], md[2], md[3], - splitValue[0], splitValue[1], - Integer.parseInt(splitValue[2])); - } - else - { + splitValue[0], splitValue[1], + Integer.parseInt(splitValue[2])); + } else { itemService.addMetadata(context, item, md[0], md[1], md[2], md[3], - value); + value); } } } @@ -233,41 +197,31 @@ public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator } } itemService.update(context, item); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error(e.getMessage(), e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { log.error(e.getMessage(), e); } } - protected String getMetadata(String formName, Record itemLookup, String name) - { + protected String getMetadata(String formName, Record itemLookup, String name) { String type = SubmissionLookupService.getType(itemLookup); String md = outputMap.get(type + "." + name); - if (StringUtils.isBlank(md)) - { + if (StringUtils.isBlank(md)) { md = outputMap.get(formName + "." + name); - if (StringUtils.isBlank(md)) - { + if (StringUtils.isBlank(md)) { md = outputMap.get(name); } } // KSTA:ToDo: Make this a modifier - if (md != null && md.contains("|")) - { + if (md != null && md.contains("|")) { String[] cond = md.trim().split("\\|"); - for (int idx = 1; idx < cond.length; idx++) - { + for (int idx = 1; idx < cond.length; idx++) { boolean temp = itemLookup.getFields().contains(cond[idx]); - if (temp) - { + if (temp) { return null; } } @@ -276,30 +230,23 @@ public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator return md; } - protected String[] splitMetadata(String metadata) - { + protected String[] splitMetadata(String metadata) { String[] mdSplit = new String[3]; - if (StringUtils.isNotBlank(metadata)) - { + if (StringUtils.isNotBlank(metadata)) { String tmpSplit[] = metadata.split("\\."); - if (tmpSplit.length == 4) - { + if (tmpSplit.length == 4) { mdSplit = new String[4]; mdSplit[0] = tmpSplit[0]; mdSplit[1] = tmpSplit[1]; mdSplit[2] = tmpSplit[2]; mdSplit[3] = tmpSplit[3]; - } - else if (tmpSplit.length == 3) - { + } else if (tmpSplit.length == 3) { mdSplit = new String[4]; mdSplit[0] = tmpSplit[0]; mdSplit[1] = tmpSplit[1]; mdSplit[2] = tmpSplit[2]; mdSplit[3] = null; - } - else if (tmpSplit.length == 2) - { + } else if (tmpSplit.length == 2) { mdSplit = new String[4]; mdSplit[0] = tmpSplit[0]; mdSplit[1] = tmpSplit[1]; @@ -310,90 +257,72 @@ public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator return mdSplit; } - protected boolean isValidMetadata(String formName, String[] md) - { - try - { + protected boolean isValidMetadata(String formName, String[] md) { + try { if (extraMetadataToKeep != null - && extraMetadataToKeep.contains(StringUtils.join( - Arrays.copyOfRange(md, 0, 3), "."))) - { + && extraMetadataToKeep.contains(StringUtils.join( + Arrays.copyOfRange(md, 0, 3), "."))) { return true; } return getDCInput(formName, md[0], md[1], md[2]) != null; - } - catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); } return false; } protected DCInput getDCInput(String formName, String schema, String element, - String qualifier) throws DCInputsReaderException - { - DCInputSet dcinputset = new DCInputsReader().getInputs(formName); - for (int idx = 0; idx < dcinputset.getNumberPages(); idx++) - { - for (DCInput dcinput : dcinputset.getPageRows(idx, true, true)) - { - if (dcinput.getSchema().equals(schema) + String qualifier) throws DCInputsReaderException { + List dcinputsets = new DCInputsReader().getInputsBySubmissionName(formName); + for (DCInputSet dcinputset : dcinputsets) { + for (DCInput[] dcrow : dcinputset.getFields()) { + for (DCInput dcinput : dcrow) { + if (dcinput.getSchema().equals(schema) && dcinput.getElement().equals(element) && ((dcinput.getQualifier() != null && dcinput - .getQualifier().equals(qualifier)) - || (dcinput.getQualifier() == null && qualifier == null))) - { - return dcinput; + .getQualifier().equals(qualifier)) + || (dcinput.getQualifier() == null && qualifier == null))) { + return dcinput; + } } } } return null; } - protected boolean isRepeatableMetadata(String formName, String[] md) - { - try - { + protected boolean isRepeatableMetadata(String formName, String[] md) { + try { DCInput dcinput = getDCInput(formName, md[0], md[1], md[2]); - if (dcinput != null) - { + if (dcinput != null) { return dcinput.isRepeatable(); } return true; - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); } return false; } - protected String[] splitValue(String value) - { + protected String[] splitValue(String value) { String[] splitted = value - .split(SubmissionLookupService.SEPARATOR_VALUE_REGEX); + .split(SubmissionLookupService.SEPARATOR_VALUE_REGEX); String[] result = new String[6]; result[0] = splitted[0]; result[2] = "-1"; result[3] = "-1"; result[4] = "-1"; - if (splitted.length > 1) - { + if (splitted.length > 1) { result[5] = "splitted"; - if (StringUtils.isNotBlank(splitted[1])) - { + if (StringUtils.isNotBlank(splitted[1])) { result[1] = splitted[1]; } - if (splitted.length > 2) - { + if (splitted.length > 2) { result[2] = String.valueOf(Integer.parseInt(splitted[2])); - if (splitted.length > 3) - { + if (splitted.length > 3) { result[3] = String.valueOf(Integer.parseInt(splitted[3])); - if (splitted.length > 4) - { + if (splitted.length > 4) { result[4] = String.valueOf(Integer - .parseInt(splitted[4])); + .parseInt(splitted[4])); } } } @@ -402,42 +331,33 @@ public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator } protected void makeSureMetadataExist(Context context, String schema, - String element, String qualifier) - { - try - { + String element, String qualifier) { + try { context.turnOffAuthorisationSystem(); boolean create = false; MetadataSchema mdschema = metadataSchemaService.find(context, schema); MetadataField mdfield = null; - if (mdschema == null) - { + if (mdschema == null) { mdschema = metadataSchemaService.create(context, schema, - SubmissionLookupService.SL_NAMESPACE_PREFIX + schema - ); + SubmissionLookupService.SL_NAMESPACE_PREFIX + schema + ); create = true; - } - else - { + } else { mdfield = metadataFieldService.findByElement(context, - mdschema, element, qualifier); + mdschema, element, qualifier); } - if (mdfield == null) - { + if (mdfield == null) { metadataFieldService.create(context, mdschema, element, qualifier, - "Campo utilizzato per la cache del provider submission-lookup: " - + schema); + "Campo utilizzato per la cache del provider submission-lookup: " + + schema); create = true; } - if (create) - { + if (create) { context.complete(); } context.restoreAuthSystemState(); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/FieldMergeModifier.java b/dspace-api/src/main/java/org/dspace/submit/lookup/FieldMergeModifier.java index 6352319f89..daae8e14e4 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/FieldMergeModifier.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/FieldMergeModifier.java @@ -8,44 +8,36 @@ package org.dspace.submit.lookup; +import java.util.List; +import java.util.Map; + import gr.ekt.bte.core.AbstractModifier; import gr.ekt.bte.core.MutableRecord; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.Value; -import java.util.List; -import java.util.Map; - /** * @author Andrea Bollini * @author Kostas Stamatis * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class FieldMergeModifier extends AbstractModifier -{ +public class FieldMergeModifier extends AbstractModifier { protected Map> mergeFieldMap; - public FieldMergeModifier() - { + public FieldMergeModifier() { super("FieldMergeModifier"); } @Override - public Record modify(MutableRecord rec) - { - if (mergeFieldMap != null) - { - for (String target_field : mergeFieldMap.keySet()) - { + public Record modify(MutableRecord rec) { + if (mergeFieldMap != null) { + for (String target_field : mergeFieldMap.keySet()) { List source_fields = mergeFieldMap.get(target_field); - for (String source_field : source_fields) - { + for (String source_field : source_fields) { List values = rec.getValues(source_field); - if (values != null && values.size() > 0) - { - for (Value value : values) - { + if (values != null && values.size() > 0) { + for (Value value : values) { rec.addValue(target_field, value); } } @@ -59,17 +51,14 @@ public class FieldMergeModifier extends AbstractModifier /** * @return the merge_field_map */ - public Map> getMergeFieldMap() - { + public Map> getMergeFieldMap() { return mergeFieldMap; } /** - * @param merge_field_map - * the merge_field_map to set + * @param merge_field_map the merge_field_map to set */ - public void setMergeFieldMap(Map> merge_field_map) - { + public void setMergeFieldMap(Map> merge_field_map) { this.mergeFieldMap = merge_field_map; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/LanguageCodeModifier.java b/dspace-api/src/main/java/org/dspace/submit/lookup/LanguageCodeModifier.java index ae25444a1f..94e885fbb9 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/LanguageCodeModifier.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/LanguageCodeModifier.java @@ -8,13 +8,6 @@ package org.dspace.submit.lookup; -import gr.ekt.bte.core.AbstractModifier; -import gr.ekt.bte.core.MutableRecord; -import gr.ekt.bte.core.Record; -import gr.ekt.bte.core.StringValue; -import gr.ekt.bte.core.Value; -import org.springframework.beans.factory.InitializingBean; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -22,49 +15,46 @@ import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; +import gr.ekt.bte.core.AbstractModifier; +import gr.ekt.bte.core.MutableRecord; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.StringValue; +import gr.ekt.bte.core.Value; +import org.springframework.beans.factory.InitializingBean; + /** * Modifier to covert ISO 639-2 alpha-3 code to ISO 639-1 alpha-2 code * * @author Keiji Suzuki */ -public class LanguageCodeModifier extends AbstractModifier implements InitializingBean -{ +public class LanguageCodeModifier extends AbstractModifier implements InitializingBean { protected static Map lang3to2 = null; @Override - public void afterPropertiesSet() throws Exception - { + public void afterPropertiesSet() throws Exception { lang3to2 = new HashMap(); - for (Locale locale : Locale.getAvailableLocales()) - { - try - { + for (Locale locale : Locale.getAvailableLocales()) { + try { lang3to2.put(locale.getISO3Language(), locale.getLanguage()); - } - catch (MissingResourceException e) - { + } catch (MissingResourceException e) { continue; } } - } + } - public LanguageCodeModifier() - { + public LanguageCodeModifier() { super("LanguageCodeModifier"); } @Override - public Record modify(MutableRecord rec) - { + public Record modify(MutableRecord rec) { List old_values = rec.getValues("language"); - if (old_values == null || old_values.size() == 0) - { + if (old_values == null || old_values.size() == 0) { return rec; } List new_values = new ArrayList(); - for (Value value : old_values) - { + for (Value value : old_values) { String lang3 = value.getAsString(); String lang2 = lang3.length() == 3 ? getLang2(lang3) : lang3; new_values.add(new StringValue(lang2)); @@ -78,15 +68,11 @@ public class LanguageCodeModifier extends AbstractModifier implements Initializi /** * Covert ISO 639-2 alpha-3 code to ISO 639-1 alpha-2 code * - * @param lang3 - * ISO 639-1 alpha-3 language code - * + * @param lang3 ISO 639-1 alpha-3 language code * @return String ISO 639-1 alpha-2 language code ("other" if code is not alpha-2) - * */ - protected String getLang2(String lang3) - { - return lang3to2.containsKey(lang3) ? lang3to2.get(lang3) : "other"; + protected String getLang2(String lang3) { + return lang3to2.containsKey(lang3) ? lang3to2.get(lang3) : "other"; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/LookupProvidersCheck.java b/dspace-api/src/main/java/org/dspace/submit/lookup/LookupProvidersCheck.java index 5372b345ca..fd24f62f3e 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/LookupProvidersCheck.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/LookupProvidersCheck.java @@ -16,29 +16,24 @@ import java.util.List; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class LookupProvidersCheck -{ +public class LookupProvidersCheck { private List providersOk = new ArrayList(); private List providersErr = new ArrayList(); - public List getProvidersOk() - { + public List getProvidersOk() { return providersOk; } - public void setProvidersOk(List providersOk) - { + public void setProvidersOk(List providersOk) { this.providersOk = providersOk; } - public List getProvidersErr() - { + public List getProvidersErr() { return providersErr; } - public void setProvidersErr(List providersErr) - { + public void setProvidersErr(List providersErr) { this.providersErr = providersErr; } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/MapConverterModifier.java b/dspace-api/src/main/java/org/dspace/submit/lookup/MapConverterModifier.java index 07e22e0c21..b4885e9271 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/MapConverterModifier.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/MapConverterModifier.java @@ -16,14 +16,13 @@ import java.util.List; import java.util.Map; import java.util.Properties; -import org.apache.commons.lang.StringUtils; -import org.dspace.services.ConfigurationService; - import gr.ekt.bte.core.AbstractModifier; import gr.ekt.bte.core.MutableRecord; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.StringValue; import gr.ekt.bte.core.Value; +import org.apache.commons.lang.StringUtils; +import org.dspace.services.ConfigurationService; /** * @author Andrea Bollini @@ -31,15 +30,14 @@ import gr.ekt.bte.core.Value; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class MapConverterModifier extends AbstractModifier -{ +public class MapConverterModifier extends AbstractModifier { protected String mappingFile; //The properties absolute filename - + protected String converterNameFile; //The properties filename protected ConfigurationService configurationService; - + protected Map mapping; protected String defaultValue = ""; @@ -51,138 +49,110 @@ public class MapConverterModifier extends AbstractModifier public final String REGEX_PREFIX = "regex."; public void init() { - this.mappingFile = configurationService.getProperty("dspace.dir") + File.separator + "config" + File.separator + "crosswalks" + File.separator + converterNameFile; - + this.mappingFile = configurationService.getProperty( + "dspace.dir") + File.separator + "config" + File.separator + "crosswalks" + File.separator + + converterNameFile; + this.mapping = new HashMap(); - + FileInputStream fis = null; - try - { + try { fis = new FileInputStream(new File(mappingFile)); Properties mapConfig = new Properties(); mapConfig.load(fis); fis.close(); - for (Object key : mapConfig.keySet()) - { - String keyS = (String)key; - if (keyS.startsWith(REGEX_PREFIX)) - { + for (Object key : mapConfig.keySet()) { + String keyS = (String) key; + if (keyS.startsWith(REGEX_PREFIX)) { String regex = keyS.substring(REGEX_PREFIX.length()); String regReplace = mapping.get(keyS); - if (regReplace == null) - { + if (regReplace == null) { regReplace = ""; - } - else if (regReplace.equalsIgnoreCase("@ident@")) - { + } else if (regReplace.equalsIgnoreCase("@ident@")) { regReplace = "$0"; } - regexConfig.put(regex,regReplace); + regexConfig.put(regex, regReplace); } - if (mapConfig.getProperty(keyS) != null) + if (mapConfig.getProperty(keyS) != null) { mapping.put(keyS, mapConfig.getProperty(keyS)); - else + } else { mapping.put(keyS, ""); - } - } - catch (Exception e) - { - throw new IllegalArgumentException("", e); - } - finally - { - if (fis != null) - { - try - { - fis.close(); } - catch (IOException ioe) - { + } + } catch (Exception e) { + throw new IllegalArgumentException("", e); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException ioe) { // ... } } } - for (String keyS : mapping.keySet()) - { - if (keyS.startsWith(REGEX_PREFIX)) - { + for (String keyS : mapping.keySet()) { + if (keyS.startsWith(REGEX_PREFIX)) { String regex = keyS.substring(REGEX_PREFIX.length()); String regReplace = mapping.get(keyS); - if (regReplace == null) - { + if (regReplace == null) { regReplace = ""; - } - else if (regReplace.equalsIgnoreCase("@ident@")) - { + } else if (regReplace.equalsIgnoreCase("@ident@")) { regReplace = "$0"; } - regexConfig.put(regex,regReplace); + regexConfig.put(regex, regReplace); } } } + /** - * @param name - * Name of file to load ArXiv data from. + * @param name Name of file to load ArXiv data from. */ - public MapConverterModifier(String name) - { + public MapConverterModifier(String name) { super(name); } /* * (non-Javadoc) - * + * * @see * gr.ekt.bte.core.AbstractModifier#modify(gr.ekt.bte.core.MutableRecord) */ @Override - public Record modify(MutableRecord record) - { - if (mapping != null && fieldKeys != null) - { - for (String key : fieldKeys) - { + public Record modify(MutableRecord record) { + if (mapping != null && fieldKeys != null) { + for (String key : fieldKeys) { List values = record.getValues(key); - if (values == null) + if (values == null) { continue; + } List newValues = new ArrayList(); - for (Value value : values) - { + for (Value value : values) { String stringValue = value.getAsString(); String tmp = ""; - if (mapping.containsKey(stringValue)) - { + if (mapping.containsKey(stringValue)) { tmp = mapping.get(stringValue); - } - else - { + } else { tmp = defaultValue; - for (String regex : regexConfig.keySet()) - { + for (String regex : regexConfig.keySet()) { if (stringValue != null - && stringValue.matches(regex)) - { + && stringValue.matches(regex)) { tmp = stringValue.replaceAll(regex, - regexConfig.get(regex)); + regexConfig.get(regex)); } } } - if ("@@ident@@".equals(tmp)) - { + if ("@@ident@@".equals(tmp)) { newValues.add(new StringValue(stringValue)); - } - else if (StringUtils.isNotBlank(tmp)) - { + } else if (StringUtils.isNotBlank(tmp)) { newValues.add(new StringValue(tmp)); - } - else + } else { newValues.add(new StringValue(stringValue)); + } } record.updateField(key, newValues); @@ -193,22 +163,19 @@ public class MapConverterModifier extends AbstractModifier } - public void setFieldKeys(List fieldKeys) - { + public void setFieldKeys(List fieldKeys) { this.fieldKeys = fieldKeys; } - public void setDefaultValue(String defaultValue) - { + public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; } - - public void setConverterNameFile(String converterNameFile) - { + + public void setConverterNameFile(String converterNameFile) { this.converterNameFile = converterNameFile; } - public void setConfigurationService(ConfigurationService configurationService) - { + + public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/MultipleSubmissionLookupDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/MultipleSubmissionLookupDataLoader.java index 307a0b1c2d..3ef5f65f80 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/MultipleSubmissionLookupDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/MultipleSubmissionLookupDataLoader.java @@ -14,9 +14,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.log4j.Logger; -import org.dspace.core.Context; - import gr.ekt.bte.core.DataLoader; import gr.ekt.bte.core.DataLoadingSpec; import gr.ekt.bte.core.Record; @@ -24,6 +21,8 @@ import gr.ekt.bte.core.RecordSet; import gr.ekt.bte.core.StringValue; import gr.ekt.bte.dataloader.FileDataLoader; import gr.ekt.bte.exceptions.MalformedSourceException; +import org.apache.log4j.Logger; +import org.dspace.core.Context; /** * @author Andrea Bollini @@ -31,11 +30,10 @@ import gr.ekt.bte.exceptions.MalformedSourceException; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class MultipleSubmissionLookupDataLoader implements DataLoader -{ +public class MultipleSubmissionLookupDataLoader implements DataLoader { private static Logger log = Logger - .getLogger(MultipleSubmissionLookupDataLoader.class); + .getLogger(MultipleSubmissionLookupDataLoader.class); protected final String NOT_FOUND_DOI = "NOT-FOUND-DOI"; @@ -44,10 +42,10 @@ public class MultipleSubmissionLookupDataLoader implements DataLoader // Depending on these values, the multiple data loader loads data from the // appropriate providers Map> identifiers = null; // Searching by identifiers - // (DOI ...) + // (DOI ...) Map> searchTerms = null; // Searching by author, title, - // date + // date String filename = null; // Uploading file @@ -55,31 +53,27 @@ public class MultipleSubmissionLookupDataLoader implements DataLoader /* * (non-Javadoc) - * + * * @see gr.ekt.bte.core.DataLoader#getRecords() */ @Override - public RecordSet getRecords() throws MalformedSourceException - { + public RecordSet getRecords() throws MalformedSourceException { RecordSet recordSet = new RecordSet(); // KSTA:ToDo: Support timeout (problematic) providers // List timeoutProviders = new ArrayList(); - for (String providerName : filterProviders().keySet()) - { + for (String providerName : filterProviders().keySet()) { DataLoader provider = dataloadersMap.get(providerName); RecordSet subRecordSet = provider.getRecords(); recordSet.addAll(subRecordSet); // Add in each record the provider name... a new provider doesn't // need to know about it! - for (Record record : subRecordSet.getRecords()) - { - if (record.isMutable()) - { + for (Record record : subRecordSet.getRecords()) { + if (record.isMutable()) { record.makeMutable().addValue( - SubmissionLookupService.PROVIDER_NAME_FIELD, - new StringValue(providerName)); + SubmissionLookupService.PROVIDER_NAME_FIELD, + new StringValue(providerName)); } } } @@ -88,40 +82,34 @@ public class MultipleSubmissionLookupDataLoader implements DataLoader // for each publication in the record set, if it has a DOI, try to find // extra pubs from the other providers if (searchTerms != null - || (identifiers != null && !identifiers - .containsKey(SubmissionLookupDataLoader.DOI))) - { // Extend + || (identifiers != null && !identifiers + .containsKey(SubmissionLookupDataLoader.DOI))) { // Extend Map> provider2foundDOIs = new HashMap>(); List foundDOIs = new ArrayList(); - for (Record publication : recordSet.getRecords()) - { + for (Record publication : recordSet.getRecords()) { String providerName = SubmissionLookupUtils.getFirstValue( - publication, - SubmissionLookupService.PROVIDER_NAME_FIELD); + publication, + SubmissionLookupService.PROVIDER_NAME_FIELD); String doi = null; if (publication.getValues(SubmissionLookupDataLoader.DOI) != null - && publication - .getValues(SubmissionLookupDataLoader.DOI) - .size() > 0) + && publication + .getValues(SubmissionLookupDataLoader.DOI) + .size() > 0) { doi = publication.getValues(SubmissionLookupDataLoader.DOI) - .iterator().next().getAsString(); - if (doi == null) - { - doi = NOT_FOUND_DOI; + .iterator().next().getAsString(); } - else - { + if (doi == null) { + doi = NOT_FOUND_DOI; + } else { doi = SubmissionLookupUtils.normalizeDOI(doi); - if (!foundDOIs.contains(doi)) - { + if (!foundDOIs.contains(doi)) { foundDOIs.add(doi); } Set tmp = provider2foundDOIs.get(providerName); - if (tmp == null) - { + if (tmp == null) { tmp = new HashSet(); provider2foundDOIs.put(providerName, tmp); } @@ -129,12 +117,10 @@ public class MultipleSubmissionLookupDataLoader implements DataLoader } } - for (String providerName : dataloadersMap.keySet()) - { + for (String providerName : dataloadersMap.keySet()) { DataLoader genProvider = dataloadersMap.get(providerName); - if (!(genProvider instanceof SubmissionLookupDataLoader)) - { + if (!(genProvider instanceof SubmissionLookupDataLoader)) { continue; } @@ -142,8 +128,7 @@ public class MultipleSubmissionLookupDataLoader implements DataLoader // Provider must support DOI if (!provider.getSupportedIdentifiers().contains( - SubmissionLookupDataLoader.DOI)) - { + SubmissionLookupDataLoader.DOI)) { continue; } @@ -153,60 +138,49 @@ public class MultipleSubmissionLookupDataLoader implements DataLoader // } Set doiToSearch = new HashSet(); Set alreadyFoundDOIs = provider2foundDOIs - .get(providerName); - for (String doi : foundDOIs) - { + .get(providerName); + for (String doi : foundDOIs) { if (alreadyFoundDOIs == null - || !alreadyFoundDOIs.contains(doi)) - { + || !alreadyFoundDOIs.contains(doi)) { doiToSearch.add(doi); } } List pPublications = null; Context context = null; - try - { - if (doiToSearch.size() > 0) - { + try { + if (doiToSearch.size() > 0) { context = new Context(); pPublications = provider.getByDOIs(context, doiToSearch); } - } - catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); - } - finally { - if(context!=null && context.isValid()) { + } finally { + if (context != null && context.isValid()) { context.abort(); } } - if (pPublications != null) - { - for (Record rec : pPublications) - { + if (pPublications != null) { + for (Record rec : pPublications) { recordSet.addRecord(rec); - if (rec.isMutable()) - { + if (rec.isMutable()) { rec.makeMutable().addValue( - SubmissionLookupService.PROVIDER_NAME_FIELD, - new StringValue(providerName)); + SubmissionLookupService.PROVIDER_NAME_FIELD, + new StringValue(providerName)); } } - + } } } log.info("BTE DataLoader finished. Items loaded: " - + recordSet.getRecords().size()); + + recordSet.getRecords().size()); // Printing debug message String totalString = ""; - for (Record record : recordSet.getRecords()) - { + for (Record record : recordSet.getRecords()) { totalString += SubmissionLookupUtils.getPrintableString(record) - + "\n"; + + "\n"; } log.debug("Records loaded:\n" + totalString); @@ -215,123 +189,99 @@ public class MultipleSubmissionLookupDataLoader implements DataLoader /* * (non-Javadoc) - * + * * @see * gr.ekt.bte.core.DataLoader#getRecords(gr.ekt.bte.core.DataLoadingSpec) */ @Override public RecordSet getRecords(DataLoadingSpec loadingSpec) - throws MalformedSourceException - { + throws MalformedSourceException { - if (loadingSpec.getOffset() > 0) // Identify the end of loading + // Identify the end of loading + if (loadingSpec.getOffset() > 0) { return new RecordSet(); + } return getRecords(); } - public Map getProvidersMap() - { + public Map getProvidersMap() { return dataloadersMap; } - public void setDataloadersMap(Map providersMap) - { + public void setDataloadersMap(Map providersMap) { this.dataloadersMap = providersMap; } - public void setIdentifiers(Map> identifiers) - { + public void setIdentifiers(Map> identifiers) { this.identifiers = identifiers; this.filename = null; this.searchTerms = null; - if (dataloadersMap != null) - { - for (String providerName : dataloadersMap.keySet()) - { + if (dataloadersMap != null) { + for (String providerName : dataloadersMap.keySet()) { DataLoader provider = dataloadersMap.get(providerName); - if (provider instanceof NetworkSubmissionLookupDataLoader) - { + if (provider instanceof NetworkSubmissionLookupDataLoader) { ((NetworkSubmissionLookupDataLoader) provider) - .setIdentifiers(identifiers); + .setIdentifiers(identifiers); } } } } - public void setSearchTerms(Map> searchTerms) - { + public void setSearchTerms(Map> searchTerms) { this.searchTerms = searchTerms; this.identifiers = null; this.filename = null; - if (dataloadersMap != null) - { - for (String providerName : dataloadersMap.keySet()) - { + if (dataloadersMap != null) { + for (String providerName : dataloadersMap.keySet()) { DataLoader provider = dataloadersMap.get(providerName); - if (provider instanceof NetworkSubmissionLookupDataLoader) - { + if (provider instanceof NetworkSubmissionLookupDataLoader) { ((NetworkSubmissionLookupDataLoader) provider) - .setSearchTerms(searchTerms); + .setSearchTerms(searchTerms); } } } } - public void setFile(String filename, String type) - { + public void setFile(String filename, String type) { this.filename = filename; this.type = type; this.identifiers = null; this.searchTerms = null; - if (dataloadersMap != null) - { - for (String providerName : dataloadersMap.keySet()) - { + if (dataloadersMap != null) { + for (String providerName : dataloadersMap.keySet()) { DataLoader provider = dataloadersMap.get(providerName); - if (provider instanceof FileDataLoader) - { + if (provider instanceof FileDataLoader) { ((FileDataLoader) provider).setFilename(filename); } } } } - public Map filterProviders() - { + public Map filterProviders() { Map result = new HashMap(); - for (String providerName : dataloadersMap.keySet()) - { + for (String providerName : dataloadersMap.keySet()) { DataLoader dataLoader = dataloadersMap.get(providerName); - if (searchTerms != null && identifiers == null && filename == null) - { - if (dataLoader instanceof SubmissionLookupDataLoader - && ((SubmissionLookupDataLoader) dataLoader) - .isSearchProvider()) - { + if (searchTerms != null && identifiers == null && filename == null) { + if (dataLoader instanceof SubmissionLookupDataLoader && + ((SubmissionLookupDataLoader) dataLoader).isSearchProvider()) { result.put(providerName, dataLoader); } - } - else if (searchTerms == null && identifiers != null - && filename == null) - { - if (dataLoader instanceof SubmissionLookupDataLoader) - { + } else if (searchTerms == null && identifiers != null && filename == null) { + if (dataLoader instanceof SubmissionLookupDataLoader) { result.put(providerName, dataLoader); } - } - else if (searchTerms == null && identifiers == null - && filename != null) - { - if (dataLoader instanceof FileDataLoader) - { - if (providerName.endsWith(type)) // add only the one that we - // are interested in + } else if (searchTerms == null && identifiers == null + && filename != null) { + if (dataLoader instanceof FileDataLoader) { + // add only the one that we are interested in + if (providerName.endsWith(type)) { result.put(providerName, dataLoader); + } } } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/NetworkSubmissionLookupDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/NetworkSubmissionLookupDataLoader.java index 7db7011ffa..43e632e59f 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/NetworkSubmissionLookupDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/NetworkSubmissionLookupDataLoader.java @@ -7,15 +7,18 @@ */ package org.dspace.submit.lookup; +import java.io.IOException; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + import gr.ekt.bte.core.DataLoadingSpec; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.RecordSet; import gr.ekt.bte.core.Value; import gr.ekt.bte.exceptions.MalformedSourceException; - -import java.io.IOException; -import java.util.*; - import org.apache.commons.lang.StringUtils; import org.apache.http.HttpException; import org.dspace.core.Context; @@ -27,22 +30,20 @@ import org.dspace.core.Context; * @author Panagiotis Koutsourakis */ public abstract class NetworkSubmissionLookupDataLoader implements - SubmissionLookupDataLoader -{ + SubmissionLookupDataLoader { Map> identifiers; // Searching by identifiers (DOI ...) Map> searchTerms; // Searching by author, title, date Map fieldMap; // mapping between service fields and local - // intermediate fields + // intermediate fields String providerName; @Override public List getByDOIs(Context context, Set doiToSearch) - throws HttpException, IOException - { + throws HttpException, IOException { Map> keys = new HashMap>(); keys.put(DOI, doiToSearch); @@ -52,47 +53,36 @@ public abstract class NetworkSubmissionLookupDataLoader implements // BTE Data Loader interface methods @Override - public RecordSet getRecords() throws MalformedSourceException - { + public RecordSet getRecords() throws MalformedSourceException { RecordSet recordSet = new RecordSet(); List results = null; - try - { - if (getIdentifiers() != null) - { // Search by identifiers + try { + if (getIdentifiers() != null) { // Search by identifiers results = getByIdentifier(null, getIdentifiers()); - } - else - { + } else { String title = getSearchTerms().get("title") != null ? getSearchTerms() - .get("title").iterator().next() - : null; + .get("title").iterator().next() + : null; String authors = getSearchTerms().get("authors") != null ? getSearchTerms() - .get("authors").iterator().next() - : null; + .get("authors").iterator().next() + : null; String year = getSearchTerms().get("year") != null ? getSearchTerms() - .get("year").iterator().next() - : String.valueOf(Calendar.getInstance().get(Calendar.YEAR)); + .get("year").iterator().next() + : String.valueOf(Calendar.getInstance().get(Calendar.YEAR)); int yearInt = Integer.parseInt(year); results = search(null, title, authors, yearInt); } - } - catch (HttpException e) - { + } catch (HttpException e) { e.printStackTrace(); - } - catch (IOException e) - { + } catch (IOException e) { e.printStackTrace(); } - if (results != null) - { - for (Record record : results) - { + if (results != null) { + for (Record record : results) { recordSet.addRecord(record); } } @@ -102,68 +92,53 @@ public abstract class NetworkSubmissionLookupDataLoader implements @Override public RecordSet getRecords(DataLoadingSpec arg0) - throws MalformedSourceException - { + throws MalformedSourceException { return getRecords(); } - public Map> getIdentifiers() - { + public Map> getIdentifiers() { return identifiers; } - public void setIdentifiers(Map> identifiers) - { + public void setIdentifiers(Map> identifiers) { this.identifiers = identifiers; } - public Map> getSearchTerms() - { + public Map> getSearchTerms() { return searchTerms; } - public void setSearchTerms(Map> searchTerms) - { + public void setSearchTerms(Map> searchTerms) { this.searchTerms = searchTerms; } - public Map getFieldMap() - { + public Map getFieldMap() { return fieldMap; } - public void setFieldMap(Map fieldMap) - { + public void setFieldMap(Map fieldMap) { this.fieldMap = fieldMap; } - public void setProviderName(String providerName) - { + public void setProviderName(String providerName) { this.providerName = providerName; } - public Record convertFields(Record publication) - { - for (String fieldName : fieldMap.keySet()) - { + public Record convertFields(Record publication) { + for (String fieldName : fieldMap.keySet()) { String md = null; - if (fieldMap != null) - { + if (fieldMap != null) { md = this.fieldMap.get(fieldName); } - if (StringUtils.isBlank(md)) - { + if (StringUtils.isBlank(md)) { continue; - } - else - { + } else { md = md.trim(); } - if (publication.isMutable()) - { + if (publication.isMutable()) { List values = publication.getValues(fieldName); publication.makeMutable().removeField(fieldName); publication.makeMutable().addField(md, values); diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedFileDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedFileDataLoader.java index fd617209c2..e8213820b6 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedFileDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedFileDataLoader.java @@ -8,13 +8,6 @@ package org.dspace.submit.lookup; -import gr.ekt.bte.core.DataLoadingSpec; -import gr.ekt.bte.core.Record; -import gr.ekt.bte.core.RecordSet; -import gr.ekt.bte.core.Value; -import gr.ekt.bte.dataloader.FileDataLoader; -import gr.ekt.bte.exceptions.MalformedSourceException; - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -22,11 +15,16 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import gr.ekt.bte.core.DataLoadingSpec; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.RecordSet; +import gr.ekt.bte.core.Value; +import gr.ekt.bte.dataloader.FileDataLoader; +import gr.ekt.bte.exceptions.MalformedSourceException; import org.apache.commons.lang.StringUtils; import org.dspace.app.util.XMLUtils; import org.w3c.dom.Document; @@ -39,45 +37,39 @@ import org.xml.sax.SAXException; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class PubmedFileDataLoader extends FileDataLoader -{ +public class PubmedFileDataLoader extends FileDataLoader { Map fieldMap; // mapping between service fields and local - // intermediate fields + // intermediate fields /** - * + * */ - public PubmedFileDataLoader() - { + public PubmedFileDataLoader() { } /** - * @param filename - * Name of file to load CiNii data from. + * @param filename Name of file to load CiNii data from. */ - public PubmedFileDataLoader(String filename) - { + public PubmedFileDataLoader(String filename) { super(filename); } /* * {@see gr.ekt.bte.core.DataLoader#getRecords()} * - * @throws MalformedSourceException + * @throws MalformedSourceException */ @Override - public RecordSet getRecords() throws MalformedSourceException - { + public RecordSet getRecords() throws MalformedSourceException { RecordSet recordSet = new RecordSet(); - try - { + try { InputStream inputStream = new FileInputStream(new File(filename)); DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -87,36 +79,24 @@ public class PubmedFileDataLoader extends FileDataLoader Element xmlRoot = inDoc.getDocumentElement(); List pubArticles = XMLUtils.getElementList(xmlRoot, - "PubmedArticle"); + "PubmedArticle"); - for (Element xmlArticle : pubArticles) - { + for (Element xmlArticle : pubArticles) { Record record = null; - try - { + try { record = PubmedUtils.convertPubmedDomToRecord(xmlArticle); recordSet.addRecord(convertFields(record)); - } - catch (Exception e) - { + } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { e.printStackTrace(); - } - catch (ParserConfigurationException e) - { + } catch (ParserConfigurationException e) { e.printStackTrace(); - } - catch (SAXException e) - { + } catch (SAXException e) { e.printStackTrace(); - } - catch (IOException e) - { + } catch (IOException e) { e.printStackTrace(); } @@ -126,42 +106,33 @@ public class PubmedFileDataLoader extends FileDataLoader /* * (non-Javadoc) - * + * * @see * gr.ekt.bte.core.DataLoader#getRecords(gr.ekt.bte.core.DataLoadingSpec) */ @Override public RecordSet getRecords(DataLoadingSpec spec) - throws MalformedSourceException - { - if (spec.getOffset() > 0) - { + throws MalformedSourceException { + if (spec.getOffset() > 0) { return new RecordSet(); } return getRecords(); } - public Record convertFields(Record publication) - { - for (String fieldName : fieldMap.keySet()) - { + public Record convertFields(Record publication) { + for (String fieldName : fieldMap.keySet()) { String md = null; - if (fieldMap != null) - { + if (fieldMap != null) { md = this.fieldMap.get(fieldName); } - if (StringUtils.isBlank(md)) - { + if (StringUtils.isBlank(md)) { continue; - } - else - { + } else { md = md.trim(); } - if (publication.isMutable()) - { + if (publication.isMutable()) { List values = publication.getValues(fieldName); publication.makeMutable().removeField(fieldName); publication.makeMutable().addField(md, values); @@ -171,8 +142,7 @@ public class PubmedFileDataLoader extends FileDataLoader return publication; } - public void setFieldMap(Map fieldMap) - { + public void setFieldMap(Map fieldMap) { this.fieldMap = fieldMap; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedOnlineDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedOnlineDataLoader.java index 194eb0a9fe..e78fd67405 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedOnlineDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedOnlineDataLoader.java @@ -7,16 +7,15 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; - import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.http.HttpException; +import gr.ekt.bte.core.Record; +import org.apache.http.HttpException; import org.apache.log4j.Logger; import org.dspace.core.Context; import org.dspace.core.LogManager; @@ -27,92 +26,73 @@ import org.dspace.core.LogManager; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class PubmedOnlineDataLoader extends NetworkSubmissionLookupDataLoader -{ +public class PubmedOnlineDataLoader extends NetworkSubmissionLookupDataLoader { protected boolean searchProvider = true; private static final Logger log = Logger.getLogger(PubmedOnlineDataLoader.class); protected PubmedService pubmedService = new PubmedService(); - public void setPubmedService(PubmedService pubmedService) - { + public void setPubmedService(PubmedService pubmedService) { this.pubmedService = pubmedService; } @Override - public List getSupportedIdentifiers() - { - return Arrays.asList(new String[] { PUBMED, DOI }); + public List getSupportedIdentifiers() { + return Arrays.asList(new String[] {PUBMED, DOI}); } - public void setSearchProvider(boolean searchProvider) - { + public void setSearchProvider(boolean searchProvider) { this.searchProvider = searchProvider; } @Override - public boolean isSearchProvider() - { + public boolean isSearchProvider() { return searchProvider; } @Override public List getByIdentifier(Context context, - Map> keys) throws HttpException, IOException - { + Map> keys) throws HttpException, IOException { Set pmids = keys != null ? keys.get(PUBMED) : null; Set dois = keys != null ? keys.get(DOI) : null; List results = new ArrayList(); if (pmids != null && pmids.size() > 0 - && (dois == null || dois.size() == 0)) - { - for (String pmid : pmids) - { + && (dois == null || dois.size() == 0)) { + for (String pmid : pmids) { Record p = null; - try - { + try { p = pubmedService.getByPubmedID(pmid); - } - catch (Exception e) - { + } catch (Exception e) { log.error(LogManager.getHeader(context, "getByIdentifier", - "pmid=" + pmid), e); + "pmid=" + pmid), e); } - if (p != null) + if (p != null) { results.add(convertFields(p)); + } } - } - else if (dois != null && dois.size() > 0 - && (pmids == null || pmids.size() == 0)) - { + } else if (dois != null && dois.size() > 0 + && (pmids == null || pmids.size() == 0)) { StringBuffer query = new StringBuffer(); - for (String d : dois) - { - if (query.length() > 0) - { + for (String d : dois) { + if (query.length() > 0) { query.append(" OR "); } query.append(d).append("[AI]"); } List pubmedResults = pubmedService.search(query.toString()); - for (Record p : pubmedResults) - { + for (Record p : pubmedResults) { results.add(convertFields(p)); } - } - else if (dois != null && dois.size() > 0 && pmids != null - && pmids.size() > 0) - { + } else if (dois != null && dois.size() > 0 && pmids != null + && pmids.size() > 0) { // EKT:ToDo: support list of dois and pmids in the search method of // pubmedService List pubmedResults = pubmedService.search(dois.iterator() - .next(), pmids.iterator().next()); - if (pubmedResults != null) - { - for (Record p : pubmedResults) - { + .next(), pmids.iterator().next()); + if (pubmedResults != null) { + for (Record p : pubmedResults) { results.add(convertFields(p)); } } @@ -123,14 +103,11 @@ public class PubmedOnlineDataLoader extends NetworkSubmissionLookupDataLoader @Override public List search(Context context, String title, String author, - int year) throws HttpException, IOException - { + int year) throws HttpException, IOException { List pubmedResults = pubmedService.search(title, author, year); List results = new ArrayList(); - if (pubmedResults != null) - { - for (Record p : pubmedResults) - { + if (pubmedResults != null) { + for (Record p : pubmedResults) { results.add(convertFields(p)); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedService.java b/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedService.java index c343eaa674..2bbb2af8bf 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedService.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedService.java @@ -7,8 +7,6 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -16,11 +14,11 @@ import java.io.InputStream; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import gr.ekt.bte.core.Record; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpException; import org.apache.http.HttpResponse; @@ -44,71 +42,62 @@ import org.xml.sax.SAXException; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class PubmedService -{ +public class PubmedService { private static final Logger log = Logger.getLogger(PubmedService.class); protected int timeout = 1000; - public void setTimeout(int timeout) - { + public void setTimeout(int timeout) { this.timeout = timeout; } public Record getByPubmedID(String pubmedid) throws HttpException, - IOException, ParserConfigurationException, SAXException - { + IOException, ParserConfigurationException, SAXException { List ids = new ArrayList(); ids.add(pubmedid.trim()); List items = getByPubmedIDs(ids); - if (items != null && items.size() > 0) - { + if (items != null && items.size() > 0) { return items.get(0); } return null; } public List search(String title, String author, int year) - throws HttpException, IOException - { + throws HttpException, IOException { StringBuffer query = new StringBuffer(); - if (StringUtils.isNotBlank(title)) - { + if (StringUtils.isNotBlank(title)) { query.append("((").append(title).append("[TI]) OR ("); // [TI] does not always work, book chapter title query.append("(").append(title).append("[book]))"); } - if (StringUtils.isNotBlank(author)) - { + if (StringUtils.isNotBlank(author)) { // [FAU] - if (query.length() > 0) + if (query.length() > 0) { query.append(" AND "); + } query.append("(").append(author).append("[AU])"); } - if (year != -1) - { + if (year != -1) { // [DP] - if (query.length() > 0) + if (query.length() > 0) { query.append(" AND "); + } query.append(year).append("[DP]"); } return search(query.toString()); } - public List search(String query) throws IOException, HttpException - { + public List search(String query) throws IOException, HttpException { List results = new ArrayList<>(); - if (!ConfigurationManager.getBooleanProperty(SubmissionLookupService.CFG_MODULE, "remoteservice.demo")) - { + if (!ConfigurationManager.getBooleanProperty(SubmissionLookupService.CFG_MODULE, "remoteservice.demo")) { HttpGet method = null; - try - { + try { HttpClient client = new DefaultHttpClient(); client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout); URIBuilder uriBuilder = new URIBuilder( - "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"); + "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"); uriBuilder.addParameter("db", "pubmed"); uriBuilder.addParameter("datetype", "edat"); uriBuilder.addParameter("retmax", "10"); @@ -120,64 +109,50 @@ public class PubmedService StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); - if (statusCode != HttpStatus.SC_OK) - { + if (statusCode != HttpStatus.SC_OK) { throw new RuntimeException("WS call failed: " - + statusLine); + + statusLine); } DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); DocumentBuilder builder; - try - { + try { builder = factory.newDocumentBuilder(); Document inDoc = builder.parse(response.getEntity().getContent()); Element xmlRoot = inDoc.getDocumentElement(); Element idList = XMLUtils.getSingleElement(xmlRoot, - "IdList"); + "IdList"); List pubmedIDs = XMLUtils.getElementValueList( - idList, "Id"); + idList, "Id"); results = getByPubmedIDs(pubmedIDs); - } - catch (ParserConfigurationException e1) - { + } catch (ParserConfigurationException e1) { + log.error(e1.getMessage(), e1); + } catch (SAXException e1) { log.error(e1.getMessage(), e1); } - catch (SAXException e1) - { - log.error(e1.getMessage(), e1); - } - } - catch (Exception e1) - { + } catch (Exception e1) { log.error(e1.getMessage(), e1); - } - finally - { - if (method != null) - { + } finally { + if (method != null) { method.releaseConnection(); } } - } - else - { + } else { InputStream stream = null; - try - { + try { File file = new File( - ConfigurationManager.getProperty("dspace.dir") - + "/config/crosswalks/demo/pubmed-search.xml"); + ConfigurationManager.getProperty("dspace.dir") + + "/config/crosswalks/demo/pubmed-search.xml"); stream = new FileInputStream(file); DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); + .newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); @@ -188,23 +163,15 @@ public class PubmedService Element xmlRoot = inDoc.getDocumentElement(); Element idList = XMLUtils.getSingleElement(xmlRoot, "IdList"); List pubmedIDs = XMLUtils.getElementValueList(idList, - "Id"); + "Id"); results = getByPubmedIDs(pubmedIDs); - } - catch (Exception e) - { + } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); - } - finally - { - if (stream != null) - { - try - { + } finally { + if (stream != null) { + try { stream.close(); - } - catch (IOException e) - { + } catch (IOException e) { e.printStackTrace(); } } @@ -214,96 +181,83 @@ public class PubmedService } public List getByPubmedIDs(List pubmedIDs) - throws HttpException, IOException, ParserConfigurationException, - SAXException - { - List results = new ArrayList(); - HttpGet method = null; - try - { - HttpClient client = new DefaultHttpClient(); - client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5 * timeout); + throws HttpException, IOException, ParserConfigurationException, + SAXException { + List results = new ArrayList(); + HttpGet method = null; + try { + HttpClient client = new DefaultHttpClient(); + client.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5 * timeout); try { URIBuilder uriBuilder = new URIBuilder( - "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi"); + "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi"); uriBuilder.addParameter("db", "pubmed"); uriBuilder.addParameter("retmode", "xml"); uriBuilder.addParameter("rettype", "full"); uriBuilder.addParameter("id", StringUtils.join( - pubmedIDs.iterator(), ",")); + pubmedIDs.iterator(), ",")); method = new HttpGet(uriBuilder.build()); - } catch (URISyntaxException ex) - { + } catch (URISyntaxException ex) { throw new RuntimeException("Request not sent", ex); } // Execute the method. - HttpResponse response = client.execute(method); + HttpResponse response = client.execute(method); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); - if (statusCode != HttpStatus.SC_OK) - { - throw new RuntimeException("WS call failed: " + statusLine); - } + if (statusCode != HttpStatus.SC_OK) { + throw new RuntimeException("WS call failed: " + statusLine); + } - DocumentBuilderFactory factory = DocumentBuilderFactory - .newInstance(); - factory.setValidating(false); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); + DocumentBuilderFactory factory = DocumentBuilderFactory + .newInstance(); + factory.setValidating(false); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document inDoc = builder - .parse(response.getEntity().getContent()); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document inDoc = builder + .parse(response.getEntity().getContent()); - Element xmlRoot = inDoc.getDocumentElement(); - List pubArticles = XMLUtils.getElementList(xmlRoot, - "PubmedArticle"); + Element xmlRoot = inDoc.getDocumentElement(); + List pubArticles = XMLUtils.getElementList(xmlRoot, + "PubmedArticle"); - for (Element xmlArticle : pubArticles) - { - Record pubmedItem = null; - try - { - pubmedItem = PubmedUtils - .convertPubmedDomToRecord(xmlArticle); - results.add(pubmedItem); - } - catch (Exception e) - { - throw new RuntimeException( - "PubmedID is not valid or not exist: " - + e.getMessage(), e); - } - } + for (Element xmlArticle : pubArticles) { + Record pubmedItem = null; + try { + pubmedItem = PubmedUtils + .convertPubmedDomToRecord(xmlArticle); + results.add(pubmedItem); + } catch (Exception e) { + throw new RuntimeException( + "PubmedID is not valid or not exist: " + + e.getMessage(), e); + } + } - return results; - } - finally - { - if (method != null) - { - method.releaseConnection(); - } - } + return results; + } finally { + if (method != null) { + method.releaseConnection(); + } + } } public List search(String doi, String pmid) throws HttpException, - IOException - { + IOException { StringBuffer query = new StringBuffer(); - if (StringUtils.isNotBlank(doi)) - { + if (StringUtils.isNotBlank(doi)) { query.append(doi); query.append("[AID]"); } - if (StringUtils.isNotBlank(pmid)) - { + if (StringUtils.isNotBlank(pmid)) { // [FAU] - if (query.length() > 0) + if (query.length() > 0) { query.append(" OR "); + } query.append(pmid).append("[PMID]"); } return search(query.toString()); diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedUtils.java b/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedUtils.java index 552db676ef..03f3e3ab03 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedUtils.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/PubmedUtils.java @@ -6,7 +6,7 @@ * http://www.dspace.org/license/ */ /** - * + * */ package org.dspace.submit.lookup; @@ -19,7 +19,6 @@ import gr.ekt.bte.core.MutableRecord; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.StringValue; import gr.ekt.bte.core.Value; - import org.apache.commons.lang.StringUtils; import org.dspace.app.util.XMLUtils; import org.dspace.submit.util.SubmissionLookupPublication; @@ -31,11 +30,14 @@ import org.w3c.dom.Element; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class PubmedUtils -{ +public class PubmedUtils { - public static Record convertPubmedDomToRecord(Element pubArticle) - { + /** + * Default constructor + */ + private PubmedUtils() { } + + public static Record convertPubmedDomToRecord(Element pubArticle) { MutableRecord record = new SubmissionLookupPublication(""); Map monthToNum = new HashMap(); @@ -53,188 +55,173 @@ public class PubmedUtils monthToNum.put("Dec", "12"); Element medline = XMLUtils.getSingleElement(pubArticle, - "MedlineCitation"); + "MedlineCitation"); Element article = XMLUtils.getSingleElement(medline, "Article"); Element pubmed = XMLUtils.getSingleElement(pubArticle, "PubmedData"); Element identifierList = XMLUtils.getSingleElement(pubmed, - "ArticleIdList"); - if (identifierList != null) - { + "ArticleIdList"); + if (identifierList != null) { List identifiers = XMLUtils.getElementList(identifierList, - "ArticleId"); - if (identifiers != null) - { - for (Element id : identifiers) - { - if ("pubmed".equals(id.getAttribute("IdType"))) - { + "ArticleId"); + if (identifiers != null) { + for (Element id : identifiers) { + if ("pubmed".equals(id.getAttribute("IdType"))) { String pubmedID = id.getTextContent().trim(); - if (pubmedID != null) + if (pubmedID != null) { record.addValue("pubmedID", new StringValue( - pubmedID)); - } - else if ("doi".equals(id.getAttribute("IdType"))) - { + pubmedID)); + } + } else if ("doi".equals(id.getAttribute("IdType"))) { String doi = id.getTextContent().trim(); - if (doi != null) + if (doi != null) { record.addValue("doi", new StringValue(doi)); + } } } } } String status = XMLUtils.getElementValue(pubmed, "PublicationStatus"); - if (status != null) + if (status != null) { record.addValue("publicationStatus", new StringValue(status)); + } String pubblicationModel = XMLUtils.getElementAttribute(medline, - "Article", "PubModel"); - if (pubblicationModel != null) + "Article", "PubModel"); + if (pubblicationModel != null) { record.addValue("pubModel", new StringValue( - pubblicationModel)); + pubblicationModel)); + } String title = XMLUtils.getElementValue(article, "ArticleTitle"); - if (title != null) + if (title != null) { record.addValue("articleTitle", new StringValue(title)); + } Element abstractElement = XMLUtils - .getSingleElement(article, "Abstract"); - if (abstractElement == null) - { + .getSingleElement(article, "Abstract"); + if (abstractElement == null) { abstractElement = XMLUtils.getSingleElement(medline, - "OtherAbstract"); + "OtherAbstract"); } - if (abstractElement != null) - { + if (abstractElement != null) { String summary = XMLUtils.getElementValue(abstractElement, - "AbstractText"); - if (summary != null) + "AbstractText"); + if (summary != null) { record.addValue("abstractText", new StringValue(summary)); + } } List authors = new LinkedList(); Element authorList = XMLUtils.getSingleElement(article, "AuthorList"); - if (authorList != null) - { + if (authorList != null) { List authorsElement = XMLUtils.getElementList(authorList, - "Author"); - if (authorsElement != null) - { - for (Element author : authorsElement) - { + "Author"); + if (authorsElement != null) { + for (Element author : authorsElement) { if (StringUtils.isBlank(XMLUtils.getElementValue(author, - "CollectiveName"))) - { + "CollectiveName"))) { authors.add(new String[] { - XMLUtils.getElementValue(author, "ForeName"), - XMLUtils.getElementValue(author, "LastName") }); + XMLUtils.getElementValue(author, "ForeName"), + XMLUtils.getElementValue(author, "LastName")}); } } } } - if (authors.size() > 0) - { + if (authors.size() > 0) { List values = new LinkedList(); - for (String[] sArray : authors) - { + for (String[] sArray : authors) { values.add(new StringValue(sArray[1] + ", " + sArray[0])); } record.addField("author", values); } Element journal = XMLUtils.getSingleElement(article, "Journal"); - if (journal != null) - { + if (journal != null) { List jnumbers = XMLUtils.getElementList(journal, "ISSN"); - if (jnumbers != null) - { - for (Element jnumber : jnumbers) - { - if ("Print".equals(jnumber.getAttribute("IssnType"))) - { + if (jnumbers != null) { + for (Element jnumber : jnumbers) { + if ("Print".equals(jnumber.getAttribute("IssnType"))) { String issn = jnumber.getTextContent().trim(); - if (issn != null) + if (issn != null) { record.addValue("printISSN", new StringValue(issn)); - } - else - { + } + } else { String eissn = jnumber.getTextContent().trim(); - if (eissn != null) + if (eissn != null) { record.addValue("electronicISSN", new StringValue(eissn)); + } } } } String journalTitle = XMLUtils.getElementValue(journal, "Title"); - if (journalTitle != null) + if (journalTitle != null) { record.addValue("journalTitle", new StringValue(journalTitle)); + } Element journalIssueElement = XMLUtils.getSingleElement(journal, - "JournalIssue"); - if (journalIssueElement != null) - { + "JournalIssue"); + if (journalIssueElement != null) { String volume = XMLUtils.getElementValue(journalIssueElement, - "Volume"); - if (volume != null) + "Volume"); + if (volume != null) { record.addValue("journalVolume", new StringValue(volume)); + } String issue = XMLUtils.getElementValue(journalIssueElement, - "Issue"); - if (issue != null) + "Issue"); + if (issue != null) { record.addValue("journalIssue", new StringValue(issue)); + } Element pubDateElement = XMLUtils.getSingleElement( - journalIssueElement, "PubDate"); + journalIssueElement, "PubDate"); String pubDate = null; - if (pubDateElement != null) - { - pubDate = XMLUtils.getElementValue(pubDateElement, "Year"); + if (pubDateElement != null) { + pubDate = XMLUtils.getElementValue(pubDateElement, "Year"); String mounth = XMLUtils.getElementValue(pubDateElement, - "Month"); + "Month"); String day = XMLUtils - .getElementValue(pubDateElement, "Day"); + .getElementValue(pubDateElement, "Day"); if (StringUtils.isNotBlank(mounth) - && monthToNum.containsKey(mounth)) - { - pubDate += "-" + monthToNum.get(mounth); - if (StringUtils.isNotBlank(day)) - { - pubDate += "-" + (day.length() == 1 ? "0" + day : day); + && monthToNum.containsKey(mounth)) { + pubDate += "-" + monthToNum.get(mounth); + if (StringUtils.isNotBlank(day)) { + pubDate += "-" + (day.length() == 1 ? "0" + day : day); } } } - if (pubDate == null){ - pubDate = XMLUtils.getElementValue(pubDateElement, "MedlineDate"); + if (pubDate == null) { + pubDate = XMLUtils.getElementValue(pubDateElement, "MedlineDate"); } - if (pubDate != null) + if (pubDate != null) { record.addValue("pubDate", new StringValue(pubDate)); + } } String language = XMLUtils.getElementValue(article, "Language"); - if (language != null) + if (language != null) { record.addValue("language", new StringValue(language)); + } List type = new LinkedList(); Element publicationTypeList = XMLUtils.getSingleElement(article, - "PublicationTypeList"); - if (publicationTypeList != null) - { + "PublicationTypeList"); + if (publicationTypeList != null) { List publicationTypes = XMLUtils.getElementList( - publicationTypeList, "PublicationType"); - for (Element publicationType : publicationTypes) - { + publicationTypeList, "PublicationType"); + for (Element publicationType : publicationTypes) { type.add(publicationType.getTextContent().trim()); } } - if (type.size() > 0) - { + if (type.size() > 0) { List values = new LinkedList(); - for (String s : type) - { + for (String s : type) { values.add(new StringValue(s)); } record.addField("publicationType", values); @@ -243,37 +230,28 @@ public class PubmedUtils List primaryKeywords = new LinkedList(); List secondaryKeywords = new LinkedList(); Element keywordsList = XMLUtils.getSingleElement(medline, - "KeywordList"); - if (keywordsList != null) - { + "KeywordList"); + if (keywordsList != null) { List keywords = XMLUtils.getElementList(keywordsList, - "Keyword"); - for (Element keyword : keywords) - { - if ("Y".equals(keyword.getAttribute("MajorTopicYN"))) - { + "Keyword"); + for (Element keyword : keywords) { + if ("Y".equals(keyword.getAttribute("MajorTopicYN"))) { primaryKeywords.add(keyword.getTextContent().trim()); - } - else - { + } else { secondaryKeywords.add(keyword.getTextContent().trim()); } } } - if (primaryKeywords.size() > 0) - { + if (primaryKeywords.size() > 0) { List values = new LinkedList(); - for (String s : primaryKeywords) - { + for (String s : primaryKeywords) { values.add(new StringValue(s)); } record.addField("primaryKeyword", values); } - if (secondaryKeywords.size() > 0) - { + if (secondaryKeywords.size() > 0) { List values = new LinkedList(); - for (String s : secondaryKeywords) - { + for (String s : secondaryKeywords) { values.add(new StringValue(s)); } record.addField("secondaryKeyword", values); @@ -282,63 +260,54 @@ public class PubmedUtils List primaryMeshHeadings = new LinkedList(); List secondaryMeshHeadings = new LinkedList(); Element meshHeadingsList = XMLUtils.getSingleElement(medline, - "MeshHeadingList"); - if (meshHeadingsList != null) - { + "MeshHeadingList"); + if (meshHeadingsList != null) { List meshHeadings = XMLUtils.getElementList( - meshHeadingsList, "MeshHeading"); - for (Element meshHeading : meshHeadings) - { + meshHeadingsList, "MeshHeading"); + for (Element meshHeading : meshHeadings) { if ("Y".equals(XMLUtils.getElementAttribute(meshHeading, - "DescriptorName", "MajorTopicYN"))) - { + "DescriptorName", "MajorTopicYN"))) { primaryMeshHeadings.add(XMLUtils.getElementValue( - meshHeading, "DescriptorName")); - } - else - { + meshHeading, "DescriptorName")); + } else { secondaryMeshHeadings.add(XMLUtils.getElementValue( - meshHeading, "DescriptorName")); + meshHeading, "DescriptorName")); } } } - if (primaryMeshHeadings.size() > 0) - { + if (primaryMeshHeadings.size() > 0) { List values = new LinkedList(); - for (String s : primaryMeshHeadings) - { + for (String s : primaryMeshHeadings) { values.add(new StringValue(s)); } record.addField("primaryMeshHeading", values); } - if (secondaryMeshHeadings.size() > 0) - { + if (secondaryMeshHeadings.size() > 0) { List values = new LinkedList(); - for (String s : secondaryMeshHeadings) - { + for (String s : secondaryMeshHeadings) { values.add(new StringValue(s)); } record.addField("secondaryMeshHeading", values); } Element paginationElement = XMLUtils.getSingleElement(article, - "Pagination"); - if (paginationElement != null) - { + "Pagination"); + if (paginationElement != null) { String startPage = XMLUtils.getElementValue(paginationElement, - "StartPage"); + "StartPage"); String endPage = XMLUtils.getElementValue(paginationElement, - "EndPage"); - if (StringUtils.isBlank(startPage)) - { + "EndPage"); + if (StringUtils.isBlank(startPage)) { startPage = XMLUtils.getElementValue(paginationElement, - "MedlinePgn"); + "MedlinePgn"); } - if (startPage != null) + if (startPage != null) { record.addValue("startPage", new StringValue(startPage)); - if (endPage != null) + } + if (endPage != null) { record.addValue("endPage", new StringValue(endPage)); + } } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/RemoveLastDotModifier.java b/dspace-api/src/main/java/org/dspace/submit/lookup/RemoveLastDotModifier.java index 7af9e9d115..ed83d24aeb 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/RemoveLastDotModifier.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/RemoveLastDotModifier.java @@ -11,13 +11,12 @@ package org.dspace.submit.lookup; import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang.StringUtils; - import gr.ekt.bte.core.AbstractModifier; import gr.ekt.bte.core.MutableRecord; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.StringValue; import gr.ekt.bte.core.Value; +import org.apache.commons.lang.StringUtils; /** * @author Andrea Bollini @@ -25,50 +24,39 @@ import gr.ekt.bte.core.Value; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class RemoveLastDotModifier extends AbstractModifier -{ +public class RemoveLastDotModifier extends AbstractModifier { List fieldKeys; /** - * @param name - * modifier name + * @param name modifier name */ - public RemoveLastDotModifier(String name) - { + public RemoveLastDotModifier(String name) { super(name); } /* * (non-Javadoc) - * + * * @see * gr.ekt.bte.core.AbstractModifier#modify(gr.ekt.bte.core.MutableRecord) */ @Override - public Record modify(MutableRecord record) - { - if (fieldKeys != null) - { - for (String key : fieldKeys) - { + public Record modify(MutableRecord record) { + if (fieldKeys != null) { + for (String key : fieldKeys) { List values = record.getValues(key); List newValues = new ArrayList(); - if (values != null) - { - for (Value value : values) - { + if (values != null) { + for (Value value : values) { String valueString = value.getAsString(); if (StringUtils.isNotBlank(valueString) - && valueString.endsWith(".")) - { + && valueString.endsWith(".")) { newValues.add(new StringValue(valueString - .substring(0, valueString.length() - 1))); - } - else - { + .substring(0, valueString.length() - 1))); + } else { newValues.add(new StringValue(valueString)); } } @@ -81,8 +69,7 @@ public class RemoveLastDotModifier extends AbstractModifier return record; } - public void setFieldKeys(List fieldKeys) - { + public void setFieldKeys(List fieldKeys) { this.fieldKeys = fieldKeys; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionItemDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionItemDataLoader.java index ba359455c8..a032331efc 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionItemDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionItemDataLoader.java @@ -8,14 +8,13 @@ package org.dspace.submit.lookup; +import java.util.List; + import gr.ekt.bte.core.DataLoader; import gr.ekt.bte.core.DataLoadingSpec; import gr.ekt.bte.core.Record; import gr.ekt.bte.core.RecordSet; import gr.ekt.bte.exceptions.MalformedSourceException; - -import java.util.List; - import org.apache.log4j.Logger; import org.dspace.submit.util.ItemSubmissionLookupDTO; @@ -25,45 +24,39 @@ import org.dspace.submit.util.ItemSubmissionLookupDTO; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class SubmissionItemDataLoader implements DataLoader -{ +public class SubmissionItemDataLoader implements DataLoader { protected List dtoList; List providers; private static Logger log = Logger - .getLogger(SubmissionItemDataLoader.class); + .getLogger(SubmissionItemDataLoader.class); - public SubmissionItemDataLoader() - { + public SubmissionItemDataLoader() { dtoList = null; providers = null; } @Override - public RecordSet getRecords() throws MalformedSourceException - { - if (dtoList == null) - { + public RecordSet getRecords() throws MalformedSourceException { + if (dtoList == null) { throw new MalformedSourceException("dtoList not initialized"); } RecordSet ret = new RecordSet(); - for (ItemSubmissionLookupDTO dto : dtoList) - { + for (ItemSubmissionLookupDTO dto : dtoList) { Record rec = dto.getTotalPublication(providers); ret.addRecord(rec); } log.info("BTE DataLoader finished. Items loaded: " - + ret.getRecords().size()); + + ret.getRecords().size()); // Printing debug message String totalString = ""; - for (Record record : ret.getRecords()) - { + for (Record record : ret.getRecords()) { totalString += SubmissionLookupUtils.getPrintableString(record) - + "\n"; + + "\n"; } log.debug("Records loaded:\n" + totalString); @@ -72,10 +65,8 @@ public class SubmissionItemDataLoader implements DataLoader @Override public RecordSet getRecords(DataLoadingSpec spec) - throws MalformedSourceException - { - if (spec.getOffset() > 0) - { + throws MalformedSourceException { + if (spec.getOffset() > 0) { return new RecordSet(); } @@ -85,34 +76,28 @@ public class SubmissionItemDataLoader implements DataLoader /** * @return the dtoList */ - public List getDtoList() - { + public List getDtoList() { return dtoList; } /** - * @param dtoList - * the dtoList to set + * @param dtoList the dtoList to set */ - public void setDtoList(List dtoList) - { + public void setDtoList(List dtoList) { this.dtoList = dtoList; } /** * @return the providers */ - public List getProviders() - { + public List getProviders() { return providers; } /** - * @param providers - * the providers to set + * @param providers the providers to set */ - public void setProviders(List providers) - { + public void setProviders(List providers) { this.providers = providers; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupDataLoader.java b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupDataLoader.java index 4c745a5317..9cef38fc86 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupDataLoader.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupDataLoader.java @@ -12,11 +12,10 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.dspace.core.Context; - import gr.ekt.bte.core.DataLoader; import gr.ekt.bte.core.Record; import org.apache.http.HttpException; +import org.dspace.core.Context; /** * @author Andrea Bollini @@ -24,8 +23,7 @@ import org.apache.http.HttpException; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public interface SubmissionLookupDataLoader extends DataLoader -{ +public interface SubmissionLookupDataLoader extends DataLoader { public final static String DOI = "doi"; @@ -46,12 +44,12 @@ public interface SubmissionLookupDataLoader extends DataLoader boolean isSearchProvider(); List search(Context context, String title, String author, int year) - throws HttpException, IOException; + throws HttpException, IOException; List getByIdentifier(Context context, Map> keys) - throws HttpException, IOException; + throws HttpException, IOException; List getByDOIs(Context context, Set doiToSearch) - throws HttpException, IOException; + throws HttpException, IOException; } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupOutputGenerator.java b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupOutputGenerator.java index 78ccdec301..a3a3a22e3d 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupOutputGenerator.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupOutputGenerator.java @@ -7,17 +7,16 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.DataOutputSpec; -import gr.ekt.bte.core.OutputGenerator; -import gr.ekt.bte.core.Record; -import gr.ekt.bte.core.RecordSet; -import gr.ekt.bte.core.Value; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import gr.ekt.bte.core.DataOutputSpec; +import gr.ekt.bte.core.OutputGenerator; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.RecordSet; +import gr.ekt.bte.core.Value; import org.dspace.submit.util.ItemSubmissionLookupDTO; /** @@ -26,45 +25,35 @@ import org.dspace.submit.util.ItemSubmissionLookupDTO; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class SubmissionLookupOutputGenerator implements OutputGenerator -{ +public class SubmissionLookupOutputGenerator implements OutputGenerator { protected List dtoList; protected final String DOI_FIELD = "doi"; protected final String NOT_FOUND_DOI = "NOT-FOUND-DOI"; - public SubmissionLookupOutputGenerator() - { + public SubmissionLookupOutputGenerator() { } @Override - public List generateOutput(RecordSet records) - { + public List generateOutput(RecordSet records) { dtoList = new ArrayList(); Map> record_sets = new HashMap>(); int counter = 0; - for (Record rec : records) - { + for (Record rec : records) { String current_doi = NOT_FOUND_DOI; List values = rec.getValues(DOI_FIELD); - if (values != null && values.size() > 0) - { + if (values != null && values.size() > 0) { current_doi = values.get(0).getAsString(); - } - else - { + } else { current_doi = NOT_FOUND_DOI + "_" + counter; } - if (record_sets.keySet().contains(current_doi)) - { + if (record_sets.keySet().contains(current_doi)) { record_sets.get(current_doi).add(rec); - } - else - { + } else { ArrayList publication = new ArrayList(); publication.add(rec); record_sets.put(current_doi, publication); @@ -72,10 +61,9 @@ public class SubmissionLookupOutputGenerator implements OutputGenerator counter++; } - for (Map.Entry> entry : record_sets.entrySet()) - { + for (Map.Entry> entry : record_sets.entrySet()) { ItemSubmissionLookupDTO dto = new ItemSubmissionLookupDTO( - entry.getValue()); + entry.getValue()); dtoList.add(dto); } @@ -83,25 +71,21 @@ public class SubmissionLookupOutputGenerator implements OutputGenerator } @Override - public List generateOutput(RecordSet records, DataOutputSpec spec) - { + public List generateOutput(RecordSet records, DataOutputSpec spec) { return generateOutput(records); } /** * @return the items */ - public List getDtoList() - { + public List getDtoList() { return dtoList; } /** - * @param items - * the items to set + * @param items the items to set */ - public void setDtoList(List items) - { + public void setDtoList(List items) { this.dtoList = items; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupService.java b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupService.java index a37e77da47..b98581b807 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupService.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupService.java @@ -7,18 +7,16 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.DataLoader; -import gr.ekt.bte.core.Record; -import gr.ekt.bte.core.TransformationEngine; -import gr.ekt.bte.dataloader.FileDataLoader; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import javax.servlet.http.HttpServletRequest; +import gr.ekt.bte.core.DataLoader; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.TransformationEngine; +import gr.ekt.bte.dataloader.FileDataLoader; import org.apache.log4j.Logger; import org.dspace.submit.util.SubmissionLookupDTO; @@ -28,8 +26,7 @@ import org.dspace.submit.util.SubmissionLookupDTO; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class SubmissionLookupService -{ +public class SubmissionLookupService { public static final String CFG_MODULE = "submission-lookup"; public static final String SL_NAMESPACE_PREFIX = "http://www.dspace.org/sl/"; @@ -55,61 +52,50 @@ public class SubmissionLookupService protected TransformationEngine phase1TransformationEngine; protected TransformationEngine phase2TransformationEngine; - + protected List detailFields = null; public void setPhase2TransformationEngine( - TransformationEngine phase2TransformationEngine) - { + TransformationEngine phase2TransformationEngine) { this.phase2TransformationEngine = phase2TransformationEngine; } public void setPhase1TransformationEngine( - TransformationEngine phase1TransformationEngine) - { + TransformationEngine phase1TransformationEngine) { this.phase1TransformationEngine = phase1TransformationEngine; MultipleSubmissionLookupDataLoader dataLoader = (MultipleSubmissionLookupDataLoader) phase1TransformationEngine - .getDataLoader(); + .getDataLoader(); this.idents2provs = new HashMap>(); this.searchProviders = new ArrayList(); this.fileProviders = new ArrayList(); - if (providers == null) - { + if (providers == null) { this.providers = new ArrayList(); - for (String providerName : dataLoader.getProvidersMap().keySet()) - { + for (String providerName : dataLoader.getProvidersMap().keySet()) { DataLoader p = dataLoader.getProvidersMap().get(providerName); this.providers.add(p); // Do not do that for file providers - if (p instanceof FileDataLoader) - { + if (p instanceof FileDataLoader) { this.fileProviders.add(providerName); - } - else if (p instanceof NetworkSubmissionLookupDataLoader) - { + } else if (p instanceof NetworkSubmissionLookupDataLoader) { NetworkSubmissionLookupDataLoader p2 = (NetworkSubmissionLookupDataLoader) p; p2.setProviderName(providerName); - if (p2.isSearchProvider()) - { + if (p2.isSearchProvider()) { searchProviders.add(providerName); } List suppIdentifiers = p2.getSupportedIdentifiers(); - if (suppIdentifiers != null) - { - for (String ident : suppIdentifiers) - { + if (suppIdentifiers != null) { + for (String ident : suppIdentifiers) { List tmp = idents2provs.get(ident); - if (tmp == null) - { + if (tmp == null) { tmp = new ArrayList(); idents2provs.put(ident, tmp); } @@ -121,33 +107,26 @@ public class SubmissionLookupService } } - public TransformationEngine getPhase1TransformationEngine() - { + public TransformationEngine getPhase1TransformationEngine() { return phase1TransformationEngine; } - public TransformationEngine getPhase2TransformationEngine() - { + public TransformationEngine getPhase2TransformationEngine() { return phase2TransformationEngine; } - public List getIdentifiers() - { + public List getIdentifiers() { List allSupportedIdentifiers = new ArrayList(); MultipleSubmissionLookupDataLoader dataLoader = (MultipleSubmissionLookupDataLoader) phase1TransformationEngine - .getDataLoader(); - for (String providerName : dataLoader.getProvidersMap().keySet()) - { + .getDataLoader(); + for (String providerName : dataLoader.getProvidersMap().keySet()) { DataLoader provider = dataLoader.getProvidersMap() - .get(providerName); - if (provider instanceof SubmissionLookupDataLoader) - { + .get(providerName); + if (provider instanceof SubmissionLookupDataLoader) { for (String identifier : ((SubmissionLookupDataLoader) provider) - .getSupportedIdentifiers()) - { - if (!allSupportedIdentifiers.contains(identifier)) - { + .getSupportedIdentifiers()) { + if (!allSupportedIdentifiers.contains(identifier)) { allSupportedIdentifiers.add(identifier); } } @@ -157,69 +136,59 @@ public class SubmissionLookupService return allSupportedIdentifiers; } - public Map> getProvidersIdentifiersMap() - { + public Map> getProvidersIdentifiersMap() { return idents2provs; } public SubmissionLookupDTO getSubmissionLookupDTO( - HttpServletRequest request, String uuidSubmission) - { + HttpServletRequest request, String uuidSubmission) { SubmissionLookupDTO dto = (SubmissionLookupDTO) request.getSession() - .getAttribute("submission_lookup_" + uuidSubmission); - if (dto == null) - { + .getAttribute("submission_lookup_" + uuidSubmission); + if (dto == null) { dto = new SubmissionLookupDTO(); storeDTOs(request, uuidSubmission, dto); } return dto; } - public void invalidateDTOs(HttpServletRequest request, String uuidSubmission) - { + public void invalidateDTOs(HttpServletRequest request, String uuidSubmission) { request.getSession().removeAttribute( - "submission_lookup_" + uuidSubmission); + "submission_lookup_" + uuidSubmission); } public void storeDTOs(HttpServletRequest request, String uuidSubmission, - SubmissionLookupDTO dto) - { + SubmissionLookupDTO dto) { request.getSession().setAttribute( - "submission_lookup_" + uuidSubmission, dto); + "submission_lookup_" + uuidSubmission, dto); } - public List getSearchProviders() - { + public List getSearchProviders() { return searchProviders; } - public List getProviders() - { + public List getProviders() { return providers; } - public static String getProviderName(Record rec) - { + public static String getProviderName(Record rec) { return SubmissionLookupUtils.getFirstValue(rec, - SubmissionLookupService.PROVIDER_NAME_FIELD); + SubmissionLookupService.PROVIDER_NAME_FIELD); } - public static String getType(Record rec) - { + public static String getType(Record rec) { return SubmissionLookupUtils.getFirstValue(rec, - SubmissionLookupDataLoader.TYPE); + SubmissionLookupDataLoader.TYPE); } - public List getFileProviders() - { + public List getFileProviders() { return this.fileProviders; } - public List getDetailFields() { - return detailFields; - } + public List getDetailFields() { + return detailFields; + } - public void setDetailFields(List detailFields) { - this.detailFields = detailFields; - } + public void setDetailFields(List detailFields) { + this.detailFields = detailFields; + } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupUtils.java b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupUtils.java index e44726087e..995fb6798f 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupUtils.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/SubmissionLookupUtils.java @@ -7,14 +7,13 @@ */ package org.dspace.submit.lookup; -import gr.ekt.bte.core.Record; -import gr.ekt.bte.core.Value; - import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.Value; import org.apache.log4j.Logger; import org.dspace.content.Item; import org.dspace.content.MetadataSchema; @@ -31,132 +30,116 @@ import org.dspace.core.Context; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class SubmissionLookupUtils -{ +public class SubmissionLookupUtils { private static Logger log = Logger.getLogger(SubmissionLookupUtils.class); - /** Location of config file */ + /** + * Default constructor + */ + private SubmissionLookupUtils() { } + + /** + * Location of config file + */ private static final String configFilePath = ConfigurationManager - .getProperty("dspace.dir") - + File.separator - + "config" - + File.separator + "crosswalks" + File.separator; + .getProperty("dspace.dir") + + File.separator + + "config" + + File.separator + "crosswalks" + File.separator; // Patter to extract the converter name if any - private static final Pattern converterPattern = Pattern - .compile(".*\\((.*)\\)"); + private static final Pattern converterPattern = Pattern.compile(".*\\((.*)\\)"); - protected static final MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + protected static final MetadataSchemaService metadataSchemaService = + ContentServiceFactory.getInstance().getMetadataSchemaService(); protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); public static LookupProvidersCheck getProvidersCheck(Context context, - Item item, String dcSchema, String dcElement, String dcQualifier) - { - try - { + Item item, String dcSchema, String dcElement, + String dcQualifier) { + try { LookupProvidersCheck check = new LookupProvidersCheck(); List schemas = metadataSchemaService.findAll(context); List values = itemService.getMetadata(item, dcSchema, dcElement, - dcQualifier, Item.ANY); + dcQualifier, Item.ANY); - for (MetadataSchema schema : schemas) - { + for (MetadataSchema schema : schemas) { boolean error = false; if (schema.getNamespace().startsWith( - SubmissionLookupService.SL_NAMESPACE_PREFIX)) - { + SubmissionLookupService.SL_NAMESPACE_PREFIX)) { List slCache = itemService.getMetadata(item, schema.getName(), - dcElement, dcQualifier, Item.ANY); - if (slCache.size() == 0) + dcElement, dcQualifier, Item.ANY); + if (slCache.size() == 0) { continue; - - if (slCache.size() != values.size()) - { - error = true; } - else - { - for (int idx = 0; idx < values.size(); idx++) - { + + if (slCache.size() != values.size()) { + error = true; + } else { + for (int idx = 0; idx < values.size(); idx++) { MetadataValue v = values.get(idx); MetadataValue sl = slCache.get(idx); // FIXME gestire authority e possibilita' multiple: // match non sicuri, affiliation, etc. - if (!v.getValue().equals(sl.getValue())) - { + if (!v.getValue().equals(sl.getValue())) { error = true; break; } } } - if (error) - { + if (error) { check.getProvidersErr().add(schema.getName()); - } - else - { + } else { check.getProvidersOk().add(schema.getName()); } } } return check; - } - catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); throw new RuntimeException(e.getMessage(), e); } } - public static String normalizeDOI(String doi) - { - if (doi != null) - { + public static String normalizeDOI(String doi) { + if (doi != null) { return doi.trim().replaceAll("^http://dx.doi.org/", "") - .replaceAll("^doi:", ""); + .replaceAll("^doi:", ""); } return null; } - public static String getFirstValue(Record rec, String field) - { + public static String getFirstValue(Record rec, String field) { List values = rec.getValues(field); String value = null; - if (values != null && values.size() > 0) - { + if (values != null && values.size() > 0) { value = values.get(0).getAsString(); } return value; } - public static List getValues(Record rec, String field) - { + public static List getValues(Record rec, String field) { List result = new ArrayList(); List values = rec.getValues(field); - if (values != null && values.size() > 0) - { - for (Value value : values) - { + if (values != null && values.size() > 0) { + for (Value value : values) { result.add(value.getAsString()); } } return result; } - public static String getPrintableString(Record record) - { + public static String getPrintableString(Record record) { StringBuilder result = new StringBuilder(); result.append("\nPublication {\n"); - for (String field : record.getFields()) - { + for (String field : record.getFields()) { result.append("--" + field + ":\n"); List values = record.getValues(field); - for (Value value : values) - { + for (Value value : values) { result.append("\t" + value.getAsString() + "\n"); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/lookup/ValueConcatenationModifier.java b/dspace-api/src/main/java/org/dspace/submit/lookup/ValueConcatenationModifier.java index 32f36f2ab7..cdc9aa87db 100644 --- a/dspace-api/src/main/java/org/dspace/submit/lookup/ValueConcatenationModifier.java +++ b/dspace-api/src/main/java/org/dspace/submit/lookup/ValueConcatenationModifier.java @@ -8,16 +8,14 @@ package org.dspace.submit.lookup; -import gr.ekt.bte.core.AbstractModifier; -import gr.ekt.bte.core.MutableRecord; -import gr.ekt.bte.core.Record; - -import gr.ekt.bte.core.StringValue; -import gr.ekt.bte.core.Value; - import java.util.ArrayList; import java.util.List; +import gr.ekt.bte.core.AbstractModifier; +import gr.ekt.bte.core.MutableRecord; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.StringValue; +import gr.ekt.bte.core.Value; import org.apache.commons.lang.StringUtils; /** @@ -26,33 +24,28 @@ import org.apache.commons.lang.StringUtils; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class ValueConcatenationModifier extends AbstractModifier -{ +public class ValueConcatenationModifier extends AbstractModifier { private String field; private String separator = ","; private boolean whitespaceAfter = true; - public ValueConcatenationModifier() - { + public ValueConcatenationModifier() { super("ValueConcatenationModifier"); } @Override - public Record modify(MutableRecord rec) - { + public Record modify(MutableRecord rec) { List values = rec.getValues(field); - if (values != null) - { + if (values != null) { List converted_values = new ArrayList(); - for (Value val : values) - { + for (Value val : values) { converted_values.add(val.getAsString()); } List final_value = new ArrayList(); String v = StringUtils.join(converted_values.iterator(), separator - + (whitespaceAfter ? " " : "")); + + (whitespaceAfter ? " " : "")); final_value.add(new StringValue(v)); rec.updateField(field, final_value); } @@ -63,51 +56,42 @@ public class ValueConcatenationModifier extends AbstractModifier /** * @return the field */ - public String getField() - { + public String getField() { return field; } /** - * @param field - * the field to set + * @param field the field to set */ - public void setField(String field) - { + public void setField(String field) { this.field = field; } /** * @return the separator */ - public String getSeparator() - { + public String getSeparator() { return separator; } /** - * @param separator - * the separator to set + * @param separator the separator to set */ - public void setSeparator(String separator) - { + public void setSeparator(String separator) { this.separator = separator; } /** * @return the whiteSpaceAfter */ - public boolean isWhitespaceAfter() - { + public boolean isWhitespaceAfter() { return whitespaceAfter; } /** - * @param whiteSpaceAfter - * the whiteSpaceAfter to set + * @param whiteSpaceAfter the whiteSpaceAfter to set */ - public void setWhitespaceAfter(boolean whiteSpaceAfter) - { + public void setWhitespaceAfter(boolean whiteSpaceAfter) { this.whitespaceAfter = whiteSpaceAfter; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/model/AccessConditionOption.java b/dspace-api/src/main/java/org/dspace/submit/model/AccessConditionOption.java new file mode 100644 index 0000000000..ca8efc09c4 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/model/AccessConditionOption.java @@ -0,0 +1,86 @@ +/** + * 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.submit.model; + +/** + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + */ +public class AccessConditionOption { + + private String name; + + private String groupName; + + private String selectGroupName; + + private Boolean hasStartDate; + + private Boolean hasEndDate; + + private String startDateLimit; + + private String endDateLimit; + + public String getName() { + return name; + } + + public void setName(String type) { + this.name = type; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public Boolean getHasStartDate() { + return hasStartDate; + } + + public void setHasStartDate(Boolean hasStartDate) { + this.hasStartDate = hasStartDate; + } + + public Boolean getHasEndDate() { + return hasEndDate; + } + + public void setHasEndDate(Boolean hasEndDate) { + this.hasEndDate = hasEndDate; + } + + public String getStartDateLimit() { + return startDateLimit; + } + + public void setStartDateLimit(String startDateLimit) { + this.startDateLimit = startDateLimit; + } + + public String getEndDateLimit() { + return endDateLimit; + } + + public void setEndDateLimit(String endDateLimit) { + this.endDateLimit = endDateLimit; + } + + public String getSelectGroupName() { + return selectGroupName; + } + + public void setSelectGroupName(String selectGroupName) { + this.selectGroupName = selectGroupName; + } + + +} diff --git a/dspace-api/src/main/java/org/dspace/submit/model/LanguageFormField.java b/dspace-api/src/main/java/org/dspace/submit/model/LanguageFormField.java new file mode 100644 index 0000000000..6a746844bc --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/model/LanguageFormField.java @@ -0,0 +1,50 @@ +/** + * 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.submit.model; + +/** + * A simple POJO to store information about the available languages for a field + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + * + */ +public class LanguageFormField { + /** + * The value to present to the user + */ + private String display; + + /** + * The internal iso code to store in the database + */ + private String code; + + public LanguageFormField(String code, String display) { + this.code = code; + this.display = display; + } + + public String getDisplay() { + return display; + } + + public void setDisplay(String display) { + this.display = display; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + +} diff --git a/dspace-api/src/main/java/org/dspace/submit/model/SelectableMetadata.java b/dspace-api/src/main/java/org/dspace/submit/model/SelectableMetadata.java new file mode 100644 index 0000000000..17b8fd6027 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/model/SelectableMetadata.java @@ -0,0 +1,61 @@ +/** + * 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.submit.model; + +/** + * The SelectableMetadata REST Resource. It is not addressable directly, only + * used as inline object in the InputForm resource. + * + * SelectableMetadata was introduced to make a clear distinction between the + * cases where a value-pairs was used as an authority list of acceptable values + * (dropdown) and where it was used to allow to pick the metadata to use to + * store the value (qualdrop_values). If a value-pair is used by a + * qualdrop_value it is not autoregistered as an authority, instead + * it is exposed as an array of SelectableMetadata object + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + */ +public class SelectableMetadata { + private String metadata; + private String label; + private String authority; + private Boolean closed; + + public String getMetadata() { + return metadata; + } + + public void setMetadata(String key) { + this.metadata = key; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public void setAuthority(String authority) { + this.authority = authority; + } + + public String getAuthority() { + return authority; + } + + public Boolean isClosed() { + return closed; + } + + public void setClosed(Boolean closed) { + this.closed = closed; + } +} diff --git a/dspace-api/src/main/java/org/dspace/submit/model/UploadConfiguration.java b/dspace-api/src/main/java/org/dspace/submit/model/UploadConfiguration.java new file mode 100644 index 0000000000..347caa00bb --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/model/UploadConfiguration.java @@ -0,0 +1,82 @@ +/** + * 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.submit.model; + +import java.util.List; + +import org.dspace.services.ConfigurationService; + +/** + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + */ +public class UploadConfiguration { + + private ConfigurationService configurationService; + + private String metadataDefinition; + private List options; + private Long maxSize; + private Boolean required; + private String name; + + public List getOptions() { + return options; + } + + public void setOptions(List options) { + this.options = options; + } + + public String getMetadata() { + return metadataDefinition; + } + + public void setMetadata(String metadata) { + this.metadataDefinition = metadata; + } + + public Long getMaxSize() { + if (maxSize == null) { + maxSize = configurationService.getLongProperty("upload.max"); + } + return maxSize; + } + + public void setMaxSize(Long maxSize) { + this.maxSize = maxSize; + } + + public Boolean isRequired() { + if (required == null) { + required = configurationService.getBooleanProperty("webui.submit.upload.required"); + } + return required; + } + + public void setRequired(Boolean required) { + this.required = required; + } + + public ConfigurationService getConfigurationService() { + return configurationService; + } + + public void setConfigurationService(ConfigurationService configurationService) { + this.configurationService = configurationService; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + +} diff --git a/dspace-api/src/main/java/org/dspace/submit/model/UploadConfigurationService.java b/dspace-api/src/main/java/org/dspace/submit/model/UploadConfigurationService.java new file mode 100644 index 0000000000..5a08e502d2 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/model/UploadConfigurationService.java @@ -0,0 +1,34 @@ +/** + * 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.submit.model; + +import java.util.Map; + +/** + * Simple bean to manage different Access Condition configuration + * + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + */ +public class UploadConfigurationService { + + /** + * Mapping the submission step process identifier with the configuration (see configuration at access-conditions + * .xml) + */ + private Map map; + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + +} diff --git a/dspace-api/src/main/java/org/dspace/submit/step/AccessStep.java b/dspace-api/src/main/java/org/dspace/submit/step/AccessStep.java index c31632bd75..3cb16908f3 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/AccessStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/AccessStep.java @@ -7,317 +7,27 @@ */ package org.dspace.submit.step; -import org.apache.commons.lang.time.DateUtils; import org.apache.log4j.Logger; -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.authorize.ResourcePolicy; -import org.dspace.authorize.factory.AuthorizeServiceFactory; -import org.dspace.authorize.service.AuthorizeService; -import org.dspace.authorize.service.ResourcePolicyService; -import org.dspace.content.Collection; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; -import org.dspace.core.Constants; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; -import org.dspace.eperson.Group; -import org.dspace.eperson.factory.EPersonServiceFactory; -import org.dspace.eperson.service.GroupService; -import org.dspace.handle.factory.HandleServiceFactory; -import org.dspace.handle.service.HandleService; import org.dspace.submit.AbstractProcessingStep; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Date; -import java.util.UUID; -/** - * This class manages the access step during the submission - * - * @author Fabio Bolognesi (fabio at atmire dot com) - * @author Mark Diggory (markd at atmire dot com) - * @author Ben Bosman (ben at atmire dot com) - * - */ -public class AccessStep extends AbstractProcessingStep -{ - - public static final int STATUS_ERROR_FORMAT_DATE = 1; - public static final int STATUS_ERROR_MISSING_DATE = 2; - public static final int STATUS_ERROR_SELECT_GROUP = 3; - public static final int STATUS_DUPLICATED_POLICY = 4; - public static final int EDIT_POLICY_STATUS_DUPLICATED_POLICY=5; - - - // edit file information - public static final int STATUS_EDIT_POLICY = 10; - - public static final String SUB_INFO_SELECTED_RP = "SUB_INFO_SELECTED_RP"; - - /** log4j logger */ +public class AccessStep extends AbstractProcessingStep { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(AccessStep.class); - // OPERATIONS - public static final String FORM_EDIT_BUTTON_CANCEL = "submit_edit_cancel"; - public static final String FORM_EDIT_BUTTON_SAVE = "submit_save"; - public static final String FORM_ACCESS_BUTTON_ADD = "submit_add_policy"; - - protected static GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - protected static AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); - protected static ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); - - - - - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException{ + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - String buttonPressed = Util.getSubmitButton(request, CANCEL_BUTTON); - - // get reference to item - Item item = subInfo.getSubmissionItem().getItem(); - - Group group = null; - if(request.getParameter("group_id")!=null){ - try{ - group=groupService.find(context, UUID.fromString(request.getParameter("group_id"))); - }catch (NumberFormatException nfe){ - return STATUS_ERROR_SELECT_GROUP; - } - } - - String name = request.getParameter("name"); - String reason = request.getParameter("reason"); - - - // SELECTED OPERATION: go to EditPolicyForm - if(wasEditPolicyPressed(context, buttonPressed, subInfo)) - return STATUS_EDIT_POLICY; - - // SELECTED OPERATION: Remove Policies - if(wasRemovePolicyPressed(buttonPressed)){ - removePolicy(context, buttonPressed); - context.dispatchEvents(); - return STATUS_COMPLETE; - } - - // SELECTED OPERATION: Save or Cancel EditPolicy. - if(comeFromEditPolicy(request)) { - return saveOrCancelEditPolicy(context, request, subInfo, buttonPressed, item, name, group, reason); - } - - - // SELECTED OPERATION: ADD Policy - if(wasAddPolicyPressed(buttonPressed)){ - - int result=-1; - if( (result = checkForm(request))!=0){ - return result; - } - - // handle private checkbox - item.setDiscoverable(true); - if(request.getParameter("private_option")!=null){ - item.setDiscoverable(false); - } - - Date dateStartDate = getEmbargoUntil(request); - ResourcePolicy rp = null; - if( (rp= authorizeService.createOrModifyPolicy(null, context, name, group, null, dateStartDate, org.dspace.core.Constants.READ, reason, item))==null){ - return STATUS_DUPLICATED_POLICY; - } - resourcePolicyService.update(context, rp); - context.dispatchEvents(); - return STATUS_COMPLETE; - } - - - // if arrive here Next, Previous or Save has been pressed - boolean isAdvancedFormEnabled= configurationService.getBooleanProperty("webui.submission.restrictstep.enableAdvancedForm", false); - - // if it is a simple form we should create the policy for Anonymous - // if Anonymous does not have right on this collection, create policies for any other groups with - // DEFAULT_ITEM_READ specified. - if(!isAdvancedFormEnabled){ - int result = checkForm(request); - if (result != 0) - { - return result; - } - authorizeService.generateAutomaticPolicies(context, getEmbargoUntilDate(request), reason, item, (Collection) handleService.resolveToObject(context, subInfo.getCollectionHandle())); - } -// else{ -// Date dateStartDate = getEmbargoUntil(request); -// createOrModifyPolicy(null, context, name, groupID, null, dateStartDate, org.dspace.core.Constants.READ, reason, item); -// } - item.setDiscoverable(true); - if(request.getParameter("private_option")!=null){ - item.setDiscoverable(false); - } - itemService.update(context, item); - context.dispatchEvents(); - - return STATUS_COMPLETE; } - public static boolean wasEditPolicyPressed(Context context, String buttonPressed, SubmissionInfo subInfo) throws SQLException { - if (buttonPressed.startsWith("submit_edit_edit_policies_") && !buttonPressed.equals(FORM_EDIT_BUTTON_CANCEL)){ - String idPolicy = buttonPressed.substring("submit_edit_edit_policies_".length()); - ResourcePolicy rp = resourcePolicyService.find(context, Integer.parseInt(idPolicy)); - subInfo.put(SUB_INFO_SELECTED_RP, rp); - return true; - } - return false; - } - - public boolean wasAddPolicyPressed(String buttonPressed) throws SQLException { - return (buttonPressed.equalsIgnoreCase(FORM_ACCESS_BUTTON_ADD)); - } - - public static boolean wasRemovePolicyPressed(String buttonPressed) throws SQLException { - return (buttonPressed.startsWith("submit_delete_edit_policies_")); - } - - public static boolean comeFromEditPolicy(HttpServletRequest request) throws SQLException { - return (request.getParameter("policy_id") != null); - } - - public static int saveOrCancelEditPolicy(Context context, HttpServletRequest request, SubmissionInfo subInfo, String buttonPressed, DSpaceObject dso, String name, Group group, String reason) throws AuthorizeException, SQLException { - if (buttonPressed.equals(FORM_EDIT_BUTTON_CANCEL)){ - return STATUS_COMPLETE; - } - else if (buttonPressed.equals(FORM_EDIT_BUTTON_SAVE)){ - String idPolicy = request.getParameter("policy_id"); - ResourcePolicy resourcePolicy = resourcePolicyService.find(context, Integer.parseInt(idPolicy)); - subInfo.put(SUB_INFO_SELECTED_RP, resourcePolicy); - Date dateStartDate = getEmbargoUntil(request); - if( (resourcePolicy= authorizeService.createOrModifyPolicy(resourcePolicy, context, name, group, null, dateStartDate, Constants.READ, reason, dso))==null){ - return EDIT_POLICY_STATUS_DUPLICATED_POLICY; - } - - resourcePolicyService.update(context, resourcePolicy); - context.dispatchEvents(); - } - return STATUS_COMPLETE; - } - - public static void removePolicy(Context context, String buttonPressed) throws SQLException, AuthorizeException { - String idPolicy = buttonPressed.substring("submit_delete_edit_policies_".length()); - ResourcePolicy rp = resourcePolicyService.find(context, Integer.parseInt(idPolicy)); - resourcePolicyService.delete(context, rp); - } - - public static int checkForm(HttpServletRequest request){ - - String selectedRadio=null; - String dateEmbargoUntil = request.getParameter("embargo_until_date"); - - - // RADIO_OPEN_ACCESS_ITEM_VISIBLE=0; - // RADIO_OPEN_ACCESS_ITEM_EMBARGOED=1; - if((selectedRadio=request.getParameter("open_access_radios"))!=null && Integer.parseInt(selectedRadio)==1 - && (dateEmbargoUntil==null || dateEmbargoUntil.equals(""))){ - return STATUS_ERROR_MISSING_DATE; - } - - - if(dateEmbargoUntil !=null && !dateEmbargoUntil.equals("")){ - Date startDate = getEmbargoUntilDate(request); - if(startDate==null){ - return STATUS_ERROR_FORMAT_DATE; - } - } - return 0; - } - - - - - - - - public static Date getEmbargoUntil(HttpServletRequest request) { - // RADIO_OPEN_ACCESS_ITEM_VISIBLE=0; - // RADIO_OPEN_ACCESS_ITEM_EMBARGOED=1; - String selectedRadio; - Date dateStartDate=null; - if((selectedRadio=request.getParameter("open_access_radios"))!=null && Integer.parseInt(selectedRadio)==1){ - Date startDate = getEmbargoUntilDate(request); - if(startDate!=null) dateStartDate=startDate; - } - return dateStartDate; - } - - private static Date getEmbargoUntilDate(HttpServletRequest request) { - Date startDate = null; - try { - startDate = DateUtils.parseDate(request.getParameter("embargo_until_date"), new String[]{"yyyy-MM-dd", "yyyy-MM", "yyyy"}); - } catch (Exception e) { - //Ignore start date is already null - } - return startDate; - } - - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - return 1; + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/CCLicenseStep.java b/dspace-api/src/main/java/org/dspace/submit/step/CCLicenseStep.java index 75f1237120..1c22849c3d 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/CCLicenseStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/CCLicenseStep.java @@ -7,269 +7,32 @@ */ package org.dspace.submit.step; -import java.util.Enumeration; -import java.util.Map; -import java.util.HashMap; -import org.apache.commons.lang3.*; -import javax.servlet.http.HttpSession; - import org.apache.log4j.Logger; -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Item; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; -import org.dspace.license.CCLookup; -import org.dspace.license.LicenseMetadataValue; import org.dspace.license.factory.LicenseServiceFactory; import org.dspace.license.service.CreativeCommonsService; import org.dspace.submit.AbstractProcessingStep; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.sql.SQLException; - -/** - * CCLicense step for DSpace Submission Process. - * - * Processes the - * user response to the license. - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - *

    - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @author Wendy Bossons (based on earlier CC license step work, but updated - * for DSpace 1.8 and CC web services api + curation) - * @version $Revision$ - */ -public class CCLicenseStep extends AbstractProcessingStep -{ - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - * - * (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag - * defined in the JSPStepManager class) - **************************************************************************/ - // user rejected the license - public static final int STATUS_LICENSE_REJECTED = 1; - - /** log4j logger */ +public class CCLicenseStep extends AbstractProcessingStep { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(CCLicenseStep.class); - protected final CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance().getCreativeCommonsService(); - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ + protected final CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance() + .getCreativeCommonsService(); + @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException,java.io.IOException - { - HttpSession session = request.getSession(); - session.setAttribute("inProgress", "TRUE"); - // check what submit button was pressed in User Interface - String buttonPressed = Util.getSubmitButton(request, NEXT_BUTTON); - String choiceButton = Util.getSubmitButton(request, SELECT_CHANGE); - Enumeration e = request.getParameterNames(); - String isFieldRequired = "FALSE"; - while (e.hasMoreElements()) - { - String parameterName = (String) e.nextElement(); - if (parameterName.equals("button_required")) - { - isFieldRequired = "TRUE"; - break; - } - } - session.setAttribute("isFieldRequired", isFieldRequired); - if (choiceButton.equals(SELECT_CHANGE)) - { - Item item = subInfo.getSubmissionItem().getItem(); - LicenseMetadataValue uriField = creativeCommonsService.getCCField("uri"); - String licenseUri = uriField.ccItemValue(item); - if (licenseUri != null) - { - removeRequiredAttributes(session); - } - return STATUS_COMPLETE; - } - else if (buttonPressed.startsWith(PROGRESS_BAR_PREFIX) || buttonPressed.equals(PREVIOUS_BUTTON)) - { - removeRequiredAttributes(session); - } - if (buttonPressed.equals(NEXT_BUTTON) || buttonPressed.equals(CANCEL_BUTTON) ) - { - return processCC(context, request, response, subInfo); - } - else - { - removeRequiredAttributes(session); - session.removeAttribute("inProgress"); - return STATUS_COMPLETE; - } + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub + } - - /** - * Process the input from the CC license page using CC Web service - * - * @param context - * The relevant DSpace Context. - * @param request - * Servlet's HTTP request object. - * @param response - * Servlet's HTTP response object. - * @param subInfo - * submission info object - * - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - protected int processCC(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException { - - HttpSession session = request.getSession(); - Map map = new HashMap(); - String licenseclass = (request.getParameter("licenseclass_chooser") != null) ? request.getParameter("licenseclass_chooser") : ""; - String jurisdiction = (configurationService.getProperty("cc.license.jurisdiction") != null) ? configurationService.getProperty("cc.license.jurisdiction") : ""; - if (licenseclass.equals("standard")) { - map.put("commercial", request.getParameter("commercial_chooser")); - map.put("derivatives", request.getParameter("derivatives_chooser")); - } else if (licenseclass.equals("recombo")) { - map.put("sampling", request.getParameter("sampling_chooser")); - } - map.put("jurisdiction", jurisdiction); - - LicenseMetadataValue uriField = creativeCommonsService.getCCField("uri"); - LicenseMetadataValue nameField = creativeCommonsService.getCCField("name"); - - Item item = subInfo.getSubmissionItem().getItem(); - if ("webui.Submission.submit.CCLicenseStep.no_license".equals(licenseclass) || "xmlui.Submission.submit.CCLicenseStep.no_license".equals(licenseclass)) - { - creativeCommonsService.removeLicense(context, uriField, nameField, item); - - itemService.update(context, item); - context.dispatchEvents(); - removeRequiredAttributes(session); - - return STATUS_COMPLETE; - } else if (StringUtils.isBlank(licenseclass) || "webui.Submission.submit.CCLicenseStep.select_change".equals(licenseclass) || "xmlui.Submission.submit.CCLicenseStep.select_change".equals(licenseclass)) - { - removeRequiredAttributes(session); - return STATUS_COMPLETE; - } - - CCLookup ccLookup = new CCLookup(); - ccLookup.issue(licenseclass, map, configurationService.getProperty("cc.license.locale")); - - if (ccLookup.isSuccess()) - { - creativeCommonsService.removeLicense(context, uriField, nameField, item); - - uriField.addItemValue(context, item, ccLookup.getLicenseUrl()); - if (configurationService.getBooleanProperty("cc.submit.addbitstream")) { - creativeCommonsService.setLicenseRDF(context, item, ccLookup.getRdf()); - } - if (configurationService.getBooleanProperty("cc.submit.setname")) { - nameField.addItemValue(context, item, ccLookup.getLicenseName()); - } - - itemService.update(context, item); - context.dispatchEvents(); - removeRequiredAttributes(session); - session.removeAttribute("inProgress"); - } - else - { - request.getSession().setAttribute("ccError", ccLookup.getErrorMessage()); - String licenseUri = uriField.ccItemValue(item); - if (licenseUri != null) - { - uriField.removeItemValue(context, item, licenseUri); - } - return STATUS_LICENSE_REJECTED; - } - return STATUS_COMPLETE; - } - - - private void removeRequiredAttributes(HttpSession session) { - session.removeAttribute("ccError"); - session.removeAttribute("isFieldRequired"); - } - - - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - return 1; + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub + } - -} + +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/submit/step/CompleteStep.java b/dspace-api/src/main/java/org/dspace/submit/step/CompleteStep.java index ad26c5409d..81966fedc9 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/CompleteStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/CompleteStep.java @@ -7,134 +7,26 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.sql.SQLException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang.StringUtils; - import org.apache.log4j.Logger; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.submit.AbstractProcessingStep; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.WorkspaceItem; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; -import org.dspace.core.LogManager; -import org.dspace.workflow.WorkflowService; -import org.dspace.workflow.factory.WorkflowServiceFactory; +import org.dspace.submit.AbstractProcessingStep; -/** - * This is the class which defines what happens once a submission completes! - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - *

    - * This step is non-interactive (i.e. no user interface), and simply performs - * the processing that is necessary after a submission has been completed! - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @version $Revision$ - */ -public class CompleteStep extends AbstractProcessingStep -{ - /** log4j logger */ +public class CompleteStep extends AbstractProcessingStep { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(CompleteStep.class); - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - // The Submission is COMPLETE!! - log.info(LogManager.getHeader(context, "submission_complete", - "Completed submission with id=" - + subInfo.getSubmissionItem().getID())); + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService(); - // Start the workflow for this Submission - boolean success = false; - try - { - workflowService.start(context, (WorkspaceItem) subInfo.getSubmissionItem()); - success = true; - } - catch (Exception e) - { - log.error("Caught exception in submission step: ",e); - throw new ServletException(e); - } - finally - { - // commit changes to database - if (success) - { - context.dispatchEvents(); - } - } - return STATUS_COMPLETE; } - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - // This class represents the non-interactive processing step - // that occurs just *before* the final confirmation page! - // (so it should only be processed once!) - return 1; + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub + } } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/DescribeStep.java b/dspace-api/src/main/java/org/dspace/submit/step/DescribeStep.java index a6b450b369..c1d679eab1 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/DescribeStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/DescribeStep.java @@ -7,1156 +7,15 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.sql.SQLException; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.dspace.app.util.DCInputsReader; -import org.dspace.app.util.DCInputsReaderException; -import org.dspace.app.util.DCInput; -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; -import org.dspace.content.authority.Choices; -import org.dspace.content.authority.factory.ContentAuthorityServiceFactory; -import org.dspace.content.authority.service.ChoiceAuthorityService; -import org.dspace.content.authority.service.MetadataAuthorityService; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.core.Context; -import org.dspace.services.factory.DSpaceServicesFactory; -import org.dspace.submit.AbstractProcessingStep; - /** - * Describe step for DSpace submission process. Handles the gathering of - * descriptive information (i.e. metadata) for an item being submitted into - * DSpace. - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - *

    - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @version $Revision$ + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) */ -public class DescribeStep extends AbstractProcessingStep -{ - /** log4j logger */ +public class DescribeStep extends MetadataStep { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(DescribeStep.class); - /** hash of all submission forms details */ - private static DCInputsReader inputsReader = null; - - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - * - * (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag - * defined in the JSPStepManager class) - **************************************************************************/ - // user requested an extra input field to be displayed - public static final int STATUS_MORE_INPUT_REQUESTED = 1; - - // there were required fields that were not filled out - public static final int STATUS_MISSING_REQUIRED_FIELDS = 2; - - // the metadata language qualifier - public static final String LANGUAGE_QUALIFIER = getDefaultLanguageQualifier(); - - protected final ChoiceAuthorityService choiceAuthorityService; - protected final MetadataAuthorityService metadataAuthorityService; - - - /** - * Constructor - * - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - */ - public DescribeStep() throws ServletException - { - //load the DCInputsReader - getInputsReader(); - metadataAuthorityService = ContentAuthorityServiceFactory.getInstance().getMetadataAuthorityService(); - choiceAuthorityService = ContentAuthorityServiceFactory.getInstance().getChoiceAuthorityService(); - } - - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * The relevant DSpace Context. - * @param request - * Servlet's HTTP request object. - * @param response - * Servlet's HTTP response object. - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - if (!request.getParameterNames().hasMoreElements()){ - //In case of an empty request do NOT just remove all metadata, just return to the submission page - return STATUS_MORE_INPUT_REQUESTED; - } - // check what submit button was pressed in User Interface - String buttonPressed = Util.getSubmitButton(request, NEXT_BUTTON); - - // get the item and current page - Item item = subInfo.getSubmissionItem().getItem(); - int currentPage = getCurrentPage(request); - - // lookup applicable inputs - Collection c = subInfo.getSubmissionItem().getCollection(); - DCInput[] inputs = null; - try - { - inputs = inputsReader.getInputs(c.getHandle()).getPageRows( - currentPage - 1, - subInfo.getSubmissionItem().hasMultipleTitles(), - subInfo.getSubmissionItem().isPublishedBefore()); - } - catch (DCInputsReaderException e) - { - throw new ServletException(e); - } - - // Fetch the document type (dc.type) - String documentType = ""; - if ( (itemService.getMetadataByMetadataString(item, "dc.type") != null) && (itemService.getMetadataByMetadataString(item, "dc.type").size() >0) ) - { - documentType = itemService.getMetadataByMetadataString(item, "dc.type").get(0).getValue(); - } - - // Step 1: - // clear out all item metadata defined on this page - for (int i = 0; i < inputs.length; i++) - { - - // Allow the clearing out of the metadata defined for other document types, provided it can change anytime - - if (!inputs[i] - .isVisible(subInfo.isInWorkflow() ? DCInput.WORKFLOW_SCOPE - : DCInput.SUBMISSION_SCOPE)) - { - continue; - } - if (inputs[i].getInputType().equals("qualdrop_value")) - { - @SuppressWarnings("unchecked") // This cast is correct - List pairs = inputs[i].getPairs(); - for (int j = 0; j < pairs.size(); j += 2) - { - String qualifier = pairs.get(j+1); - itemService.clearMetadata(context, item, inputs[i].getSchema(), inputs[i].getElement(), qualifier, Item.ANY); - } - } - else - { - String qualifier = inputs[i].getQualifier(); - itemService.clearMetadata(context, item, inputs[i].getSchema(), inputs[i].getElement(), qualifier, Item.ANY); - } - } - - // Clear required-field errors first since missing authority - // values can add them too. - clearErrorFields(request); - - // Step 2: - // now update the item metadata. - String fieldName; - boolean moreInput = false; - for (int j = 0; j < inputs.length; j++) - { - // Omit fields not allowed for this document type - if(!inputs[j].isAllowedFor(documentType)) - { - continue; - } - - if (!inputs[j] - .isVisible(subInfo.isInWorkflow() ? DCInput.WORKFLOW_SCOPE - : DCInput.SUBMISSION_SCOPE)) - { - continue; - } - String element = inputs[j].getElement(); - String qualifier = inputs[j].getQualifier(); - String schema = inputs[j].getSchema(); - if (qualifier != null && !qualifier.equals(Item.ANY)) - { - fieldName = schema + "_" + element + '_' + qualifier; - } - else - { - fieldName = schema + "_" + element; - } - - String fieldKey = metadataAuthorityService.makeFieldKey(schema, element, qualifier); - String inputType = inputs[j].getInputType(); - if (inputType.equals("name")) - { - readNames(context, request, item, schema, element, qualifier, inputs[j] - .getRepeatable()); - } - else if (inputType.equals("date")) - { - readDate(context, request, item, schema, element, qualifier); - } - // choice-controlled input with "select" presentation type is - // always rendered as a dropdown menu - else if (inputType.equals("dropdown") || inputType.equals("list") || - (choiceAuthorityService.isChoicesConfigured(fieldKey) && - "select".equals(choiceAuthorityService.getPresentation(fieldKey)))) - { - String[] vals = request.getParameterValues(fieldName); - if (vals != null) - { - for (int z = 0; z < vals.length; z++) - { - if (!vals[z].equals("")) - { - itemService.addMetadata(context, item, schema, element, qualifier, LANGUAGE_QUALIFIER, - vals[z]); - } - } - } - } - else if (inputType.equals("series")) - { - readSeriesNumbers(context, request, item, schema, element, qualifier, - inputs[j].getRepeatable()); - } - else if (inputType.equals("qualdrop_value")) - { - List quals = getRepeatedParameter(request, schema + "_" - + element, schema + "_" + element + "_qualifier"); - List vals = getRepeatedParameter(request, schema + "_" - + element, schema + "_" + element + "_value"); - for (int z = 0; z < vals.size(); z++) - { - String thisQual = quals.get(z); - if ("".equals(thisQual)) - { - thisQual = null; - } - String thisVal = vals.get(z); - if (!buttonPressed.equals("submit_" + schema + "_" - + element + "_remove_" + z) - && !thisVal.equals("")) - { - itemService.addMetadata(context, item, schema, element, thisQual, null, - thisVal); - } - } - } - else if ((inputType.equals("onebox")) - || (inputType.equals("twobox")) - || (inputType.equals("textarea"))) - { - readText(context, request, item, schema, element, qualifier, inputs[j] - .getRepeatable(), LANGUAGE_QUALIFIER, inputs[j].getLanguage()); - } - else - { - throw new ServletException("Field " + fieldName - + " has an unknown input type: " + inputType); - } - - // determine if more input fields were requested - if (!moreInput - && buttonPressed.equals("submit_" + fieldName + "_add")) - { - subInfo.setMoreBoxesFor(fieldName); - subInfo.setJumpToField(fieldName); - moreInput = true; - } - // was XMLUI's "remove" button pushed? - else if (buttonPressed.equals("submit_" + fieldName + "_delete")) - { - subInfo.setJumpToField(fieldName); - } - } - - // Step 3: - // Check to see if any fields are missing - // Only check for required fields if user clicked the "next", the "previous" or the "progress bar" button - if (buttonPressed.equals(NEXT_BUTTON) - || buttonPressed.startsWith(PROGRESS_BAR_PREFIX) - || buttonPressed.equals(PREVIOUS_BUTTON) - || buttonPressed.equals(CANCEL_BUTTON)) - { - for (int i = 0; i < inputs.length; i++) - { - // Do not check the required attribute if it is not visible or not allowed for the document type - String scope = subInfo.isInWorkflow() ? DCInput.WORKFLOW_SCOPE : DCInput.SUBMISSION_SCOPE; - if ( !( inputs[i].isVisible(scope) && inputs[i].isAllowedFor(documentType) ) ) - { - continue; - } - - String qualifier = inputs[i].getQualifier(); - if (qualifier == null - && inputs[i].getInputType().equals("qualdrop_value")) - { - qualifier = Item.ANY; - } - List values = itemService.getMetadata(item, inputs[i].getSchema(), - inputs[i].getElement(), qualifier, Item.ANY); - - if ((inputs[i].isRequired() && values.size() == 0) && - inputs[i].isVisible(subInfo.isInWorkflow() ? DCInput.WORKFLOW_SCOPE : DCInput.SUBMISSION_SCOPE)) - { - // since this field is missing add to list of error fields - addErrorField(request, getFieldName(inputs[i])); - } - } - } - - // Step 4: - // Save changes to database - ContentServiceFactory.getInstance().getInProgressSubmissionService(subInfo.getSubmissionItem()).update(context, subInfo.getSubmissionItem()); - - // commit changes - context.dispatchEvents(); - - // check for request for more input fields, first - if (moreInput) - { - return STATUS_MORE_INPUT_REQUESTED; - } - // if one or more fields errored out, return - else if (getErrorFields(request) != null && getErrorFields(request).size() > 0) - { - return STATUS_MISSING_REQUIRED_FIELDS; - } - - // completed without errors - return STATUS_COMPLETE; - } - - - - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - */ - @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - // by default, use the "default" collection handle - String collectionHandle = DCInputsReader.DEFAULT_COLLECTION; - - if (subInfo.getSubmissionItem() != null) - { - collectionHandle = subInfo.getSubmissionItem().getCollection() - .getHandle(); - } - - // get number of input pages (i.e. "Describe" pages) - try - { - return getInputsReader().getNumberInputPages(collectionHandle); - } - catch (DCInputsReaderException e) - { - throw new ServletException(e); - } - } - - /** - * - * @return the current DCInputsReader - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - */ - public static DCInputsReader getInputsReader() throws ServletException - { - // load inputsReader only the first time - if (inputsReader == null) - { - // read configurable submissions forms data - try - { - inputsReader = new DCInputsReader(); - } - catch (DCInputsReaderException e) - { - throw new ServletException(e); - } - } - - return inputsReader; - } - - /** - * @param filename - * file to get the input reader for - * @return the current DCInputsReader - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - */ - public static DCInputsReader getInputsReader(String filename) throws ServletException - { - try - { - inputsReader = new DCInputsReader(filename); - } - catch (DCInputsReaderException e) - { - throw new ServletException(e); - } - return inputsReader; - } - - /** - * @return the default language qualifier for metadata - */ - - public static String getDefaultLanguageQualifier() - { - String language = ""; - language = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("default.language"); - if (StringUtils.isEmpty(language)) - { - language = "en"; - } - return language; - } - - // **************************************************************** - // **************************************************************** - // METHODS FOR FILLING DC FIELDS FROM METADATA FORMS - // **************************************************************** - // **************************************************************** - - /** - * Set relevant metadata fields in an item from name values in the form. - * Some fields are repeatable in the form. If this is the case, and the - * field is "dc.contributor.author", the names in the request will be from - * the fields as follows: - * - * dc_contributor_author_last: last name of first author - * dc_contributor_author_first: first name(s) of first author - * dc_contributor_author_last_1: last name of second author - * dc_contributor_author_first_1: first name(s) of second author - * - * and so on. If the field is unqualified: - * - * dc_contributor_last: last name of first contributor - * dc_contributor_first: first name(s) of first contributor - * - * If the parameter "submit_dc_contributor_author_remove_n" is set, that - * value is removed. - * - * Otherwise the parameters are of the form: - * - * dc_contributor_author_last dc_contributor_author_first - * - * The values will be put in separate DCValues, in the form "last name, - * first name(s)", ordered as they appear in the list. These will replace - * any existing values. - * - * @param context - * The relevant DSpace Context. - * @param request - * the request object - * @param item - * the item to update - * @param schema - * the metadata schema - * @param element - * the metadata element - * @param qualifier - * the metadata qualifier, or null if unqualified - * @param repeated - * set to true if the field is repeatable on the form - * @throws SQLException - * An exception that provides information on a database access error or other errors. - */ - protected void readNames(Context context, HttpServletRequest request, Item item, - String schema, String element, String qualifier, boolean repeated) throws SQLException { - String metadataField = metadataFieldService.findByElement(context, schema, element, qualifier).toString(); - - String fieldKey = metadataAuthorityService.makeFieldKey(schema, element, qualifier); - boolean isAuthorityControlled = metadataAuthorityService.isAuthorityControlled(fieldKey); - - // Names to add - List firsts = new LinkedList(); - List lasts = new LinkedList(); - List auths = new LinkedList(); - List confs = new LinkedList(); - - if (repeated) - { - firsts = getRepeatedParameter(request, metadataField, metadataField - + "_first"); - lasts = getRepeatedParameter(request, metadataField, metadataField - + "_last"); - - if(isAuthorityControlled) - { - auths = getRepeatedParameter(request, metadataField, metadataField - + "_authority"); - confs = getRepeatedParameter(request, metadataField, metadataField - + "_confidence"); - } - - // Find out if the relevant "remove" button was pressed - // TODO: These separate remove buttons are only relevant - // for DSpace JSP UI, and the code below can be removed - // once the DSpace JSP UI is obsolete! - String buttonPressed = Util.getSubmitButton(request, ""); - String removeButton = "submit_" + metadataField + "_remove_"; - - if (buttonPressed.startsWith(removeButton)) - { - int valToRemove = Integer.parseInt(buttonPressed - .substring(removeButton.length())); - - firsts.remove(valToRemove); - lasts.remove(valToRemove); - if(isAuthorityControlled) - { - if(valToRemove < auths.size()) - { - auths.remove(valToRemove); - confs.remove(valToRemove); - } - } - } - } - else - { - // Just a single name - String lastName = request.getParameter(metadataField + "_last"); - String firstNames = request.getParameter(metadataField + "_first"); - String authority = request.getParameter(metadataField + "_authority"); - String confidence = request.getParameter(metadataField + "_confidence"); - - if (lastName != null) - { - lasts.add(lastName); - } - if (firstNames != null) - { - firsts.add(firstNames); - } - auths.add(authority == null ? "" : authority); - confs.add(confidence == null ? "" : confidence); - } - - // Remove existing values, already done in doProcessing see also bug DS-203 - // item.clearMetadata(schema, element, qualifier, Item.ANY); - - // Put the names in the correct form - for (int i = 0; i < lasts.size(); i++) - { - String f = firsts.get(i); - String l = lasts.get(i); - - // only add if lastname is non-empty - if ((l != null) && !((l.trim()).equals(""))) - { - // Ensure first name non-null - if (f == null) - { - f = ""; - } - - // If there is a comma in the last name, we take everything - // after that comma, and add it to the right of the - // first name - int comma = l.indexOf(','); - - if (comma >= 0) - { - f = f + l.substring(comma + 1); - l = l.substring(0, comma); - - // Remove leading whitespace from first name - while (f.startsWith(" ")) - { - f = f.substring(1); - } - } - - // Add to the database -- unless required authority is missing - if (isAuthorityControlled) - { - String authKey = auths.size() > i ? auths.get(i) : null; - String sconf = (authKey != null && confs.size() > i) ? confs.get(i) : null; - if (metadataAuthorityService.isAuthorityRequired(fieldKey) && - (authKey == null || authKey.length() == 0)) - { - log.warn("Skipping value of "+metadataField+" because the required Authority key is missing or empty."); - addErrorField(request, metadataField); - } - else - { - itemService.addMetadata(context, item, schema, element, qualifier, null, - new DCPersonName(l, f).toString(), authKey, - (sconf != null && sconf.length() > 0) ? - Choices.getConfidenceValue(sconf) : Choices.CF_ACCEPTED); - } - } - else - { - itemService.addMetadata(context, item, schema, element, qualifier, null, - new DCPersonName(l, f).toString()); - } - } - } - } - - /** - * Fill out an item's metadata values from a plain standard text field. If - * the field isn't repeatable, the input field name is called: - * - * element_qualifier - * - * or for an unqualified element: - * - * element - * - * Repeated elements are appended with an underscore then an integer. e.g.: - * - * dc_title_alternative dc_title_alternative_1 - * - * The values will be put in separate DCValues, ordered as they appear in - * the list. These will replace any existing values. - * - * @param context - * The relevant DSpace Context. - * @param request - * Servlet's HTTP request object. - * @param item - * the item to update - * @param schema - * the short schema name - * @param element - * the metadata element - * @param qualifier - * the metadata qualifier, or null if unqualified - * @param repeated - * set to true if the field is repeatable on the form - * @param lang - * language to set (ISO code) - * @param hasLanguageTag - * to check if the field has a language tag - * @throws SQLException - * An exception that provides information on a database access error or other errors. - */ - protected void readText(Context context, HttpServletRequest request, Item item, String schema, - String element, String qualifier, boolean repeated, String lang, boolean hasLanguageTag) - throws SQLException - { - // FIXME: Of course, language should be part of form, or determined - // some other way - String metadataField = metadataFieldService.findByElement(context, schema, element, qualifier).toString(); - - String fieldKey = metadataAuthorityService.makeFieldKey(schema, element, qualifier); - boolean isAuthorityControlled = metadataAuthorityService.isAuthorityControlled(fieldKey); - - // Values to add - TreeMap vals = null; - List auths = null; - List confs = null; - - if (repeated) - { - vals = getRepeatedParameterWithTheirIndices(request, metadataField, metadataField); - if (isAuthorityControlled) - { - auths = getRepeatedParameter(request, metadataField, metadataField+"_authority"); - confs = getRepeatedParameter(request, metadataField, metadataField+"_confidence"); - } - - // Find out if the relevant "remove" button was pressed - // TODO: These separate remove buttons are only relevant - // for DSpace JSP UI, and the code below can be removed - // once the DSpace JSP UI is obsolete! - String buttonPressed = Util.getSubmitButton(request, ""); - String removeButton = "submit_" + metadataField + "_remove_"; - - if (buttonPressed.startsWith(removeButton)) - { - int valToRemove = Integer.parseInt(buttonPressed - .substring(removeButton.length())); - - //find the key from the given position - //for more information take a look at < Edit-metadata.jsp> - int key = vals.keySet().toArray(new Integer[vals.size()])[valToRemove]; - vals.remove(key); - if(isAuthorityControlled) - { - auths.remove(valToRemove); - confs.remove(valToRemove); - } - } - } - else - { - // Just a single name - vals = new TreeMap(); - String value = request.getParameter(metadataField); - if (value != null) - { - vals.put(0, value.trim()); - } - if (isAuthorityControlled) - { - auths = new LinkedList(); - confs = new LinkedList(); - String av = request.getParameter(metadataField+"_authority"); - String cv = request.getParameter(metadataField+"_confidence"); - auths.add(av == null ? "":av.trim()); - confs.add(cv == null ? "":cv.trim()); - } - } - - // Remove existing values, already done in doProcessing see also bug DS-203 - // item.clearMetadata(schema, element, qualifier, Item.ANY); - - int i=0; - - // Put the names in the correct form - for(Map.Entry entry: vals.entrySet()) - { - // Add to the database if non-empty - - String s = entry.getValue(); - int key = entry.getKey(); - if ((s != null) && !s.equals("")) - { - if (hasLanguageTag && !repeated && key == 0) - { - // the field is like dc_title[lang] for none repeatable element, - // dc_title_alternative_2[lang] otherwise - lang = request.getParameter(metadataField + "[lang]"); - - } - else if (hasLanguageTag && repeated) - { - lang = request.getParameter(metadataField + "_" + key + "[lang]"); - } - - if (isAuthorityControlled) - { - String authKey = auths.size() > i ? auths.get(i) : null; - String sconf = (authKey != null && confs.size() > i) ? confs.get(i) : null; - if (metadataAuthorityService.isAuthorityRequired(fieldKey) && - (authKey == null || authKey.length() == 0)) - { - log.warn("Skipping value of "+metadataField+" because the required Authority key is missing or empty."); - addErrorField(request, metadataField); - } - else - { - itemService.addMetadata(context, item, schema, element, qualifier, lang, s, - authKey, (sconf != null && sconf.length() > 0) ? - Choices.getConfidenceValue(sconf) : Choices.CF_ACCEPTED); - } - } - else - { - itemService.addMetadata(context, item, schema, element, qualifier, lang, s); - } - } - i++; - } - } - - /** - * Fill out a metadata date field with the value from a form. The date is - * taken from the three parameters: - * - * element_qualifier_year element_qualifier_month element_qualifier_day - * - * The granularity is determined by the values that are actually set. If the - * year isn't set (or is invalid) - * - * @param context - * The relevant DSpace Context. - * @param request - * the request object - * @param item - * the item to update - * @param schema - * the metadata schema - * @param element - * the metadata element - * @param qualifier - * the metadata qualifier, or null if unqualified - * @throws SQLException if database error - */ - protected void readDate(Context context, HttpServletRequest request, Item item, String schema, - String element, String qualifier) throws SQLException - { - String metadataField = metadataFieldService.findByElement(context, schema, element, qualifier).toString(); - - int year = Util.getIntParameter(request, metadataField + "_year"); - int month = Util.getIntParameter(request, metadataField + "_month"); - int day = Util.getIntParameter(request, metadataField + "_day"); - - // FIXME: Probably should be some more validation - // Make a standard format date - DCDate d = new DCDate(year, month, day, -1, -1, -1); - - // already done in doProcessing see also bug DS-203 - // item.clearMetadata(schema, element, qualifier, Item.ANY); - - if (year > 0) - { - // Only put in date if there is one! - itemService.addMetadata(context, item, schema, element, qualifier, null, d.toString()); - } - } - - /** - * Set relevant metadata fields in an item from series/number values in the - * form. Some fields are repeatable in the form. If this is the case, and - * the field is "relation.ispartof", the names in the request will be from - * the fields as follows: - * - * dc_relation_ispartof_series dc_relation_ispartof_number - * dc_relation_ispartof_series_1 dc_relation_ispartof_number_1 - * - * and so on. If the field is unqualified: - * - * dc_relation_series dc_relation_number - * - * Otherwise the parameters are of the form: - * - * dc_relation_ispartof_series dc_relation_ispartof_number - * - * The values will be put in separate DCValues, in the form "last name, - * first name(s)", ordered as they appear in the list. These will replace - * any existing values. - * - * @param context - * The relevant DSpace Context. - * @param request - * Servlet's HTTP request object. - * @param item - * the item to update - * @param schema - * the metadata schema - * @param element - * the metadata element - * @param qualifier - * the metadata qualifier, or null if unqualified - * @param repeated - * set to true if the field is repeatable on the form - * @throws SQLException - * An exception that provides information on a database access error or other errors. - */ - protected void readSeriesNumbers(Context context, HttpServletRequest request, Item item, - String schema, String element, String qualifier, boolean repeated) throws SQLException { - String metadataField = metadataFieldService.findByElement(context, schema, element, qualifier).toString(); - - // Names to add - List series = new LinkedList(); - List numbers = new LinkedList(); - - if (repeated) - { - series = getRepeatedParameter(request, metadataField, metadataField - + "_series"); - numbers = getRepeatedParameter(request, metadataField, - metadataField + "_number"); - - // Find out if the relevant "remove" button was pressed - String buttonPressed = Util.getSubmitButton(request, ""); - String removeButton = "submit_" + metadataField + "_remove_"; - - if (buttonPressed.startsWith(removeButton)) - { - int valToRemove = Integer.parseInt(buttonPressed - .substring(removeButton.length())); - - series.remove(valToRemove); - numbers.remove(valToRemove); - } - } - else - { - // Just a single name - String s = request.getParameter(metadataField + "_series"); - String n = request.getParameter(metadataField + "_number"); - - // Only put it in if there was a name present - if ((s != null) && !s.equals("")) - { - // if number is null, just set to a nullstring - if (n == null) - { - n = ""; - } - - series.add(s); - numbers.add(n); - } - } - - // Remove existing values, already done in doProcessing see also bug DS-203 - // item.clearMetadata(schema, element, qualifier, Item.ANY); - - // Put the names in the correct form - for (int i = 0; i < series.size(); i++) - { - String s = (series.get(i)).trim(); - String n = (numbers.get(i)).trim(); - - // Only add non-empty - if (!s.equals("") || !n.equals("")) - { - itemService.addMetadata(context, item, schema, element, qualifier, null, - new DCSeriesNumber(s, n).toString()); - } - } - } - - /** - * Get repeated values from a form. If "foo" is passed in as the parameter, - * values in the form of parameters "foo", "foo_1", "foo_2", etc. are - * returned. - *

    - * This method can also handle "composite fields" (metadata fields which may - * require multiple params, etc. a first name and last name). - * - * @param request - * the HTTP request containing the form information - * @param metadataField - * the metadata field which can store repeated values - * @param param - * the repeated parameter on the page (used to fill out the - * metadataField) - * - * @return a List of Strings - */ - protected List getRepeatedParameter(HttpServletRequest request, - String metadataField, String param) - { - List vals = new LinkedList(); - - int i = 1; //start index at the first of the previously entered values - boolean foundLast = false; - - // Iterate through the values in the form. - while (!foundLast) - { - String s = null; - - //First, add the previously entered values. - // This ensures we preserve the order that these values were entered - s = request.getParameter(param + "_" + i); - - // If there are no more previously entered values, - // see if there's a new value entered in textbox - if (s==null) - { - s = request.getParameter(param); - //this will be the last value added - foundLast = true; - } - - // We're only going to add non-null values - if (s != null) - { - boolean addValue = true; - - // Check to make sure that this value was not selected to be - // removed. - // (This is for the "remove multiple" option available in - // Manakin) - String[] selected = request.getParameterValues(metadataField - + "_selected"); - - if (selected != null) - { - for (int j = 0; j < selected.length; j++) - { - if (selected[j].equals(metadataField + "_" + i)) - { - addValue = false; - } - } - } - - if (addValue) - { - vals.add(s.trim()); - } - } - - i++; - } - - log.debug("getRepeatedParameter: metadataField=" + metadataField - + " param=" + metadataField + ", return count = "+vals.size()); - - return vals; - } - - /** - * This Methode has the same function as the getRepeatedParameter. - * For repeated values with language tag their indices are needed to - * properly identify their language tag - * - * @param request - * the HTTP request containing the form information - * @param metadataField - * the metadata field which can store repeated values - * @param param - * the repeated parameter on the page (used to fill out the - * metadataField) - * @return a TreeMap of Integer and Strings - */ - protected TreeMap getRepeatedParameterWithTheirIndices(HttpServletRequest request, - String metadataField, String param) - { - LinkedHashMap vals = new LinkedHashMap(); - - int i = 1; //start index at the first of the previously entered values - boolean foundLast = false; - - // Iterate through the values in the form. - while (!foundLast) - { - String s = null; - - //First, add the previously entered values. - // This ensures we preserve the order that these values were entered - s = request.getParameter(param + "_" + i); - - // If there are no more previously entered values, - // see if there's a new value entered in textbox - if (s==null) - { - s = request.getParameter(param); - //this will be the last value added - foundLast = true; - } - - // We're only going to add non-null values - if (s != null) - { - boolean addValue = true; - - // Check to make sure that this value was not selected to be - // removed. - String[] selected = request.getParameterValues(metadataField - + "_selected"); - - if (selected != null) - { - for (int j = 0; j < selected.length; j++) - { - if (selected[j].equals(metadataField + "_" + i)) - { - addValue = false; - } - } - } - - if (addValue) - { - vals.put(i, s.trim()); - } - } - - i++; - } - - log.debug("getRepeatedParameterWithTheirIndices: metadataField=" + metadataField - + " param=" + metadataField + ", return count = "+vals.size()); - - return new TreeMap(vals); - } - - /** - * Return the HTML / DRI field name for the given input. - * - * @param input - * represents line in an imput form - * @return metadata field in the "schema_element_qualifier" format - */ - public static String getFieldName(DCInput input) - { - String dcSchema = input.getSchema(); - String dcElement = input.getElement(); - String dcQualifier = input.getQualifier(); - if (dcQualifier != null && !dcQualifier.equals(Item.ANY)) - { - return dcSchema + "_" + dcElement + '_' + dcQualifier; - } - else - { - return dcSchema + "_" + dcElement; - } - - } } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/ExtractionStep.java b/dspace-api/src/main/java/org/dspace/submit/step/ExtractionStep.java new file mode 100644 index 0000000000..70f0cacfef --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/step/ExtractionStep.java @@ -0,0 +1,22 @@ +/** + * 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.submit.step; + +import org.apache.log4j.Logger; + +/** + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + */ +public class ExtractionStep extends MetadataStep { + /** + * log4j logger + */ + private static Logger log = Logger + .getLogger(ExtractionStep.class); + +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/submit/step/InitialQuestionsStep.java b/dspace-api/src/main/java/org/dspace/submit/step/InitialQuestionsStep.java index 9c7d7104da..e5d9615add 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/InitialQuestionsStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/InitialQuestionsStep.java @@ -7,347 +7,21 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.WorkspaceItemService; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; import org.dspace.submit.AbstractProcessingStep; -/** - * Initial Submission servlet for DSpace. Handles the initial questions which - * are asked to users to gather information regarding what metadata needs to be - * gathered. - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - *

    - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @version $Revision$ - */ -public class InitialQuestionsStep extends AbstractProcessingStep -{ - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - * - * (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag - * defined in the JSPStepManager class) - **************************************************************************/ - // pruning of metadata needs to take place - public static final int STATUS_VERIFY_PRUNE = 1; +public class InitialQuestionsStep extends AbstractProcessingStep { - // pruning was cancelled by user - public static final int STATUS_CANCEL_PRUNE = 2; - - // user attempted to upload a thesis, when theses are not accepted - public static final int STATUS_THESIS_REJECTED = 3; - - /** - * Global flags to determine if we need to prune anything - */ - protected boolean willRemoveTitles = false; - - protected boolean willRemoveDate = false; - - protected boolean willRemoveFiles = false; - - protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - // Get the values from the initial questions form - boolean multipleTitles = Util.getBoolParameter(request, - "multiple_titles"); - boolean publishedBefore = Util.getBoolParameter(request, - "published_before"); - boolean multipleFiles = Util.getBoolParameter(request, - "multiple_files"); - boolean isThesis = configurationService.getBooleanProperty("webui.submit.blocktheses") - && Util.getBoolParameter(request, "is_thesis"); + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - if (subInfo.isInWorkflow()) - { - // Thesis question does not appear in workflow mode.. - isThesis = false; - - // Pretend "multiple files" is true in workflow mode - // (There will always be the license file) - multipleFiles = true; - } - - // First and foremost - if it's a thesis, reject the submission - if (isThesis) - { - WorkspaceItem wi = (WorkspaceItem) subInfo.getSubmissionItem(); - workspaceItemService.deleteAll(context, wi); - subInfo.setSubmissionItem(null); - - // Remember that we've removed a thesis in the session - request.getSession().setAttribute("removed_thesis", - Boolean.TRUE); - - return STATUS_THESIS_REJECTED; // since theses are disabled, throw - // an error! - } - - // Next, check if we are pruning some existing metadata - Item item = subInfo.getSubmissionItem().getItem(); - if (request.getParameter("do_not_prune") != null) - { - return STATUS_CANCEL_PRUNE; // cancelled pruning! - } - else if (request.getParameter("prune") != null) - { - processVerifyPrune(context, request, response, subInfo, - multipleTitles, publishedBefore, multipleFiles); - } - else - // otherwise, check if pruning is necessary - { - // Now check to see if the changes will remove any values - // (i.e. multiple files, titles or an issue date.) - - if (subInfo.getSubmissionItem() != null) - { - // shouldn't need to check if submission is null, but just in case! - if (!multipleTitles) - { - List altTitles = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "title", "alternative", Item.ANY); - - willRemoveTitles = altTitles.size() > 0; - } - - if (!publishedBefore) - { - List dateIssued = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); - List citation = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "citation", Item.ANY); - List publisher = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "publisher", null, Item.ANY); - - willRemoveDate = (dateIssued.size() > 0) - || (citation.size() > 0) || (publisher.size() > 0); - } - - if (!multipleFiles) - { - // see if number of bitstreams in "ORIGINAL" bundle > 1 - // FIXME: Assumes multiple bundles, clean up someday... - List bundles = itemService - .getBundles(item, "ORIGINAL"); - - if (bundles.size() > 0) - { - List bitstreams = bundles.get(0).getBitstreams(); - - willRemoveFiles = bitstreams.size() > 1; - } - } - } - - // If anything is going to be removed from the item as a result - // of changing the answer to one of the questions, we need - // to inform the user and make sure that's OK, before saving! - if (willRemoveTitles || willRemoveDate || willRemoveFiles) - { - //save what we will need to prune to request (for UI to process) - request.setAttribute("will.remove.titles", Boolean.valueOf(willRemoveTitles)); - request.setAttribute("will.remove.date", Boolean.valueOf(willRemoveDate)); - request.setAttribute("will.remove.files", Boolean.valueOf(willRemoveFiles)); - - return STATUS_VERIFY_PRUNE; // we will need to do pruning! - } - } - - // If step is complete, save the changes - subInfo.getSubmissionItem().setMultipleTitles(multipleTitles); - subInfo.getSubmissionItem().setPublishedBefore(publishedBefore); - - // "Multiple files" irrelevant in workflow mode - if (!subInfo.isInWorkflow()) - { - subInfo.getSubmissionItem().setMultipleFiles(multipleFiles); - } - - // If this work has not been published before & no issued date is set, - // then the assumption is that TODAY is the issued date. - // (This logic is necessary since the date field is hidden on DescribeStep when publishedBefore==false) - if(!publishedBefore) - { - List dateIssued = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); - if(dateIssued.size()==0) - { - //Set issued date to "today" (NOTE: InstallItem will determine the actual date for us) - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "issued", null, "today"); - } - } - - // commit all changes to DB - ContentServiceFactory.getInstance().getInProgressSubmissionService(subInfo.getSubmissionItem()).update(context, subInfo.getSubmissionItem()); - context.dispatchEvents(); - - return STATUS_COMPLETE; // no errors! } - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - // always just one page of initial questions - return 1; - } + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - /** - * Process input from "verify prune" page - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @param multipleTitles - * if there is multiple titles - * @param publishedBefore - * if published before - * @param multipleFiles - * if there will be multiple files - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - protected void processVerifyPrune(Context context, - HttpServletRequest request, HttpServletResponse response, - SubmissionInfo subInfo, boolean multipleTitles, - boolean publishedBefore, boolean multipleFiles) - throws ServletException, IOException, SQLException, - AuthorizeException - { - // get the item to prune - Item item = subInfo.getSubmissionItem().getItem(); - - if (!multipleTitles && subInfo.getSubmissionItem().hasMultipleTitles()) - { - itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, "title", "alternative", Item.ANY); - } - - if (!publishedBefore && subInfo.getSubmissionItem().isPublishedBefore()) - { - itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); - itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "citation", Item.ANY); - itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, "publisher", null, Item.ANY); - } - - if (!multipleFiles && subInfo.getSubmissionItem().hasMultipleFiles()) - { - // remove all but first bitstream from bundle[0] - // FIXME: Assumes multiple bundles, clean up someday... - // (only messes with the first bundle.) - List bundles = itemService.getBundles(item, "ORIGINAL"); - - if (bundles.size() > 0) - { - Iterator bitstreams = bundles.get(0).getBitstreams().iterator(); - //Do NOT remove the first one - if(bitstreams.hasNext()) - { - bitstreams.next(); - } - - while (bitstreams.hasNext()) - { - //TODO: HIBERNATE, write unit test for this - Bitstream bitstream = bitstreams.next(); - bundleService.removeBitstream(context, bundles.get(0), bitstream); - } - } - } } } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/LicenseStep.java b/dspace-api/src/main/java/org/dspace/submit/step/LicenseStep.java index 7129173550..d54dbac79c 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/LicenseStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/LicenseStep.java @@ -7,172 +7,27 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.sql.SQLException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.apache.log4j.Logger; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Item; -import org.dspace.content.LicenseUtils; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; -import org.dspace.core.LogManager; -import org.dspace.eperson.EPerson; import org.dspace.submit.AbstractProcessingStep; -/** - * License step for DSpace Submission Process. Processes the - * user response to the license. - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - *

    - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @version $Revision$ - */ -public class LicenseStep extends AbstractProcessingStep -{ - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - * - * (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag - * defined in the JSPStepManager class) - **************************************************************************/ - // user rejected the license - public static final int STATUS_LICENSE_REJECTED = 1; +public class LicenseStep extends AbstractProcessingStep { - /** log4j logger */ + /** + * log4j logger + */ private static Logger log = Logger.getLogger(LicenseStep.class); - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - String buttonPressed = Util.getSubmitButton(request, CANCEL_BUTTON); - - boolean licenseGranted = false; - - // For Manakin: - // Accepting the license means checking a box and clicking Next - String decision = request.getParameter("decision"); - if (decision != null && decision.equalsIgnoreCase("accept") - && buttonPressed.equals(NEXT_BUTTON)) - { - licenseGranted = true; - } - // For JSP-UI: User just needed to click "I Accept" button - else if (buttonPressed.equals("submit_grant")) - { - licenseGranted = true; - }// JSP-UI: License was explicitly rejected - else if (buttonPressed.equals("submit_reject")) - { - licenseGranted = false; - }// Manakin UI: user didn't make a decision and clicked Next-> - else if (buttonPressed.equals(NEXT_BUTTON)) - { - // no decision made (this will cause Manakin to display an error) - return STATUS_LICENSE_REJECTED; - } - - if (licenseGranted - && (buttonPressed.equals("submit_grant") || buttonPressed - .equals(NEXT_BUTTON))) - { - // License granted - log.info(LogManager.getHeader(context, "accept_license", - subInfo.getSubmissionLogInfo())); - - // Add the license to the item - Item item = subInfo.getSubmissionItem().getItem(); - EPerson submitter = context.getCurrentUser(); - - // remove any existing DSpace license (just in case the user - // accepted it previously) - itemService.removeDSpaceLicense(context, item); - - String license = LicenseUtils.getLicenseText(context - .getCurrentLocale(), subInfo.getSubmissionItem() - .getCollection(), item, submitter); - - LicenseUtils.grantLicense(context, item, license); - - // commit changes - context.dispatchEvents(); - } - - // completed without errors - return STATUS_COMPLETE; - } - - - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ - @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - return 1; + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub } + @Override + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub + + } } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/MetadataStep.java b/dspace-api/src/main/java/org/dspace/submit/step/MetadataStep.java new file mode 100644 index 0000000000..c0998bcb2e --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/submit/step/MetadataStep.java @@ -0,0 +1,197 @@ +/** + * 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.submit.step; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import gr.ekt.bte.core.DataLoader; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.Value; +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpException; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.InProgressSubmission; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.core.Context; +import org.dspace.core.Utils; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.dspace.submit.AbstractProcessingStep; +import org.dspace.submit.listener.MetadataListener; +import org.dspace.submit.lookup.SubmissionLookupDataLoader; + +//FIXME move to the ExtractionStep +/** + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + */ +public class MetadataStep extends AbstractProcessingStep { + /** + * log4j logger + */ + private static Logger log = Logger.getLogger(MetadataStep.class); + + protected List listeners = DSpaceServicesFactory.getInstance().getServiceManager() + .getServicesByType(MetadataListener.class); + + protected Map> metadataMap = new HashMap>(); + private Map> results = new HashMap>(); + private Map mappingIdentifier = new HashMap(); + + @Override + public void doPreProcessing(Context context, InProgressSubmission wsi) { + for (MetadataListener listener : listeners) { + for (String metadata : listener.getMetadata().keySet()) { + String[] tokenized = Utils.tokenize(metadata); + List mm = itemService.getMetadata(wsi.getItem(), tokenized[0], tokenized[1], + tokenized[2], Item.ANY); + if (mm != null && !mm.isEmpty()) { + metadataMap.put(metadata, mm); + } else { + metadataMap.put(metadata, new ArrayList()); + } + mappingIdentifier.put(metadata, listener.getMetadata().get(metadata)); + } + } + } + + @Override + public void doPostProcessing(Context context, InProgressSubmission wsi) { + external: + for (String metadata : metadataMap.keySet()) { + String[] tokenized = Utils.tokenize(metadata); + List currents = itemService.getMetadata(wsi.getItem(), tokenized[0], tokenized[1], + tokenized[2], Item.ANY); + if (currents != null && !currents.isEmpty()) { + List olds = metadataMap.get(metadata); + if (olds.isEmpty()) { + process(context, metadata, currents); + continue external; + } + internal: + for (MetadataValue current : currents) { + + boolean found = false; + for (MetadataValue old : olds) { + if (old.getValue().equals(current.getValue())) { + found = true; + } + } + if (!found) { + process(context, metadata, current); + } + } + } + } + + if (!results.isEmpty()) { + for (MetadataListener listener : listeners) { + for (DataLoader dataLoader : listener.getDataloadersMap().values()) { + SubmissionLookupDataLoader submissionLookupDataLoader = (SubmissionLookupDataLoader) dataLoader; + try { + List recordSet = submissionLookupDataLoader.getByIdentifier(context, results); + List resultSet = convertFields(recordSet, bteBatchImportService.getOutputMap()); + enrichItem(context, resultSet, wsi.getItem()); + } catch (HttpException | IOException | SQLException | AuthorizeException e) { + log.error(e.getMessage(), e); + } + } + } + } + } + + protected void enrichItem(Context context, List rset, Item item) throws SQLException, AuthorizeException { + for (Record record : rset) { + for (String field : record.getFields()) { + try { + String[] tfield = Utils.tokenize(field); + List mdvs = itemService + .getMetadata(item, tfield[0], tfield[1], tfield[2], Item.ANY); + if (mdvs == null || mdvs.isEmpty()) { + for (Value value : record.getValues(field)) { + + itemService.addMetadata(context, item, tfield[0], tfield[1], tfield[2], null, + value.getAsString()); + } + } else { + external: + for (Value value : record.getValues(field)) { + boolean found = false; + for (MetadataValue mdv : mdvs) { + if (mdv.getValue().equals(value.getAsString())) { + found = true; + continue external; + } + } + if (!found) { + itemService.addMetadata(context, item, tfield[0], tfield[1], tfield[2], null, + value.getAsString()); + } + } + } + } catch (SQLException e) { + log.error(e.getMessage(), e); + } + } + } + itemService.update(context, item); + + } + + private void process(Context context, String metadata, List currents) { + for (MetadataValue current : currents) { + process(context, metadata, current); + } + } + + private void process(Context context, String metadata, MetadataValue current) { + String key = mappingIdentifier.get(metadata); + Set identifiers = null; + if (!results.containsKey(key)) { + identifiers = new HashSet(); + } else { + identifiers = results.get(key); + } + identifiers.add(current.getValue()); + results.put(key, identifiers); + } + + public List convertFields(List recordSet, Map fieldMap) { + List result = new ArrayList(); + for (Record publication : recordSet) { + for (String fieldName : fieldMap.keySet()) { + String md = null; + if (fieldMap != null) { + md = fieldMap.get(fieldName); + } + + if (StringUtils.isBlank(md)) { + continue; + } else { + md = md.trim(); + } + + if (publication.isMutable()) { + List values = publication.getValues(md); + publication.makeMutable().removeField(md); + publication.makeMutable().addField(fieldName, values); + } + } + + result.add(publication); + } + return result; + } +} diff --git a/dspace-api/src/main/java/org/dspace/submit/step/SampleStep.java b/dspace-api/src/main/java/org/dspace/submit/step/SampleStep.java index 80620e5575..705422d015 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/SampleStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/SampleStep.java @@ -7,169 +7,22 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.sql.SQLException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.authorize.AuthorizeException; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; import org.dspace.submit.AbstractProcessingStep; -/** - * This is a Sample Step class which can be used as template for creating new - * custom Step processing classes! - *

    - * Please Note: The basic methods you will want to override are described below. - * However, obviously, you are completely free to create your own methods for - * this Step, or override other methods. For more examples, look at the code - * from one of the provided DSpace step classes in the "org.dspace.submit.step" - * package. - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - *

    - * If you are utilizing the JSP-UI, you will also be required to create - * a class which implements org.dspace.app.webui.submit.JSPStep, and provide - * the necessary JSP-related methods. There is a corresponding sample - * of such a class at org.dspace.app.webui.submit.step.JSPSampleStep. - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @version $Revision$ - */ -public class SampleStep extends AbstractProcessingStep -{ +public class SampleStep extends AbstractProcessingStep { - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - * - * (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag - * defined in the JSPStepManager class) - **************************************************************************/ - public static final int STATUS_USER_INPUT_ERROR = 1; - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - /* - * In this method, you should do any processing of any user input (if - * this step requires user input). If this step does not require user - * interaction (i.e. it has no UI), then ALL of the backend processing - * should occur in this method. - * - * Processing may include, but is not limited to: - * - * 1) Saving user input data to the database (e.g. saving metadata from - * a web form that a user filled out) 2) Performing ALL backend - * processing for non-interactive steps 3) Determine if any errors - * occurred during processing, and if so, return those error flags. - * - * For steps with user interaction, this method is called right after - * the web form or page is submitted. For steps without user - * interaction, this method is called whenever the step itself is - * supposed to be processed. - * - */ + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - /* - * HINT: - * - * If any errors occurred, its recommended to create a global "flag" to - * represent that error. It's much easier then for the - * JSP-UI or Manakin XML-UI to determine what to do with that error. - * - * For example, if an error occurred, you may specify the following - * return call: - * - * return USER_INPUT_ERROR_FLAG; - * - * (Note: this flag is defined at the top of this class) - */ - - // If no errors occurred, and there were no other special messages to - // report to the doPostProcessing() method, just return STATUS_COMPLETE! - return STATUS_COMPLETE; } - - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - /* - * This method reports how many "pages" to put in - * the Progress Bar for this Step. - * - * Most steps should just return 1 (which means the Step only appears - * once in the Progress Bar). - * - * If this Step should be shown as multiple "Pages" in the Progress Bar, - * then return a value higher than 1. For example, return 2 in order to - * have this Step appear twice in a row within the Progress Bar. - * - * If you return 0, this Step will not appear in the Progress Bar at - * ALL! Therefore it is important for non-interactive steps to return 0. - */ + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - // in most cases, you'll want to just return 1 - return 1; } + } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/SelectCollectionStep.java b/dspace-api/src/main/java/org/dspace/submit/step/SelectCollectionStep.java index 83d60ea1d2..11b9b3e126 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/SelectCollectionStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/SelectCollectionStep.java @@ -7,150 +7,24 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.sql.SQLException; -import java.util.UUID; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Collection; -import org.dspace.content.WorkspaceItem; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.WorkspaceItemService; +import org.apache.log4j.Logger; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; import org.dspace.submit.AbstractProcessingStep; -/** - * SelectCollection Step which processes the collection that the user selected - * in that step of the DSpace Submission process - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @version $Revision$ - */ -public class SelectCollectionStep extends AbstractProcessingStep -{ - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - * - * (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag - * defined in the JSPStepManager class) - **************************************************************************/ - // no collection was selected - public static final int STATUS_NO_COLLECTION = 1; +public class SelectCollectionStep extends AbstractProcessingStep { - // invalid collection or error finding collection - public static final int STATUS_INVALID_COLLECTION = 2; + private static final Logger log = Logger.getLogger(SelectCollectionStep.class); - protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - // First we find the collection which was selected - UUID id = Util.getUUIDParameter(request, "collection"); + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - // if the user didn't select a collection, - // send him/her back to "select a collection" page - if (id == null) - { - return STATUS_NO_COLLECTION; - } - - // try to load the collection - Collection col = collectionService.find(context, id); - - // Show an error if the collection is invalid - if (col == null) - { - return STATUS_INVALID_COLLECTION; - } - else - { - // create our new Workspace Item - WorkspaceItem wi = workspaceItemService.create(context, col, true); - - // update Submission Information with this Workspace Item - subInfo.setSubmissionItem(wi); - - // commit changes to database - context.dispatchEvents(); - - // need to reload current submission process config, - // since it is based on the Collection selected - subInfo.reloadSubmissionConfig(request); - } - - // no errors occurred - return STATUS_COMPLETE; } - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - // there is always just one page in the "select a collection" step! - return 1; + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub + } } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/SkipInitialQuestionsStep.java b/dspace-api/src/main/java/org/dspace/submit/step/SkipInitialQuestionsStep.java deleted file mode 100644 index 245862ace0..0000000000 --- a/dspace-api/src/main/java/org/dspace/submit/step/SkipInitialQuestionsStep.java +++ /dev/null @@ -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.submit.step; - -import java.io.IOException; -import java.sql.SQLException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.InProgressSubmission; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.core.Context; -import org.dspace.submit.AbstractProcessingStep; - -/** - * This is a Simple Step class that need to be used when you want skip the - * initial questions step! - *

    - * At the moment this step is required because part of the behaviour of the - * InitialQuestionStep is required to be managed also in the DescribeStep (see - * JIRA [DS-83] Hardcoded behaviour of Initial question step in the submission) - *

    - * - * @see org.dspace.submit.AbstractProcessingStep - * @see org.dspace.submit.step.InitialQuestionsStep - * @see org.dspace.submit.step.DescribeStep - * - * @author Andrea Bollini - * @version $Revision$ - */ -public class SkipInitialQuestionsStep extends AbstractProcessingStep -{ - /** - * Simply we flags the submission as the user had checked both multi-title, - * multi-files and published before so that the input-form configuration - * will be used as is - */ - @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - InProgressSubmission submissionItem = subInfo.getSubmissionItem(); - submissionItem.setMultipleFiles(true); - submissionItem.setMultipleTitles(true); - submissionItem.setPublishedBefore(true); - ContentServiceFactory.getInstance().getInProgressSubmissionService(submissionItem).update(context, submissionItem); - return STATUS_COMPLETE; - } - - @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - return 1; - } -} diff --git a/dspace-api/src/main/java/org/dspace/submit/step/StartSubmissionLookupStep.java b/dspace-api/src/main/java/org/dspace/submit/step/StartSubmissionLookupStep.java index 2d331abdec..903100d1f6 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/StartSubmissionLookupStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/StartSubmissionLookupStep.java @@ -7,308 +7,27 @@ */ package org.dspace.submit.step; -import gr.ekt.bte.core.Record; -import gr.ekt.bte.core.TransformationEngine; -import gr.ekt.bte.core.TransformationSpec; -import gr.ekt.bte.exceptions.BadTransformationSpec; -import gr.ekt.bte.exceptions.MalformedSourceException; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.UUID; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.dspace.app.util.DCInputSet; -import org.dspace.app.util.DCInputsReader; -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Collection; -import org.dspace.content.WorkspaceItem; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; -import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.submit.AbstractProcessingStep; -import org.dspace.submit.lookup.DSpaceWorkspaceItemOutputGenerator; -import org.dspace.submit.lookup.SubmissionItemDataLoader; -import org.dspace.submit.lookup.SubmissionLookupService; -import org.dspace.submit.util.ItemSubmissionLookupDTO; -import org.dspace.submit.util.SubmissionLookupDTO; -import org.dspace.submit.util.SubmissionLookupPublication; -/** - * StartSubmissionLookupStep is used when you want enabled the user to auto fill - * the item in submission with metadata retrieved from external bibliographic - * services (like pubmed, arxiv, and so on...) - * - *

    - * At the moment this step is only available for JSPUI - *

    - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Andrea Bollini - * @author Kostas Stamatis - * @author Luigi Andrea Pascarelli - * @author Panagiotis Koutsourakis - * @version $Revision$ - */ -public class StartSubmissionLookupStep extends AbstractProcessingStep -{ - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - * - * (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag - * defined in the JSPStepManager class) - **************************************************************************/ - // no collection was selected - public static final int STATUS_NO_COLLECTION = 1; - - // invalid collection or error finding collection - public static final int STATUS_INVALID_COLLECTION = 2; - - public static final int STATUS_NO_SUUID = 3; - - public static final int STATUS_SUBMISSION_EXPIRED = 4; - - private SubmissionLookupService slService = DSpaceServicesFactory.getInstance().getServiceManager() - .getServiceByName( - SubmissionLookupService.class.getCanonicalName(), - SubmissionLookupService.class); - - /** log4j logger */ +public class StartSubmissionLookupStep extends AbstractProcessingStep { + /** + * log4j logger + */ private static Logger log = Logger - .getLogger(StartSubmissionLookupStep.class); + .getLogger(StartSubmissionLookupStep.class); - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - // First we find the collection which was selected - UUID id = Util.getUUIDParameter(request, "collectionid"); - String titolo = request.getParameter("search_title"); - String date = request.getParameter("search_year"); - String autori = request.getParameter("search_authors"); - String uuidSubmission = request.getParameter("suuid"); - String uuidLookup = request.getParameter("iuuid"); - String fuuidLookup = request.getParameter("fuuid"); + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - if (StringUtils.isBlank(uuidSubmission)) - { - return STATUS_NO_SUUID; - } - - SubmissionLookupDTO submissionDTO = slService.getSubmissionLookupDTO( - request, uuidSubmission); - - if (submissionDTO == null) - { - return STATUS_SUBMISSION_EXPIRED; - } - - ItemSubmissionLookupDTO itemLookup = null; - if (fuuidLookup == null || fuuidLookup.isEmpty()) - { - if (StringUtils.isNotBlank(uuidLookup)) - { - itemLookup = submissionDTO.getLookupItem(uuidLookup); - if (itemLookup == null) - { - return STATUS_SUBMISSION_EXPIRED; - } - } - } - // if the user didn't select a collection, - // send him/her back to "select a collection" page - if (id == null) - { - return STATUS_NO_COLLECTION; - } - - // try to load the collection - Collection col = collectionService.find(context, id); - - // Show an error if the collection is invalid - if (col == null) - { - return STATUS_INVALID_COLLECTION; - } - else - { - // create our new Workspace Item - DCInputSet inputSet = null; - try - { - inputSet = new DCInputsReader().getInputs(col.getHandle()); - } - catch (Exception e) - { - log.error(e.getMessage(), e); - throw new RuntimeException(e); - } - - List dto = new ArrayList(); - - if (itemLookup != null) - { - dto.add(itemLookup); - } - else if (fuuidLookup != null && !fuuidLookup.isEmpty()) - { - String[] ss = fuuidLookup.split(","); - for (String s : ss) - { - itemLookup = submissionDTO.getLookupItem(s); - if (itemLookup == null) - { - return STATUS_SUBMISSION_EXPIRED; - } - dto.add(itemLookup); - } - } - else - { - SubmissionLookupPublication manualPub = new SubmissionLookupPublication( - SubmissionLookupService.MANUAL_USER_INPUT); - manualPub.add("title", titolo); - manualPub.add("year", date); - manualPub.add("allauthors", autori); - - Enumeration e = request.getParameterNames(); - - while (e.hasMoreElements()) - { - String parameterName = (String) e.nextElement(); - String parameterValue = request.getParameter(parameterName); - - if (parameterName.startsWith("identifier_") - && StringUtils.isNotBlank(parameterValue)) - { - manualPub - .add(parameterName.substring("identifier_" - .length()), parameterValue); - } - } - List publications = new ArrayList(); - publications.add(manualPub); - dto.add(new ItemSubmissionLookupDTO(publications)); - - } - - List result = null; - - TransformationEngine transformationEngine = slService - .getPhase2TransformationEngine(); - if (transformationEngine != null) - { - SubmissionItemDataLoader dataLoader = (SubmissionItemDataLoader) transformationEngine - .getDataLoader(); - dataLoader.setDtoList(dto); - // dataLoader.setProviders() - - DSpaceWorkspaceItemOutputGenerator outputGenerator = (DSpaceWorkspaceItemOutputGenerator) transformationEngine - .getOutputGenerator(); - outputGenerator.setCollection(col); - outputGenerator.setContext(context); - outputGenerator.setFormName(inputSet.getFormName()); - outputGenerator.setDto(dto.get(0)); - - try - { - transformationEngine.transform(new TransformationSpec()); - result = outputGenerator.getWitems(); - } - catch (BadTransformationSpec e1) - { - e1.printStackTrace(); - } - catch (MalformedSourceException e1) - { - e1.printStackTrace(); - } - } - - if (result != null && result.size() > 0) - { - // update Submission Information with this Workspace Item - subInfo.setSubmissionItem(result.iterator().next()); - } - - // commit changes to database - context.dispatchEvents(); - - // need to reload current submission process config, - // since it is based on the Collection selected - subInfo.reloadSubmissionConfig(request); - } - - slService.invalidateDTOs(request, uuidSubmission); - // no errors occurred - return STATUS_COMPLETE; } - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - // there is always just one page in the "select a collection" step! - return 1; + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub + } -} +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/submit/step/UploadStep.java b/dspace-api/src/main/java/org/dspace/submit/step/UploadStep.java index bb63380272..8e528eb0a4 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/UploadStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/UploadStep.java @@ -7,779 +7,27 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.Enumeration; -import java.util.UUID; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang.StringUtils; - import org.apache.log4j.Logger; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.BitstreamFormatService; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; -import org.dspace.curate.Curator; import org.dspace.submit.AbstractProcessingStep; -/** - * Upload step for DSpace. Processes the actual upload of files - * for an item being submitted into DSpace. - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - */ -public class UploadStep extends AbstractProcessingStep -{ - /** Button to upload a file * */ - public static final String SUBMIT_UPLOAD_BUTTON = "submit_upload"; - - /** Button to skip uploading a file * */ - public static final String SUBMIT_SKIP_BUTTON = "submit_skip"; - - /** Button to submit more files * */ - public static final String SUBMIT_MORE_BUTTON = "submit_more"; - - /** Button to cancel editing of file info * */ - public static final String CANCEL_EDIT_BUTTON = "submit_edit_cancel"; - - /*************************************************************************** - * STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or - * additional user interaction may be required) - * - * (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag - * defined in the JSPStepManager class) - **************************************************************************/ - // integrity error occurred - public static final int STATUS_INTEGRITY_ERROR = 1; - - // error in uploading file - public static final int STATUS_UPLOAD_ERROR = 2; - - // error - no files uploaded! - public static final int STATUS_NO_FILES_ERROR = 5; - - // format of uploaded file is unknown - public static final int STATUS_UNKNOWN_FORMAT = 10; - - // virus checker unavailable ? - public static final int STATUS_VIRUS_CHECKER_UNAVAILABLE = 14; - - // file failed virus check - public static final int STATUS_CONTAINS_VIRUS = 16; - - // edit file information - public static final int STATUS_EDIT_BITSTREAM = 20; - - // return from editing file information - public static final int STATUS_EDIT_COMPLETE = 25; - - /** log4j logger */ +public class UploadStep extends AbstractProcessingStep { + /** + * log4j logger + */ private static final Logger log = Logger.getLogger(UploadStep.class); - /** is the upload required? */ - protected boolean fileRequired = configurationService.getBooleanProperty("webui.submit.upload.required", true); - - protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * The relevant DSpace Context. - * @param request - * Servlet's HTTP request object. - * @param response - * Servlet's HTTP response object. - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - // get button user pressed - String buttonPressed = Util.getSubmitButton(request, NEXT_BUTTON); + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - // get reference to item - Item item = subInfo.getSubmissionItem().getItem(); - - // ----------------------------------- - // Step #0: Upload new files (if any) - // ----------------------------------- - String contentType = request.getContentType(); - - // if multipart form, then we are uploading a file - if ((contentType != null) - && (contentType.indexOf("multipart/form-data") != -1)) - { - // This is a multipart request, so it's a file upload - // (return any status messages or errors reported) - int status = processUploadFile(context, request, response, subInfo); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - } - - // if user pressed jump-to button in process bar, - // return success (so that jump will occur) - if (buttonPressed.startsWith(PROGRESS_BAR_PREFIX) || - buttonPressed.startsWith(PREVIOUS_BUTTON)) - { - // check if a file is required to be uploaded - if (fileRequired && !itemService.hasUploadedFiles(item)) - { - return STATUS_NO_FILES_ERROR; - } - else - { - return STATUS_COMPLETE; - } - } - - // --------------------------------------------- - // Step #1: Check if this was just a request to - // edit file information. - // (or canceled editing information) - // --------------------------------------------- - // check if we're already editing a specific bitstream - if (request.getParameter("bitstream_id") != null) - { - if (buttonPressed.equals(CANCEL_EDIT_BUTTON)) - { - // canceled an edit bitstream request - subInfo.setBitstream(null); - - // this flag will just return us to the normal upload screen - return STATUS_EDIT_COMPLETE; - } - else - { - // load info for bitstream we are editing - Bitstream b = bitstreamService.find(context, Util.getUUIDParameter(request, - "bitstream_id")); - - // save bitstream to submission info - subInfo.setBitstream(b); - } - } - else if (buttonPressed.startsWith("submit_edit_")) - { - // get ID of bitstream that was requested for editing - String bitstreamID = buttonPressed.substring("submit_edit_" - .length()); - - Bitstream b = bitstreamService - .find(context, UUID.fromString(bitstreamID)); - - // save bitstream to submission info - subInfo.setBitstream(b); - - // return appropriate status flag to say we are now editing the - // bitstream - return STATUS_EDIT_BITSTREAM; - } - - // --------------------------------------------- - // Step #2: Process any remove file request(s) - // --------------------------------------------- - // Remove-selected requests come from Manakin - if (buttonPressed.equalsIgnoreCase("submit_remove_selected")) - { - // this is a remove multiple request! - - if (request.getParameter("remove") != null) - { - // get all files to be removed - String[] removeIDs = request.getParameterValues("remove"); - - // remove each file in the list - for (int i = 0; i < removeIDs.length; i++) - { - UUID id = UUID.fromString(removeIDs[i]); - - int status = processRemoveFile(context, item, id); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - } - - // remove current bitstream from Submission Info - subInfo.setBitstream(null); - } - } - else if (buttonPressed.startsWith("submit_remove_")) - { - // A single file "remove" button must have been pressed - - UUID id = UUID.fromString(buttonPressed.substring(14)); - int status = processRemoveFile(context, item, id); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - - // remove current bitstream from Submission Info - subInfo.setBitstream(null); - } - - // ------------------------------------------------- - // Step #3: Check for a change in file description - // ------------------------------------------------- - // We have to check for descriptions from users using the resumable upload - // and from users using the simple upload. - // Beginning with the resumable ones. - Enumeration parameterNames = request.getParameterNames(); - Map descriptions = new HashMap<>(); - while (parameterNames.hasMoreElements()) - { - String name = parameterNames.nextElement(); - if (StringUtils.startsWithIgnoreCase(name, "description[")) - { - descriptions.put( - name.substring("description[".length(), name.length()-1), - request.getParameter(name)); - } - } - if (!descriptions.isEmpty()) - { - // we got descriptions from the resumable upload - if (item != null) - { - List bundles = itemService.getBundles(item, "ORIGINAL"); - for (Bundle bundle : bundles) - { - List bitstreams = bundle.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { - if (descriptions.containsKey(bitstream.getName())) - { - bitstream.setDescription(context, descriptions.get(bitstream.getName())); - bitstreamService.update(context, bitstream); - } - } - } - } - return STATUS_COMPLETE; - } - - // Going on with descriptions from the simple upload - String fileDescription = request.getParameter("description"); - - if (fileDescription != null && fileDescription.length() > 0) - { - // save this file description - int status = processSaveFileDescription(context, request, response, - subInfo); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - } - - // ------------------------------------------ - // Step #4: Check for a file format change - // (if user had to manually specify format) - // ------------------------------------------ - int formatTypeID = Util.getIntParameter(request, "format"); - String formatDesc = request.getParameter("format_description"); - - // if a format id or description was found, then save this format! - if (formatTypeID >= 0 - || (formatDesc != null && formatDesc.length() > 0)) - { - // save this specified format - int status = processSaveFileFormat(context, request, response, - subInfo); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - } - - // --------------------------------------------------- - // Step #5: Check if primary bitstream has changed - // ------------------------------------------------- - if (request.getParameter("primary_bitstream_id") != null) - { - List bundles = itemService.getBundles(item, "ORIGINAL"); - if (bundles.size() > 0) - { - bundles.get(0).setPrimaryBitstreamID(bitstreamService.find(context, Util.getUUIDParameter(request, - "primary_bitstream_id"))); - bundleService.update(context, bundles.get(0)); - } - } - - // --------------------------------------------------- - // Step #6: Determine if there is an error because no - // files have been uploaded. - // --------------------------------------------------- - //check if a file is required to be uploaded - if (fileRequired && !itemService.hasUploadedFiles(item) - && !buttonPressed.equals(SUBMIT_MORE_BUTTON)) - { - return STATUS_NO_FILES_ERROR; - } - - context.dispatchEvents(); - - return STATUS_COMPLETE; } - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * Servlet's HTTP request object. - * @param subInfo - * The current submission information object - * @return the number of pages in this step - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - // Despite using many JSPs, this step only appears - // ONCE in the Progress Bar, so it's only ONE page - return 1; - } + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub - // **************************************************************** - // **************************************************************** - // METHODS FOR UPLOADING FILES (and associated information) - // **************************************************************** - // **************************************************************** - - /** - * Remove a file from an item - * - * @param context - * The relevant DSpace Context. - * @param item - * Item where file should be removed from - * @param bitstreamID - * The id of bitstream representing the file to remove - * @return Status or error flag which will be processed by - * UI-related code! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - protected int processRemoveFile(Context context, Item item, UUID bitstreamID) - throws IOException, SQLException, AuthorizeException - { - Bitstream bitstream; - - // Try to find bitstream - try - { - bitstream = bitstreamService.find(context, bitstreamID); - } - catch (NumberFormatException nfe) - { - bitstream = null; - } - - if (bitstream == null) - { - // Invalid or mangled bitstream ID - // throw an error and return immediately - return STATUS_INTEGRITY_ERROR; - } - - // remove bitstream from bundle.. - // delete bundle if it's now empty - List bundles = bitstream.getBundles(); - - Bundle bundle = bundles.get(0); - bundleService.removeBitstream(context, bundle, bitstream); - - List bitstreams = bundle.getBitstreams(); - - // remove bundle if it's now empty - if (bitstreams.size() < 1) - { - itemService.removeBundle(context, item, bundle); - itemService.update(context, item); - } - - // no errors occurred - return STATUS_COMPLETE; - } - - /** - * Process the upload of a new file! - * - * @param context - * The relevant DSpace Context. - * @param request - * Servlet's HTTP request object. - * @param response - * Servlet's HTTP response object. - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * UI-related code! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - public int processUploadFile(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - boolean formatKnown = true; - boolean fileOK = false; - BitstreamFormat bf = null; - Bitstream b = null; - - //NOTE: File should already be uploaded. - //Manakin does this automatically via Cocoon. - //For JSP-UI, the SubmissionController.uploadFiles() does the actual upload - - Enumeration attNames = request.getAttributeNames(); - - //loop through our request attributes - while(attNames.hasMoreElements()) - { - String attr = (String) attNames.nextElement(); - - //if this ends with "-path", this attribute - //represents a newly uploaded file - if(attr.endsWith("-path")) - { - //strip off the -path to get the actual parameter - //that the file was uploaded as - String param = attr.replace("-path", ""); - - // Load the file's path and input stream and description - String filePath = (String) request.getAttribute(param + "-path"); - InputStream fileInputStream = (InputStream) request.getAttribute(param + "-inputstream"); - - //attempt to get description from attribute first, then direct from a parameter - String fileDescription = (String) request.getAttribute(param + "-description"); - if(fileDescription==null ||fileDescription.length()==0) - { - fileDescription = request.getParameter("description"); - } - - // if information wasn't passed by User Interface, we had a problem - // with the upload - if (filePath == null || fileInputStream == null) - { - return STATUS_UPLOAD_ERROR; - } - - if (subInfo == null) - { - // In any event, if we don't have the submission info, the request - // was malformed - return STATUS_INTEGRITY_ERROR; - } - - - // Create the bitstream - Item item = subInfo.getSubmissionItem().getItem(); - - // do we already have a bundle? - List bundles = itemService.getBundles(item, "ORIGINAL"); - - if (bundles.size() < 1) - { - // set bundle's name to ORIGINAL - b = itemService.createSingleBitstream(context, fileInputStream, item, "ORIGINAL"); - } - else - { - // we have a bundle already, just add bitstream - b = bitstreamService.create(context, bundles.get(0), fileInputStream); - } - - // Strip all but the last filename. It would be nice - // to know which OS the file came from. - String noPath = filePath; - - while (noPath.indexOf('/') > -1) - { - noPath = noPath.substring(noPath.indexOf('/') + 1); - } - - while (noPath.indexOf('\\') > -1) - { - noPath = noPath.substring(noPath.indexOf('\\') + 1); - } - - b.setName(context, noPath); - b.setSource(context, filePath); - b.setDescription(context, fileDescription); - - // Identify the format - bf = bitstreamFormatService.guessFormat(context, b); - b.setFormat(context, bf); - - // Update to DB - bitstreamService.update(context, b); - itemService.update(context, item); - - if ((bf != null) && (bf.isInternal())) - { - log.warn("Attempt to upload file format marked as internal system use only"); - backoutBitstream(context, subInfo, b, item); - return STATUS_UPLOAD_ERROR; - } - - // Check for virus - if (configurationService.getBooleanProperty("submission-curation.virus-scan")) - { - Curator curator = new Curator(); - curator.addTask("vscan").curate(context, item); - int status = curator.getStatus("vscan"); - if (status == Curator.CURATE_ERROR) - { - backoutBitstream(context, subInfo, b, item); - return STATUS_VIRUS_CHECKER_UNAVAILABLE; - } - else if (status == Curator.CURATE_FAIL) - { - backoutBitstream(context, subInfo, b, item); - return STATUS_CONTAINS_VIRUS; - } - } - - // If we got this far then everything is more or less ok. - - context.dispatchEvents(); - - // save this bitstream to the submission info, as the - // bitstream we're currently working with - subInfo.setBitstream(b); - - //if format was not identified - if (bf == null) - { - return STATUS_UNKNOWN_FORMAT; - } - - }//end if attribute ends with "-path" - }//end while - - - return STATUS_COMPLETE; - - - } - - /* - * If we created a new Bitstream but now realise there is a problem then remove it. - */ - protected void backoutBitstream(Context context, SubmissionInfo subInfo, Bitstream b, Item item) - throws SQLException, AuthorizeException, IOException - { - // remove bitstream from bundle.. - List bundles = b.getBundles(); - if (bundles.isEmpty()) - throw new SQLException("Bitstream is not in any Bundles."); - - Bundle firstBundle = bundles.get(0); - - bundleService.removeBitstream(context, firstBundle, b); - - List bitstreams = firstBundle.getBitstreams(); - - // remove bundle if it's now empty - if (bitstreams.isEmpty()) - { - itemService.removeBundle(context, item, firstBundle); - itemService.update(context, item); - } - else - bundleService.update(context, firstBundle); - - subInfo.setBitstream(null); - } - - /** - * Process input from get file type page - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * - * @return Status or error flag which will be processed by - * UI-related code! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - protected int processSaveFileFormat(Context context, - HttpServletRequest request, HttpServletResponse response, - SubmissionInfo subInfo) throws ServletException, IOException, - SQLException, AuthorizeException - { - if (subInfo.getBitstream() != null) - { - // Did the user select a format? - int typeID = Util.getIntParameter(request, "format"); - - BitstreamFormat format = bitstreamFormatService.find(context, typeID); - - if (format != null) - { - subInfo.getBitstream().setFormat(context, format); - } - else - { - String userDesc = request.getParameter("format_description"); - - subInfo.getBitstream().setUserFormatDescription(context, userDesc); - } - - // update database - bitstreamService.update(context, subInfo.getBitstream()); - } - else - { - return STATUS_INTEGRITY_ERROR; - } - - return STATUS_COMPLETE; - } - - /** - * Process input from the "change file description" page - * - * @param context - * The relevant DSpace Context. - * @param request - * Servlet's HTTP request object. - * @param response - * Servlet's HTTP response object. - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * UI-related code! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - * @throws ServletException - * A general exception a servlet can throw when it encounters difficulty. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - */ - protected int processSaveFileDescription(Context context, - HttpServletRequest request, HttpServletResponse response, - SubmissionInfo subInfo) throws ServletException, IOException, - SQLException, AuthorizeException - { - if (subInfo.getBitstream() != null) - { - subInfo.getBitstream().setDescription(context, - request.getParameter("description")); - bitstreamService.update(context, subInfo.getBitstream()); - - context.dispatchEvents(); - } - else - { - return STATUS_INTEGRITY_ERROR; - } - - return STATUS_COMPLETE; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/UploadWithEmbargoStep.java b/dspace-api/src/main/java/org/dspace/submit/step/UploadWithEmbargoStep.java index 63df78cced..572b252773 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/UploadWithEmbargoStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/UploadWithEmbargoStep.java @@ -7,621 +7,12 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Date; -import java.util.Enumeration; -import java.util.List; -import java.util.UUID; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.time.DateUtils; -import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.dspace.app.util.SubmissionInfo; -import org.dspace.app.util.Util; -import org.dspace.authorize.AuthorizeException; -import org.dspace.authorize.ResourcePolicy; -import org.dspace.authorize.factory.AuthorizeServiceFactory; -import org.dspace.authorize.service.ResourcePolicyService; -import org.dspace.content.*; -import org.dspace.core.Context; -import org.dspace.curate.Curator; -import org.dspace.eperson.Group; -import org.dspace.eperson.factory.EPersonServiceFactory; -import org.dspace.eperson.service.GroupService; -import org.dspace.handle.factory.HandleServiceFactory; -import org.dspace.handle.service.HandleService; -/** - * Upload step with the advanced embargo system for DSpace. Processes the actual - * upload of files for an item being submitted into DSpace. - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.step.UploadStep - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @author Keiji Suzuki - * @version $Revision$ - */ -public class UploadWithEmbargoStep extends UploadStep -{ - public static final int STATUS_EDIT_POLICIES = 30; - - public static final int STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP = 31; - public static final int STATUS_EDIT_POLICIES_DUPLICATED_POLICY = 32; - - public static final int STATUS_EDIT_POLICY_ERROR_SELECT_GROUP = 33; - public static final int STATUS_EDIT_POLICY_DUPLICATED_POLICY = 34; - - - /** log4j logger */ +public class UploadWithEmbargoStep extends UploadStep { + /** + * log4j logger + */ private static Logger log = Logger.getLogger(UploadWithEmbargoStep.class); - protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); - - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ - @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - // get button user pressed - String buttonPressed = Util.getSubmitButton(request, NEXT_BUTTON); - - // get reference to item - Item item = subInfo.getSubmissionItem().getItem(); - - // ----------------------------------- - // Step #0: Upload new files (if any) - // ----------------------------------- - String contentType = request.getContentType(); - - // if multipart form, then we are uploading a file - if ((contentType != null) - && (contentType.indexOf("multipart/form-data") != -1)) - { - // This is a multipart request, so it's a file upload - // (return any status messages or errors reported) - int status = processUploadFile(context, request, response, subInfo); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - } - - // if user pressed jump-to button in process bar, - // return success (so that jump will occur) - if (buttonPressed.startsWith(PROGRESS_BAR_PREFIX) || - buttonPressed.startsWith(PREVIOUS_BUTTON)) - { - // check if a file is required to be uploaded - if (fileRequired && !itemService.hasUploadedFiles(item)) - { - return STATUS_NO_FILES_ERROR; - } - else - { - return STATUS_COMPLETE; - } - } - - // POLICIES FORM MANAGEMENT - int result = editBitstreamPolicies(request, context, subInfo, buttonPressed); - if(result != -1) return result; - - // --------------------------------------------- - // Step #1: Check if this was just a request to - // edit file information. - // (or canceled editing information) - // --------------------------------------------- - // check if we're already editing a specific bitstream - if (request.getParameter("bitstream_id") != null) - { - if (buttonPressed.equals(CANCEL_EDIT_BUTTON)) - { - // canceled an edit bitstream request - subInfo.setBitstream(null); - - // this flag will just return us to the normal upload screen - return STATUS_EDIT_COMPLETE; - } - else - { - // load info for bitstream we are editing - Bitstream b = bitstreamService.find(context, Util.getUUIDParameter(request - , "bitstream_id")); - - // save bitstream to submission info - subInfo.setBitstream(b); - } - } - else if (buttonPressed.startsWith("submit_edit_")) - { - // get ID of bitstream that was requested for editing - String bitstreamID = buttonPressed.substring("submit_edit_" - .length()); - - Bitstream b = bitstreamService - .find(context, UUID.fromString(bitstreamID)); - - // save bitstream to submission info - subInfo.setBitstream(b); - - // return appropriate status flag to say we are now editing the - // bitstream - return STATUS_EDIT_BITSTREAM; - } - - // --------------------------------------------- - // Step #2: Process any remove file request(s) - // --------------------------------------------- - // Remove-selected requests come from Manakin - if (buttonPressed.equalsIgnoreCase("submit_remove_selected")) - { - // this is a remove multiple request! - - if (request.getParameter("remove") != null) - { - // get all files to be removed - String[] removeIDs = request.getParameterValues("remove"); - - // remove each file in the list - for (int i = 0; i < removeIDs.length; i++) - { - UUID id = UUID.fromString(removeIDs[i]); - - int status = processRemoveFile(context, item, id); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - } - - // remove current bitstream from Submission Info - subInfo.setBitstream(null); - } - } - else if (buttonPressed.startsWith("submit_remove_")) - { - // A single file "remove" button must have been pressed - - UUID id = UUID.fromString(buttonPressed.substring(14)); - int status = processRemoveFile(context, item, id); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - - // remove current bitstream from Submission Info - subInfo.setBitstream(null); - } - - // ------------------------------------------------- - // Step #3: Check for a change in file description - // ------------------------------------------------- - // We have to check for descriptions from users using the resumable upload - // and from users using the simple upload. - // Beginning with the resumable ones. - Enumeration parameterNames = request.getParameterNames(); - Map descriptions = new HashMap(); - while (parameterNames.hasMoreElements()) - { - String name = parameterNames.nextElement(); - if (StringUtils.startsWithIgnoreCase(name, "description[")) - { - descriptions.put( - name.substring("description[".length(), name.length()-1), - request.getParameter(name)); - } - } - if (!descriptions.isEmpty()) - { - // we got descriptions from the resumable upload - if (item != null) - { - List bundles = itemService.getBundles(item, "ORIGINAL"); - for (Bundle bundle : bundles) - { - List bitstreams = bundle.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { - if (descriptions.containsKey(bitstream.getName())) - { - bitstream.setDescription(context, descriptions.get(bitstream.getName())); - bitstreamService.update(context, bitstream); - } - } - } - } - return STATUS_COMPLETE; - } - - // Going on with descriptions from the simple upload - String fileDescription = request.getParameter("description"); - - if (fileDescription != null && fileDescription.length() > 0) - { - // save this file description - int status = processSaveFileDescription(context, request, response, - subInfo); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - } - - // ------------------------------------------ - // Step #4: Check for a file format change - // (if user had to manually specify format) - // ------------------------------------------ - int formatTypeID = Util.getIntParameter(request, "format"); - String formatDesc = request.getParameter("format_description"); - - // if a format id or description was found, then save this format! - if (formatTypeID >= 0 - || (formatDesc != null && formatDesc.length() > 0)) - { - // save this specified format - int status = processSaveFileFormat(context, request, response, - subInfo); - - // if error occurred, return immediately - if (status != STATUS_COMPLETE) - { - return status; - } - } - - - // execute only if comes from EditBitstreamStep - if(buttonPressed.equals("submit_save")){ - processAccessFields(context, request, subInfo, subInfo.getBitstream()); - } - - - // --------------------------------------------------- - // Step #5: Check if primary bitstream has changed - // ------------------------------------------------- - if (request.getParameter("primary_bitstream_id") != null) - { - List bundles = itemService.getBundles(item, "ORIGINAL"); - if (bundles.size() > 0) - { - bundles.get(0).setPrimaryBitstreamID(bitstreamService.find(context, Util.getUUIDParameter(request - , "primary_bitstream_id"))); - bundleService.update(context, bundles.get(0)); - } - } - - // --------------------------------------------------- - // Step #6: Determine if there is an error because no - // files have been uploaded. - // --------------------------------------------------- - //check if a file is required to be uploaded - if (fileRequired && !itemService.hasUploadedFiles(item)) - { - return STATUS_NO_FILES_ERROR; - } - return STATUS_COMPLETE; - } - - /** - * Process the upload of a new file! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * - * @return Status or error flag which will be processed by - * UI-related code! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ - @Override - public int processUploadFile(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - boolean formatKnown = true; - boolean fileOK = false; - BitstreamFormat bf = null; - Bitstream b = null; - - //NOTE: File should already be uploaded. - //Manakin does this automatically via Cocoon. - //For JSP-UI, the SubmissionController.uploadFiles() does the actual upload - - Enumeration attNames = request.getAttributeNames(); - - //loop through our request attributes - while(attNames.hasMoreElements()) - { - String attr = (String) attNames.nextElement(); - - //if this ends with "-path", this attribute - //represents a newly uploaded file - if(attr.endsWith("-path")) - { - //strip off the -path to get the actual parameter - //that the file was uploaded as - String param = attr.replace("-path", ""); - - // Load the file's path and input stream and description - String filePath = (String) request.getAttribute(param + "-path"); - InputStream fileInputStream = (InputStream) request.getAttribute(param + "-inputstream"); - - //attempt to get description from attribute first, then direct from a parameter - String fileDescription = (String) request.getAttribute(param + "-description"); - if(fileDescription==null ||fileDescription.length()==0) - { - fileDescription = request.getParameter("description"); - } - - // if information wasn't passed by User Interface, we had a problem - // with the upload - if (filePath == null || fileInputStream == null) - { - return STATUS_UPLOAD_ERROR; - } - - if (subInfo == null) - { - // In any event, if we don't have the submission info, the request - // was malformed - return STATUS_INTEGRITY_ERROR; - } - - - // Create the bitstream - Item item = subInfo.getSubmissionItem().getItem(); - - // do we already have a bundle? - List bundles = itemService.getBundles(item, "ORIGINAL"); - - if (bundles.size() < 1) - { - // set bundle's name to ORIGINAL - b = itemService.createSingleBitstream(context, fileInputStream, item, "ORIGINAL"); - } - else - { - // we have a bundle already, just add bitstream - b = bitstreamService.create(context, bundles.get(0), fileInputStream); - } - - // Strip all but the last filename. It would be nice - // to know which OS the file came from. - String noPath = filePath; - - while (noPath.indexOf('/') > -1) - { - noPath = noPath.substring(noPath.indexOf('/') + 1); - } - - while (noPath.indexOf('\\') > -1) - { - noPath = noPath.substring(noPath.indexOf('\\') + 1); - } - - b.setName(context, noPath); - b.setSource(context, filePath); - b.setDescription(context, fileDescription); - - // Identify the format - bf = bitstreamFormatService.guessFormat(context, b); - b.setFormat(context, bf); - - // Update to DB - bitstreamService.update(context, b); - itemService.update(context, item); - - - processAccessFields(context, request, subInfo, b); - - - - - if ((bf != null) && (bf.isInternal())) - { - log.warn("Attempt to upload file format marked as internal system use only"); - backoutBitstream(context, subInfo, b, item); - return STATUS_UPLOAD_ERROR; - } - - // Check for virus - if (configurationService.getBooleanProperty("submission-curation.virus-scan")) - { - Curator curator = new Curator(); - curator.addTask("vscan").curate(item); - int status = curator.getStatus("vscan"); - if (status == Curator.CURATE_ERROR) - { - backoutBitstream(context, subInfo, b, item); - return STATUS_VIRUS_CHECKER_UNAVAILABLE; - } - else if (status == Curator.CURATE_FAIL) - { - backoutBitstream(context, subInfo, b, item); - return STATUS_CONTAINS_VIRUS; - } - } - - // If we got this far then everything is more or less ok. - - // Comment - not sure if this is the right place for a commit here - // but I'm not brave enough to remove it - Robin. - context.dispatchEvents(); - - // save this bitstream to the submission info, as the - // bitstream we're currently working with - subInfo.setBitstream(b); - - //if format was not identified - if (bf == null) - { - return STATUS_UNKNOWN_FORMAT; - } - - }//end if attribute ends with "-path" - }//end while - - - return STATUS_COMPLETE; - - - } - - private void processAccessFields(Context context, HttpServletRequest request, SubmissionInfo subInfo, Bitstream b) throws SQLException, AuthorizeException { - // ResourcePolicy Management - boolean isAdvancedFormEnabled= configurationService.getBooleanProperty("webui.submission.restrictstep.enableAdvancedForm", false); - // if it is a simple form we should create the policy for Anonymous - // if Anonymous does not have right on this collection, create policies for any other groups with - // DEFAULT_ITEM_READ specified. - if(!isAdvancedFormEnabled){ - Date startDate = null; - try { - startDate = DateUtils.parseDate(request.getParameter("embargo_until_date"), new String[]{"yyyy-MM-dd", "yyyy-MM", "yyyy"}); - } catch (Exception e) { - //Ignore start date already null - } - String reason = request.getParameter("reason"); - authorizeService.generateAutomaticPolicies(context, startDate, reason, b, (Collection) handleService.resolveToObject(context, subInfo.getCollectionHandle())); - } - } - - - private int editBitstreamPolicies(HttpServletRequest request, Context context, SubmissionInfo subInfo, String buttonPressed) - throws SQLException, AuthorizeException { - - // FORM: EditBitstreamPolicies SELECTED OPERATION: Return - if (buttonPressed.equals("bitstream_list_submit_return")){ - return STATUS_COMPLETE; - } - // FORM: UploadStep SELECTED OPERATION: go to EditBitstreamPolicies - else if (buttonPressed.startsWith("submit_editPolicy_")){ - UUID bitstreamID = UUID.fromString(buttonPressed.substring("submit_editPolicy_".length())); - Bitstream b = bitstreamService.find(context, bitstreamID); - subInfo.setBitstream(b); - return STATUS_EDIT_POLICIES; - } - // FORM: EditBitstreamPolicies SELECTED OPERATION: Add New Policy. - else if (buttonPressed.startsWith(AccessStep.FORM_ACCESS_BUTTON_ADD)){ - Bitstream b = bitstreamService.find(context, Util.getUUIDParameter(request, "bitstream_id")); - subInfo.setBitstream(b); - - int result=-1; - if( (result = AccessStep.checkForm(request))!=0){ - return result; - } - Date dateStartDate = AccessStep.getEmbargoUntil(request); - String reason = request.getParameter("reason"); - String name = request.getParameter("name"); - - Group group = null; - if(request.getParameter("group_id")!=null){ - try{ - group=groupService.find(context, Util.getUUIDParameter(request, "group_id")); - }catch (NumberFormatException nfe){ - return STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP; - } - } - ResourcePolicy rp; - if( (rp= authorizeService.createOrModifyPolicy(null, context, name, group, null, dateStartDate, org.dspace.core.Constants.READ, reason, b))==null){ - return STATUS_EDIT_POLICIES_DUPLICATED_POLICY; - } - resourcePolicyService.update(context, rp); - context.dispatchEvents(); - return STATUS_EDIT_POLICIES; - } - // FORM: EditBitstreamPolicies SELECTED OPERATION: go to EditPolicyForm - else if(org.dspace.submit.step.AccessStep.wasEditPolicyPressed(context, buttonPressed, subInfo)){ - Bitstream b = bitstreamService.find(context, Util.getUUIDParameter(request, "bitstream_id")); - subInfo.setBitstream(b); - return org.dspace.submit.step.AccessStep.STATUS_EDIT_POLICY; - } - // FORM: EditPolicy SELECTED OPERATION: Save or Cancel. - else if(org.dspace.submit.step.AccessStep.comeFromEditPolicy(request)) { - Bitstream b = bitstreamService.find(context, Util.getUUIDParameter(request, "bitstream_id")); - subInfo.setBitstream(b); - String reason = request.getParameter("reason"); - String name = request.getParameter("name"); - - Group group = groupService.findByName(context, Group.ANONYMOUS); - if(request.getParameter("group_id")!=null){ - try{ - group=groupService.find(context, UUID.fromString(request.getParameter("group_id"))); - }catch (NumberFormatException nfe){ - return STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP; - } - } - if(org.dspace.submit.step.AccessStep.saveOrCancelEditPolicy(context, request, - subInfo, buttonPressed, b, name, group, reason)==org.dspace.submit.step.AccessStep.EDIT_POLICY_STATUS_DUPLICATED_POLICY) - return STATUS_EDIT_POLICY_DUPLICATED_POLICY; - - return STATUS_EDIT_POLICIES; - } - // FORM: EditBitstreamPolicies SELECTED OPERATION: Remove Policies - if(org.dspace.submit.step.AccessStep.wasRemovePolicyPressed(buttonPressed)){ - Bitstream b = bitstreamService.find(context, Util.getUUIDParameter(request, "bitstream_id")); - subInfo.setBitstream(b); - org.dspace.submit.step.AccessStep.removePolicy(context, buttonPressed); - context.dispatchEvents(); - return STATUS_EDIT_POLICIES; - } - return -1; - } } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/VerifyStep.java b/dspace-api/src/main/java/org/dspace/submit/step/VerifyStep.java index 47fa3c3b77..2e9d9caa8a 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/VerifyStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/VerifyStep.java @@ -7,96 +7,21 @@ */ package org.dspace.submit.step; -import java.io.IOException; -import java.sql.SQLException; - - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.dspace.app.util.SubmissionInfo; -import org.dspace.authorize.AuthorizeException; +import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; import org.dspace.submit.AbstractProcessingStep; -/** - * Verify step for DSpace. Processes the user response to the - * information they are presented with on the Review/Verify page. - *

    - * This class performs all the behind-the-scenes processing that - * this particular step requires. This class's methods are utilized - * by both the JSP-UI and the Manakin XML-UI - * - * @see org.dspace.app.util.SubmissionConfig - * @see org.dspace.app.util.SubmissionStepConfig - * @see org.dspace.submit.AbstractProcessingStep - * - * @author Tim Donohue - * @version $Revision$ - */ -public class VerifyStep extends AbstractProcessingStep -{ - /** - * Do any processing of the information input by the user, and/or perform - * step processing (if no user interaction required) - *

    - * It is this method's job to save any data to the underlying database, as - * necessary, and return error messages (if any) which can then be processed - * by the appropriate user interface (JSP-UI or XML-UI) - *

    - * NOTE: If this step is a non-interactive step (i.e. requires no UI), then - * it should perform *all* of its processing in this method! - * - * @param context - * current DSpace context - * @param request - * current servlet request object - * @param response - * current servlet response object - * @param subInfo - * submission info object - * @return Status or error flag which will be processed by - * doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned, - * no errors occurred!) - */ +public class VerifyStep extends AbstractProcessingStep { + @Override - public int doProcessing(Context context, HttpServletRequest request, - HttpServletResponse response, SubmissionInfo subInfo) - throws ServletException, IOException, SQLException, - AuthorizeException - { - // nothing to process/save from the Verify Step. - return STATUS_COMPLETE; + public void doPreProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub + } - /** - * Retrieves the number of pages that this "step" extends over. This method - * is used to build the progress bar. - *

    - * This method may just return 1 for most steps (since most steps consist of - * a single page). But, it should return a number greater than 1 for any - * "step" which spans across a number of HTML pages. For example, the - * configurable "Describe" step (configured using input-forms.xml) overrides - * this method to return the number of pages that are defined by its - * configuration file. - *

    - * Steps which are non-interactive (i.e. they do not display an interface to - * the user) should return a value of 1, so that they are only processed - * once! - * - * @param request - * The HTTP Request - * @param subInfo - * The current submission information object - * - * @return the number of pages in this step - */ @Override - public int getNumberOfPages(HttpServletRequest request, - SubmissionInfo subInfo) throws ServletException - { - // always just one page for verify step - return 1; + public void doPostProcessing(Context context, InProgressSubmission wsi) { + // TODO Auto-generated method stub + } } diff --git a/dspace-api/src/main/java/org/dspace/submit/step/XMLUIStartSubmissionLookupStep.java b/dspace-api/src/main/java/org/dspace/submit/step/XMLUIStartSubmissionLookupStep.java deleted file mode 100644 index f65899c3d8..0000000000 --- a/dspace-api/src/main/java/org/dspace/submit/step/XMLUIStartSubmissionLookupStep.java +++ /dev/null @@ -1,85 +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.submit.step; - -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.dspace.app.util.SubmissionInfo; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Item; -import org.dspace.content.MetadataValue; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.ItemService; -import org.dspace.core.Context; -import org.dspace.importer.external.exception.MetadataSourceException; -import org.dspace.importer.external.datamodel.ImportRecord; -import org.dspace.importer.external.metadatamapping.MetadatumDTO; -import org.dspace.importer.external.service.ImportService; -import org.dspace.submit.AbstractProcessingStep; -import org.dspace.utils.DSpace; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.sql.SQLException; - -/** - * Created by jonas - jonas@atmire.com on 06/11/15. - */ -public class XMLUIStartSubmissionLookupStep extends AbstractProcessingStep { - - private static String publicationUrl = null; - private static Logger log = Logger.getLogger(XMLUIStartSubmissionLookupStep.class); - private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - - @Override - public int doProcessing(Context context, HttpServletRequest request, HttpServletResponse response, SubmissionInfo subInfo) throws ServletException, IOException, AuthorizeException, SQLException { - String publicationID = request.getParameter("publication_id"); - - if (StringUtils.isNotBlank(publicationID)) { - /* Get an instance of the ImportService to be able to retrieve records based on several factors, such as url, publicationID, etc*/ - ImportService importService = new DSpace().getServiceManager().getServiceByName("importService", ImportService.class); - Item item = subInfo.getSubmissionItem().getItem(); - try { - ImportRecord record = importService.getRecord(getPublicationUrl(), publicationID); - - - for (MetadataValue metadatum : itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY)) { - itemService.clearMetadata(context, item, metadatum.getMetadataField().getMetadataSchema().getName(), metadatum.getMetadataField().getElement(), metadatum.getMetadataField().getQualifier(), metadatum.getLanguage()); - } - - for (MetadatumDTO metadatum : record.getValueList()) { - itemService.addMetadata(context, item, metadatum.getSchema(), metadatum.getElement(), metadatum.getQualifier(),null, metadatum.getValue()); - } - - itemService.update(context, item); - - context.dispatchEvents(); - - } catch (MetadataSourceException e) { - log.error(e); - } - - } - return 0; - } - - @Override - public int getNumberOfPages(HttpServletRequest request, SubmissionInfo subInfo) throws ServletException { - return 1; - } - - public String getPublicationUrl(){ - if(publicationUrl==null){ - publicationUrl=configurationService.getProperty("publication-lookup.url", "*"); - } - return publicationUrl; - } -} diff --git a/dspace-api/src/main/java/org/dspace/submit/util/ItemSubmissionLookupDTO.java b/dspace-api/src/main/java/org/dspace/submit/util/ItemSubmissionLookupDTO.java index d0ee00553e..de144838ec 100644 --- a/dspace-api/src/main/java/org/dspace/submit/util/ItemSubmissionLookupDTO.java +++ b/dspace-api/src/main/java/org/dspace/submit/util/ItemSubmissionLookupDTO.java @@ -7,17 +7,16 @@ */ package org.dspace.submit.util; -import gr.ekt.bte.core.DataLoader; -import gr.ekt.bte.core.MutableRecord; -import gr.ekt.bte.core.Record; -import gr.ekt.bte.core.Value; - import java.io.Serializable; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.UUID; +import gr.ekt.bte.core.DataLoader; +import gr.ekt.bte.core.MutableRecord; +import gr.ekt.bte.core.Record; +import gr.ekt.bte.core.Value; import org.dspace.submit.lookup.SubmissionLookupService; /** @@ -26,8 +25,7 @@ import org.dspace.submit.lookup.SubmissionLookupService; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class ItemSubmissionLookupDTO implements Serializable -{ +public class ItemSubmissionLookupDTO implements Serializable { private static final long serialVersionUID = 1; private static final String MERGED_PUBLICATION_PROVIDER = "merged"; @@ -38,64 +36,48 @@ public class ItemSubmissionLookupDTO implements Serializable private String uuid; - public ItemSubmissionLookupDTO(List publications) - { + public ItemSubmissionLookupDTO(List publications) { this.uuid = UUID.randomUUID().toString(); this.publications = publications; } - public List getPublications() - { + public List getPublications() { return publications; } - public Set getProviders() - { + public Set getProviders() { Set orderedProviders = new LinkedHashSet(); - for (Record p : publications) - { + for (Record p : publications) { orderedProviders.add(SubmissionLookupService.getProviderName(p)); } return orderedProviders; } - public String getUUID() - { + public String getUUID() { return uuid; } - public Record getTotalPublication(List providers) - { - if (publications == null) - { + public Record getTotalPublication(List providers) { + if (publications == null) { return null; - } - else if (publications.size() == 1) - { + } else if (publications.size() == 1) { return publications.get(0); - } - else - { + } else { MutableRecord pub = new SubmissionLookupPublication( - MERGED_PUBLICATION_PROVIDER); + MERGED_PUBLICATION_PROVIDER); // for (SubmissionLookupProvider prov : providers) // { - for (Record p : publications) - { + for (Record p : publications) { // if // (!SubmissionLookupService.getProviderName(p).equals(prov.getShortName())) // { // continue; // } - for (String field : p.getFields()) - { + for (String field : p.getFields()) { List values = p.getValues(field); - if (values != null && values.size() > 0) - { - if (!pub.getFields().contains(field)) - { - for (Value v : values) - { + if (values != null && values.size() > 0) { + if (!pub.getFields().contains(field)) { + for (Value v : values) { pub.addValue(field, v); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/util/SubmissionLookupDTO.java b/dspace-api/src/main/java/org/dspace/submit/util/SubmissionLookupDTO.java index 599d7ecd5b..dc3d500183 100644 --- a/dspace-api/src/main/java/org/dspace/submit/util/SubmissionLookupDTO.java +++ b/dspace-api/src/main/java/org/dspace/submit/util/SubmissionLookupDTO.java @@ -17,32 +17,25 @@ import java.util.UUID; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class SubmissionLookupDTO implements Serializable -{ +public class SubmissionLookupDTO implements Serializable { private static final long serialVersionUID = 1; private String uuid; private List items; - public SubmissionLookupDTO() - { + public SubmissionLookupDTO() { this.uuid = UUID.randomUUID().toString(); } - public void setItems(List items) - { + public void setItems(List items) { this.items = items; } - public ItemSubmissionLookupDTO getLookupItem(String uuidLookup) - { - if (items != null) - { - for (ItemSubmissionLookupDTO item : items) - { - if (item.getUUID().equals(uuidLookup)) - { + public ItemSubmissionLookupDTO getLookupItem(String uuidLookup) { + if (items != null) { + for (ItemSubmissionLookupDTO item : items) { + if (item.getUUID().equals(uuidLookup)) { return item; } } diff --git a/dspace-api/src/main/java/org/dspace/submit/util/SubmissionLookupPublication.java b/dspace-api/src/main/java/org/dspace/submit/util/SubmissionLookupPublication.java index 55267c6c6b..e5b51cf95b 100644 --- a/dspace-api/src/main/java/org/dspace/submit/util/SubmissionLookupPublication.java +++ b/dspace-api/src/main/java/org/dspace/submit/util/SubmissionLookupPublication.java @@ -7,10 +7,6 @@ */ package org.dspace.submit.util; -import gr.ekt.bte.core.MutableRecord; -import gr.ekt.bte.core.StringValue; -import gr.ekt.bte.core.Value; - import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; @@ -18,6 +14,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import gr.ekt.bte.core.MutableRecord; +import gr.ekt.bte.core.StringValue; +import gr.ekt.bte.core.Value; import org.apache.commons.lang.StringUtils; import org.dspace.submit.lookup.SubmissionLookupDataLoader; @@ -27,41 +26,33 @@ import org.dspace.submit.lookup.SubmissionLookupDataLoader; * @author Luigi Andrea Pascarelli * @author Panagiotis Koutsourakis */ -public class SubmissionLookupPublication implements MutableRecord, Serializable -{ +public class SubmissionLookupPublication implements MutableRecord, Serializable { private String providerName; private Map> storage = new HashMap>(); - public SubmissionLookupPublication(String providerName) - { + public SubmissionLookupPublication(String providerName) { this.providerName = providerName; } // needed to serialize it with JSON - public Map> getStorage() - { + public Map> getStorage() { return storage; } @Override - public Set getFields() - { + public Set getFields() { return storage.keySet(); } - public List remove(String md) - { + public List remove(String md) { return storage.remove(md); } - public void add(String md, String nValue) - { - if (StringUtils.isNotBlank(nValue)) - { + public void add(String md, String nValue) { + if (StringUtils.isNotBlank(nValue)) { List tmp = storage.get(md); - if (tmp == null) - { + if (tmp == null) { tmp = new ArrayList(); storage.put(md, tmp); } @@ -69,82 +60,64 @@ public class SubmissionLookupPublication implements MutableRecord, Serializable } } - public String getFirstValue(String md) - { + public String getFirstValue(String md) { List tmp = storage.get(md); - if (tmp == null || tmp.size() == 0) - { + if (tmp == null || tmp.size() == 0) { return null; } return tmp.get(0); } - public String getProviderName() - { + public String getProviderName() { return providerName; } - public String getType() - { + public String getType() { return getFirstValue(SubmissionLookupDataLoader.TYPE); } // BTE Record interface methods @Override - public boolean hasField(String md) - { + public boolean hasField(String md) { return storage.containsKey(md); } @Override - public List getValues(String md) - { + public List getValues(String md) { List stringValues = storage.get(md); - if (stringValues == null) - { + if (stringValues == null) { return null; } List values = new ArrayList(); - for (String value : stringValues) - { + for (String value : stringValues) { values.add(new StringValue(value)); } return values; } @Override - public boolean isMutable() - { + public boolean isMutable() { return true; } @Override - public MutableRecord makeMutable() - { + public MutableRecord makeMutable() { return this; } @Override - public boolean addField(String md, List values) - { - if (storage.containsKey(md)) - { + public boolean addField(String md, List values) { + if (storage.containsKey(md)) { List stringValues = storage.get(md); - if (values != null) - { - for (Value value : values) - { + if (values != null) { + for (Value value : values) { stringValues.add(value.getAsString()); } } - } - else - { + } else { List tmp = new ArrayList(); - if (values != null) - { - for (Value value : values) - { + if (values != null) { + for (Value value : values) { tmp.add(value.getAsString()); } } @@ -155,15 +128,11 @@ public class SubmissionLookupPublication implements MutableRecord, Serializable } @Override - public boolean addValue(String md, Value value) - { - if (storage.containsKey(md)) - { + public boolean addValue(String md, Value value) { + if (storage.containsKey(md)) { List stringValues = storage.get(md); stringValues.add(value.getAsString()); - } - else - { + } else { List tmp = new ArrayList(); tmp.add(value.getAsString()); @@ -174,20 +143,16 @@ public class SubmissionLookupPublication implements MutableRecord, Serializable } @Override - public boolean removeField(String md) - { - if (storage.containsKey(md)) - { + public boolean removeField(String md) { + if (storage.containsKey(md)) { storage.remove(md); } return false; } @Override - public boolean removeValue(String md, Value value) - { - if (storage.containsKey(md)) - { + public boolean removeValue(String md, Value value) { + if (storage.containsKey(md)) { List stringValues = storage.get(md); stringValues.remove(value.getAsString()); } @@ -195,11 +160,9 @@ public class SubmissionLookupPublication implements MutableRecord, Serializable } @Override - public boolean updateField(String md, List values) - { + public boolean updateField(String md, List values) { List stringValues = new ArrayList(); - for (Value value : values) - { + for (Value value : values) { stringValues.add(value.getAsString()); } storage.put(md, stringValues); @@ -208,20 +171,14 @@ public class SubmissionLookupPublication implements MutableRecord, Serializable } @Override - public boolean updateValue(String md, Value valueOld, Value valueNew) - { - if (storage.containsKey(md)) - { + public boolean updateValue(String md, Value valueOld, Value valueNew) { + if (storage.containsKey(md)) { List stringValues = storage.get(md); List newStringValues = storage.get(md); - for (String s : stringValues) - { - if (s.equals(valueOld.getAsString())) - { + for (String s : stringValues) { + if (s.equals(valueOld.getAsString())) { newStringValues.add(valueNew.getAsString()); - } - else - { + } else { newStringValues.add(s); } } diff --git a/dspace-api/src/main/java/org/dspace/testing/PubMedToImport.java b/dspace-api/src/main/java/org/dspace/testing/PubMedToImport.java index 2601548b48..52c5599b3e 100644 --- a/dspace-api/src/main/java/org/dspace/testing/PubMedToImport.java +++ b/dspace-api/src/main/java/org/dspace/testing/PubMedToImport.java @@ -7,6 +7,16 @@ */ package org.dspace.testing; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; @@ -21,16 +31,6 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - /** * Simple class to transform a medline.xml file from PubMed into DSpace import package(s) * @@ -50,6 +50,11 @@ public class PubMedToImport { private static File outputDir = null; + /** + * Default constructor + */ + private PubMedToImport() { } + public static void main(String args[]) { Options options = new Options(); @@ -81,9 +86,9 @@ public class PubMedToImport { SAXParser saxParser = factory.newSAXParser(); saxParser.parse(source, new PubMedHandler()); - + } catch (Exception e) { - + // ignore } } @@ -114,8 +119,8 @@ public class PubMedToImport { } @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException - { + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { if ("PubmedArticle".equals(qName)) { System.out.println("Starting record " + recordCount); } else if ("CommensCorrectionsList".equals(qName)) { @@ -134,8 +139,7 @@ public class PubMedToImport { } @Override - public void endElement(String uri, String localName, String qName) throws SAXException - { + public void endElement(String uri, String localName, String qName) throws SAXException { if (!isCorrection) { if ("PMID".equals(qName)) { addDCValue("identifier", null, value.toString()); @@ -169,13 +173,12 @@ public class PubMedToImport { } isFirstName = false; - isLastName = false; + isLastName = false; super.endElement(uri, localName, qName); } @Override - public void characters(char[] chars, int start, int length) throws SAXException - { + public void characters(char[] chars, int start, int length) throws SAXException { if (isFirstName) { firstName.append(chars, start, length); // firstName = String.copyValueOf(chars, start, length); @@ -190,26 +193,23 @@ public class PubMedToImport { super.characters(chars, start, length); } - private void writeItem() throws IOException - { + private void writeItem() throws IOException { File itemDir = new File(outputDir, String.valueOf(recordCount)); itemDir.mkdirs(); new File(itemDir, "contents").createNewFile(); - + Document doc = new Document(); Element root = new Element("dublin_core"); doc.setRootElement(root); - for (MockMetadataValue dcValue : dcValues) - { + for (MockMetadataValue dcValue : dcValues) { Element dcNode = new Element("dcvalue"); dcNode.setAttribute("element", dcValue.element); - if (!StringUtils.isEmpty(dcValue.qualifier)) - { + if (!StringUtils.isEmpty(dcValue.qualifier)) { dcNode.setAttribute("qualifier", dcValue.qualifier); } @@ -236,8 +236,7 @@ public class PubMedToImport { } - protected static class MockMetadataValue - { + protected static class MockMetadataValue { public String schema; public String element; public String qualifier; diff --git a/dspace-api/src/main/java/org/dspace/text/filter/DecomposeDiactritics.java b/dspace-api/src/main/java/org/dspace/text/filter/DecomposeDiactritics.java index d7fa39752d..2091617582 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/DecomposeDiactritics.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/DecomposeDiactritics.java @@ -11,20 +11,17 @@ import com.ibm.icu.text.Normalizer; /** * Decompose diacritic characters to character + diacritic - * + * * @author Graham Triggs */ -public class DecomposeDiactritics implements TextFilter -{ +public class DecomposeDiactritics implements TextFilter { @Override - public String filter(String str) - { + public String filter(String str) { return Normalizer.normalize(str, Normalizer.NFD); } @Override - public String filter(String str, String lang) - { + public String filter(String str, String lang) { return Normalizer.normalize(str, Normalizer.NFD); } } diff --git a/dspace-api/src/main/java/org/dspace/text/filter/InitialArticleWord.java b/dspace-api/src/main/java/org/dspace/text/filter/InitialArticleWord.java index 332e73debd..700b25748e 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/InitialArticleWord.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/InitialArticleWord.java @@ -11,92 +11,78 @@ package org.dspace.text.filter; * Abstract class for implementing initial article word filters * Allows you to create new classes with their own rules for mapping * languages to article word lists. - * + * * @author Graham Triggs */ -public abstract class InitialArticleWord implements TextFilter -{ +public abstract class InitialArticleWord implements TextFilter { /** * When no language is passed, use null and let implementation decide what to do */ @Override - public String filter(String str) - { + public String filter(String str) { return filter(str, null); } - + /** * Do an initial definite/indefinite article filter on the passed string. - * On matching an initial word, can strip or move to the end, depending on the + * On matching an initial word, can strip or move to the end, depending on the * configuration of the implementing class. - * + * * @param str The string to parse * @param lang The language of the passed string * @return String The filtered string */ @Override - public String filter(String str, String lang) - { + public String filter(String str, String lang) { // Get the list of article words for this language String[] articleWordArr = getArticleWords(lang); // If we have an article word array, process the string - if (articleWordArr != null && articleWordArr.length > 0) - { + if (articleWordArr != null && articleWordArr.length > 0) { String initialArticleWord = null; - int curPos = 0; + int curPos = 0; int initialStart = -1; - int initialEnd = -1; - + int initialEnd = -1; + // Iterate through the characters until we find something significant, or hit the end - while (initialEnd < 0 && curPos < str.length()) - { + while (initialEnd < 0 && curPos < str.length()) { // Have we found a significant character - if (Character.isLetterOrDigit(str.charAt(curPos))) - { + if (Character.isLetterOrDigit(str.charAt(curPos))) { // Mark this as the cut point for the initial word initialStart = curPos; - + // Loop through the article words looking for a match - for (int idx = 0; initialEnd < 0 && idx < articleWordArr.length; idx++) - { + for (int idx = 0; initialEnd < 0 && idx < articleWordArr.length; idx++) { // Extract a fragment from the string to test // Must be same length as the article word - if (idx > 1 && initialArticleWord != null) - { + if (idx > 1 && initialArticleWord != null) { // Only need to do so if we haven't already got one // of the right length - if (initialArticleWord.length() != articleWordArr[idx].length()) - { + if (initialArticleWord.length() != articleWordArr[idx].length()) { initialArticleWord = extractText(str, curPos, articleWordArr[idx].length()); } - } - else - { + } else { initialArticleWord = extractText(str, curPos, articleWordArr[idx].length()); } // Does the fragment match an article word? - if (initialArticleWord!= null && initialArticleWord.equalsIgnoreCase(articleWordArr[idx])) - { + if (initialArticleWord != null && initialArticleWord.equalsIgnoreCase(articleWordArr[idx])) { // Check to see if the next character in the source // is a whitespace boolean isNextWhitespace = Character.isWhitespace( - str.charAt(curPos + articleWordArr[idx].length()) - ); - + str.charAt(curPos + articleWordArr[idx].length()) + ); + // Check to see if the last character of the article word is a letter or digit - boolean endsLetterOrDigit = Character.isLetterOrDigit(initialArticleWord.charAt(initialArticleWord.length() - 1)); - + boolean endsLetterOrDigit = Character + .isLetterOrDigit(initialArticleWord.charAt(initialArticleWord.length() - 1)); + // If the last character of the article word is a letter or digit, // then it must be followed by whitespace, if not, it can be anything // Setting endPos signifies that we have found an article word - if (endsLetterOrDigit && isNextWhitespace) - { + if (endsLetterOrDigit && isNextWhitespace) { initialEnd = curPos + initialArticleWord.length(); - } - else if (!endsLetterOrDigit) - { + } else if (!endsLetterOrDigit) { initialEnd = curPos + initialArticleWord.length(); } } @@ -105,56 +91,49 @@ public abstract class InitialArticleWord implements TextFilter // Quit the loop, as we have a significant character break; } - + // Keep going curPos++; } - + // If endPos is positive, then we've found an article word - if (initialEnd > 0) - { + if (initialEnd > 0) { // Find a cut point in the source string, removing any whitespace after the article word int cutPos = initialEnd; - while (cutPos < str.length() && Character.isWhitespace(str.charAt(cutPos))) - { + while (cutPos < str.length() && Character.isWhitespace(str.charAt(cutPos))) { cutPos++; } - + // Are we stripping the article word? - if (stripInitialArticle) - { + if (stripInitialArticle) { // Yes, simply return everything after the cut return str.substring(cutPos); - } - else - { + } else { // No - move the initial article word to the end return new StringBuffer(str.substring(cutPos)) - .append(wordSeparator) - .append(str.substring(initialStart, initialEnd)) - .toString(); + .append(wordSeparator) + .append(str.substring(initialStart, initialEnd)) + .toString(); } } } - + // Didn't do any processing, or didn't find an initial article word // Return the original string return str; } - - protected InitialArticleWord(boolean stripWord) - { + + protected InitialArticleWord(boolean stripWord) { stripInitialArticle = stripWord; } - - protected InitialArticleWord() - { + + protected InitialArticleWord() { stripInitialArticle = false; } /** * Abstract method to get the list of words to use in the initial word filter - * + * * @param lang The language to retrieve article words for * @return An array of definite/indefinite article words */ @@ -166,30 +145,27 @@ public abstract class InitialArticleWord implements TextFilter // Flag to signify initial article word should be removed // If false, then the initial article word is appended to the end private boolean stripInitialArticle = false; - + /** * Helper method to extract text from a string. * Ensures that there is significant data (ie. non-whitespace) * after the segment requested. - * + * * @param str * @param pos * @param len * @return */ - private String extractText(String str, int pos, int len) - { + private String extractText(String str, int pos, int len) { int testPos = pos + len; - while (testPos < str.length() && Character.isWhitespace(str.charAt(testPos))) - { + while (testPos < str.length() && Character.isWhitespace(str.charAt(testPos))) { testPos++; } - - if (testPos < str.length()) - { + + if (testPos < str.length()) { return str.substring(pos, pos + len); } - + return null; } } diff --git a/dspace-api/src/main/java/org/dspace/text/filter/Language.java b/dspace-api/src/main/java/org/dspace/text/filter/Language.java index 18edd95ca9..9be68d2ddf 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/Language.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/Language.java @@ -12,147 +12,130 @@ import java.util.Map; /** * Define languages - both as IANA and ISO639-2 codes - * + * * @author Graham Triggs */ -public class Language -{ +public class Language { public final String IANA; public final String ISO639_1; public final String ISO639_2; - public static final Language AFRIKAANS = Language.create("af", "af", "afr"); - public static final Language ALBANIAN = Language.create("sq", "sq", "alb"); - public static final Language ARABIC = Language.create("ar", "ar", "ara"); - public static final Language BALUCHI = Language.create("bal", "", "bal"); - public static final Language BASQUE = Language.create("eu", "", "baq"); - public static final Language BRAHUI = Language.create("", "", ""); - public static final Language CATALAN = Language.create("ca", "ca", "cat"); - public static final Language CLASSICAL_GREEK = Language.create("grc", "", "grc"); - public static final Language DANISH = Language.create("da", "da", "dan"); - public static final Language DUTCH = Language.create("nl", "ni", "dut"); - public static final Language ENGLISH = Language.create("en", "en", "eng"); - public static final Language ESPERANTO = Language.create("eo", "eo", "epo"); - public static final Language FRENCH = Language.create("fr", "fr", "fre"); - public static final Language FRISIAN = Language.create("fy", "fy", "fri"); - public static final Language GALICIAN = Language.create("gl", "gl", "glg"); - public static final Language GERMAN = Language.create("de", "de", "ger"); - public static final Language GREEK = Language.create("el", "el", "gre"); - public static final Language HAWAIIAN = Language.create("haw", "", "haw"); - public static final Language HEBREW = Language.create("he", "he", "heb"); - public static final Language HUNGARIAN = Language.create("hu", "hu", "hun"); - public static final Language ICELANDIC = Language.create("is", "is", "ice"); - public static final Language IRISH = Language.create("ga", "ga", "gle"); - public static final Language ITALIAN = Language.create("it", "it", "ita"); - public static final Language MALAGASY = Language.create("mg", "mg", "mlg"); - public static final Language MALTESE = Language.create("mt", "mt", "mlt"); - public static final Language NEAPOLITAN_ITALIAN = Language.create("nap", "", "nap"); - public static final Language NORWEGIAN = Language.create("no", "no", "nor"); - public static final Language PORTUGUESE = Language.create("pt", "pt", "por"); - public static final Language PANJABI = Language.create("pa", "pa", "pan"); - public static final Language PERSIAN = Language.create("fa", "fa", "per"); - public static final Language PROVENCAL = Language.create("pro", "", "pro"); - public static final Language PROVENCAL_OCCITAN = Language.create("oc", "oc", "oci"); - public static final Language ROMANIAN = Language.create("ro", "ro", "rum"); - public static final Language SCOTS = Language.create("sco", "", "sco"); - public static final Language SCOTTISH_GAELIC = Language.create("gd", "gd", "gae"); - public static final Language SHETLAND_ENGLISH = Language.create("", "", ""); - public static final Language SPANISH = Language.create("es", "es", "spa"); - public static final Language SWEDISH = Language.create("sv", "sv", "swe"); - public static final Language TAGALOG = Language.create("tl", "tl", "tgl"); - public static final Language TURKISH = Language.create("tr", "tr", "tur"); - public static final Language URDU = Language.create("ur", "ur", "urd"); - public static final Language WALLOON = Language.create("wa", "wa", "wln"); - public static final Language WELSH = Language.create("cy", "cy", "wel"); - public static final Language YIDDISH = Language.create("yi", "yi", "yid"); + public static final Language AFRIKAANS = Language.create("af", "af", "afr"); + public static final Language ALBANIAN = Language.create("sq", "sq", "alb"); + public static final Language ARABIC = Language.create("ar", "ar", "ara"); + public static final Language BALUCHI = Language.create("bal", "", "bal"); + public static final Language BASQUE = Language.create("eu", "", "baq"); + public static final Language BRAHUI = Language.create("", "", ""); + public static final Language CATALAN = Language.create("ca", "ca", "cat"); + public static final Language CLASSICAL_GREEK = Language.create("grc", "", "grc"); + public static final Language DANISH = Language.create("da", "da", "dan"); + public static final Language DUTCH = Language.create("nl", "ni", "dut"); + public static final Language ENGLISH = Language.create("en", "en", "eng"); + public static final Language ESPERANTO = Language.create("eo", "eo", "epo"); + public static final Language FRENCH = Language.create("fr", "fr", "fre"); + public static final Language FRISIAN = Language.create("fy", "fy", "fri"); + public static final Language GALICIAN = Language.create("gl", "gl", "glg"); + public static final Language GERMAN = Language.create("de", "de", "ger"); + public static final Language GREEK = Language.create("el", "el", "gre"); + public static final Language HAWAIIAN = Language.create("haw", "", "haw"); + public static final Language HEBREW = Language.create("he", "he", "heb"); + public static final Language HUNGARIAN = Language.create("hu", "hu", "hun"); + public static final Language ICELANDIC = Language.create("is", "is", "ice"); + public static final Language IRISH = Language.create("ga", "ga", "gle"); + public static final Language ITALIAN = Language.create("it", "it", "ita"); + public static final Language MALAGASY = Language.create("mg", "mg", "mlg"); + public static final Language MALTESE = Language.create("mt", "mt", "mlt"); + public static final Language NEAPOLITAN_ITALIAN = Language.create("nap", "", "nap"); + public static final Language NORWEGIAN = Language.create("no", "no", "nor"); + public static final Language PORTUGUESE = Language.create("pt", "pt", "por"); + public static final Language PANJABI = Language.create("pa", "pa", "pan"); + public static final Language PERSIAN = Language.create("fa", "fa", "per"); + public static final Language PROVENCAL = Language.create("pro", "", "pro"); + public static final Language PROVENCAL_OCCITAN = Language.create("oc", "oc", "oci"); + public static final Language ROMANIAN = Language.create("ro", "ro", "rum"); + public static final Language SCOTS = Language.create("sco", "", "sco"); + public static final Language SCOTTISH_GAELIC = Language.create("gd", "gd", "gae"); + public static final Language SHETLAND_ENGLISH = Language.create("", "", ""); + public static final Language SPANISH = Language.create("es", "es", "spa"); + public static final Language SWEDISH = Language.create("sv", "sv", "swe"); + public static final Language TAGALOG = Language.create("tl", "tl", "tgl"); + public static final Language TURKISH = Language.create("tr", "tr", "tur"); + public static final Language URDU = Language.create("ur", "ur", "urd"); + public static final Language WALLOON = Language.create("wa", "wa", "wln"); + public static final Language WELSH = Language.create("cy", "cy", "wel"); + public static final Language YIDDISH = Language.create("yi", "yi", "yid"); - public static Language getLanguage(String lang) - { + public static Language getLanguage(String lang) { return LanguageMaps.getLanguage(lang); } - public static Language getLanguageForIANA(String iana) - { + public static Language getLanguageForIANA(String iana) { return LanguageMaps.getLanguageForIANA(iana); } - - public static Language getLanguageForISO639_2(String iso) - { + + public static Language getLanguageForISO639_2(String iso) { return LanguageMaps.getLanguageForISO639_2(iso); } - - private static synchronized Language create(String iana, String iso639_1, String iso639_2) - { + + private static synchronized Language create(String iana, String iso639_1, String iso639_2) { Language lang = LanguageMaps.getLanguageForIANA(iana); - + lang = (lang != null ? lang : LanguageMaps.getLanguageForISO639_1(iso639_1)); lang = (lang != null ? lang : LanguageMaps.getLanguageForISO639_2(iso639_2)); - + return (lang != null ? lang : new Language(iana, iso639_1, iso639_2)); } - - private static class LanguageMaps - { - private static final Map langMapIANA = new HashMap(); + + private static class LanguageMaps { + private static final Map langMapIANA = new HashMap(); private static final Map langMapISO639_1 = new HashMap(); private static final Map langMapISO639_2 = new HashMap(); - static void add(Language l) - { - if (l.IANA != null && l.IANA.length() > 0 && !langMapIANA.containsKey(l.IANA)) - { + static void add(Language l) { + if (l.IANA != null && l.IANA.length() > 0 && !langMapIANA.containsKey(l.IANA)) { langMapIANA.put(l.IANA, l); } - - if (l.ISO639_1 != null && l.ISO639_1.length() > 0 && !langMapISO639_1.containsKey(l.ISO639_1)) - { + + if (l.ISO639_1 != null && l.ISO639_1.length() > 0 && !langMapISO639_1.containsKey(l.ISO639_1)) { langMapISO639_1.put(l.ISO639_1, l); } - if (l.ISO639_2 != null && l.ISO639_2.length() > 0 && !langMapISO639_2.containsKey(l.ISO639_2)) - { + if (l.ISO639_2 != null && l.ISO639_2.length() > 0 && !langMapISO639_2.containsKey(l.ISO639_2)) { langMapISO639_2.put(l.ISO639_2, l); } } - public static Language getLanguage(String lang) - { - if (langMapIANA.containsKey(lang)) - { + public static Language getLanguage(String lang) { + if (langMapIANA.containsKey(lang)) { return langMapIANA.get(lang); } return langMapISO639_2.get(lang); } - public static Language getLanguageForIANA(String iana) - { + public static Language getLanguageForIANA(String iana) { return langMapIANA.get(iana); } - - public static Language getLanguageForISO639_1(String iso) - { + + public static Language getLanguageForISO639_1(String iso) { return langMapISO639_1.get(iso); } - public static Language getLanguageForISO639_2(String iso) - { + public static Language getLanguageForISO639_2(String iso) { return langMapISO639_2.get(iso); } } - - private Language(String iana, String iso639_1, String iso639_2) - { - IANA = iana; + + private Language(String iana, String iso639_1, String iso639_2) { + IANA = iana; ISO639_1 = iso639_1; ISO639_2 = iso639_2; - + LanguageMaps.add(this); } - - private Language() - { - IANA = null; + + private Language() { + IANA = null; ISO639_1 = null; ISO639_2 = null; } diff --git a/dspace-api/src/main/java/org/dspace/text/filter/LowerCaseAndTrim.java b/dspace-api/src/main/java/org/dspace/text/filter/LowerCaseAndTrim.java index 55ca2b0b6f..7e5edb5a01 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/LowerCaseAndTrim.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/LowerCaseAndTrim.java @@ -9,21 +9,18 @@ package org.dspace.text.filter; /** * Lowercase and trim leading / trailing whitespace - * + * * @author Graham Triggs */ -public class LowerCaseAndTrim implements TextFilter -{ +public class LowerCaseAndTrim implements TextFilter { @Override - public String filter(String str) - { + public String filter(String str) { return str.toLowerCase().trim(); } @Override - public String filter(String str, String lang) - { + public String filter(String str, String lang) { return str.toLowerCase().trim(); } diff --git a/dspace-api/src/main/java/org/dspace/text/filter/MARC21InitialArticleWord.java b/dspace-api/src/main/java/org/dspace/text/filter/MARC21InitialArticleWord.java index 39362a3e74..3985f19320 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/MARC21InitialArticleWord.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/MARC21InitialArticleWord.java @@ -8,7 +8,12 @@ package org.dspace.text.filter; import java.io.Serializable; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; @@ -17,21 +22,18 @@ import org.dspace.services.factory.DSpaceServicesFactory; /** * Implements MARC 21 standards to disregard initial * definite or indefinite article in sorting. - * + * * Note: This only works for languages defined with IANA code entries. - * + * * @author Graham Triggs */ -public class MARC21InitialArticleWord extends InitialArticleWord -{ - public MARC21InitialArticleWord() - { +public class MARC21InitialArticleWord extends InitialArticleWord { + public MARC21InitialArticleWord() { // Default behaviour is to strip the initial word completely super(true); } - public MARC21InitialArticleWord(boolean stripWord) - { + public MARC21InitialArticleWord(boolean stripWord) { super(stripWord); } @@ -40,185 +42,186 @@ public class MARC21InitialArticleWord extends InitialArticleWord * for this language. */ @Override - protected String[] getArticleWords(String lang) - { + protected String[] getArticleWords(String lang) { // No language - no words - if (StringUtils.isEmpty(lang)) - { + if (StringUtils.isEmpty(lang)) { return defaultWords; } Language l = Language.getLanguage(lang); - + // Is the language in our map? - if (l != null && ianaArticleMap.containsKey(l.IANA)) - { + if (l != null && ianaArticleMap.containsKey(l.IANA)) { // Get the list of words for this language ArticlesForLang articles = ianaArticleMap.get(l.IANA); - - if (articles != null) - { + + if (articles != null) { return articles.words; } } - + return null; } - + // Mapping of IANA codes to article word lists private static Map ianaArticleMap = new HashMap(); private static String[] defaultWords = null; - // Static initialisation - convert word -> languages map + // Static initialisation - convert word -> languages map // into language -> words map - static - { + static { /* Define a mapping for article words to the languages that have them. * Take from: http://www.loc.gov/marc/bibliographic/bdapp-e.html */ Object[][] articleWordArray = { - { "a", Language.ENGLISH, Language.GALICIAN, Language.HUNGARIAN, Language.PORTUGUESE, Language.ROMANIAN, Language.SCOTS, Language.YIDDISH }, - { "a'", Language.SCOTTISH_GAELIC }, - { "al", Language.ROMANIAN }, - { "al-", Language.ARABIC, Language.BALUCHI, Language.BRAHUI, Language.PANJABI, Language.PERSIAN, Language.TURKISH, Language.URDU }, - { "am", Language.SCOTTISH_GAELIC }, - { "an", Language.ENGLISH, Language.IRISH, Language.SCOTS, Language.SCOTTISH_GAELIC, Language.YIDDISH }, - { "an t-", Language.IRISH, Language.SCOTTISH_GAELIC }, - { "ane", Language.SCOTS }, - { "ang", Language.TAGALOG }, - { "ang mga", Language.TAGALOG }, - { "as", Language.GALICIAN, Language.PORTUGUESE }, - { "az", Language.HUNGARIAN }, - { "bat", Language.BASQUE }, - { "bir", Language.TURKISH }, - { "d'", Language.ENGLISH }, - { "da", Language.SHETLAND_ENGLISH }, - { "das", Language.GERMAN }, - { "de", Language.DANISH, Language.DUTCH, Language.ENGLISH, Language.FRISIAN, Language.NORWEGIAN, Language.SWEDISH }, - { "dei", Language.NORWEGIAN }, - { "dem", Language.GERMAN }, - { "den", Language.DANISH, Language.GERMAN, Language.NORWEGIAN, Language.SWEDISH }, - { "der", Language.GERMAN, Language.YIDDISH }, - { "des", Language.GERMAN, Language.WALLOON }, - { "det", Language.DANISH, Language.NORWEGIAN, Language.SWEDISH }, - { "di", Language.YIDDISH }, - { "die", Language.AFRIKAANS, Language.GERMAN, Language.YIDDISH }, - { "dos", Language.YIDDISH }, - { "e", Language.NORWEGIAN }, - { "e", Language.FRISIAN }, // should be 'e - leading apostrophes are ignored - { "een", Language.DUTCH }, - { "eene", Language.DUTCH }, - { "egy", Language.HUNGARIAN }, - { "ei", Language.NORWEGIAN }, - { "ein", Language.GERMAN, Language.NORWEGIAN, Language.WALLOON }, - { "eine", Language.GERMAN }, - { "einem", Language.GERMAN }, - { "einen", Language.GERMAN }, - { "einer", Language.GERMAN }, - { "eines", Language.GERMAN }, - { "eit", Language.NORWEGIAN }, - { "el", Language.CATALAN, Language.SPANISH }, - { "el-", Language.ARABIC }, - { "els", Language.CATALAN }, - { "en", Language.CATALAN, Language.DANISH, Language.NORWEGIAN, Language.SWEDISH }, - { "enne", Language.WALLOON }, - { "et", Language.DANISH, Language.NORWEGIAN }, - { "ett", Language.SWEDISH }, - { "eyn", Language.YIDDISH }, - { "eyne", Language.YIDDISH }, - { "gl'", Language.ITALIAN }, - { "gli", Language.PROVENCAL }, - { "ha-", Language.HEBREW }, - { "hai", Language.CLASSICAL_GREEK, Language.GREEK }, - { "he", Language.HAWAIIAN }, - { "h\u0113", Language.CLASSICAL_GREEK, Language.GREEK }, // e macron - { "he-", Language.HEBREW }, - { "heis", Language.GREEK }, - { "hen", Language.GREEK }, - { "hena", Language.GREEK }, - { "henas", Language.GREEK }, - { "het", Language.DUTCH }, - { "hin", Language.ICELANDIC }, - { "hina", Language.ICELANDIC }, - { "hinar", Language.ICELANDIC }, - { "hinir", Language.ICELANDIC }, - { "hinn", Language.ICELANDIC }, - { "hinna", Language.ICELANDIC }, - { "hinnar", Language.ICELANDIC }, - { "hinni", Language.ICELANDIC }, - { "hins", Language.ICELANDIC }, - { "hinu", Language.ICELANDIC }, - { "hinum", Language.ICELANDIC }, - { "hi\u01d2", Language.ICELANDIC }, - { "ho", Language.CLASSICAL_GREEK, Language.GREEK }, - { "hoi", Language.CLASSICAL_GREEK, Language.GREEK }, - { "i", Language.ITALIAN }, - { "ih'", Language.PROVENCAL }, - { "il", Language.ITALIAN, Language.PROVENCAL_OCCITAN }, - { "il-", Language.MALTESE }, - { "in", Language.FRISIAN }, - { "it", Language.FRISIAN }, - { "ka", Language.HAWAIIAN }, - { "ke", Language.HAWAIIAN }, - { "l'", Language.CATALAN, Language.FRENCH, Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.WALLOON }, - { "l-", Language.MALTESE }, - { "la", Language.CATALAN, Language.ESPERANTO, Language.FRENCH, Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.SPANISH }, - { "las", Language.PROVENCAL_OCCITAN, Language.SPANISH }, - { "le", Language.FRENCH, Language.ITALIAN, Language.PROVENCAL_OCCITAN }, - { "les", Language.CATALAN, Language.FRENCH, Language.PROVENCAL_OCCITAN, Language.WALLOON }, - { "lh", Language.PROVENCAL_OCCITAN }, - { "lhi", Language.PROVENCAL_OCCITAN }, - { "li", Language.PROVENCAL_OCCITAN }, - { "lis", Language.PROVENCAL_OCCITAN }, - { "lo", Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.SPANISH }, - { "los", Language.PROVENCAL_OCCITAN, Language.SPANISH }, - { "lou", Language.PROVENCAL_OCCITAN }, - { "lu", Language.PROVENCAL_OCCITAN }, - { "mga", Language.TAGALOG }, - { "m\u0303ga", Language.TAGALOG }, - { "mia", Language.GREEK }, - { "n", Language.AFRIKAANS, Language.DUTCH, Language.FRISIAN }, // should be 'n - leading apostrophes are ignored - { "na", Language.HAWAIIAN, Language.IRISH, Language.SCOTTISH_GAELIC }, - { "na h-", Language.IRISH, Language.SCOTTISH_GAELIC }, - { "nje", Language.ALBANIAN }, - { "ny", Language.MALAGASY }, - { "o", Language.NEAPOLITAN_ITALIAN }, // should be 'o - leading apostrophes are ignored - { "o", Language.GALICIAN, Language.HAWAIIAN, Language.PORTUGUESE, Language.ROMANIAN }, - { "os", Language.PORTUGUESE }, - { "r", Language.ICELANDIC }, // should be 'r - leading apostrophes are ignored - { "s", Language.GERMAN }, // should be 's - leading apostrophes are ignored - { "sa", Language.TAGALOG }, - { "sa mga", Language.TAGALOG }, - { "si", Language.TAGALOG }, - { "sin\u00e1", Language.TAGALOG }, - { "t", Language.DUTCH, Language.FRISIAN }, // should be 't - leading apostrophes are ignored - { "ta", Language.CLASSICAL_GREEK, Language.GREEK }, - { "tais", Language.CLASSICAL_GREEK }, - { "tas", Language.CLASSICAL_GREEK }, - { "t\u0113", Language.CLASSICAL_GREEK }, // e macron - { "t\u0113n", Language.CLASSICAL_GREEK, Language.GREEK }, // e macron - { "t\u0113s", Language.CLASSICAL_GREEK, Language.GREEK }, // e macron - { "the", Language.ENGLISH }, - { "t\u014d", Language.CLASSICAL_GREEK, Language.GREEK }, // o macron - { "tois", Language.CLASSICAL_GREEK }, - { "t\u014dn", Language.CLASSICAL_GREEK, Language.GREEK }, // o macron - { "tou", Language.CLASSICAL_GREEK, Language.GREEK }, - { "um", Language.PORTUGUESE }, - { "uma", Language.PORTUGUESE }, - { "un", Language.CATALAN, Language.FRENCH, Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.ROMANIAN, Language.SPANISH }, - { "un'", Language.ITALIAN }, - { "una", Language.CATALAN, Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.SPANISH }, - { "une", Language.FRENCH }, - { "unei", Language.ROMANIAN }, - { "unha", Language.GALICIAN }, - { "uno", Language.ITALIAN, Language.PROVENCAL_OCCITAN }, - { "uns", Language.PROVENCAL_OCCITAN }, - { "unui", Language.ROMANIAN }, - { "us", Language.PROVENCAL_OCCITAN }, - { "y", Language.WELSH }, - { "ye", Language.ENGLISH }, - { "yr", Language.WELSH } + {"a", Language.ENGLISH, Language.GALICIAN, Language.HUNGARIAN, Language.PORTUGUESE, Language.ROMANIAN, + Language.SCOTS, Language.YIDDISH}, + {"a'", Language.SCOTTISH_GAELIC}, + {"al", Language.ROMANIAN}, + {"al-", Language.ARABIC, Language.BALUCHI, Language.BRAHUI, Language.PANJABI, Language.PERSIAN, + Language.TURKISH, Language.URDU}, + {"am", Language.SCOTTISH_GAELIC}, + {"an", Language.ENGLISH, Language.IRISH, Language.SCOTS, Language.SCOTTISH_GAELIC, Language.YIDDISH}, + {"an t-", Language.IRISH, Language.SCOTTISH_GAELIC}, + {"ane", Language.SCOTS}, + {"ang", Language.TAGALOG}, + {"ang mga", Language.TAGALOG}, + {"as", Language.GALICIAN, Language.PORTUGUESE}, + {"az", Language.HUNGARIAN}, + {"bat", Language.BASQUE}, + {"bir", Language.TURKISH}, + {"d'", Language.ENGLISH}, + {"da", Language.SHETLAND_ENGLISH}, + {"das", Language.GERMAN}, + {"de", Language.DANISH, Language.DUTCH, Language.ENGLISH, Language.FRISIAN, Language.NORWEGIAN, + Language.SWEDISH}, + {"dei", Language.NORWEGIAN}, + {"dem", Language.GERMAN}, + {"den", Language.DANISH, Language.GERMAN, Language.NORWEGIAN, Language.SWEDISH}, + {"der", Language.GERMAN, Language.YIDDISH}, + {"des", Language.GERMAN, Language.WALLOON}, + {"det", Language.DANISH, Language.NORWEGIAN, Language.SWEDISH}, + {"di", Language.YIDDISH}, + {"die", Language.AFRIKAANS, Language.GERMAN, Language.YIDDISH}, + {"dos", Language.YIDDISH}, + {"e", Language.NORWEGIAN}, + {"e", Language.FRISIAN}, // should be 'e - leading apostrophes are ignored + {"een", Language.DUTCH}, + {"eene", Language.DUTCH}, + {"egy", Language.HUNGARIAN}, + {"ei", Language.NORWEGIAN}, + {"ein", Language.GERMAN, Language.NORWEGIAN, Language.WALLOON}, + {"eine", Language.GERMAN}, + {"einem", Language.GERMAN}, + {"einen", Language.GERMAN}, + {"einer", Language.GERMAN}, + {"eines", Language.GERMAN}, + {"eit", Language.NORWEGIAN}, + {"el", Language.CATALAN, Language.SPANISH}, + {"el-", Language.ARABIC}, + {"els", Language.CATALAN}, + {"en", Language.CATALAN, Language.DANISH, Language.NORWEGIAN, Language.SWEDISH}, + {"enne", Language.WALLOON}, + {"et", Language.DANISH, Language.NORWEGIAN}, + {"ett", Language.SWEDISH}, + {"eyn", Language.YIDDISH}, + {"eyne", Language.YIDDISH}, + {"gl'", Language.ITALIAN}, + {"gli", Language.PROVENCAL}, + {"ha-", Language.HEBREW}, + {"hai", Language.CLASSICAL_GREEK, Language.GREEK}, + {"he", Language.HAWAIIAN}, + {"h\u0113", Language.CLASSICAL_GREEK, Language.GREEK}, // e macron + {"he-", Language.HEBREW}, + {"heis", Language.GREEK}, + {"hen", Language.GREEK}, + {"hena", Language.GREEK}, + {"henas", Language.GREEK}, + {"het", Language.DUTCH}, + {"hin", Language.ICELANDIC}, + {"hina", Language.ICELANDIC}, + {"hinar", Language.ICELANDIC}, + {"hinir", Language.ICELANDIC}, + {"hinn", Language.ICELANDIC}, + {"hinna", Language.ICELANDIC}, + {"hinnar", Language.ICELANDIC}, + {"hinni", Language.ICELANDIC}, + {"hins", Language.ICELANDIC}, + {"hinu", Language.ICELANDIC}, + {"hinum", Language.ICELANDIC}, + {"hi\u01d2", Language.ICELANDIC}, + {"ho", Language.CLASSICAL_GREEK, Language.GREEK}, + {"hoi", Language.CLASSICAL_GREEK, Language.GREEK}, + {"i", Language.ITALIAN}, + {"ih'", Language.PROVENCAL}, + {"il", Language.ITALIAN, Language.PROVENCAL_OCCITAN}, + {"il-", Language.MALTESE}, + {"in", Language.FRISIAN}, + {"it", Language.FRISIAN}, + {"ka", Language.HAWAIIAN}, + {"ke", Language.HAWAIIAN}, + {"l'", Language.CATALAN, Language.FRENCH, Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.WALLOON}, + {"l-", Language.MALTESE}, + {"la", Language.CATALAN, Language.ESPERANTO, Language.FRENCH, Language.ITALIAN, Language.PROVENCAL_OCCITAN, + Language.SPANISH}, + {"las", Language.PROVENCAL_OCCITAN, Language.SPANISH}, + {"le", Language.FRENCH, Language.ITALIAN, Language.PROVENCAL_OCCITAN}, + {"les", Language.CATALAN, Language.FRENCH, Language.PROVENCAL_OCCITAN, Language.WALLOON}, + {"lh", Language.PROVENCAL_OCCITAN}, + {"lhi", Language.PROVENCAL_OCCITAN}, + {"li", Language.PROVENCAL_OCCITAN}, + {"lis", Language.PROVENCAL_OCCITAN}, + {"lo", Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.SPANISH}, + {"los", Language.PROVENCAL_OCCITAN, Language.SPANISH}, + {"lou", Language.PROVENCAL_OCCITAN}, + {"lu", Language.PROVENCAL_OCCITAN}, + {"mga", Language.TAGALOG}, + {"m\u0303ga", Language.TAGALOG}, + {"mia", Language.GREEK}, + {"n", Language.AFRIKAANS, Language.DUTCH, Language.FRISIAN}, // should be 'n - leading + // apostrophes are ignored + {"na", Language.HAWAIIAN, Language.IRISH, Language.SCOTTISH_GAELIC}, + {"na h-", Language.IRISH, Language.SCOTTISH_GAELIC}, + {"nje", Language.ALBANIAN}, + {"ny", Language.MALAGASY}, + {"o", Language.NEAPOLITAN_ITALIAN}, // should be 'o - leading apostrophes are ignored + {"o", Language.GALICIAN, Language.HAWAIIAN, Language.PORTUGUESE, Language.ROMANIAN}, + {"os", Language.PORTUGUESE}, + {"r", Language.ICELANDIC}, // should be 'r - leading apostrophes are ignored + {"s", Language.GERMAN}, // should be 's - leading apostrophes are ignored + {"sa", Language.TAGALOG}, + {"sa mga", Language.TAGALOG}, + {"si", Language.TAGALOG}, + {"sin\u00e1", Language.TAGALOG}, + {"t", Language.DUTCH, Language.FRISIAN}, // should be 't - leading apostrophes are ignored + {"ta", Language.CLASSICAL_GREEK, Language.GREEK}, + {"tais", Language.CLASSICAL_GREEK}, + {"tas", Language.CLASSICAL_GREEK}, + {"t\u0113", Language.CLASSICAL_GREEK}, // e macron + {"t\u0113n", Language.CLASSICAL_GREEK, Language.GREEK}, // e macron + {"t\u0113s", Language.CLASSICAL_GREEK, Language.GREEK}, // e macron + {"the", Language.ENGLISH}, + {"t\u014d", Language.CLASSICAL_GREEK, Language.GREEK}, // o macron + {"tois", Language.CLASSICAL_GREEK}, + {"t\u014dn", Language.CLASSICAL_GREEK, Language.GREEK}, // o macron + {"tou", Language.CLASSICAL_GREEK, Language.GREEK}, + {"um", Language.PORTUGUESE}, + {"uma", Language.PORTUGUESE}, + {"un", Language.CATALAN, Language.FRENCH, Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.ROMANIAN, + Language.SPANISH}, + {"un'", Language.ITALIAN}, + {"una", Language.CATALAN, Language.ITALIAN, Language.PROVENCAL_OCCITAN, Language.SPANISH}, + {"une", Language.FRENCH}, + {"unei", Language.ROMANIAN}, + {"unha", Language.GALICIAN}, + {"uno", Language.ITALIAN, Language.PROVENCAL_OCCITAN}, + {"uns", Language.PROVENCAL_OCCITAN}, + {"unui", Language.ROMANIAN}, + {"us", Language.PROVENCAL_OCCITAN}, + {"y", Language.WELSH}, + {"ye", Language.ENGLISH}, + {"yr", Language.WELSH} }; // Initialize the lang -> article map @@ -230,110 +233,97 @@ public class MARC21InitialArticleWord extends InitialArticleWord // Iterate through word/language array // Generate temporary language map Map> langWordMap = new HashMap>(); - for (wordIdx = 0; wordIdx < articleWordArray.length; wordIdx++) - { - for (langIdx = 1; langIdx < articleWordArray[wordIdx].length; langIdx++) - { - Language lang = (Language)articleWordArray[wordIdx][langIdx]; + for (wordIdx = 0; wordIdx < articleWordArray.length; wordIdx++) { + for (langIdx = 1; langIdx < articleWordArray[wordIdx].length; langIdx++) { + Language lang = (Language) articleWordArray[wordIdx][langIdx]; - if (lang != null && lang.IANA.length() > 0) - { + if (lang != null && lang.IANA.length() > 0) { List words = langWordMap.get(lang); - - if (words == null) - { + + if (words == null) { words = new ArrayList(); langWordMap.put(lang, words); } - + // Add language to list if we haven't done so already - if (!words.contains(articleWordArray[wordIdx][0])) - { - words.add((String)articleWordArray[wordIdx][0]); + if (!words.contains(articleWordArray[wordIdx][0])) { + words.add((String) articleWordArray[wordIdx][0]); } } } } - + // Iterate through languages - for (Map.Entry> langToWord : langWordMap.entrySet()) - { + for (Map.Entry> langToWord : langWordMap.entrySet()) { Language lang = langToWord.getKey(); List wordList = langToWord.getValue(); // Convert the list into an array of strings String[] words = new String[wordList.size()]; - for (int idx = 0; idx < wordList.size(); idx++) - { + for (int idx = 0; idx < wordList.size(); idx++) { words[idx] = wordList.get(idx); } // Sort the array into length order - longest to shortest // This ensures maximal matching on the article words - Arrays.sort(words, new MARC21InitialArticleWord.InverseLengthComparator() ); + Arrays.sort(words, new MARC21InitialArticleWord.InverseLengthComparator()); // Add language/article entry to map ianaArticleMap.put(lang.IANA, new MARC21InitialArticleWord.ArticlesForLang(lang, words)); } // Setup default stop words for null languages - String[] defaultLangs = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("marc21wordfilter.defaultlang"); - if (ArrayUtils.isNotEmpty(defaultLangs)) - { - int wordCount = 0; - ArticlesForLang[] afl = new ArticlesForLang[defaultLangs.length]; + String[] defaultLangs = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("marc21wordfilter.defaultlang"); + if (ArrayUtils.isNotEmpty(defaultLangs)) { + int wordCount = 0; + ArticlesForLang[] afl = new ArticlesForLang[defaultLangs.length]; - for (int idx = 0; idx < afl.length; idx++) - { - Language l = Language.getLanguage(defaultLangs[idx]); - if (l != null && ianaArticleMap.containsKey(l.IANA)) - { - afl[idx] = ianaArticleMap.get(l.IANA); - if (afl[idx] != null) - { - wordCount += afl[idx].words.length; - } + for (int idx = 0; idx < afl.length; idx++) { + Language l = Language.getLanguage(defaultLangs[idx]); + if (l != null && ianaArticleMap.containsKey(l.IANA)) { + afl[idx] = ianaArticleMap.get(l.IANA); + if (afl[idx] != null) { + wordCount += afl[idx].words.length; } } + } - if (wordCount > 0) - { - int destPos = 0; - defaultWords = new String[wordCount]; - for (int idx = 0; idx < afl.length; idx++) - { - if (afl[idx] != null) - { - System.arraycopy(afl[idx].words, 0, defaultWords, destPos, afl[idx].words.length); - destPos += afl[idx].words.length; - } + if (wordCount > 0) { + int destPos = 0; + defaultWords = new String[wordCount]; + for (int idx = 0; idx < afl.length; idx++) { + if (afl[idx] != null) { + System.arraycopy(afl[idx].words, 0, defaultWords, destPos, afl[idx].words.length); + destPos += afl[idx].words.length; } } + } } } // Wrapper class for inserting word arrays into a map - private static class ArticlesForLang - { + private static class ArticlesForLang { final Language lang; final String[] words; - - ArticlesForLang(Language lang, String[] words) - { - this.lang = lang; - this.words = (String[]) ArrayUtils.clone(words); + + ArticlesForLang(Language lang, String[] words) { + this.lang = lang; + this.words = (String[]) ArrayUtils.clone(words); } } - + // Compare strings according to their length - longest to shortest - private static class InverseLengthComparator implements Comparator, Serializable - { + private static class InverseLengthComparator implements Comparator, Serializable { @Override - public int compare(Object arg0, Object arg1) - { - return ((String)arg1).length() - ((String)arg0).length(); - }; - - }; + public int compare(Object arg0, Object arg1) { + return ((String) arg1).length() - ((String) arg0).length(); + } + + ; + + } + + ; } diff --git a/dspace-api/src/main/java/org/dspace/text/filter/StandardInitialArticleWord.java b/dspace-api/src/main/java/org/dspace/text/filter/StandardInitialArticleWord.java index f7a2eada13..ade72b150f 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/StandardInitialArticleWord.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/StandardInitialArticleWord.java @@ -9,25 +9,22 @@ package org.dspace.text.filter; /** * Implements existing DSpace initial article word behaviour - * + * * Note: This only works for languages defined with ISO code entries. - * + * * @author Graham Triggs */ -public class StandardInitialArticleWord extends InitialArticleWord -{ - private static final String[] articleWords = { "the", "an", "a" }; +public class StandardInitialArticleWord extends InitialArticleWord { + private static final String[] articleWords = {"the", "an", "a"}; @Override - protected String[] getArticleWords(String lang) - { - if (lang != null && lang.startsWith("en")) - { + protected String[] getArticleWords(String lang) { + if (lang != null && lang.startsWith("en")) { return articleWords; } - + return null; } } - + diff --git a/dspace-api/src/main/java/org/dspace/text/filter/StripDiacritics.java b/dspace-api/src/main/java/org/dspace/text/filter/StripDiacritics.java index bde5523d7c..380ca7fd41 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/StripDiacritics.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/StripDiacritics.java @@ -9,21 +9,17 @@ package org.dspace.text.filter; /** * Strips decomposed diacritic characters from the supplied string - * - * @author Graham Triggs * + * @author Graham Triggs */ -public class StripDiacritics implements TextFilter -{ +public class StripDiacritics implements TextFilter { @Override - public String filter(String str) - { + public String filter(String str) { return str.replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); } @Override - public String filter(String str, String lang) - { + public String filter(String str, String lang) { return str.replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); } diff --git a/dspace-api/src/main/java/org/dspace/text/filter/StripLeadingNonAlphaNum.java b/dspace-api/src/main/java/org/dspace/text/filter/StripLeadingNonAlphaNum.java index d1a422b206..7d46cc5709 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/StripLeadingNonAlphaNum.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/StripLeadingNonAlphaNum.java @@ -7,20 +7,16 @@ */ package org.dspace.text.filter; -public class StripLeadingNonAlphaNum implements TextFilter -{ +public class StripLeadingNonAlphaNum implements TextFilter { @Override - public String filter(String str) - { + public String filter(String str) { int i = 0; - while (i < str.length() && !Character.isLetterOrDigit(str.charAt(i))) - { + while (i < str.length() && !Character.isLetterOrDigit(str.charAt(i))) { i++; } - if (i > 0) - { + if (i > 0) { return str.substring(i); } @@ -28,8 +24,7 @@ public class StripLeadingNonAlphaNum implements TextFilter } @Override - public String filter(String str, String lang) - { + public String filter(String str, String lang) { return filter(str); } } diff --git a/dspace-api/src/main/java/org/dspace/text/filter/TextFilter.java b/dspace-api/src/main/java/org/dspace/text/filter/TextFilter.java index 94349f6f80..6efc8a5f45 100644 --- a/dspace-api/src/main/java/org/dspace/text/filter/TextFilter.java +++ b/dspace-api/src/main/java/org/dspace/text/filter/TextFilter.java @@ -9,11 +9,11 @@ package org.dspace.text.filter; /** * Define an interface for all browse ordering filters. + * * @author Graham Triggs */ -public interface TextFilter -{ - public String filter(String str); - +public interface TextFilter { + public String filter(String str); + public String filter(String str, String lang); } diff --git a/dspace-api/src/main/java/org/dspace/usage/AbstractUsageEventListener.java b/dspace-api/src/main/java/org/dspace/usage/AbstractUsageEventListener.java index 1ad1c50fed..8eb5a55465 100644 --- a/dspace-api/src/main/java/org/dspace/usage/AbstractUsageEventListener.java +++ b/dspace-api/src/main/java/org/dspace/usage/AbstractUsageEventListener.java @@ -13,44 +13,41 @@ import org.dspace.services.model.EventListener; /** * AbstractUsageEventListener is used as the base class for listening events running * in the EventService. - * + * * @author Mark Diggory (mdiggory at atmire.com) * @version $Revision: $ */ public abstract class AbstractUsageEventListener implements EventListener { - public AbstractUsageEventListener() { - super(); - } + public AbstractUsageEventListener() { + super(); + } - /** - * Empty String[] flags to have Listener - * consume any event name prefixes. - */ - @Override - public String[] getEventNamePrefixes() { - return new String[0]; - } + /** + * Empty String[] flags to have Listener + * consume any event name prefixes. + */ + @Override + public String[] getEventNamePrefixes() { + return new String[0]; + } - /** - * Currently consumes events generated for - * all resources. - */ - @Override - public String getResourcePrefix() { - return null; - } + /** + * Currently consumes events generated for + * all resources. + */ + @Override + public String getResourcePrefix() { + return null; + } - public void setEventService(EventService service) { - if(service != null) - { + public void setEventService(EventService service) { + if (service != null) { service.registerEventListener(this); - } - else - { + } else { throw new IllegalStateException("EventService handed to Listener cannot be null"); } - - } - -} \ No newline at end of file + + } + +} diff --git a/dspace-api/src/main/java/org/dspace/usage/LoggerUsageEventListener.java b/dspace-api/src/main/java/org/dspace/usage/LoggerUsageEventListener.java index 2c4de92d87..9ffcf78110 100644 --- a/dspace-api/src/main/java/org/dspace/usage/LoggerUsageEventListener.java +++ b/dspace-api/src/main/java/org/dspace/usage/LoggerUsageEventListener.java @@ -16,71 +16,60 @@ import org.dspace.services.model.Event; import org.dspace.usage.UsageEvent.Action; /** - * * @author Mark Diggory (mdiggory at atmire.com) - * */ -public class LoggerUsageEventListener extends AbstractUsageEventListener{ +public class LoggerUsageEventListener extends AbstractUsageEventListener { - /** log4j category */ + /** + * log4j category + */ private static Logger log = Logger - .getLogger(LoggerUsageEventListener.class); - - @Override - public void receiveEvent(Event event) { - + .getLogger(LoggerUsageEventListener.class); + + @Override + public void receiveEvent(Event event) { + //Search events are already logged - //UsageSearchEvent is already logged in the search classes, no need to repeat this logging - if(event instanceof UsageEvent && !(event instanceof UsageSearchEvent)) - { - UsageEvent ue = (UsageEvent)event; + //UsageSearchEvent is already logged in the search classes, no need to repeat this logging + if (event instanceof UsageEvent && !(event instanceof UsageSearchEvent)) { + UsageEvent ue = (UsageEvent) event; - log.info(LogManager.getHeader( - ue.getContext(), - formatAction(ue.getAction(), ue.getObject()), - formatMessage(ue.getObject())) - ); - - } - } + log.info(LogManager.getHeader( + ue.getContext(), + formatAction(ue.getAction(), ue.getObject()), + formatMessage(ue.getObject())) + ); - private static String formatAction(Action action, DSpaceObject object) - { - try - { - String objText = Constants.typeText[object.getType()].toLowerCase(); - return action.text() + "_" + objText; - }catch(Exception e) - { - - } - return ""; - - } - - private static String formatMessage(DSpaceObject object) - { - try - { - String objText = Constants.typeText[object.getType()].toLowerCase(); - String handle = object.getHandle(); - - /* Emulate Item logger */ - if(handle != null && object instanceof Item) - { + } + } + + private static String formatAction(Action action, DSpaceObject object) { + try { + String objText = Constants.typeText[object.getType()].toLowerCase(); + return action.text() + "_" + objText; + } catch (Exception e) { + // ignore + } + return ""; + + } + + private static String formatMessage(DSpaceObject object) { + try { + String objText = Constants.typeText[object.getType()].toLowerCase(); + String handle = object.getHandle(); + + /* Emulate Item logger */ + if (handle != null && object instanceof Item) { return "handle=" + object.getHandle(); - } - else - { + } else { return objText + "_id=" + object.getID(); } - } - catch(Exception e) - { - - } - return ""; - - } + } catch (Exception e) { + // ignore + } + return ""; + + } } diff --git a/dspace-api/src/main/java/org/dspace/usage/PassiveUsageEventListener.java b/dspace-api/src/main/java/org/dspace/usage/PassiveUsageEventListener.java index c53fe5887a..515217d807 100644 --- a/dspace-api/src/main/java/org/dspace/usage/PassiveUsageEventListener.java +++ b/dspace-api/src/main/java/org/dspace/usage/PassiveUsageEventListener.java @@ -12,19 +12,18 @@ import org.dspace.services.model.Event; /** * A null implementation of AbstractUsageEvent to absorb events harmlessly and * cheaply. - * + * * @author Mark H. Wood * @author Mark Diggory (mdiggory at atmire.com) * @version $Revision: 3734 $ */ -public class PassiveUsageEventListener extends AbstractUsageEventListener -{ - /** +public class PassiveUsageEventListener extends AbstractUsageEventListener { + /** * Do nothing and return. Effectively, the event is discarded. */ - @Override - public void receiveEvent(Event event) { - return; - } + @Override + public void receiveEvent(Event event) { + return; + } } diff --git a/dspace-api/src/main/java/org/dspace/usage/TabFileUsageEventListener.java b/dspace-api/src/main/java/org/dspace/usage/TabFileUsageEventListener.java index 64daea6017..dc1aeb56c9 100644 --- a/dspace-api/src/main/java/org/dspace/usage/TabFileUsageEventListener.java +++ b/dspace-api/src/main/java/org/dspace/usage/TabFileUsageEventListener.java @@ -29,104 +29,108 @@ import org.slf4j.LoggerFactory; * will be interpreted as relative to the directory named in {@code log.dir}. * If no name is configured, it defaults to "usage-events.tsv". If the file is * new or empty, a column heading record will be written when the file is opened. - * + * * @author Mark H. Wood * @author Mark Diggory */ public class TabFileUsageEventListener - extends AbstractUsageEventListener -{ - /** log category. */ + extends AbstractUsageEventListener { + /** + * log category. + */ private static final Logger errorLog = LoggerFactory - .getLogger(TabFileUsageEventListener.class); + .getLogger(TabFileUsageEventListener.class); - /** ISO 8601 Basic string format for record timestamps. */ + /** + * ISO 8601 Basic string format for record timestamps. + */ private static final SimpleDateFormat dateFormat = new SimpleDateFormat( - "yyyyMMdd'T'HHmmssSSS"); + "yyyyMMdd'T'HHmmssSSS"); - /** File on which to write event records. */ + /** + * File on which to write event records. + */ private PrintWriter eventLog; - /** Is this instance initialized? */ + /** + * Is this instance initialized? + */ private boolean initialized = false; /** * Set up a usage event listener for writing TSV records to a file. */ - private void init() - { + private void init() { ConfigurationService configurationService - = new DSpace().getConfigurationService(); + = new DSpace().getConfigurationService(); String logPath = configurationService.getPropertyAsType( - "usageEvent.tabFileLogger.file", - "usage-events.tsv"); + "usageEvent.tabFileLogger.file", + "usage-events.tsv"); String logDir = null; - if (!new File(logPath).isAbsolute()) - { + if (!new File(logPath).isAbsolute()) { logDir = configurationService.getProperty("log.report.dir"); } File logFile = new File(logDir, logPath); - try - { + try { eventLog = new PrintWriter(new OutputStreamWriter( - new FileOutputStream(logFile, true))); + new FileOutputStream(logFile, true))); errorLog.debug("Writing to {}", logFile.getAbsolutePath()); - } - catch (FileNotFoundException e) - { + } catch (FileNotFoundException e) { errorLog.error("{} cannot open file, will not log events: {}", - TabFileUsageEventListener.class.getName(), - e.getMessage()); + TabFileUsageEventListener.class.getName(), + e.getMessage()); throw new IllegalArgumentException("Cannot open event log file", e); } - if (logFile.length() <= 0) - { + if (logFile.length() <= 0) { eventLog.println("date" - + '\t' + "event" - + '\t' + "objectType" - + '\t' + "objectId" - + '\t' + "sessionId" - + '\t' + "sourceAddress" - + '\t' + "eperson"); + + '\t' + "event" + + '\t' + "objectType" + + '\t' + "objectId" + + '\t' + "sessionId" + + '\t' + "sourceAddress" + + '\t' + "eperson"); } initialized = true; } - + @Override - public synchronized void receiveEvent(Event event) - { - if (!initialized) + public synchronized void receiveEvent(Event event) { + if (!initialized) { init(); + } - if (errorLog.isDebugEnabled()) + if (errorLog.isDebugEnabled()) { errorLog.debug("got: {}", event.toString()); + } - if(!(event instanceof UsageEvent)) + if (!(event instanceof UsageEvent)) { return; + } - if (null == eventLog) + if (null == eventLog) { return; + } - UsageEvent ue = (UsageEvent)event; + UsageEvent ue = (UsageEvent) event; eventLog.append(dateFormat.format(new Date())) - .append('\t').append(ue.getName()) // event type - .append('\t').append(Constants.typeText[ue.getObject().getType()]) - .append('\t').append(ue.getObject().getID().toString()) - .append('\t').append(ue.getRequest().getSession().getId()) - .append('\t').append(ue.getRequest().getRemoteAddr()); + .append('\t').append(ue.getName()) // event type + .append('\t').append(Constants.typeText[ue.getObject().getType()]) + .append('\t').append(ue.getObject().getID().toString()) + .append('\t').append(ue.getRequest().getSession().getId()) + .append('\t').append(ue.getRequest().getRemoteAddr()); String epersonName = (null == ue.getContext().getCurrentUser() - ? "anonymous" - : ue.getContext().getCurrentUser().getEmail()); + ? "anonymous" + : ue.getContext().getCurrentUser().getEmail()); eventLog.append('\t').append(epersonName); eventLog.println(); eventLog.flush(); - } + } } diff --git a/dspace-api/src/main/java/org/dspace/usage/UsageEvent.java b/dspace-api/src/main/java/org/dspace/usage/UsageEvent.java index f2250db0b0..ed137e9d6d 100644 --- a/dspace-api/src/main/java/org/dspace/usage/UsageEvent.java +++ b/dspace-api/src/main/java/org/dspace/usage/UsageEvent.java @@ -15,242 +15,229 @@ import org.dspace.core.Context; import org.dspace.services.model.Event; /** - * * @author Mark Diggory (mdiggory at atmire.com) - * */ public class UsageEvent extends Event { - - public static enum Action { - VIEW ("view"), - CREATE ("create"), - UPDATE ("update"), - DELETE ("delete"), - ADD ("add"), - REMOVE ("remove"), - BROWSE ("browse"), - SEARCH ("search"), - WORKFLOW ("workflow"), - LOGIN ("login"), - SUBSCRIBE ("subscribe"), - UNSUBSCRIBE ("unsubscribe"), - WITHDRAW ("withdraw"), - REINSTATE ("reinstate"); - - private final String text; - - Action(String text) { - this.text = text; - } - String text() { return text; } - } - - /** - * - */ - private static final long serialVersionUID = 1L; - private HttpServletRequest request; - - private String ip; - - private String userAgent; - - private String xforwardedfor; - - private Context context; - - private DSpaceObject object; + public static enum Action { + VIEW("view"), + CREATE("create"), + UPDATE("update"), + DELETE("delete"), + ADD("add"), + REMOVE("remove"), + BROWSE("browse"), + SEARCH("search"), + WORKFLOW("workflow"), + LOGIN("login"), + SUBSCRIBE("subscribe"), + UNSUBSCRIBE("unsubscribe"), + WITHDRAW("withdraw"), + REINSTATE("reinstate"); - private Action action; + private final String text; - private static String checkParams(Action action, HttpServletRequest request, Context context, DSpaceObject object) - { + Action(String text) { + this.text = text; + } + + String text() { + return text; + } + } + + /** + * + */ + private static final long serialVersionUID = 1L; + + private HttpServletRequest request; + + private String ip; + + private String userAgent; + + private String xforwardedfor; + + private Context context; + + private DSpaceObject object; + + private Action action; + + private static String checkParams(Action action, HttpServletRequest request, Context context, DSpaceObject object) { StringBuilder eventName = new StringBuilder(); - if(action == null) - { + if (action == null) { throw new IllegalStateException("action cannot be null"); } - - if(action != Action.WORKFLOW && request == null) - { + + if (action != Action.WORKFLOW && request == null) { throw new IllegalStateException("request cannot be null"); } - - if(context == null) - { + + if (context == null) { throw new IllegalStateException("context cannot be null"); } - - if(action != Action.WORKFLOW && action != Action.SEARCH && object == null) - { + + if (action != Action.WORKFLOW && action != Action.SEARCH && object == null) { throw new IllegalStateException("object cannot be null"); - }else - if(object != null){ + } else if (object != null) { String objText = Constants.typeText[object.getType()].toLowerCase(); eventName.append(objText).append(":"); } eventName.append(action.text()); - - return eventName.toString(); - } - - private static String checkParams(Action action, Context context, DSpaceObject object) - { + + return eventName.toString(); + } + + private static String checkParams(Action action, Context context, DSpaceObject object) { StringBuilder eventName = new StringBuilder(); - if(action == null) - { + if (action == null) { throw new IllegalStateException("action cannot be null"); } - -// if(action != Action.WORKFLOW) + +// if(action != Action.WORKFLOW) // { // throw new IllegalStateException("request cannot be null"); // } - - if(context == null) - { + + if (context == null) { throw new IllegalStateException("context cannot be null"); } - - if(action != Action.WORKFLOW && action != Action.SEARCH && object == null) - { + + if (action != Action.WORKFLOW && action != Action.SEARCH && object == null) { throw new IllegalStateException("object cannot be null"); - }else - if(object != null){ + } else if (object != null) { String objText = Constants.typeText[object.getType()].toLowerCase(); eventName.append(objText).append(":"); } eventName.append(action.text()); - - return eventName.toString(); - } - - public UsageEvent(Action action, HttpServletRequest request, Context context, DSpaceObject object) - { - - super(checkParams(action, request, context, object)); - - this.action = action; - - this.setResourceReference(object != null ? Constants.typeText[object.getType()].toLowerCase() + ":" + object.getID() : null); - - switch(action) - { - case CREATE: - case UPDATE: - case DELETE: - case WITHDRAW: - case REINSTATE: - case ADD: - case REMOVE: - this.setModify(true); - break; - default : - this.setModify(false); - } - - if(context != null && context.getCurrentUser() != null) - { - this.setUserId( - String.valueOf(context.getCurrentUser().getID())); - } - this.request = request; - this.context = context; - this.object = object; - } - public UsageEvent(Action action, String ip, String userAgent, String xforwardedfor, Context context, DSpaceObject object) - { - - super(checkParams(action, context, object)); - - this.action = action; - - this.setResourceReference(object != null ? Constants.typeText[object.getType()].toLowerCase() + ":" + object.getID() : null); - - switch(action) - { - case CREATE: - case UPDATE: - case DELETE: - case WITHDRAW: - case REINSTATE: - case ADD: - case REMOVE: - this.setModify(true); - break; - default : - this.setModify(false); - } - - if(context != null && context.getCurrentUser() != null) - { - this.setUserId( - String.valueOf(context.getCurrentUser().getID())); - } - this.request = null; - this.ip = ip; - this.userAgent = userAgent; - this.xforwardedfor = xforwardedfor; - this.context = context; - this.object = object; - } + return eventName.toString(); + } - - public HttpServletRequest getRequest() { - return request; - } + public UsageEvent(Action action, HttpServletRequest request, Context context, DSpaceObject object) { - public String getIp() { - return ip; - } + super(checkParams(action, request, context, object)); - public void setIp(String ip) { - this.ip = ip; - } + this.action = action; - public String getUserAgent() { - return userAgent; - } + this.setResourceReference( + object != null ? Constants.typeText[object.getType()].toLowerCase() + ":" + object.getID() : null); - public void setUserAgent(String userAgent) { - this.userAgent = userAgent; - } + switch (action) { + case CREATE: + case UPDATE: + case DELETE: + case WITHDRAW: + case REINSTATE: + case ADD: + case REMOVE: + this.setModify(true); + break; + default: + this.setModify(false); + } - public String getXforwardedfor() { - return xforwardedfor; - } + if (context != null && context.getCurrentUser() != null) { + this.setUserId( + String.valueOf(context.getCurrentUser().getID())); + } + this.request = request; + this.context = context; + this.object = object; + } - public void setXforwardedfor(String xforwardedfor) { - this.xforwardedfor = xforwardedfor; - } + public UsageEvent(Action action, String ip, String userAgent, String xforwardedfor, Context context, + DSpaceObject object) { - public void setRequest(HttpServletRequest request) { - this.request = request; - } + super(checkParams(action, context, object)); - public Context getContext() { - return context; - } + this.action = action; - public void setContext(Context context) { - this.context = context; - } + this.setResourceReference( + object != null ? Constants.typeText[object.getType()].toLowerCase() + ":" + object.getID() : null); - public DSpaceObject getObject() { - return object; - } + switch (action) { + case CREATE: + case UPDATE: + case DELETE: + case WITHDRAW: + case REINSTATE: + case ADD: + case REMOVE: + this.setModify(true); + break; + default: + this.setModify(false); + } - public void setObject(DSpaceObject object) { - this.object = object; - } + if (context != null && context.getCurrentUser() != null) { + this.setUserId( + String.valueOf(context.getCurrentUser().getID())); + } + this.request = null; + this.ip = ip; + this.userAgent = userAgent; + this.xforwardedfor = xforwardedfor; + this.context = context; + this.object = object; + } + + + public HttpServletRequest getRequest() { + return request; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getUserAgent() { + return userAgent; + } + + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + + public String getXforwardedfor() { + return xforwardedfor; + } + + public void setXforwardedfor(String xforwardedfor) { + this.xforwardedfor = xforwardedfor; + } + + public void setRequest(HttpServletRequest request) { + this.request = request; + } + + public Context getContext() { + return context; + } + + public void setContext(Context context) { + this.context = context; + } + + public DSpaceObject getObject() { + return object; + } + + public void setObject(DSpaceObject object) { + this.object = object; + } + + public Action getAction() { + return this.action; + } - public Action getAction() { - return this.action; - } - } diff --git a/dspace-api/src/main/java/org/dspace/usage/UsageSearchEvent.java b/dspace-api/src/main/java/org/dspace/usage/UsageSearchEvent.java index efc9143f9b..516242e1b7 100644 --- a/dspace-api/src/main/java/org/dspace/usage/UsageSearchEvent.java +++ b/dspace-api/src/main/java/org/dspace/usage/UsageSearchEvent.java @@ -7,12 +7,12 @@ */ package org.dspace.usage; +import java.util.List; +import javax.servlet.http.HttpServletRequest; + import org.dspace.content.DSpaceObject; import org.dspace.core.Context; -import javax.servlet.http.HttpServletRequest; -import java.util.List; - /** * Extends the standard usage event to contain search information * search information includes the query/queries used and the scope @@ -21,19 +21,22 @@ import java.util.List; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class UsageSearchEvent extends UsageEvent{ +public class UsageSearchEvent extends UsageEvent { private List queries; private DSpaceObject scope; - /** Optional search parameters **/ + /** + * Optional search parameters + **/ private int rpp; private String sortBy; private String sortOrder; private int page; - public UsageSearchEvent(Action action, HttpServletRequest request, Context context, DSpaceObject object, List queries, DSpaceObject scope) { + public UsageSearchEvent(Action action, HttpServletRequest request, Context context, DSpaceObject object, + List queries, DSpaceObject scope) { super(action, request, context, object); this.queries = queries; diff --git a/dspace-api/src/main/java/org/dspace/usage/UsageWorkflowEvent.java b/dspace-api/src/main/java/org/dspace/usage/UsageWorkflowEvent.java index 2d9f2bbcc7..3cf3874236 100644 --- a/dspace-api/src/main/java/org/dspace/usage/UsageWorkflowEvent.java +++ b/dspace-api/src/main/java/org/dspace/usage/UsageWorkflowEvent.java @@ -17,7 +17,6 @@ import org.dspace.eperson.Group; /** * Extends the standard usage event to contain workflow information * - * * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) @@ -32,7 +31,8 @@ public class UsageWorkflowEvent extends UsageEvent { private EPerson actor; private InProgressSubmission workflowItem; - public UsageWorkflowEvent(Context context, Item item, InProgressSubmission workflowItem, String workflowStep, String oldState, Collection scope, EPerson actor) { + public UsageWorkflowEvent(Context context, Item item, InProgressSubmission workflowItem, String workflowStep, + String oldState, Collection scope, EPerson actor) { super(Action.WORKFLOW, null, context, item); this.workflowItem = workflowItem; this.workflowStep = workflowStep; diff --git a/dspace-api/src/main/java/org/dspace/usage/package-info.java b/dspace-api/src/main/java/org/dspace/usage/package-info.java index 6273fd3812..5883bcf358 100644 --- a/dspace-api/src/main/java/org/dspace/usage/package-info.java +++ b/dspace-api/src/main/java/org/dspace/usage/package-info.java @@ -25,7 +25,6 @@ * {@code EventService}, as with the stock listeners. *

    * - * @see org.dspace.statistics.ElasticSearchLoggerEventListener * @see org.dspace.google.GoogleRecorderEventListener * @see org.dspace.statistics.SolrLoggerUsageEventListener */ diff --git a/dspace-api/src/main/java/org/dspace/util/MultiFormatDateParser.java b/dspace-api/src/main/java/org/dspace/util/MultiFormatDateParser.java index 869e5a2aff..87dc6d9db8 100644 --- a/dspace-api/src/main/java/org/dspace/util/MultiFormatDateParser.java +++ b/dspace-api/src/main/java/org/dspace/util/MultiFormatDateParser.java @@ -22,7 +22,7 @@ import java.util.TimeZone; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import javax.inject.Inject; -import org.dspace.kernel.DSpaceKernel; + import org.dspace.servicemanager.DSpaceKernelInit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,49 +37,50 @@ import org.slf4j.LoggerFactory; * * @author mwood */ -public class MultiFormatDateParser -{ +public class MultiFormatDateParser { private static final Logger log = LoggerFactory.getLogger(MultiFormatDateParser.class); - /** A list of rules, each binding a regular expression to a date format. */ + /** + * A list of rules, each binding a regular expression to a date format. + */ private static final ArrayList rules = new ArrayList<>(); private static final TimeZone UTC_ZONE = TimeZone.getTimeZone("UTC"); - /** Format for displaying a result of testing. */ + /** + * Format for displaying a result of testing. + */ private static final ThreadLocal formatter; - static - { - formatter = new ThreadLocal(){ - @Override - protected DateFormat initialValue() { - DateFormat dateTimeInstance = SimpleDateFormat.getDateTimeInstance(); - dateTimeInstance.setTimeZone(UTC_ZONE); - return dateTimeInstance; - } - }; + + static { + formatter = new ThreadLocal() { + @Override + protected DateFormat initialValue() { + DateFormat dateTimeInstance = SimpleDateFormat.getDateTimeInstance(); + dateTimeInstance.setTimeZone(UTC_ZONE); + return dateTimeInstance; + } + }; } @Inject - public void setPatterns(Map patterns) - { - for (Entry rule : patterns.entrySet()) - { + public void setPatterns(Map patterns) { + for (Entry rule : patterns.entrySet()) { Pattern pattern; try { - pattern = Pattern.compile(rule.getKey(),Pattern.CASE_INSENSITIVE); + pattern = Pattern.compile(rule.getKey(), Pattern.CASE_INSENSITIVE); } catch (PatternSyntaxException ex) { log.error("Skipping format with unparseable pattern '{}'", - rule.getKey()); + rule.getKey()); continue; } SimpleDateFormat format; try { - format = new SimpleDateFormat(rule.getValue()); + format = new SimpleDateFormat(rule.getValue()); } catch (IllegalArgumentException ex) { log.error("Skipping uninterpretable date format '{}'", - rule.getValue()); + rule.getValue()); continue; } format.setCalendar(Calendar.getInstance(UTC_ZONE)); @@ -96,20 +97,17 @@ public class MultiFormatDateParser * @param dateString the supposed date to be parsed. * @return the result of the first successful parse, or {@code null} if none. */ - static public Date parse(String dateString) - { - for (Rule candidate : rules) - { - if (candidate.pattern.matcher(dateString).matches()) - { + static public Date parse(String dateString) { + for (Rule candidate : rules) { + if (candidate.pattern.matcher(dateString).matches()) { Date result; try { - synchronized(candidate.format) { + synchronized (candidate.format) { result = candidate.format.parse(dateString); } } catch (ParseException ex) { log.info("Date string '{}' matched pattern '{}' but did not parse: {}", - new String[] {dateString, candidate.format.toPattern(), ex.getMessage()}); + new String[] {dateString, candidate.format.toPattern(), ex.getMessage()}); continue; } return result; @@ -120,33 +118,31 @@ public class MultiFormatDateParser } public static void main(String[] args) - throws IOException - { + throws IOException { DSpaceKernelInit.getKernel(null); // Mainly to initialize Spring // TODO direct log to stdout/stderr somehow - if (args.length > 0) // Test data supplied on the command line - { - for (String arg : args) - { + // Test data supplied on the command line + if (args.length > 0) { + for (String arg : args) { testDate(arg); } - } - else // Get test data from the environment - { + } else { + // Else, get test data from the environment String arg; - if (null == System.console()) // Possibly piped input - { + // Possibly piped input + if (null == System.console()) { BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); String line; - while (null != (line = input.readLine())) + while (null != (line = input.readLine())) { testDate(line.trim()); - } - else // Loop, prompting for input - while(null != (arg = System.console().readLine("Enter a date-time: "))) - { + } + } else { + // Loop, prompting for input + while (null != (arg = System.console().readLine("Enter a date-time: "))) { testDate(arg); } + } } } @@ -155,13 +151,11 @@ public class MultiFormatDateParser * * @param arg date-time string to be tested. */ - private static void testDate(String arg) - { + private static void testDate(String arg) { Date result = parse(arg); - if (null == result) + if (null == result) { System.out.println("Did not match any pattern."); - else - { + } else { System.out.println(formatter.get().format(result)); } } @@ -169,12 +163,11 @@ public class MultiFormatDateParser /** * Holder for a pair: compiled regex, compiled SimpleDateFormat. */ - private static class Rule - { + private static class Rule { final Pattern pattern; final SimpleDateFormat format; - public Rule(Pattern pattern, SimpleDateFormat format) - { + + public Rule(Pattern pattern, SimpleDateFormat format) { this.pattern = pattern; this.format = format; } diff --git a/dspace-api/src/main/java/org/dspace/util/SolrImportExport.java b/dspace-api/src/main/java/org/dspace/util/SolrImportExport.java index e931a04458..b0ab3b4005 100644 --- a/dspace-api/src/main/java/org/dspace/util/SolrImportExport.java +++ b/dspace-api/src/main/java/org/dspace/util/SolrImportExport.java @@ -7,8 +7,25 @@ */ package org.dspace.util; -import org.apache.commons.cli.*; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.URL; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -28,27 +45,19 @@ import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.FacetParams; import org.dspace.core.ConfigurationManager; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.net.URL; -import java.text.*; -import java.util.*; - /** * Utility class to export, clear and import Solr indexes. + * * @author Andrea Schweer schweer@waikato.ac.nz for the LCoNZ Institutional Research Repositories */ -public class SolrImportExport -{ +public class SolrImportExport { private static final ThreadLocal SOLR_DATE_FORMAT; private static final ThreadLocal SOLR_DATE_FORMAT_NO_MS; private static final ThreadLocal EXPORT_DATE_FORMAT; - private static final String EXPORT_SEP = "_export_"; + private static final String EXPORT_SEP = "_export_"; - static - { + static { SOLR_DATE_FORMAT = new ThreadLocal() { @Override protected DateFormat initialValue() { @@ -88,104 +97,88 @@ public class SolrImportExport private static final Logger log = Logger.getLogger(SolrImportExport.class); + /** + * Default constructor + */ + private SolrImportExport() { } + /** * Entry point for command-line invocation + * * @param args command-line arguments; see help for description * @throws ParseException if the command-line arguments cannot be parsed */ - public static void main(String[] args) throws ParseException - { + public static void main(String[] args) throws ParseException { CommandLineParser parser = new PosixParser(); Options options = makeOptions(); - try - { + try { CommandLine line = parser.parse(options, args); - if (line.hasOption(HELP_OPTION)) - { + if (line.hasOption(HELP_OPTION)) { printHelpAndExit(options, 0); } String[] indexNames = {"statistics"}; - if (line.hasOption(INDEX_NAME_OPTION)) - { + if (line.hasOption(INDEX_NAME_OPTION)) { indexNames = line.getOptionValues(INDEX_NAME_OPTION); - } - else - { + } else { System.err.println("No index name provided, defaulting to \"statistics\"."); } String directoryName = makeDirectoryName(line.getOptionValue(DIRECTORY_OPTION)); String action = line.getOptionValue(ACTION_OPTION, "export"); - if ("import".equals(action)) - { - for (String indexName : indexNames) - { + if ("import".equals(action)) { + for (String indexName : indexNames) { File importDir = new File(directoryName); - if (!importDir.exists() || !importDir.canRead()) - { + if (!importDir.exists() || !importDir.canRead()) { System.err.println("Import directory " + directoryName - + " doesn't exist or is not readable by the current user. Not importing index " - + indexName); + + " doesn't exist or is not readable by the current user. Not " + + "importing index " + + indexName); continue; // skip this index } - try - { + try { String solrUrl = makeSolrUrl(indexName); boolean clear = line.hasOption(CLEAR_OPTION); importIndex(indexName, importDir, solrUrl, clear); - } - catch (IOException | SolrServerException | SolrImportExportException e) - { + } catch (IOException | SolrServerException | SolrImportExportException e) { System.err.println("Problem encountered while trying to import index " + indexName + "."); e.printStackTrace(System.err); } } - } - else if ("export".equals(action)) - { - for (String indexName : indexNames) - { + } else if ("export".equals(action)) { + for (String indexName : indexNames) { String lastValue = line.getOptionValue(LAST_OPTION); File exportDir = new File(directoryName); - if (exportDir.exists() && !exportDir.canWrite()) - { + if (exportDir.exists() && !exportDir.canWrite()) { System.err.println("Export directory " + directoryName - + " is not writable by the current user. Not exporting index " - + indexName); + + " is not writable by the current user. Not exporting index " + + indexName); continue; } - if (!exportDir.exists()) - { + if (!exportDir.exists()) { boolean created = exportDir.mkdirs(); - if (!created) - { + if (!created) { System.err.println("Export directory " + directoryName - + " could not be created. Not exporting index " + indexName); + + " could not be created. Not exporting index " + indexName); } continue; } - try - { + try { String solrUrl = makeSolrUrl(indexName); String timeField = makeTimeField(indexName); - exportIndex(indexName, exportDir, solrUrl, timeField, lastValue, line.hasOption(OVERWRITE_OPTION)); - } - catch (SolrServerException | IOException | SolrImportExportException e) - { + exportIndex(indexName, exportDir, solrUrl, timeField, lastValue, + line.hasOption(OVERWRITE_OPTION)); + } catch (SolrServerException | IOException | SolrImportExportException e) { System.err.println("Problem encountered while trying to export index " + indexName + "."); e.printStackTrace(System.err); } } - } - else if ("reindex".equals(action)) - { - for (String indexName : indexNames) - { + } else if ("reindex".equals(action)) { + for (String indexName : indexNames) { try { boolean keepExport = line.hasOption(KEEP_OPTION); boolean overwrite = line.hasOption(OVERWRITE_OPTION); @@ -194,15 +187,11 @@ public class SolrImportExport e.printStackTrace(); } } - } - else - { + } else { System.err.println("Unknown action " + action + "; must be import, export or reindex."); printHelpAndExit(options, 1); } - } - catch (ParseException e) - { + } catch (ParseException e) { System.err.println("Cannot read command options"); printHelpAndExit(options, 1); } @@ -210,21 +199,28 @@ public class SolrImportExport private static Options makeOptions() { Options options = new Options(); - options.addOption(ACTION_OPTION, "action", true, "The action to perform: import, export or reindex. Default: export."); - options.addOption(CLEAR_OPTION, "clear", false, "When importing, also clear the index first. Ignored when action is export or reindex."); - options.addOption(OVERWRITE_OPTION, "force-overwrite", false, "When exporting or re-indexing, allow overwrite of existing export files"); + options.addOption(ACTION_OPTION, "action", true, + "The action to perform: import, export or reindex. Default: export."); + options.addOption(CLEAR_OPTION, "clear", false, + "When importing, also clear the index first. Ignored when action is export or reindex."); + options.addOption(OVERWRITE_OPTION, "force-overwrite", false, + "When exporting or re-indexing, allow overwrite of existing export files"); options.addOption(DIRECTORY_OPTION, "directory", true, - "The absolute path for the directory to use for import or export. If omitted, [dspace]/solr-export is used."); - options.addOption(HELP_OPTION, "help", false, "Get help on options for this command."); + "The absolute path for the directory to use for import or export. If omitted, " + + "[dspace]/solr-export is used."); + options.addOption(HELP_OPTION, "help", false, "Get help on options for this command."); options.addOption(INDEX_NAME_OPTION, "index-name", true, - "The names of the indexes to process. At least one is required. Available indexes are: authority, statistics."); - options.addOption(KEEP_OPTION, "keep", false, "When reindexing, keep the contents of the data export directory." + - " By default, the contents of this directory will be deleted once the reindex has finished." + - " Ignored when action is export or import."); - options.addOption(LAST_OPTION, "last", true, "When exporting, export records from the last [timeperiod] only." + + "The names of the indexes to process. At least one is required. Available indexes are: " + + "authority, statistics."); + options + .addOption(KEEP_OPTION, "keep", false, "When reindexing, keep the contents of the data export directory." + + " By default, the contents of this directory will be deleted once the reindex has finished." + + " Ignored when action is export or import."); + options.addOption(LAST_OPTION, "last", true, "When exporting, export records from the last [timeperiod] only." + " This can be one of: 'd' (beginning of yesterday through to now);" + " 'm' (beginning of the previous month through to end of the previous month);" + - " a number, in which case the last [number] of days are exported, through to now (use 0 for today's data)." + + " a number, in which case the last [number] of days are exported, through to now (use 0 for today's data)" + + "." + " Date calculation is done in UTC. If omitted, all documents are exported."); return options; } @@ -232,14 +228,17 @@ public class SolrImportExport /** * Reindexes the specified core * - * @param indexName the name of the core to reindex - * @param exportDirName the name of the directory to use for export. If this directory doesn't exist, it will be created. - * @param keepExport whether to keep the contents of the exportDir after the reindex. If keepExport is false and the - * export directory was created by this method, the export directory will be deleted at the end of the reimport. - * @param overwrite allow export files to be overwritten during re-index + * @param indexName the name of the core to reindex + * @param exportDirName the name of the directory to use for export. If this directory doesn't exist, it will be + * created. + * @param keepExport whether to keep the contents of the exportDir after the reindex. If keepExport is false + * and the + * export directory was created by this method, the export directory will be deleted at the + * end of the reimport. + * @param overwrite allow export files to be overwritten during re-index */ private static void reindex(String indexName, String exportDirName, boolean keepExport, boolean overwrite) - throws IOException, SolrServerException, SolrImportExportException { + throws IOException, SolrServerException, SolrImportExportException { String tempIndexName = indexName + "-temp"; String origSolrUrl = makeSolrUrl(indexName); @@ -249,16 +248,18 @@ public class SolrImportExport //The configuration details for the statistics shards reside within the "statistics" folder String instanceIndexName = indexName.startsWith("statistics-") ? "statistics" : indexName; - String solrInstanceDir = ConfigurationManager.getProperty("dspace.dir") + File.separator + "solr" + File.separator + instanceIndexName; + String solrInstanceDir = ConfigurationManager + .getProperty("dspace.dir") + File.separator + "solr" + File.separator + instanceIndexName; // the [dspace]/solr/[indexName]/conf directory needs to be available on the local machine for this to work // -- we need access to the schema.xml and solrconfig.xml file, plus files referenced from there // if this directory can't be found, output an error message and skip this index File solrInstance = new File(solrInstanceDir); - if (!solrInstance.exists() || !solrInstance.canRead() || !solrInstance.isDirectory()) - { - throw new SolrImportExportException("Directory " + solrInstanceDir + "/conf/ doesn't exist or isn't readable." + - " The reindexing process requires the Solr configuration directory for this index to be present on the local machine" + - " even if Solr is running on a different host. Not reindexing index " + indexName); + if (!solrInstance.exists() || !solrInstance.canRead() || !solrInstance.isDirectory()) { + throw new SolrImportExportException( + "Directory " + solrInstanceDir + "/conf/ doesn't exist or isn't readable." + + " The reindexing process requires the Solr configuration directory for this index to be present " + + "on the local machine" + + " even if Solr is running on a different host. Not reindexing index " + indexName); } String timeField = makeTimeField(indexName); @@ -266,17 +267,14 @@ public class SolrImportExport // Ensure the export directory exists and is writable File exportDir = new File(exportDirName); boolean createdExportDir = exportDir.mkdirs(); - if (!createdExportDir && !exportDir.exists()) - { + if (!createdExportDir && !exportDir.exists()) { throw new SolrImportExportException("Could not create export directory " + exportDirName); } - if (!exportDir.canWrite()) - { + if (!exportDir.canWrite()) { throw new SolrImportExportException("Can't write to export directory " + exportDirName); } - try - { + try { HttpSolrServer adminSolr = new HttpSolrServer(baseSolrUrl); // try to find out size of core and compare with free space in export directory @@ -284,32 +282,31 @@ public class SolrImportExport Object coreSizeObj = status.getCoreStatus(indexName).get("sizeInBytes"); long coreSize = coreSizeObj != null ? Long.valueOf(coreSizeObj.toString()) : -1; long usableExportSpace = exportDir.getUsableSpace(); - if (coreSize >= 0 && usableExportSpace < coreSize) - { + if (coreSize >= 0 && usableExportSpace < coreSize) { System.err.println("Not enough space in export directory " + exportDirName - + "; need at least as much space as the index (" - + FileUtils.byteCountToDisplaySize(coreSize) - + ") but usable space in export directory is only " - + FileUtils.byteCountToDisplaySize(usableExportSpace) - + ". Not continuing with reindex, please use the " + DIRECTORY_OPTION - + " option to specify an alternative export directy with sufficient space."); + + "; need at least as much space as the index (" + + FileUtils.byteCountToDisplaySize(coreSize) + + ") but usable space in export directory is only " + + FileUtils.byteCountToDisplaySize(usableExportSpace) + + ". Not continuing with reindex, please use the " + DIRECTORY_OPTION + + " option to specify an alternative export directy with sufficient space."); return; } // Create a temp directory to store temporary core data - File tempDataDir = new File(ConfigurationManager.getProperty("dspace.dir") + File.separator + "temp" + File.separator + "solr-data"); + File tempDataDir = new File(ConfigurationManager.getProperty( + "dspace.dir") + File.separator + "temp" + File.separator + "solr-data"); boolean createdTempDataDir = tempDataDir.mkdirs(); - if (!createdTempDataDir && !tempDataDir.exists()) - { - throw new SolrImportExportException("Could not create temporary data directory " + tempDataDir.getCanonicalPath()); + if (!createdTempDataDir && !tempDataDir.exists()) { + throw new SolrImportExportException( + "Could not create temporary data directory " + tempDataDir.getCanonicalPath()); } - if (!tempDataDir.canWrite()) - { - throw new SolrImportExportException("Can't write to temporary data directory " + tempDataDir.getCanonicalPath()); + if (!tempDataDir.canWrite()) { + throw new SolrImportExportException( + "Can't write to temporary data directory " + tempDataDir.getCanonicalPath()); } - try - { + try { // create a temporary core to hold documents coming in during the reindex CoreAdminRequest.Create createRequest = new CoreAdminRequest.Create(); createRequest.setInstanceDir(solrInstanceDir); @@ -317,11 +314,10 @@ public class SolrImportExport createRequest.setCoreName(tempIndexName); createRequest.process(adminSolr).getStatus(); - } - catch (SolrServerException e) - { + } catch (SolrServerException e) { // try to continue -- it may just be that the core already existed from a previous, failed attempt - System.err.println("Caught exception when trying to create temporary core: " + e.getMessage() + "; trying to recover."); + System.err.println("Caught exception when trying to create temporary core: " + e + .getMessage() + "; trying to recover."); e.printStackTrace(System.err); } @@ -332,18 +328,16 @@ public class SolrImportExport swapRequest.setAction(CoreAdminParams.CoreAdminAction.SWAP); swapRequest.process(adminSolr); - try - { + try { // export from the actual core (from temp core name, actual data dir) exportIndex(indexName, exportDir, tempSolrUrl, timeField, overwrite); // clear actual core (temp core name, clearing actual data dir) & import importIndex(indexName, exportDir, tempSolrUrl, true); - } - catch (Exception e) - { + } catch (Exception e) { // we ran into some problems with the export/import -- keep going to try and restore the solr cores - System.err.println("Encountered problem during reindex: " + e.getMessage() + ", will attempt to restore Solr cores"); + System.err.println( + "Encountered problem during reindex: " + e.getMessage() + ", will attempt to restore Solr cores"); e.printStackTrace(System.err); } @@ -358,7 +352,8 @@ public class SolrImportExport swapRequest.setAction(CoreAdminParams.CoreAdminAction.SWAP); swapRequest.process(adminSolr); - // export all docs from now-temp core into export directory -- this won't cause name collisions with the actual export + // export all docs from now-temp core into export directory -- this won't cause name collisions with the + // actual export // because the core name for the temporary export has -temp in it while the actual core doesn't exportIndex(tempIndexName, exportDir, tempSolrUrl, timeField, overwrite); // ...and import them into the now-again-actual core *without* clearing @@ -371,16 +366,12 @@ public class SolrImportExport CoreAdminRequest.unloadCore(tempIndexName, false, false, adminSolr); // clean up temporary data dir if this method created it - if (createdTempDataDir && tempDataDir.exists()) - { + if (createdTempDataDir && tempDataDir.exists()) { FileUtils.deleteDirectory(tempDataDir); } - } - finally - { + } finally { // clean up export dir if appropriate - if (!keepExport && createdExportDir && exportDir.exists()) - { + if (!keepExport && createdExportDir && exportDir.exists()) { FileUtils.deleteDirectory(exportDir); } } @@ -391,45 +382,46 @@ public class SolrImportExport * See #makeExportFilename for the file names that are generated. * * @param indexName The index to export. - * @param toDir The target directory for the export. Will be created if it doesn't exist yet. The directory must be writeable. - * @param solrUrl The solr URL for the index to export. Must not be null. + * @param toDir The target directory for the export. Will be created if it doesn't exist yet. The directory + * must be writeable. + * @param solrUrl The solr URL for the index to export. Must not be null. * @param timeField The time field to use for sorting the export. Must not be null. * @param overwrite If set, allow export files to be overwritten - * @throws SolrServerException if there is a problem with exporting the index. - * @throws IOException if there is a problem creating the files or communicating with Solr. + * @throws SolrServerException if there is a problem with exporting the index. + * @throws IOException if there is a problem creating the files or communicating with Solr. * @throws SolrImportExportException if there is a problem in communicating with Solr. */ public static void exportIndex(String indexName, File toDir, String solrUrl, String timeField, boolean overwrite) - throws SolrServerException, SolrImportExportException, IOException { + throws SolrServerException, SolrImportExportException, IOException { exportIndex(indexName, toDir, solrUrl, timeField, null, overwrite); } /** - * Import previously exported documents (or externally created CSV files that have the appropriate structure) into the specified index. + * Import previously exported documents (or externally created CSV files that have the appropriate structure) + * into the specified index. + * * @param indexName the index to import. - * @param fromDir the source directory. Must exist and be readable. - * The importer will look for files whose name starts with
    indexName
    - * and ends with .csv (to match what is generated by #makeExportFilename). - * @param solrUrl The solr URL for the index to export. Must not be null. - * @param clear if true, clear the index before importing. + * @param fromDir the source directory. Must exist and be readable. + * The importer will look for files whose name starts with
    indexName
    + * and ends with .csv (to match what is generated by #makeExportFilename). + * @param solrUrl The solr URL for the index to export. Must not be null. + * @param clear if true, clear the index before importing. * @param overwrite if true, skip _version_ field on import to disable Solr's optimistic concurrency functionality - * @throws IOException if there is a problem reading the files or communicating with Solr. - * @throws SolrServerException if there is a problem reading the files or communicating with Solr. + * @throws IOException if there is a problem reading the files or communicating with Solr. + * @throws SolrServerException if there is a problem reading the files or communicating with Solr. * @throws SolrImportExportException if there is a problem communicating with Solr. */ public static void importIndex(final String indexName, File fromDir, String solrUrl, boolean clear) - throws IOException, SolrServerException, SolrImportExportException - { - if (StringUtils.isBlank(solrUrl)) - { - throw new SolrImportExportException("Could not construct solr URL for index" + indexName + ", aborting export."); + throws IOException, SolrServerException, SolrImportExportException { + if (StringUtils.isBlank(solrUrl)) { + throw new SolrImportExportException( + "Could not construct solr URL for index" + indexName + ", aborting export."); } - if (!fromDir.exists() || !fromDir.canRead()) - { + if (!fromDir.exists() || !fromDir.canRead()) { throw new SolrImportExportException("Source directory " + fromDir - + " doesn't exist or isn't readable, aborting export of index " - + indexName); + + " doesn't exist or isn't readable, aborting export of index " + + indexName); } HttpSolrServer solr = new HttpSolrServer(solrUrl); @@ -437,33 +429,28 @@ public class SolrImportExport // must get multivalue fields before clearing List multivaluedFields = getMultiValuedFields(solr); - if (clear) - { + if (clear) { clearIndex(solrUrl); } - File[] files = fromDir.listFiles(new FilenameFilter() - { + File[] files = fromDir.listFiles(new FilenameFilter() { @Override - public boolean accept(File dir, String name) - { + public boolean accept(File dir, String name) { return name.startsWith(indexName + EXPORT_SEP) && name.endsWith(".csv"); } }); - if (files == null || files.length == 0) - { + if (files == null || files.length == 0) { log.warn("No export files found in directory " + fromDir.getCanonicalPath() + " for index " + indexName); return; } Arrays.sort(files); - for (File file : files) - { + for (File file : files) { log.info("Importing file " + file.getCanonicalPath()); ContentStreamUpdateRequest contentStreamUpdateRequest = new ContentStreamUpdateRequest("/update/csv"); - contentStreamUpdateRequest.setParam("skip", "_version_"); + contentStreamUpdateRequest.setParam("skip", "_version_"); for (String mvField : multivaluedFields) { contentStreamUpdateRequest.setParam("f." + mvField + ".split", "true"); contentStreamUpdateRequest.setParam("f." + mvField + ".separator", MULTIPLE_VALUES_SPLITTER); @@ -480,28 +467,23 @@ public class SolrImportExport /** * Determine the names of all multi-valued fields from the data in the index. + * * @param solr the solr server to query. * @return A list containing all multi-valued fields, or an empty list if none are found / there aren't any. */ - private static List getMultiValuedFields(HttpSolrServer solr) - { + private static List getMultiValuedFields(HttpSolrServer solr) { List result = new ArrayList<>(); - try - { + try { LukeRequest request = new LukeRequest(); // this needs to be a non-schema request, otherwise we'll miss dynamic fields LukeResponse response = request.process(solr); Map fields = response.getFieldInfo(); - for (LukeResponse.FieldInfo info : fields.values()) - { - if (info.getSchema().contains(FieldFlag.MULTI_VALUED.getAbbreviation() + "")) - { + for (LukeResponse.FieldInfo info : fields.values()) { + if (info.getSchema().contains(FieldFlag.MULTI_VALUED.getAbbreviation() + "")) { result.add(info.getName()); } } - } - catch (IOException | SolrServerException e) - { + } catch (IOException | SolrServerException e) { log.fatal("Cannot determine which fields are multi valued: " + e.getMessage(), e); } return result; @@ -510,12 +492,11 @@ public class SolrImportExport /** * Remove all documents from the Solr index with the given URL, then commit and optimise the index. * - * @throws IOException if there is a problem in communicating with Solr. - * @throws SolrServerException if there is a problem in communicating with Solr. * @param solrUrl URL of the Solr core to clear. + * @throws IOException if there is a problem in communicating with Solr. + * @throws SolrServerException if there is a problem in communicating with Solr. */ - public static void clearIndex(String solrUrl) throws IOException, SolrServerException - { + public static void clearIndex(String solrUrl) throws IOException, SolrServerException { HttpSolrServer solr = new HttpSolrServer(solrUrl); solr.deleteByQuery("*:*"); solr.commit(); @@ -523,43 +504,44 @@ public class SolrImportExport } /** - * Exports documents from the given index to the specified target directory in batches of #ROWS_PER_FILE, starting at fromWhen (or all documents). + * Exports documents from the given index to the specified target directory in batches of #ROWS_PER_FILE, + * starting at fromWhen (or all documents). * See #makeExportFilename for the file names that are generated. * * @param indexName The index to export. - * @param toDir The target directory for the export. Will be created if it doesn't exist yet. The directory must be writeable. - * @param solrUrl The solr URL for the index to export. Must not be null. + * @param toDir The target directory for the export. Will be created if it doesn't exist yet. The directory + * must be writeable. + * @param solrUrl The solr URL for the index to export. Must not be null. * @param timeField The time field to use for sorting the export. Must not be null. - * @param fromWhen Optionally, from when to export. See options for allowed values. If null or empty, all documents will be exported. - * @param overwrite If set, allow export files to be overwritten - * @throws SolrServerException if there is a problem with exporting the index. - * @throws IOException if there is a problem creating the files or communicating with Solr. + * @param fromWhen Optionally, from when to export. See options for allowed values. If null or empty, all + * documents will be exported. + * @param overwrite If set, allow export files to be overwritten + * @throws SolrServerException if there is a problem with exporting the index. + * @throws IOException if there is a problem creating the files or communicating with Solr. * @throws SolrImportExportException if there is a problem in communicating with Solr. */ - public static void exportIndex(String indexName, File toDir, String solrUrl, String timeField, String fromWhen, boolean overwrite) - throws SolrServerException, IOException, SolrImportExportException - { - log.info(String.format("Export Index [%s] to [%s] using [%s] Time Field[%s] FromWhen[%s]", indexName, toDir, solrUrl, timeField, fromWhen)); - if (StringUtils.isBlank(solrUrl)) - { - throw new SolrImportExportException("Could not construct solr URL for index" + indexName + ", aborting export."); + public static void exportIndex(String indexName, File toDir, String solrUrl, String timeField, String fromWhen, + boolean overwrite) + throws SolrServerException, IOException, SolrImportExportException { + log.info(String.format("Export Index [%s] to [%s] using [%s] Time Field[%s] FromWhen[%s]", indexName, toDir, + solrUrl, timeField, fromWhen)); + if (StringUtils.isBlank(solrUrl)) { + throw new SolrImportExportException( + "Could not construct solr URL for index" + indexName + ", aborting export."); } - if (!toDir.exists() || !toDir.canWrite()) - { + if (!toDir.exists() || !toDir.canWrite()) { throw new SolrImportExportException("Target directory " + toDir - + " doesn't exist or is not writable, aborting export of index " - + indexName); + + " doesn't exist or is not writable, aborting export of index " + + indexName); } HttpSolrServer solr = new HttpSolrServer(solrUrl); SolrQuery query = new SolrQuery("*:*"); - if (StringUtils.isNotBlank(fromWhen)) - { + if (StringUtils.isNotBlank(fromWhen)) { String lastValueFilter = makeFilterQuery(timeField, fromWhen); - if (StringUtils.isNotBlank(lastValueFilter)) - { + if (StringUtils.isNotBlank(lastValueFilter)) { query.addFilterQuery(lastValueFilter); } } @@ -568,13 +550,17 @@ public class SolrImportExport query.setGetFieldStatistics(timeField); Map fieldInfo = solr.query(query).getFieldStatsInfo(); if (fieldInfo == null || !fieldInfo.containsKey(timeField)) { - log.warn(String.format("Queried [%s]. No fieldInfo found while exporting index [%s] time field [%s] from [%s]. Export cancelled.", + log.warn(String.format( + "Queried [%s]. No fieldInfo found while exporting index [%s] time field [%s] from [%s]. Export " + + "cancelled.", solrUrl, indexName, timeField, fromWhen)); return; } FieldStatsInfo timeFieldInfo = fieldInfo.get(timeField); if (timeFieldInfo == null || timeFieldInfo.getMin() == null) { - log.warn(String.format("Queried [%s]. No earliest date found while exporting index [%s] time field [%s] from [%s]. Export cancelled.", + log.warn(String.format( + "Queried [%s]. No earliest date found while exporting index [%s] time field [%s] from [%s]. Export " + + "cancelled.", solrUrl, indexName, timeField, fromWhen)); return; } @@ -595,12 +581,9 @@ public class SolrImportExport for (RangeFacet.Count monthFacet : monthFacets) { Date monthStartDate; String monthStart = monthFacet.getValue(); - try - { + try { monthStartDate = SOLR_DATE_FORMAT_NO_MS.get().parse(monthStart); - } - catch (java.text.ParseException e) - { + } catch (java.text.ParseException e) { throw new SolrImportExportException("Could not read start of month batch as date: " + monthStart, e); } int docsThisMonth = monthFacet.getCount(); @@ -611,31 +594,33 @@ public class SolrImportExport monthQuery.set("fl", "*"); monthQuery.setParam("csv.mv.separator", MULTIPLE_VALUES_SPLITTER); - monthQuery.addFilterQuery(timeField + ":[" +monthStart + " TO " + monthStart + "+1MONTH]"); + monthQuery.addFilterQuery(timeField + ":[" + monthStart + " TO " + monthStart + "+1MONTH]"); - for (int i = 0; i < docsThisMonth; i+= ROWS_PER_FILE) - { + for (int i = 0; i < docsThisMonth; i += ROWS_PER_FILE) { monthQuery.setStart(i); URL url = new URL(solrUrl + "/select?" + monthQuery.toString()); - File file = new File(toDir.getCanonicalPath(), makeExportFilename(indexName, monthStartDate, docsThisMonth, i)); - if (file.createNewFile() || overwrite) - { + File file = new File(toDir.getCanonicalPath(), + makeExportFilename(indexName, monthStartDate, docsThisMonth, i)); + if (file.createNewFile() || overwrite) { FileUtils.copyURLToFile(url, file); - String message = String.format("Solr export to file [%s] complete. Export for Index [%s] Month [%s] Batch [%d] Num Docs [%d]", - file.getCanonicalPath(), indexName, monthStart, i, docsThisMonth); + String message = String.format( + "Solr export to file [%s] complete. Export for Index [%s] Month [%s] Batch [%d] Num Docs [%d]", + file.getCanonicalPath(), indexName, monthStart, i, docsThisMonth); log.info(message); - } - else if (file.exists()) - { - String message = String.format("Solr export file [%s] already exists. Export failed for Index [%s] Month [%s] Batch [%d] Num Docs [%d]", - file.getCanonicalPath(), indexName, monthStart, i, docsThisMonth); - throw new SolrImportExportException(message); - } - else - { - String message = String.format("Cannot create solr export file [%s]. Export failed for Index [%s] Month [%s] Batch [%d] Num Docs [%d]", - file.getCanonicalPath(), indexName, monthStart, i, docsThisMonth); throw new SolrImportExportException(message); + } else if (file.exists()) { + String message = String.format( + "Solr export file [%s] already exists. Export failed for Index [%s] Month [%s] Batch [%d] " + + "Num Docs [%d]", + file.getCanonicalPath(), indexName, monthStart, i, docsThisMonth); + throw new SolrImportExportException(message); + } else { + String message = String.format( + "Cannot create solr export file [%s]. Export failed for Index [%s] Month [%s] Batch [%d] Num" + + " Docs [%d]", + file.getCanonicalPath(), indexName, monthStart, i, docsThisMonth); + throw new + SolrImportExportException(message); } } } @@ -643,24 +628,21 @@ public class SolrImportExport /** * Return a filter query that represents the export date range passed in as lastValue + * * @param timeField the time field to use for the date range * @param lastValue the requested date range, see options for acceptable values * @return a filter query representing the date range, or null if no suitable date range can be created. */ private static String makeFilterQuery(String timeField, String lastValue) { - if ("m".equals(lastValue)) - { + if ("m".equals(lastValue)) { // export data from the previous month return timeField + ":[NOW/MONTH-1MONTH TO NOW/MONTH]"; } int days; - if ("d".equals(lastValue)) - { + if ("d".equals(lastValue)) { days = 1; - } - else - { + } else { // other acceptable value: a number, specifying how many days back to export days = Integer.valueOf(lastValue); // TODO check value? } @@ -673,10 +655,8 @@ public class SolrImportExport * @param directoryValue a specific directory name. Optional. * @return directoryValue if given as a non-blank string. A default directory otherwise. */ - private static String makeDirectoryName(String directoryValue) - { - if (StringUtils.isNotBlank(directoryValue)) - { + private static String makeDirectoryName(String directoryValue) { + if (StringUtils.isNotBlank(directoryValue)) { return directoryValue; } return ConfigurationManager.getProperty("dspace.dir") + File.separator + "solr-export" + File.separator; @@ -685,17 +665,17 @@ public class SolrImportExport /** * Creates a filename for the export batch. * - * @param indexName The name of the index being exported. - * @param exportStart The start timestamp of the export + * @param indexName The name of the index being exported. + * @param exportStart The start timestamp of the export * @param totalRecords The total number of records in the export. - * @param index The index of the current batch. + * @param index The index of the current batch. * @return A file name that is appropriate to use for exporting the batch of data described by the parameters. */ - private static String makeExportFilename(String indexName, Date exportStart, long totalRecords, int index) - { + private static String makeExportFilename(String indexName, Date exportStart, long totalRecords, int index) { String exportFileNumber = ""; if (totalRecords > ROWS_PER_FILE) { - exportFileNumber = StringUtils.leftPad("" + (index / ROWS_PER_FILE), (int) Math.ceil(Math.log10(totalRecords / ROWS_PER_FILE)), "0"); + exportFileNumber = StringUtils + .leftPad("" + (index / ROWS_PER_FILE), (int) Math.ceil(Math.log10(totalRecords / ROWS_PER_FILE)), "0"); } return indexName + EXPORT_SEP @@ -708,19 +688,16 @@ public class SolrImportExport * Returns the full URL for the specified index name. * * @param indexName the index name whose Solr URL is required. If the index name starts with - * "statistics" or is "authority", the Solr base URL will be looked up - * in the corresponding DSpace configuration file. Otherwise, it will fall back to a default. + * "statistics" or is "authority", the Solr base URL will be looked up + * in the corresponding DSpace configuration file. Otherwise, it will fall back to a default. * @return the full URL to the Solr index, as a String. */ - private static String makeSolrUrl(String indexName) - { - if (indexName.startsWith("statistics")) - { + private static String makeSolrUrl(String indexName) { + if (indexName.startsWith("statistics")) { // TODO account for year shards properly? - return ConfigurationManager.getProperty("solr-statistics", "server") + indexName.replaceFirst("statistics", ""); - } - else if ("authority".equals(indexName)) - { + return ConfigurationManager.getProperty("solr-statistics", "server") + indexName + .replaceFirst("statistics", ""); + } else if ("authority".equals(indexName)) { return ConfigurationManager.getProperty("solr.authority.server"); } return "http://localhost:8080/solr/" + indexName; // TODO better default? @@ -732,14 +709,10 @@ public class SolrImportExport * @param indexName the index name whose Solr URL is required. * @return the name of the time field, or null if no suitable field can be determined. */ - private static String makeTimeField(String indexName) - { - if (indexName.startsWith("statistics")) - { + private static String makeTimeField(String indexName) { + if (indexName.startsWith("statistics")) { return "time"; - } - else if ("authority".equals(indexName)) - { + } else if ("authority".equals(indexName)) { return "last_modified_date"; } return null; // TODO some sort of default? @@ -748,11 +721,10 @@ public class SolrImportExport /** * A utility method to print out all available command-line options and exit given the specified code. * - * @param options the supported options. + * @param options the supported options. * @param exitCode the exit code to use. The method will call System#exit(int) with the given code. */ - private static void printHelpAndExit(Options options, int exitCode) - { + private static void printHelpAndExit(Options options, int exitCode) { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp(SolrImportExport.class.getSimpleName() + "\n", options); System.out.println("\n\nCommand Defaults"); diff --git a/dspace-api/src/main/java/org/dspace/util/SolrImportExportException.java b/dspace-api/src/main/java/org/dspace/util/SolrImportExportException.java index 6cc35a2bfc..b38a468607 100644 --- a/dspace-api/src/main/java/org/dspace/util/SolrImportExportException.java +++ b/dspace-api/src/main/java/org/dspace/util/SolrImportExportException.java @@ -10,15 +10,12 @@ package org.dspace.util; /** * @author Andrea Schweer schweer@waikato.ac.nz for the LCoNZ Institutional Research Repositories */ -public class SolrImportExportException extends Exception -{ - public SolrImportExportException(String message) - { - super(message); - } +public class SolrImportExportException extends Exception { + public SolrImportExportException(String message) { + super(message); + } - public SolrImportExportException(String message, Throwable cause) - { - super(message, cause); - } + public SolrImportExportException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/dspace-api/src/main/java/org/dspace/util/UUIDUtils.java b/dspace-api/src/main/java/org/dspace/util/UUIDUtils.java index ac116f5917..6f57c1fa29 100644 --- a/dspace-api/src/main/java/org/dspace/util/UUIDUtils.java +++ b/dspace-api/src/main/java/org/dspace/util/UUIDUtils.java @@ -7,21 +7,26 @@ */ package org.dspace.util; -import org.apache.commons.lang3.StringUtils; - import java.util.UUID; +import org.apache.commons.lang3.StringUtils; + /** * Utility class to read UUIDs */ public class UUIDUtils { + /** + * Default constructor + */ + private UUIDUtils() { } + public static UUID fromString(final String identifier) { UUID output = null; - if(StringUtils.isNotBlank(identifier)) { + if (StringUtils.isNotBlank(identifier)) { try { output = UUID.fromString(identifier.trim()); - } catch(IllegalArgumentException e) { + } catch (IllegalArgumentException e) { output = null; } } diff --git a/dspace-api/src/main/java/org/dspace/versioning/AbstractVersionProvider.java b/dspace-api/src/main/java/org/dspace/versioning/AbstractVersionProvider.java index 5977e80715..8b0ca9aeb8 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/AbstractVersionProvider.java +++ b/dspace-api/src/main/java/org/dspace/versioning/AbstractVersionProvider.java @@ -7,9 +7,20 @@ */ package org.dspace.versioning; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.Set; + import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.service.AuthorizeService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; import org.dspace.content.service.ItemService; @@ -17,15 +28,7 @@ import org.dspace.core.Context; import org.dspace.storage.bitstore.service.BitstreamStorageService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import java.util.Set; -import org.dspace.authorize.ResourcePolicy; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -51,20 +54,21 @@ public abstract class AbstractVersionProvider { MetadataField metadataField = aMd.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); String unqualifiedMetadataField = metadataSchema.getName() + "." + metadataField.getElement(); - if(getIgnoredMetadataFields().contains(metadataField.toString('.')) || - getIgnoredMetadataFields().contains(unqualifiedMetadataField + "." + Item.ANY)) - { + if (getIgnoredMetadataFields().contains(metadataField.toString('.')) || + getIgnoredMetadataFields().contains(unqualifiedMetadataField + "." + Item.ANY)) { //Skip this metadata field continue; } - itemService.addMetadata(context, itemNew, metadataField, aMd.getLanguage(), aMd.getValue(), aMd.getAuthority(), aMd.getConfidence()); + itemService + .addMetadata(context, itemNew, metadataField, aMd.getLanguage(), aMd.getValue(), aMd.getAuthority(), + aMd.getConfidence()); } } - protected void createBundlesAndAddBitstreams(Context c, Item itemNew, Item nativeItem) throws SQLException, AuthorizeException, IOException { - for(Bundle nativeBundle : nativeItem.getBundles()) - { + protected void createBundlesAndAddBitstreams(Context c, Item itemNew, Item nativeItem) + throws SQLException, AuthorizeException, IOException { + for (Bundle nativeBundle : nativeItem.getBundles()) { Bundle bundleNew = bundleService.create(c, itemNew, nativeBundle.getName()); // DSpace knows several types of resource policies (see the class // org.dspace.authorize.ResourcePolicy): Submission, Workflow, Custom @@ -72,13 +76,15 @@ public abstract class AbstractVersionProvider { // set automatically as neccessary. We need to copy the custom policies // only to preserve customly set policies and embargos (which are // realized by custom policies with a start date). - List bundlePolicies = - authorizeService.findPoliciesByDSOAndType(c, nativeBundle, ResourcePolicy.TYPE_CUSTOM); + List bundlePolicies = + authorizeService.findPoliciesByDSOAndType(c, nativeBundle, ResourcePolicy.TYPE_CUSTOM); authorizeService.addPolicies(c, bundlePolicies, bundleNew); - - for(Bitstream nativeBitstream : nativeBundle.getBitstreams()) - { - Bitstream bitstreamNew = createBitstream(c, nativeBitstream); + + for (Bitstream nativeBitstream : nativeBundle.getBitstreams()) { + // Metadata and additional information like internal identifier, + // file size, checksum, and checksum algorithm are set by the bitstreamStorageService.clone(...) + // and respectively bitstreamService.clone(...) method. + Bitstream bitstreamNew = bitstreamStorageService.clone(c, nativeBitstream); bundleService.addBitstream(c, bundleNew, bitstreamNew); @@ -88,30 +94,21 @@ public abstract class AbstractVersionProvider { // Now, we need to copy the TYPE_CUSTOM resource policies from old bitstream // to the new bitstream, like we did above for bundles - List bitstreamPolicies = - authorizeService.findPoliciesByDSOAndType(c, nativeBitstream, ResourcePolicy.TYPE_CUSTOM); + List bitstreamPolicies = + authorizeService.findPoliciesByDSOAndType(c, nativeBitstream, ResourcePolicy.TYPE_CUSTOM); authorizeService.addPolicies(c, bitstreamPolicies, bitstreamNew); - if(nativeBundle.getPrimaryBitstream() != null && nativeBundle.getPrimaryBitstream().equals(nativeBitstream)) - { + if (nativeBundle.getPrimaryBitstream() != null && nativeBundle.getPrimaryBitstream() + .equals(nativeBitstream)) { bundleNew.setPrimaryBitstreamID(bitstreamNew); } - + bitstreamService.update(c, bitstreamNew); } } } - protected Bitstream createBitstream(Context context, Bitstream nativeBitstream) throws AuthorizeException, SQLException, IOException { - Bitstream newBitstream = bitstreamStorageService.clone(context, nativeBitstream); - List bitstreamMeta = bitstreamService.getMetadata(nativeBitstream, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue value : bitstreamMeta) { - bitstreamService.addMetadata(context, newBitstream, value.getMetadataField(), value.getLanguage(), value.getValue(), value.getAuthority(), value.getConfidence()); - } - return newBitstream; - } - public void setIgnoredMetadataFields(Set ignoredMetadataFields) { this.ignoredMetadataFields = ignoredMetadataFields; } diff --git a/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java b/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java index 83610e9947..9f02b18a95 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java +++ b/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java @@ -7,7 +7,13 @@ */ package org.dspace.versioning; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + +import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.ResourcePolicy; import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.WorkspaceItemService; @@ -15,26 +21,17 @@ import org.dspace.core.Context; import org.dspace.identifier.IdentifierException; import org.dspace.identifier.service.IdentifierService; import org.dspace.versioning.service.VersionHistoryService; -import org.springframework.beans.factory.annotation.Autowired; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import org.apache.log4j.Logger; -import org.dspace.authorize.ResourcePolicy; import org.dspace.versioning.service.VersioningService; import org.dspace.workflow.WorkflowItemService; +import org.springframework.beans.factory.annotation.Autowired; /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) */ -public class DefaultItemVersionProvider extends AbstractVersionProvider implements ItemVersionProvider -{ - +public class DefaultItemVersionProvider extends AbstractVersionProvider implements ItemVersionProvider { + Logger log = Logger.getLogger(DefaultItemVersionProvider.class); @Autowired(required = true) @@ -50,28 +47,24 @@ public class DefaultItemVersionProvider extends AbstractVersionProvider implemen @Override public Item createNewItemAndAddItInWorkspace(Context context, Item nativeItem) { - try - { + try { WorkspaceItem workspaceItem = workspaceItemService.create(context, nativeItem.getOwningCollection(), false); Item itemNew = workspaceItem.getItem(); itemService.update(context, itemNew); return itemNew; - }catch (SQLException | AuthorizeException e) { + } catch (SQLException | AuthorizeException e) { throw new RuntimeException(e.getMessage(), e); } } @Override public void deleteVersionedItem(Context c, Version versionToDelete, VersionHistory history) - throws SQLException - { - try - { + throws SQLException { + try { // if versionToDelete is the current version we have to reinstate the previous version // and reset canonical - if(versionHistoryService.isLastVersion(c, history, versionToDelete) - && versioningService.getVersionsByHistory(c, history).size() > 1) - { + if (versionHistoryService.isLastVersion(c, history, versionToDelete) + && versioningService.getVersionsByHistory(c, history).size() > 1) { // if a new version gets archived, the old one is set to false. // we need to do the oposite now, if the old version was previously // unarchived. If the old version is still archived, the new @@ -80,16 +73,16 @@ public class DefaultItemVersionProvider extends AbstractVersionProvider implemen // version gets archived. Item item = versionHistoryService.getPrevious(c, history, versionToDelete).getItem(); if (!item.isArchived() - || workspaceItemService.findByItem(c, versionToDelete.getItem()) != null - || workflowItemService.findByItem(c, versionToDelete.getItem()) != null) - { + || workspaceItemService.findByItem(c, versionToDelete.getItem()) != null + || workflowItemService.findByItem(c, versionToDelete.getItem()) != null) { item.setArchived(true); itemService.update(c, item); } } - // assign tombstone to the Identifier and reset canonical to the previous version only if there is a previous version - Item itemToDelete=versionToDelete.getItem(); + // assign tombstone to the Identifier and reset canonical to the previous version only if there is a + // previous version + Item itemToDelete = versionToDelete.getItem(); identifierService.delete(c, itemToDelete); } catch (SQLException | AuthorizeException | IdentifierException e) { throw new RuntimeException(e.getMessage(), e); @@ -97,14 +90,11 @@ public class DefaultItemVersionProvider extends AbstractVersionProvider implemen } @Override - public Item updateItemState(Context c, Item itemNew, Item previousItem) - { - try - { + public Item updateItemState(Context c, Item itemNew, Item previousItem) { + try { copyMetadata(c, itemNew, previousItem); createBundlesAndAddBitstreams(c, itemNew, previousItem); - try - { + try { identifierService.reserve(c, itemNew); } catch (IdentifierException e) { throw new RuntimeException("Can't create Identifier!", e); @@ -115,12 +105,12 @@ public class DefaultItemVersionProvider extends AbstractVersionProvider implemen // set automatically as neccessary. We need to copy the custom policies // only to preserve customly set policies and embargos (which are // realized by custom policies with a start date). - List policies = - authorizeService.findPoliciesByDSOAndType(c, previousItem, ResourcePolicy.TYPE_CUSTOM); + List policies = + authorizeService.findPoliciesByDSOAndType(c, previousItem, ResourcePolicy.TYPE_CUSTOM); authorizeService.addPolicies(c, policies, itemNew); itemService.update(c, itemNew); return itemNew; - }catch (IOException | SQLException | AuthorizeException e) { + } catch (IOException | SQLException | AuthorizeException e) { throw new RuntimeException(e.getMessage(), e); } } diff --git a/dspace-api/src/main/java/org/dspace/versioning/ItemVersionProvider.java b/dspace-api/src/main/java/org/dspace/versioning/ItemVersionProvider.java index be85985dc9..83369e0465 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/ItemVersionProvider.java +++ b/dspace-api/src/main/java/org/dspace/versioning/ItemVersionProvider.java @@ -8,18 +8,19 @@ package org.dspace.versioning; import java.sql.SQLException; + import org.dspace.content.Item; import org.dspace.core.Context; /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) */ public interface ItemVersionProvider { public Item createNewItemAndAddItInWorkspace(Context c, Item item); + public void deleteVersionedItem(Context c, Version versionToDelete, VersionHistory history) throws SQLException; + public Item updateItemState(Context c, Item itemNew, Item previousItem); } diff --git a/dspace-api/src/main/java/org/dspace/versioning/Version.java b/dspace-api/src/main/java/org/dspace/versioning/Version.java index d79b33e9cd..a926fba0f8 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/Version.java +++ b/dspace-api/src/main/java/org/dspace/versioning/Version.java @@ -7,30 +7,39 @@ */ package org.dspace.versioning; +import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.dspace.eperson.EPerson; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.util.Date; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) */ @Entity -@Table(name="versionitem") +@Table(name = "versionitem") public class Version implements ReloadableEntity { @Id - @Column(name="versionitem_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="versionitem_seq") - @SequenceGenerator(name="versionitem_seq", sequenceName="versionitem_seq", allocationSize = 1) + @Column(name = "versionitem_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "versionitem_seq") + @SequenceGenerator(name = "versionitem_seq", sequenceName = "versionitem_seq", allocationSize = 1) private Integer id; @ManyToOne(fetch = FetchType.LAZY) @@ -61,11 +70,10 @@ public class Version implements ReloadableEntity { * or * {@link org.dspace.versioning.service.VersioningService#createNewVersion(Context, Item, String)} * or - * {@link org.dspace.versioning.service.VersioningService#createNewVersion(Context, VersionHistory, Item, String, Date, int)} - * + * {@link org.dspace.versioning.service.VersioningService#createNewVersion(Context, VersionHistory, + * Item, String, Date, int)} */ - protected Version() - { + protected Version() { } @@ -123,19 +131,16 @@ public class Version implements ReloadableEntity { @Override public boolean equals(Object o) { - if (this == o) - { + if (this == o) { return true; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(o); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } - final Version that = (Version)o; - if (this.getID() != that.getID()) - { + final Version that = (Version) o; + if (this.getID() != that.getID()) { return false; } @@ -144,8 +149,8 @@ public class Version implements ReloadableEntity { @Override public int hashCode() { - int hash=7; - hash=79*hash+ this.getID(); + int hash = 7; + hash = 79 * hash + this.getID(); return hash; } } diff --git a/dspace-api/src/main/java/org/dspace/versioning/VersionHistory.java b/dspace-api/src/main/java/org/dspace/versioning/VersionHistory.java index abdb92fe1f..a8efdc329a 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/VersionHistory.java +++ b/dspace-api/src/main/java/org/dspace/versioning/VersionHistory.java @@ -7,33 +7,40 @@ */ package org.dspace.versioning; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +import org.apache.log4j.Logger; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.hibernate.proxy.HibernateProxyHelper; -import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; -import org.apache.log4j.Logger; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Pascal-Nicolas Becker (dspace at pascal dash becker dot de) */ @Entity -@Table(name="versionhistory") +@Table(name = "versionhistory") public class VersionHistory implements ReloadableEntity { - + private static final Logger log = Logger.getLogger(VersionHistory.class); @Id - @Column(name="versionhistory_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="versionhistory_seq") - @SequenceGenerator(name="versionhistory_seq", sequenceName="versionhistory_seq", allocationSize = 1) + @Column(name = "versionhistory_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "versionhistory_seq") + @SequenceGenerator(name = "versionhistory_seq", sequenceName = "versionhistory_seq", allocationSize = 1) private Integer id; //We use fetchtype eager for versions since we always require our versions when loading the history @@ -44,10 +51,8 @@ public class VersionHistory implements ReloadableEntity { /** * Protected constructor, create object using: * {@link org.dspace.versioning.service.VersionHistoryService#create(Context)} - * */ - protected VersionHistory() - { + protected VersionHistory() { } @@ -56,12 +61,14 @@ public class VersionHistory implements ReloadableEntity { } /** - * Please use {@link org.dspace.versioning.service.VersioningService#getVersionsByHistory(Context, VersionHistory)} instead. - * + * Please use + * {@link org.dspace.versioning.service.VersioningService#getVersionsByHistory(Context, VersionHistory)} instead. + * * To keep version number stables we keep information about deleted Versions. - * {@code org.dspace.versioning.service.VersioningService#getVersionsByHistory(Context, VersionHistory) VersioningService#getVersionsByHistory} filters + * {@code org.dspace.versioning.service.VersioningService#getVersionsByHistory(Context, VersionHistory) + * VersioningService#getVersionsByHistory} filters * such versions and returns only active versions. - * + * * @return list of versions */ protected List getVersions() { @@ -72,8 +79,7 @@ public class VersionHistory implements ReloadableEntity { this.versions = versions; } - void addVersionAtStart(Version version) - { + void addVersionAtStart(Version version) { this.versions.add(0, version); } @@ -82,21 +88,17 @@ public class VersionHistory implements ReloadableEntity { } @Override - public boolean equals(Object o) - { - if (this == o) - { + public boolean equals(Object o) { + if (this == o) { return true; } Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(o); - if (getClass() != objClass) - { + if (getClass() != objClass) { return false; } - final VersionHistory that = (VersionHistory)o; - if (this.getID() != that.getID()) - { + final VersionHistory that = (VersionHistory) o; + if (this.getID() != that.getID()) { return false; } @@ -104,10 +106,9 @@ public class VersionHistory implements ReloadableEntity { } @Override - public int hashCode() - { + public int hashCode() { int hash = 7; - hash = 79*hash + this.getID(); + hash = 79 * hash + this.getID(); return hash; } diff --git a/dspace-api/src/main/java/org/dspace/versioning/VersionHistoryServiceImpl.java b/dspace-api/src/main/java/org/dspace/versioning/VersionHistoryServiceImpl.java index 96f9e7d682..c7a2f9044c 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/VersionHistoryServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/versioning/VersionHistoryServiceImpl.java @@ -7,7 +7,12 @@ */ package org.dspace.versioning; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; import org.dspace.core.Context; @@ -16,29 +21,20 @@ import org.dspace.versioning.service.VersionHistoryService; import org.dspace.versioning.service.VersioningService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Pascal-Nicolas Becker (dspace at pascal dash becker dot de) */ -public class VersionHistoryServiceImpl implements VersionHistoryService -{ +public class VersionHistoryServiceImpl implements VersionHistoryService { @Autowired(required = true) protected VersionHistoryDAO versionHistoryDAO; - + @Autowired(required = true) private VersioningService versioningService; - protected VersionHistoryServiceImpl() - { + protected VersionHistoryServiceImpl() { } @@ -59,7 +55,7 @@ public class VersionHistoryServiceImpl implements VersionHistoryService @Override public void update(Context context, List versionHistories) throws SQLException, AuthorizeException { - if(CollectionUtils.isNotEmpty(versionHistories)) { + if (CollectionUtils.isNotEmpty(versionHistories)) { for (VersionHistory versionHistory : versionHistories) { versionHistoryDAO.save(context, versionHistory); } @@ -74,56 +70,50 @@ public class VersionHistoryServiceImpl implements VersionHistoryService // LIST order: descending @Override public Version getPrevious(Context context, VersionHistory versionHistory, Version version) - throws SQLException - { + throws SQLException { List versions = versioningService.getVersionsByHistory(context, versionHistory); int index = versions.indexOf(version); - if (index + 1 < versions.size()) - { - return versions.get(index+1); + if (index + 1 < versions.size()) { + return versions.get(index + 1); } - + return null; } // LIST order: descending @Override public Version getNext(Context c, VersionHistory versionHistory, Version version) - throws SQLException - { + throws SQLException { List versions = versioningService.getVersionsByHistory(c, versionHistory); int index = versions.indexOf(version); - if (index -1 >= 0) - { - return versions.get(index -1); + if (index - 1 >= 0) { + return versions.get(index - 1); } - + return null; } @Override public Version getVersion(Context context, VersionHistory versionHistory, Item item) - throws SQLException - { + throws SQLException { Version v = versioningService.getVersion(context, item); - if (v != null); + if (v != null) { + ; + } { - if (versionHistory.equals(v.getVersionHistory())) - { + if (versionHistory.equals(v.getVersionHistory())) { return v; } } return null; } - + @Override public boolean hasNext(Context context, VersionHistory versionHistory, Item item) - throws SQLException - { + throws SQLException { Version version = getVersion(context, versionHistory, item); - if (version == null) - { + if (version == null) { return false; } return hasNext(context, versionHistory, version); @@ -131,34 +121,31 @@ public class VersionHistoryServiceImpl implements VersionHistoryService @Override public boolean hasNext(Context context, VersionHistory versionHistory, Version version) - throws SQLException - { - return getNext(context, versionHistory, version)!=null; + throws SQLException { + return getNext(context, versionHistory, version) != null; } @Override public boolean hasVersionHistory(Context context, Item item) - throws SQLException - { + throws SQLException { return findByItem(context, item) != null; } - + @Override public void add(Context context, VersionHistory versionHistory, Version version) - throws SQLException - { + throws SQLException { List versions = versionHistory.getVersions(); - if(versions==null) versions=new ArrayList(); + if (versions == null) { + versions = new ArrayList(); + } versions.add(0, version); } @Override public Version getLatestVersion(Context context, VersionHistory versionHistory) - throws SQLException - { + throws SQLException { List versions = versioningService.getVersionsByHistory(context, versionHistory); - if(versions != null && !versions.isEmpty()) - { + if (versions != null && !versions.isEmpty()) { return versions.get(0); } return null; @@ -166,48 +153,40 @@ public class VersionHistoryServiceImpl implements VersionHistoryService @Override public Version getFirstVersion(Context context, VersionHistory versionHistory) - throws SQLException - { + throws SQLException { List versions = versioningService.getVersionsByHistory(context, versionHistory); - if (versions == null) - { + if (versions == null) { return null; } - - if (versions.size()-1 >= 0) - { - return versions.get(versions.size()-1); + + if (versions.size() - 1 >= 0) { + return versions.get(versions.size() - 1); } - + return null; } @Override - public boolean isFirstVersion(Context context, Item item) throws SQLException - { + public boolean isFirstVersion(Context context, Item item) throws SQLException { VersionHistory vh = findByItem(context, item); - if (vh == null) - { + if (vh == null) { return true; } Version version = versioningService.getVersion(context, item); return isFirstVersion(context, vh, version); } - + @Override public boolean isFirstVersion(Context context, VersionHistory versionHistory, Version version) - throws SQLException - { + throws SQLException { return getFirstVersion(context, versionHistory).equals(version); } - + @Override - public boolean isLastVersion(Context context, Item item) throws SQLException - { + public boolean isLastVersion(Context context, Item item) throws SQLException { VersionHistory vh = findByItem(context, item); - if (vh == null) - { + if (vh == null) { return true; } Version version = versioningService.getVersion(context, item); @@ -216,14 +195,12 @@ public class VersionHistoryServiceImpl implements VersionHistoryService @Override public boolean isLastVersion(Context context, VersionHistory versionHistory, Version version) - throws SQLException - { + throws SQLException { return getLatestVersion(context, versionHistory).equals(version); } @Override - public void remove(VersionHistory versionHistory, Version version) - { + public void remove(VersionHistory versionHistory, Version version) { List versions = versionHistory.getVersions(); versions.remove(version); } diff --git a/dspace-api/src/main/java/org/dspace/versioning/VersioningConsumer.java b/dspace-api/src/main/java/org/dspace/versioning/VersioningConsumer.java index db1380a7eb..6683419844 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/VersioningConsumer.java +++ b/dspace-api/src/main/java/org/dspace/versioning/VersioningConsumer.java @@ -7,6 +7,9 @@ */ package org.dspace.versioning; +import java.util.HashSet; +import java.util.Set; + import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; @@ -18,12 +21,7 @@ import org.dspace.versioning.factory.VersionServiceFactory; import org.dspace.versioning.service.VersionHistoryService; import org.dspace.versioning.service.VersioningService; -import java.util.HashSet; -import java.util.Set; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -45,35 +43,36 @@ public class VersioningConsumer implements Consumer { } @Override - public void finish(Context ctx) throws Exception {} + public void finish(Context ctx) throws Exception { + } @Override public void consume(Context ctx, Event event) throws Exception { - if(itemsToProcess == null){ + if (itemsToProcess == null) { itemsToProcess = new HashSet(); } int st = event.getSubjectType(); int et = event.getEventType(); - if(st == Constants.ITEM && et == Event.INSTALL){ + if (st == Constants.ITEM && et == Event.INSTALL) { Item item = (Item) event.getSubject(ctx); if (item != null && item.isArchived()) { VersionHistory history = versionHistoryService.findByItem(ctx, item); if (history != null) { Version latest = versionHistoryService.getLatestVersion(ctx, history); Version previous = versionHistoryService.getPrevious(ctx, history, latest); - if(previous != null){ + if (previous != null) { Item previousItem = previous.getItem(); - if(previousItem != null){ + if (previousItem != null) { previousItem.setArchived(false); itemsToProcess.add(previousItem); //Fire a new modify event for our previous item - //Due to the need to reindex the item in the search + //Due to the need to reindex the item in the search //and browse index we need to fire a new event - ctx.addEvent(new Event(Event.MODIFY, - previousItem.getType(), previousItem.getID(), - null, itemService.getIdentifiers(ctx, previousItem))); + ctx.addEvent(new Event(Event.MODIFY, + previousItem.getType(), previousItem.getID(), + null, itemService.getIdentifiers(ctx, previousItem))); } } } @@ -83,8 +82,8 @@ public class VersioningConsumer implements Consumer { @Override public void end(Context ctx) throws Exception { - if(itemsToProcess != null){ - for(Item item : itemsToProcess){ + if (itemsToProcess != null) { + for (Item item : itemsToProcess) { ctx.turnOffAuthorisationSystem(); try { itemService.update(ctx, item); diff --git a/dspace-api/src/main/java/org/dspace/versioning/VersioningServiceImpl.java b/dspace-api/src/main/java/org/dspace/versioning/VersioningServiceImpl.java index 1ab4cde711..1a07df16e7 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/VersioningServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/versioning/VersioningServiceImpl.java @@ -27,13 +27,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Pascal-Nicolas Becker (dspace at pascal dash becker dot de) -*/ + */ public class VersioningServiceImpl implements VersioningService { @Autowired(required = true) @@ -46,7 +44,7 @@ public class VersioningServiceImpl implements VersioningService { private WorkspaceItemService workspaceItemService; @Autowired(required = true) protected WorkflowItemService workflowItemService; - + private DefaultItemVersionProvider provider; @Required @@ -54,30 +52,30 @@ public class VersioningServiceImpl implements VersioningService { this.provider = provider; } - protected VersioningServiceImpl() - { + protected VersioningServiceImpl() { } - /** Service Methods */ + /** + * Service Methods + */ @Override - public Version createNewVersion(Context c, Item item){ + public Version createNewVersion(Context c, Item item) { return createNewVersion(c, item, null); } @Override public Version createNewVersion(Context c, Item item, String summary) { - try{ + try { VersionHistory vh = versionHistoryService.findByItem(c, item); - if(vh==null) - { + if (vh == null) { // first time: create 2 versions: old and new one - vh= versionHistoryService.create(c); + vh = versionHistoryService.create(c); // get dc:date.accessioned to be set as first version date... List values = itemService.getMetadata(item, "dc", "date", "accessioned", Item.ANY); Date versionDate = new Date(); - if(values!=null && values.size() > 0){ + if (values != null && values.size() > 0) { String date = values.get(0).getValue(); versionDate = new DCDate(date).toDate(); } @@ -93,26 +91,25 @@ public class VersioningServiceImpl implements VersioningService { provider.updateItemState(c, itemNew, item); return version; - }catch (Exception e) { + } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } @Override public void removeVersion(Context c, Version version) throws SQLException { - try{ + try { // we will first delete the version and then the item // after deletion of the version we cannot find the item anymore // so we need to get the item now Item item = version.getItem(); VersionHistory history = version.getVersionHistory(); - if (item != null) - { + if (item != null) { // take care of the item identifiers provider.deleteVersionedItem(c, version, history); } - + // to keep version number stables, we do not delete versions, // we set all fields null except versionnumber and versionhistory version.setItem(null); @@ -124,39 +121,35 @@ public class VersioningServiceImpl implements VersioningService { // if all versions of a version history were deleted, // we delete the version history. if (this.getVersionsByHistory(c, history) == null - || this.getVersionsByHistory(c, history).isEmpty()) - { + || this.getVersionsByHistory(c, history).isEmpty()) { // hard delete the previously soft deleted versions - for (Version v : history.getVersions()) - { + for (Version v : history.getVersions()) { versionDAO.delete(c, v); } // delete the version history versionHistoryService.delete(c, history); } - + // Completely delete the item if (item != null) { // DS-1814 introduce the possibility that submitter can create // new versions. To avoid authorithation problems we need to // check whether a corresponding workspaceItem exists. - if (!item.isArchived()) - { - WorkspaceItem wsi = workspaceItemService.findByItem(c, item); - if(wsi != null) { + if (!item.isArchived()) { + WorkspaceItem wsi = workspaceItemService.findByItem(c, item); + if (wsi != null) { workspaceItemService.deleteAll(c, wsi); - } else { - WorkflowItem wfi = workflowItemService.findByItem(c, item); - if (wfi != null) { - workflowItemService.delete(c, wfi); - } - } - } - else { + } else { + WorkflowItem wfi = workflowItemService.findByItem(c, item); + if (wfi != null) { + workflowItemService.delete(c, wfi); + } + } + } else { itemService.delete(c, item); } } - }catch (Exception e) { + } catch (Exception e) { c.abort(); throw new RuntimeException(e.getMessage(), e); } @@ -165,7 +158,7 @@ public class VersioningServiceImpl implements VersioningService { @Override public void removeVersion(Context c, Item item) throws SQLException { Version version = versionDAO.findByItem(c, item); - if(version!=null){ + if (version != null) { removeVersion(c, version); } } @@ -177,12 +170,12 @@ public class VersioningServiceImpl implements VersioningService { @Override - public Version restoreVersion(Context c, Version version){ + public Version restoreVersion(Context c, Version version) { return restoreVersion(c, version, null); } @Override - public Version restoreVersion(Context c, Version version, String summary) { + public Version restoreVersion(Context c, Version version, String summary) { return null; } @@ -200,7 +193,8 @@ public class VersioningServiceImpl implements VersioningService { } @Override - public Version createNewVersion(Context context, VersionHistory history, Item item, String summary, Date date, int versionNumber) { + public Version createNewVersion(Context context, VersionHistory history, Item item, String summary, Date date, + int versionNumber) { try { Version version = versionDAO.create(context, new Version()); @@ -217,7 +211,7 @@ public class VersioningServiceImpl implements VersioningService { throw new RuntimeException(e.getMessage(), e); } } - + @Override public List getVersionsByHistory(Context c, VersionHistory vh) throws SQLException { List versions = versionDAO.findVersionsWithItems(c, vh); @@ -227,20 +221,20 @@ public class VersioningServiceImpl implements VersioningService { // **** PROTECTED METHODS!! - protected Version createVersion(Context c, VersionHistory vh, Item item, String summary, Date date) throws SQLException { + protected Version createVersion(Context c, VersionHistory vh, Item item, String summary, Date date) + throws SQLException { return createNewVersion(c, vh, item, summary, date, getNextVersionNumer(c, vh)); } - protected int getNextVersionNumer(Context c, VersionHistory vh) throws SQLException{ + protected int getNextVersionNumer(Context c, VersionHistory vh) throws SQLException { int next = versionDAO.getNextVersionNumber(c, vh); - + // check if we have uncommited versions in DSpace's cache - if (versionHistoryService.getLatestVersion(c, vh) != null - && versionHistoryService.getLatestVersion(c, vh).getVersionNumber() >= next) - { + if (versionHistoryService.getLatestVersion(c, vh) != null + && versionHistoryService.getLatestVersion(c, vh).getVersionNumber() >= next) { next = versionHistoryService.getLatestVersion(c, vh).getVersionNumber() + 1; } - + return next; } } diff --git a/dspace-api/src/main/java/org/dspace/versioning/dao/VersionDAO.java b/dspace-api/src/main/java/org/dspace/versioning/dao/VersionDAO.java index c255fc2897..52bcb978f1 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/dao/VersionDAO.java +++ b/dspace-api/src/main/java/org/dspace/versioning/dao/VersionDAO.java @@ -7,26 +7,26 @@ */ package org.dspace.versioning.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.versioning.Version; - -import java.sql.SQLException; -import java.util.List; import org.dspace.versioning.VersionHistory; /** * Database Access Object interface class for the Version object. - * The implementation of this class is responsible for all database calls for the Version object and is autowired by spring + * The implementation of this class is responsible for all database calls for the Version object and is autowired by + * spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com */ -public interface VersionDAO extends GenericDAO -{ +public interface VersionDAO extends GenericDAO { public Version findByItem(Context context, Item item) throws SQLException; - + /** * This method returns all versions of an version history that have items * assigned. We do not delete versions to keep version numbers stable. To @@ -34,17 +34,14 @@ public interface VersionDAO extends GenericDAO * method returns only versions that aren't soft deleted and have items * assigned. * - * @param context - * The relevant DSpace Context. - * @param versionHistory - * version history + * @param context The relevant DSpace Context. + * @param versionHistory version history * @return all versions of an version history that have items assigned. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findVersionsWithItems(Context context, VersionHistory versionHistory) - throws SQLException; + throws SQLException; public int getNextVersionNumber(Context c, VersionHistory vh) throws SQLException; - + } diff --git a/dspace-api/src/main/java/org/dspace/versioning/dao/VersionHistoryDAO.java b/dspace-api/src/main/java/org/dspace/versioning/dao/VersionHistoryDAO.java index 26e981062d..63e8cc7c53 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/dao/VersionHistoryDAO.java +++ b/dspace-api/src/main/java/org/dspace/versioning/dao/VersionHistoryDAO.java @@ -7,18 +7,17 @@ */ package org.dspace.versioning.dao; +import java.sql.SQLException; + import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.versioning.VersionHistory; -import java.sql.SQLException; -import java.util.List; -import org.dspace.versioning.Version; - /** * Database Access Object interface class for the VersionHistory object. - * The implementation of this class is responsible for all database calls for the VersionHistory object and is autowired by spring + * The implementation of this class is responsible for all database calls for the VersionHistory object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionDAOImpl.java b/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionDAOImpl.java index 7804cc7d95..6633c892ea 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionDAOImpl.java @@ -7,19 +7,21 @@ */ package org.dspace.versioning.dao.impl; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.dspace.content.Item; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.versioning.Version; import org.dspace.versioning.VersionHistory; +import org.dspace.versioning.Version_; import org.dspace.versioning.dao.VersionDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the Version object. @@ -32,39 +34,50 @@ import java.util.List; * @author kevinvandevelde at atmire.com * @author Pascal-Nicolas Becker (dspace at pascal dash becker dot de) */ -public class VersionDAOImpl extends AbstractHibernateDAO implements VersionDAO -{ - protected VersionDAOImpl() - { +public class VersionDAOImpl extends AbstractHibernateDAO implements VersionDAO { + protected VersionDAOImpl() { super(); } @Override public Version findByItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, Version.class); - criteria.add(Restrictions.eq("item", item)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Version.class); + Root versionRoot = criteriaQuery.from(Version.class); + criteriaQuery.select(versionRoot); + criteriaQuery.where(criteriaBuilder.equal(versionRoot.get(Version_.item), item)); + return singleResult(context, criteriaQuery); } @Override public int getNextVersionNumber(Context c, VersionHistory vh) throws SQLException { - Query q = this.createQuery(c, - "SELECT (COALESCE(MAX(versionNumber), 0) + 1) " - + "FROM Version WHERE versionHistory.id = :historyId"); + Query q = this.createQuery(c, + "SELECT (COALESCE(MAX(versionNumber), 0) + 1) " + + "FROM Version WHERE versionHistory.id = :historyId"); q.setParameter("historyId", vh.getID()); - int next = (Integer) q.uniqueResult(); + int next = (Integer) q.getSingleResult(); return next; } - + @Override public List findVersionsWithItems(Context context, VersionHistory versionHistory) - throws SQLException - { - Criteria criteria = createCriteria(context, Version.class); - criteria.add(Restrictions.eq("versionHistory", versionHistory)); - criteria.add(Restrictions.and(Restrictions.isNotNull("item"))); - criteria.addOrder(Order.desc("versionNumber")); - return list(criteria); + throws SQLException { + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Version.class); + Root versionRoot = criteriaQuery.from(Version.class); + criteriaQuery.select(versionRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(versionRoot.get(Version_.versionHistory), versionHistory), + criteriaBuilder.isNotNull(versionRoot.get(Version_.item)) + ) + ); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.desc(versionRoot.get(Version_.versionNumber))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, false, Version.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionHistoryDAOImpl.java b/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionHistoryDAOImpl.java index 4c3b76e5c5..eac78c3e62 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionHistoryDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionHistoryDAOImpl.java @@ -7,18 +7,21 @@ */ package org.dspace.versioning.dao.impl; -import org.dspace.content.Item; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.versioning.VersionHistory; -import org.dspace.versioning.dao.VersionHistoryDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; + +import org.dspace.content.Item; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; import org.dspace.versioning.Version; -import org.hibernate.criterion.Order; +import org.dspace.versioning.VersionHistory; +import org.dspace.versioning.Version_; +import org.dspace.versioning.dao.VersionHistoryDAO; /** * Hibernate implementation of the Database Access Object interface class for the VersionHistory object. @@ -30,19 +33,24 @@ import org.hibernate.criterion.Order; * @author Ben Bosman (ben at atmire dot com) * @author kevinvandevelde at atmire.com */ -public class VersionHistoryDAOImpl extends AbstractHibernateDAO implements VersionHistoryDAO -{ - protected VersionHistoryDAOImpl() - { +public class VersionHistoryDAOImpl extends AbstractHibernateDAO implements VersionHistoryDAO { + protected VersionHistoryDAOImpl() { super(); } @Override public VersionHistory findByItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, VersionHistory.class); - criteria.createAlias("versions", "v"); - criteria.add(Restrictions.eq("v.item", item)); - criteria.addOrder(Order.desc("v.versionNumber")); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, VersionHistory.class); + Root versionHistoryRoot = criteriaQuery.from(VersionHistory.class); + Join join = versionHistoryRoot.join("versions"); + criteriaQuery.select(versionHistoryRoot); + criteriaQuery.where(criteriaBuilder.equal(join.get(Version_.item), item)); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.desc(join.get(Version_.versionNumber))); + criteriaQuery.orderBy(orderList); + + return singleResult(context, criteriaQuery); } } diff --git a/dspace-api/src/main/java/org/dspace/versioning/factory/VersionServiceFactory.java b/dspace-api/src/main/java/org/dspace/versioning/factory/VersionServiceFactory.java index b0a64fb63a..ecc3315a72 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/factory/VersionServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/versioning/factory/VersionServiceFactory.java @@ -12,7 +12,8 @@ import org.dspace.versioning.service.VersionHistoryService; import org.dspace.versioning.service.VersioningService; /** - * Abstract factory to get services for the versioning package, use VersionServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the versioning package, use VersionServiceFactory.getInstance() to retrieve + * an implementation * * @author kevinvandevelde at atmire.com */ @@ -22,8 +23,8 @@ public abstract class VersionServiceFactory { public abstract VersioningService getVersionService(); - public static VersionServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("versionServiceFactory", VersionServiceFactory.class); + public static VersionServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("versionServiceFactory", VersionServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/versioning/factory/VersionServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/versioning/factory/VersionServiceFactoryImpl.java index 53b1a1fac1..613cb4faf4 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/factory/VersionServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/versioning/factory/VersionServiceFactoryImpl.java @@ -12,7 +12,8 @@ import org.dspace.versioning.service.VersioningService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the versioning package, use VersionServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the versioning package, use VersionServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/versioning/service/VersionHistoryService.java b/dspace-api/src/main/java/org/dspace/versioning/service/VersionHistoryService.java index ca7e3a6d64..e7c88879a5 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/service/VersionHistoryService.java +++ b/dspace-api/src/main/java/org/dspace/versioning/service/VersionHistoryService.java @@ -7,66 +7,63 @@ */ package org.dspace.versioning.service; +import java.sql.SQLException; + import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.service.DSpaceCRUDService; import org.dspace.versioning.Version; import org.dspace.versioning.VersionHistory; -import java.sql.SQLException; -import java.util.List; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Pascal-Nicolas Becker (dspace at pascal dash becker dot de) */ public interface VersionHistoryService extends DSpaceCRUDService { - + public void add(Context context, VersionHistory versionHistory, Version version) - throws SQLException; - + throws SQLException; + public VersionHistory findByItem(Context context, Item item) - throws SQLException; - + throws SQLException; + public Version getFirstVersion(Context context, VersionHistory versionHistory) - throws SQLException; - + throws SQLException; + public Version getLatestVersion(Context context, VersionHistory versionHistory) - throws SQLException; - + throws SQLException; + public Version getNext(Context context, VersionHistory versionHistory, Version version) - throws SQLException; - + throws SQLException; + public Version getPrevious(Context context, VersionHistory versionHistory, Version version) - throws SQLException; - + throws SQLException; + public Version getVersion(Context context, VersionHistory versionHistory, Item item) - throws SQLException; - + throws SQLException; + public boolean hasNext(Context context, VersionHistory versionHistory, Item item) - throws SQLException; + throws SQLException; public boolean hasNext(Context context, VersionHistory versionHistory, Version version) - throws SQLException; - + throws SQLException; + public boolean hasVersionHistory(Context context, Item item) - throws SQLException; - + throws SQLException; + public boolean isFirstVersion(Context context, Item item) - throws SQLException; + throws SQLException; public boolean isFirstVersion(Context context, VersionHistory versionHistory, Version version) - throws SQLException; + throws SQLException; public boolean isLastVersion(Context context, Item item) - throws SQLException; + throws SQLException; public boolean isLastVersion(Context context, VersionHistory versionHistory, Version version) - throws SQLException; + throws SQLException; public void remove(VersionHistory versionHistory, Version version); diff --git a/dspace-api/src/main/java/org/dspace/versioning/service/VersioningService.java b/dspace-api/src/main/java/org/dspace/versioning/service/VersioningService.java index 8b60d4637c..56d52e3953 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/service/VersioningService.java +++ b/dspace-api/src/main/java/org/dspace/versioning/service/VersioningService.java @@ -7,18 +7,16 @@ */ package org.dspace.versioning.service; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; + import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.versioning.Version; import org.dspace.versioning.VersionHistory; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; - /** - * - * * @author Fabio Bolognesi (fabio at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -28,20 +26,17 @@ public interface VersioningService { Version createNewVersion(Context c, Item itemId); Version createNewVersion(Context c, Item itemId, String summary); - + /** * Returns all versions of a version history. - * To keep version numbers stable we do not delete versions, we do only set + * To keep version numbers stable we do not delete versions, we do only set * the item, date, summary and eperson null. This methods returns only those * versions that have an item assigned. * - * @param c - * The relevant DSpace Context. - * @param vh - * version history + * @param c The relevant DSpace Context. + * @param vh version history * @return All versions of a version history that have an item assigned. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ List getVersionsByHistory(Context c, VersionHistory vh) throws SQLException; @@ -59,5 +54,6 @@ public interface VersioningService { Version getVersion(Context c, Item item) throws SQLException; - Version createNewVersion(Context context, VersionHistory history, Item item, String summary, Date date, int versionNumber); + Version createNewVersion(Context context, VersionHistory history, Item item, String summary, Date date, + int versionNumber); } diff --git a/dspace-api/src/main/java/org/dspace/vocabulary/ControlledVocabulary.java b/dspace-api/src/main/java/org/dspace/vocabulary/ControlledVocabulary.java index 40ac765cd3..314467ffcb 100644 --- a/dspace-api/src/main/java/org/dspace/vocabulary/ControlledVocabulary.java +++ b/dspace-api/src/main/java/org/dspace/vocabulary/ControlledVocabulary.java @@ -7,6 +7,15 @@ */ package org.dspace.vocabulary; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +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.dspace.core.ConfigurationManager; import org.w3c.dom.Document; @@ -14,15 +23,6 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - /** * This class represents a single controlled vocabulary node * It also contains references to its child nodes @@ -48,22 +48,25 @@ public class ControlledVocabulary { * * @param fileName the name of the vocabulary file. * @return a controlled vocabulary object - * @throws IOException Should something go wrong with reading the file - * @throws SAXException Error during xml parsing + * @throws IOException Should something go wrong with reading the file + * @throws SAXException Error during xml parsing * @throws ParserConfigurationException Error during xml parsing - * @throws TransformerException Error during xml parsing - * TODO: add some caching ! + * @throws TransformerException Error during xml parsing + * TODO: add some caching ! */ - public static ControlledVocabulary loadVocabulary(String fileName) throws IOException, SAXException, ParserConfigurationException, TransformerException { + public static ControlledVocabulary loadVocabulary(String fileName) + throws IOException, SAXException, ParserConfigurationException, TransformerException { StringBuilder filePath = new StringBuilder(); - filePath.append(ConfigurationManager.getProperty("dspace.dir")).append(File.separatorChar).append("config").append(File.separatorChar).append("controlled-vocabularies").append(File.separator).append(fileName).append(".xml"); + filePath.append(ConfigurationManager.getProperty("dspace.dir")).append(File.separatorChar).append("config") + .append(File.separatorChar).append("controlled-vocabularies").append(File.separator).append(fileName) + .append(".xml"); File controlledVocFile = new File(filePath.toString()); - if(controlledVocFile.exists()){ + if (controlledVocFile.exists()) { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = builder.parse(controlledVocFile); return loadVocabularyNode(XPathAPI.selectSingleNode(document, "node"), ""); - }else{ + } else { return null; } @@ -71,7 +74,8 @@ public class ControlledVocabulary { /** * Loads a single node & all its child nodes recursively - * @param node The current node that we need to parse + * + * @param node The current node that we need to parse * @param initialValue the value of parent node * @return a vocabulary node with all its children * @throws TransformerException should something go wrong with loading the xml @@ -79,27 +83,27 @@ public class ControlledVocabulary { private static ControlledVocabulary loadVocabularyNode(Node node, String initialValue) throws TransformerException { Node idNode = node.getAttributes().getNamedItem("id"); String id = null; - if(idNode != null){ + if (idNode != null) { id = idNode.getNodeValue(); } Node labelNode = node.getAttributes().getNamedItem("label"); String label = null; - if(labelNode != null){ + if (labelNode != null) { label = labelNode.getNodeValue(); } String value; - if(0 < initialValue.length()){ + if (0 < initialValue.length()) { value = initialValue + "::" + label; - }else{ + } else { value = label; } NodeList subNodes = XPathAPI.selectNodeList(node, "isComposedBy/node"); List subVocabularies = new ArrayList(subNodes.getLength()); - for(int i = 0; i < subNodes.getLength(); i++){ + for (int i = 0; i < subNodes.getLength(); i++) { subVocabularies.add(loadVocabularyNode(subNodes.item(i), value)); } - + return new ControlledVocabulary(id, label, value, subVocabularies); } diff --git a/dspace-api/src/main/java/org/dspace/workflow/WorkflowException.java b/dspace-api/src/main/java/org/dspace/workflow/WorkflowException.java index e6e0fc853c..f05ab80486 100644 --- a/dspace-api/src/main/java/org/dspace/workflow/WorkflowException.java +++ b/dspace-api/src/main/java/org/dspace/workflow/WorkflowException.java @@ -15,7 +15,7 @@ package org.dspace.workflow; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class WorkflowException extends Exception{ +public class WorkflowException extends Exception { private String reason; @@ -23,10 +23,11 @@ public class WorkflowException extends Exception{ super(cause); } - public WorkflowException(String reason){ + public WorkflowException(String reason) { this.reason = reason; } - public String toString(){ + + public String toString() { return reason; } } diff --git a/dspace-api/src/main/java/org/dspace/workflow/WorkflowItem.java b/dspace-api/src/main/java/org/dspace/workflow/WorkflowItem.java index 60e344f4d1..fbfc4cb015 100644 --- a/dspace-api/src/main/java/org/dspace/workflow/WorkflowItem.java +++ b/dspace-api/src/main/java/org/dspace/workflow/WorkflowItem.java @@ -7,7 +7,6 @@ */ package org.dspace.workflow; - import org.dspace.content.InProgressSubmission; import org.dspace.core.ReloadableEntity; diff --git a/dspace-api/src/main/java/org/dspace/workflow/WorkflowItemService.java b/dspace-api/src/main/java/org/dspace/workflow/WorkflowItemService.java index 9afd234521..48ee20b9ad 100644 --- a/dspace-api/src/main/java/org/dspace/workflow/WorkflowItemService.java +++ b/dspace-api/src/main/java/org/dspace/workflow/WorkflowItemService.java @@ -7,6 +7,10 @@ */ package org.dspace.workflow; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.Item; @@ -14,13 +18,10 @@ import org.dspace.content.service.InProgressSubmissionService; import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the Workflow items. - * All WorkflowItem service classes should implement this class since it offers some basic methods which all WorkflowItems + * All WorkflowItem service classes should implement this class since it offers some basic methods which all + * WorkflowItems * are required to have. * * @author kevinvandevelde at atmire.com @@ -32,40 +33,29 @@ public interface WorkflowItemService extends InProgressS /** * Get a workflow item from the database. * - * @param context - * The relevant DSpace Context. - * @param id - * ID of the workflow item - * + * @param context The relevant DSpace Context. + * @param id ID of the workflow item * @return the workflow item, or null if the ID is invalid. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public T find(Context context, int id) throws SQLException; /** * return all workflowitems * - * @param context - * The relevant DSpace Context. - * + * @param context The relevant DSpace Context. * @return List of all workflowItems in system - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findAll(Context context) throws SQLException; /** * Get all workflow items for a particular collection. * - * @param context - * The relevant DSpace Context. - * @param collection - * the collection - * + * @param context The relevant DSpace Context. + * @param collection the collection * @return array of the corresponding workflow items - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findByCollection(Context context, Collection collection) throws SQLException; @@ -73,14 +63,10 @@ public interface WorkflowItemService extends InProgressS * Check to see if a particular item is currently under Workflow. * If so, its WorkflowItem is returned. If not, null is returned * - * @param context - * The relevant DSpace Context. - * @param item - * the item - * + * @param context The relevant DSpace Context. + * @param item the item * @return workflow item corresponding to the item, or null - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public T findByItem(Context context, Item item) throws SQLException; @@ -88,50 +74,35 @@ public interface WorkflowItemService extends InProgressS * Get all workflow items that were original submissions by a particular * e-person. * - * @param context - * The relevant DSpace Context. - * @param ep - * the eperson - * + * @param context The relevant DSpace Context. + * @param ep the eperson * @return the corresponding workflow items - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findBySubmitter(Context context, EPerson ep) throws SQLException; /** * Delete all workflow items present in the specified collection. * - * @param context - * The relevant DSpace Context. - * @param collection - * the containing collection - * - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param collection the containing collection + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ - public void deleteByCollection(Context context, Collection collection) throws SQLException, IOException, AuthorizeException; + public void deleteByCollection(Context context, Collection collection) + throws SQLException, IOException, AuthorizeException; /** * Delete the specified workflow item. * - * @param context - * The relevant DSpace Context. - * @param workflowItem - * which workflow item to delete - * - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param workflowItem which workflow item to delete + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void delete(Context context, T workflowItem) throws SQLException, AuthorizeException, IOException; diff --git a/dspace-api/src/main/java/org/dspace/workflow/WorkflowService.java b/dspace-api/src/main/java/org/dspace/workflow/WorkflowService.java index 5a81410e17..53da1660db 100644 --- a/dspace-api/src/main/java/org/dspace/workflow/WorkflowService.java +++ b/dspace-api/src/main/java/org/dspace/workflow/WorkflowService.java @@ -7,102 +7,92 @@ */ package org.dspace.workflow; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; -import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.xmlworkflow.WorkflowConfigurationException; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the WorkflowService framework. - * All WorkflowServices service classes should implement this class since it offers some basic methods which all Workflows + * All WorkflowServices service classes should implement this class since it offers some basic methods which all + * Workflows * are required to have. * - * @author kevinvandevelde at atmire.com * @param some implementation of workflow item. + * @author kevinvandevelde at atmire.com */ public interface WorkflowService { - - + + /** * startWorkflow() begins a workflow - in a single transaction do away with * the PersonalWorkspace entry and turn it into a WorkflowItem. * - * @param context - * The relevant DSpace Context. - * @param wsi - * The WorkspaceItem to convert to a workflow item + * @param context The relevant DSpace Context. + * @param wsi The WorkspaceItem to convert to a workflow item * @return The resulting workflow item - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws WorkflowException if workflow error + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws WorkflowException if workflow error */ - public T start(Context context, WorkspaceItem wsi) throws SQLException, AuthorizeException, IOException, WorkflowException; + public T start(Context context, WorkspaceItem wsi) + throws SQLException, AuthorizeException, IOException, WorkflowException; /** * startWithoutNotify() starts the workflow normally, but disables * notifications (useful for large imports,) for the first workflow step - * subsequent notifications happen normally * - * @param c - * The relevant DSpace Context. - * @param wsi - * workspace item + * @param c The relevant DSpace Context. + * @param wsi workspace item * @return the resulting workflow item. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws WorkflowException if workflow error + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws WorkflowException if workflow error */ - public T startWithoutNotify(Context c, WorkspaceItem wsi) throws SQLException, AuthorizeException, IOException, WorkflowException; + public T startWithoutNotify(Context c, WorkspaceItem wsi) + throws SQLException, AuthorizeException, IOException, WorkflowException; /** * abort() aborts a workflow, completely deleting it (administrator do this) * (it will basically do a reject from any state - the item ends up back in * the user's PersonalWorkspace * - * @param c - * The relevant DSpace Context. - * @param wi - * WorkflowItem to operate on - * @param e - * EPerson doing the operation + * @param c The relevant DSpace Context. + * @param wi WorkflowItem to operate on + * @param e EPerson doing the operation * @return workspace item returned to workspace - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ public WorkspaceItem abort(Context c, T wi, EPerson e) throws SQLException, AuthorizeException, IOException; - public WorkspaceItem sendWorkflowItemBackSubmission(Context c, T workflowItem, EPerson e, String provenance, String rejection_message) throws SQLException, AuthorizeException, IOException; + public WorkspaceItem sendWorkflowItemBackSubmission(Context c, T workflowItem, EPerson e, String provenance, + String rejection_message) + throws SQLException, AuthorizeException, IOException; public String getMyDSpaceLink(); - public void deleteCollection(Context context, Collection collection) throws SQLException, IOException, AuthorizeException; + public void deleteCollection(Context context, Collection collection) + throws SQLException, IOException, AuthorizeException; public List getEPersonDeleteConstraints(Context context, EPerson ePerson) throws SQLException; - public Group getWorkflowRoleGroup(Context context, Collection collection, String roleName, Group roleGroup) throws SQLException, IOException, WorkflowConfigurationException, AuthorizeException, WorkflowException; + public Group getWorkflowRoleGroup(Context context, Collection collection, String roleName, Group roleGroup) + throws SQLException, IOException, WorkflowConfigurationException, AuthorizeException, WorkflowException; public List getFlywayMigrationLocations(); } diff --git a/dspace-api/src/main/java/org/dspace/workflow/factory/WorkflowServiceFactory.java b/dspace-api/src/main/java/org/dspace/workflow/factory/WorkflowServiceFactory.java index 2e4020c9c6..b338e54f5a 100644 --- a/dspace-api/src/main/java/org/dspace/workflow/factory/WorkflowServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/workflow/factory/WorkflowServiceFactory.java @@ -12,7 +12,8 @@ import org.dspace.workflow.WorkflowItemService; import org.dspace.workflow.WorkflowService; /** - * Abstract factory to get services for the workflow package, use WorkflowServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the workflow package, use WorkflowServiceFactory.getInstance() to retrieve an + * implementation * * @author kevinvandevelde at atmire.com */ @@ -22,8 +23,8 @@ public abstract class WorkflowServiceFactory { public abstract WorkflowItemService getWorkflowItemService(); - public static WorkflowServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("workflowServiceFactory", WorkflowServiceFactory.class); + public static WorkflowServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("workflowServiceFactory", WorkflowServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowItem.java b/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowItem.java index 53ce3972c0..3bbe11f0a7 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowItem.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowItem.java @@ -7,45 +7,59 @@ */ package org.dspace.workflowbasic; +import java.sql.SQLException; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.core.Context; -import org.dspace.core.ReloadableEntity; import org.dspace.eperson.EPerson; import org.dspace.workflow.WorkflowItem; -import javax.persistence.*; -import java.sql.SQLException; - /** * Class representing an item going through the workflow process in DSpace - * + * * @author Robert Tansley * @version $Revision$ */ @Entity @Table(name = "workflowitem") -public class BasicWorkflowItem implements WorkflowItem -{ +public class BasicWorkflowItem implements WorkflowItem { @Id @Column(name = "workflow_id", unique = true, nullable = false) - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="workflowitem_seq") - @SequenceGenerator(name="workflowitem_seq", sequenceName="workflowitem_seq", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "workflowitem_seq") + @SequenceGenerator(name = "workflowitem_seq", sequenceName = "workflowitem_seq", allocationSize = 1) private Integer workflowitemId; - /** The item this workflow object pertains to */ + /** + * The item this workflow object pertains to + */ @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "item_id", unique = true) private Item item; - /** The collection the item is being submitted to */ + /** + * The collection the item is being submitted to + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "collection_id") private Collection collection; - /** EPerson owning the current state */ + /** + * EPerson owning the current state + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "owner") private EPerson owner; @@ -65,70 +79,60 @@ public class BasicWorkflowItem implements WorkflowItem /** * Protected constructor, create object using: * {@link org.dspace.workflowbasic.service.BasicWorkflowItemService#create(Context, Item, Collection)} - * */ - protected BasicWorkflowItem() - { + protected BasicWorkflowItem() { } /** * Get the internal ID of this workflow item - * + * * @return the internal identifier */ @Override - public Integer getID() - { + public Integer getID() { return workflowitemId; } /** * get owner of WorkflowItem - * + * * @return EPerson owner */ - public EPerson getOwner() - { + public EPerson getOwner() { return owner; } /** * set owner of WorkflowItem - * - * @param ep - * owner + * + * @param ep owner */ - public void setOwner(EPerson ep) - { + public void setOwner(EPerson ep) { this.owner = ep; } /** * Get state of WorkflowItem - * + * * @return state */ - public int getState() - { + public int getState() { return state; } /** * Set state of WorkflowItem - * - * @param newstate - * new state (from WorkflowManager) + * + * @param newstate new state (from WorkflowManager) */ - public void setState(int newstate) - { + public void setState(int newstate) { this.state = newstate; } // InProgressSubmission methods @Override - public Item getItem() - { + public Item getItem() { return item; } @@ -137,8 +141,7 @@ public class BasicWorkflowItem implements WorkflowItem } @Override - public Collection getCollection() - { + public Collection getCollection() { return collection; } @@ -147,44 +150,37 @@ public class BasicWorkflowItem implements WorkflowItem } @Override - public EPerson getSubmitter() throws SQLException - { + public EPerson getSubmitter() throws SQLException { return item.getSubmitter(); } @Override - public boolean hasMultipleFiles() - { + public boolean hasMultipleFiles() { return multipleFiles; } @Override - public void setMultipleFiles(boolean b) - { + public void setMultipleFiles(boolean b) { this.multipleFiles = b; } @Override - public boolean hasMultipleTitles() - { + public boolean hasMultipleTitles() { return multipleTitles; } @Override - public void setMultipleTitles(boolean b) - { + public void setMultipleTitles(boolean b) { this.multipleTitles = b; } @Override - public boolean isPublishedBefore() - { + public boolean isPublishedBefore() { return publishedBefore; } @Override - public void setPublishedBefore(boolean b) - { + public void setPublishedBefore(boolean b) { this.publishedBefore = b; } } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowItemServiceImpl.java index fa5246140b..86134c62b5 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowItemServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.workflowbasic; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; @@ -20,11 +25,6 @@ import org.dspace.workflowbasic.service.BasicWorkflowItemService; import org.dspace.workflowbasic.service.TaskListItemService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Service implementation for the BasicWorkflowItem object. * This class is responsible for all business logic calls for the BasicWorkflowItem object and is autowired by spring. @@ -34,7 +34,9 @@ import java.util.List; */ public class BasicWorkflowItemServiceImpl implements BasicWorkflowItemService { - /** log4j category */ + /** + * log4j category + */ protected static Logger log = Logger.getLogger(BasicWorkflowItem.class); @Autowired(required = true) @@ -46,15 +48,16 @@ public class BasicWorkflowItemServiceImpl implements BasicWorkflowItemService { protected TaskListItemService taskListItemService; - protected BasicWorkflowItemServiceImpl() - { + protected BasicWorkflowItemServiceImpl() { } @Override - public BasicWorkflowItem create(Context context, Item item, Collection collection) throws SQLException, AuthorizeException { - if(findByItem(context, item) != null){ - throw new IllegalArgumentException("Unable to create a workflow item for an item that already has a workflow item."); + public BasicWorkflowItem create(Context context, Item item, Collection collection) + throws SQLException, AuthorizeException { + if (findByItem(context, item) != null) { + throw new IllegalArgumentException( + "Unable to create a workflow item for an item that already has a workflow item."); } BasicWorkflowItem workflowItem = workflowItemDAO.create(context, new BasicWorkflowItem()); workflowItem.setItem(item); @@ -67,20 +70,15 @@ public class BasicWorkflowItemServiceImpl implements BasicWorkflowItemService { public BasicWorkflowItem find(Context context, int id) throws SQLException { BasicWorkflowItem workflowItem = workflowItemDAO.findByID(context, BasicWorkflowItem.class, id); - if (workflowItem == null) - { - if (log.isDebugEnabled()) - { + if (workflowItem == null) { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_workflow_item", - "not_found,workflow_id=" + id)); + "not_found,workflow_id=" + id)); } - } - else - { - if (log.isDebugEnabled()) - { + } else { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_workflow_item", - "workflow_id=" + id)); + "workflow_id=" + id)); } } return workflowItem; @@ -97,7 +95,8 @@ public class BasicWorkflowItemServiceImpl implements BasicWorkflowItemService { } @Override - public void deleteByCollection(Context context, Collection collection) throws SQLException, IOException, AuthorizeException { + public void deleteByCollection(Context context, Collection collection) + throws SQLException, IOException, AuthorizeException { List workflowItems = findByCollection(context, collection); Iterator iterator = workflowItems.iterator(); while (iterator.hasNext()) { @@ -108,7 +107,8 @@ public class BasicWorkflowItemServiceImpl implements BasicWorkflowItemService { } @Override - public void delete(Context context, BasicWorkflowItem workflowItem) throws SQLException, AuthorizeException, IOException { + public void delete(Context context, BasicWorkflowItem workflowItem) + throws SQLException, AuthorizeException, IOException { Item item = workflowItem.getItem(); deleteWrapper(context, workflowItem); itemService.delete(context, item); @@ -135,9 +135,9 @@ public class BasicWorkflowItemServiceImpl implements BasicWorkflowItemService { @Override public void update(Context context, BasicWorkflowItem workflowItem) throws SQLException, AuthorizeException { - // FIXME check auth + // FIXME check auth log.info(LogManager.getHeader(context, "update_workflow_item", - "workflow_item_id=" + workflowItem.getID())); + "workflow_item_id=" + workflowItem.getID())); // Update the item @@ -161,4 +161,11 @@ public class BasicWorkflowItemServiceImpl implements BasicWorkflowItemService { public int countTotal(Context context) throws SQLException { return workflowItemDAO.countRows(context); } + + @Override + public void move(Context context, BasicWorkflowItem inProgressSubmission, Collection fromCollection, + Collection toCollection) { + // TODO not implemented yet + + } } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowServiceImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowServiceImpl.java index a2fba15fef..c20de75ff8 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowServiceImpl.java @@ -7,7 +7,20 @@ */ package org.dspace.workflowbasic; -import org.apache.commons.collections.CollectionUtils; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.UUID; +import javax.mail.MessagingException; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; @@ -42,21 +55,7 @@ import org.dspace.workflowbasic.service.BasicWorkflowService; import org.dspace.workflowbasic.service.TaskListItemService; import org.springframework.beans.factory.annotation.Autowired; -import javax.mail.MessagingException; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import java.util.UUID; - -public class BasicWorkflowServiceImpl implements BasicWorkflowService -{ +public class BasicWorkflowServiceImpl implements BasicWorkflowService { @Autowired(required = true) protected AuthorizeService authorizeService; @@ -81,14 +80,14 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService @Autowired(required = true) protected ConfigurationService configurationService; - protected BasicWorkflowServiceImpl() - { + protected BasicWorkflowServiceImpl() { } - /** Symbolic names of workflow steps. */ - protected final String workflowText[] = - { + /** + * Symbolic names of workflow steps. + */ + protected final String workflowText[] = { "SUBMIT", // 0 "STEP1POOL", // 1 "STEP1", // 2 @@ -102,42 +101,41 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService /* support for 'no notification' */ protected Map noEMail = new HashMap<>(); - /** log4j logger */ + /** + * log4j logger + */ private final Logger log = Logger.getLogger(BasicWorkflowServiceImpl.class); @Override - public int getWorkflowID(String state) - { - for (int i = 0; i < workflowText.length; ++i) - { - if (state.equalsIgnoreCase(workflowText[i])) - { + public int getWorkflowID(String state) { + for (int i = 0; i < workflowText.length; ++i) { + if (state.equalsIgnoreCase(workflowText[i])) { return i; } } return -1; } - + /** * This methods grants the appropriate permissions to reviewers so that they - * can read and edit metadata and read files and edit files if allowed by + * can read and edit metadata and read files and edit files if allowed by * configuration. * In most cases this method must be called within a try-finally-block that * temporary disables the authentication system. This is not done by this * method as it should be done carefully and only in contexts in which * granting the permissions is authorized by some previous checks. - * + * * @param context - * @param wfi While all policies are granted on item, bundle or bitstream - * level, this method takes an workflowitem for convenience and - * uses wfi.getItem() to get the actual item. + * @param wfi While all policies are granted on item, bundle or bitstream + * level, this method takes an workflowitem for convenience and + * uses wfi.getItem() to get the actual item. * @param reviewer EPerson to grant the rights to. * @throws SQLException - * @throws AuthorizeException + * @throws AuthorizeException */ - protected void grantReviewerPolicies(Context context, BasicWorkflowItem wfi, EPerson reviewer) throws SQLException, AuthorizeException - { - if(reviewer == null) { + protected void grantReviewerPolicies(Context context, BasicWorkflowItem wfi, EPerson reviewer) + throws SQLException, AuthorizeException { + if (reviewer == null) { return; } @@ -149,62 +147,64 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService } catch (IndexOutOfBoundsException ex) { originalBundle = null; } - + // grant item level policies - for (int action : new int[] {Constants.READ, Constants.WRITE, Constants.ADD, Constants.REMOVE, Constants.DELETE}) - { + for (int action : + new int[] {Constants.READ, Constants.WRITE, Constants.ADD, Constants.REMOVE, Constants.DELETE}) { authorizeService.addPolicy(context, item, action, reviewer, ResourcePolicy.TYPE_WORKFLOW); } - + // set bitstream and bundle policies - if (originalBundle != null) - { + if (originalBundle != null) { authorizeService.addPolicy(context, originalBundle, Constants.READ, reviewer, ResourcePolicy.TYPE_WORKFLOW); // shall reviewers be able to edit files? boolean editFiles = configurationService.getBooleanProperty("workflow.reviewer.file-edit", false); // if a reviewer should be able to edit bitstreams, we need add // permissions regarding the bundle "ORIGINAL" and its bitstreams - if (editFiles) - { - authorizeService.addPolicy(context, originalBundle, Constants.ADD, reviewer, ResourcePolicy.TYPE_WORKFLOW); - authorizeService.addPolicy(context, originalBundle, Constants.REMOVE, reviewer, ResourcePolicy.TYPE_WORKFLOW); + if (editFiles) { + authorizeService + .addPolicy(context, originalBundle, Constants.ADD, reviewer, ResourcePolicy.TYPE_WORKFLOW); + authorizeService + .addPolicy(context, originalBundle, Constants.REMOVE, reviewer, ResourcePolicy.TYPE_WORKFLOW); // Whenever a new bitstream is added, it inherit the policies of the bundle. // So we need to add all policies newly created bitstreams should get. - authorizeService.addPolicy(context, originalBundle, Constants.WRITE, reviewer, ResourcePolicy.TYPE_WORKFLOW); - authorizeService.addPolicy(context, originalBundle, Constants.DELETE, reviewer, ResourcePolicy.TYPE_WORKFLOW); + authorizeService + .addPolicy(context, originalBundle, Constants.WRITE, reviewer, ResourcePolicy.TYPE_WORKFLOW); + authorizeService + .addPolicy(context, originalBundle, Constants.DELETE, reviewer, ResourcePolicy.TYPE_WORKFLOW); } - for (Bitstream bitstream : originalBundle.getBitstreams()) - { + for (Bitstream bitstream : originalBundle.getBitstreams()) { authorizeService.addPolicy(context, bitstream, Constants.READ, reviewer, ResourcePolicy.TYPE_WORKFLOW); - + // add further rights if reviewer should be able to edit bitstreams - if (editFiles) - { - authorizeService.addPolicy(context, bitstream, Constants.WRITE, reviewer, ResourcePolicy.TYPE_WORKFLOW); - authorizeService.addPolicy(context, bitstream, Constants.DELETE, reviewer, ResourcePolicy.TYPE_WORKFLOW); + if (editFiles) { + authorizeService + .addPolicy(context, bitstream, Constants.WRITE, reviewer, ResourcePolicy.TYPE_WORKFLOW); + authorizeService + .addPolicy(context, bitstream, Constants.DELETE, reviewer, ResourcePolicy.TYPE_WORKFLOW); } } } } - + /** * This methods revokes any permission granted by the basic workflow systems * on the item specified as attribute. At time of writing this method these * permissions will all be granted by - * {@link #grantReviewerPolicies(org.dspace.core.Context, org.dspace.workflowbasic.BasicWorkflowItem, org.dspace.eperson.EPerson)}. + * {@link #grantReviewerPolicies(org.dspace.core.Context, org.dspace.workflowbasic.BasicWorkflowItem, + * org.dspace.eperson.EPerson)}. * In most cases this method must be called within a try-finally-block that * temporary disables the authentication system. This is not done by this * method as it should be done carefully and only in contexts in which * revoking the permissions is authorized by some previous checks. - * + * * @param context * @param item * @throws SQLException - * @throws AuthorizeException + * @throws AuthorizeException */ - protected void revokeReviewerPolicies(Context context, Item item) throws SQLException, AuthorizeException - { + protected void revokeReviewerPolicies(Context context, Item item) throws SQLException, AuthorizeException { // get bundle "ORIGINAL" Bundle originalBundle; try { @@ -212,33 +212,30 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService } catch (IndexOutOfBoundsException ex) { originalBundle = null; } - + // remove bitstream and bundle level policies - if (originalBundle != null) - { + if (originalBundle != null) { // We added policies for Bitstreams of the bundle "original" only - for (Bitstream bitstream : originalBundle.getBitstreams()) - { + for (Bitstream bitstream : originalBundle.getBitstreams()) { authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_WORKFLOW); } - + authorizeService.removeAllPoliciesByDSOAndType(context, originalBundle, ResourcePolicy.TYPE_WORKFLOW); } - + // remove item level policies authorizeService.removeAllPoliciesByDSOAndType(context, item, ResourcePolicy.TYPE_WORKFLOW); } @Override public BasicWorkflowItem start(Context context, WorkspaceItem wsi) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { Item myitem = wsi.getItem(); Collection collection = wsi.getCollection(); log.info(LogManager.getHeader(context, "start_workflow", "workspace_item_id=" - + wsi.getID() + "item_id=" + myitem.getID() + "collection_id=" - + collection.getID())); + + wsi.getID() + "item_id=" + myitem.getID() + "collection_id=" + + collection.getID())); // record the start of the workflow w/provenance message recordStart(context, myitem); @@ -262,8 +259,7 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService @Override public BasicWorkflowItem startWithoutNotify(Context c, WorkspaceItem wsi) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { // make a hash table entry with item ID for no notify // notify code checks no notify hash for item id noEMail.put(wsi.getItem().getID(), Boolean.TRUE); @@ -273,280 +269,265 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService @Override public List getOwnedTasks(Context context, EPerson e) - throws java.sql.SQLException - { + throws java.sql.SQLException { return workflowItemService.findByOwner(context, e); } @Override - public List getPooledTasks(Context context, EPerson e) throws SQLException - { + public List getPooledTasks(Context context, EPerson e) throws SQLException { return workflowItemService.findPooledTasks(context, e); } @Override public void claim(Context context, BasicWorkflowItem workflowItem, EPerson e) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { int taskstate = workflowItem.getState(); - switch (taskstate) - { - case WFSTATE_STEP1POOL: + switch (taskstate) { + case WFSTATE_STEP1POOL: - authorizeService.authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_1, true); - doState(context, workflowItem, WFSTATE_STEP1, e); + authorizeService + .authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_1, true); + doState(context, workflowItem, WFSTATE_STEP1, e); - break; + break; - case WFSTATE_STEP2POOL: + case WFSTATE_STEP2POOL: - authorizeService.authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_2, true); - doState(context, workflowItem, WFSTATE_STEP2, e); + authorizeService + .authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_2, true); + doState(context, workflowItem, WFSTATE_STEP2, e); - break; + break; - case WFSTATE_STEP3POOL: + case WFSTATE_STEP3POOL: - authorizeService.authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_3, true); - doState(context, workflowItem, WFSTATE_STEP3, e); + authorizeService + .authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_3, true); + doState(context, workflowItem, WFSTATE_STEP3, e); - break; + break; - default: - throw new IllegalArgumentException("Workflow Step " + taskstate + " is out of range."); + default: + throw new IllegalArgumentException("Workflow Step " + taskstate + " is out of range."); } log.info(LogManager.getHeader(context, "claim_task", "workflow_item_id=" - + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() - + "collection_id=" + workflowItem.getCollection().getID() - + "newowner_id=" + workflowItem.getOwner().getID() + "old_state=" - + taskstate + "new_state=" + workflowItem.getState())); + + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() + + "collection_id=" + workflowItem.getCollection().getID() + + "newowner_id=" + workflowItem.getOwner().getID() + "old_state=" + + taskstate + "new_state=" + workflowItem.getState())); } @Override public void advance(Context context, BasicWorkflowItem workflowItem, EPerson e) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { advance(context, workflowItem, e, true, true); } @Override public boolean advance(Context context, BasicWorkflowItem workflowItem, EPerson e, - boolean curate, boolean record) - throws SQLException, IOException, AuthorizeException - { + boolean curate, boolean record) + throws SQLException, IOException, AuthorizeException { int taskstate = workflowItem.getState(); boolean archived = false; // perform curation tasks if needed - if (curate && workflowCuratorService.needsCuration(workflowItem)) - { - if (! workflowCuratorService.doCuration(context, workflowItem)) { + if (curate && workflowCuratorService.needsCuration(workflowItem)) { + if (!workflowCuratorService.doCuration(context, workflowItem)) { // don't proceed - either curation tasks queued, or item rejected log.info(LogManager.getHeader(context, "advance_workflow", - "workflow_item_id=" + workflowItem.getID() + ",item_id=" - + workflowItem.getItem().getID() + ",collection_id=" - + workflowItem.getCollection().getID() + ",old_state=" - + taskstate + ",doCuration=false")); + "workflow_item_id=" + workflowItem.getID() + ",item_id=" + + workflowItem.getItem().getID() + ",collection_id=" + + workflowItem.getCollection().getID() + ",old_state=" + + taskstate + ",doCuration=false")); return false; } } - - switch (taskstate) - { - case WFSTATE_SUBMIT: - archived = doState(context, workflowItem, WFSTATE_STEP1POOL, e); - break; + switch (taskstate) { + case WFSTATE_SUBMIT: + archived = doState(context, workflowItem, WFSTATE_STEP1POOL, e); + break; - case WFSTATE_STEP1: - // advance(...) will call itself if no workflow step group exists - // so we need to check permissions only if a workflow step group is - // in place. - if (workflowItem.getCollection().getWorkflowStep1() != null && e != null) - { - authorizeService.authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_1, true); - } - - // Record provenance - if (record) - { - recordApproval(context, workflowItem, e); - } - archived = doState(context, workflowItem, WFSTATE_STEP2POOL, e); + case WFSTATE_STEP1: + // advance(...) will call itself if no workflow step group exists + // so we need to check permissions only if a workflow step group is + // in place. + if (workflowItem.getCollection().getWorkflowStep1() != null && e != null) { + authorizeService + .authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_1, true); + } - break; + // Record provenance + if (record) { + recordApproval(context, workflowItem, e); + } + archived = doState(context, workflowItem, WFSTATE_STEP2POOL, e); + break; - case WFSTATE_STEP2: - // advance(...) will call itself if no workflow step group exists - // so we need to check permissions only if a workflow step group is - // in place. - if (workflowItem.getCollection().getWorkflowStep2() != null && e != null) - { - authorizeService.authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_2, true); - } - - // Record provenance - if (record) - { - recordApproval(context, workflowItem, e); - } - archived = doState(context, workflowItem, WFSTATE_STEP3POOL, e); + case WFSTATE_STEP2: + // advance(...) will call itself if no workflow step group exists + // so we need to check permissions only if a workflow step group is + // in place. + if (workflowItem.getCollection().getWorkflowStep2() != null && e != null) { + authorizeService + .authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_2, true); + } - break; + // Record provenance + if (record) { + recordApproval(context, workflowItem, e); + } + archived = doState(context, workflowItem, WFSTATE_STEP3POOL, e); + break; - case WFSTATE_STEP3: - // advance(...) will call itself if no workflow step group exists - // so we need to check permissions only if a workflow step group is - // in place. - if (workflowItem.getCollection().getWorkflowStep3() != null && e != null) - { - authorizeService.authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_3, true); - } + case WFSTATE_STEP3: + // advance(...) will call itself if no workflow step group exists + // so we need to check permissions only if a workflow step group is + // in place. + if (workflowItem.getCollection().getWorkflowStep3() != null && e != null) { + authorizeService + .authorizeAction(context, e, workflowItem.getCollection(), Constants.WORKFLOW_STEP_3, true); + } - // We don't record approval for editors, since they can't reject, - // and thus didn't actually make a decision - archived = doState(context, workflowItem, WFSTATE_ARCHIVE, e); + // We don't record approval for editors, since they can't reject, + // and thus didn't actually make a decision + archived = doState(context, workflowItem, WFSTATE_ARCHIVE, e); + break; - break; - - // error handling? shouldn't get here + default: + // error handling? shouldn't get here + break; } log.info(LogManager.getHeader(context, "advance_workflow", - "workflow_item_id=" + workflowItem.getID() + ",item_id=" - + workflowItem.getItem().getID() + ",collection_id=" - + workflowItem.getCollection().getID() + ",old_state=" - + taskstate + ",new_state=" + workflowItem.getState())); + "workflow_item_id=" + workflowItem.getID() + ",item_id=" + + workflowItem.getItem().getID() + ",collection_id=" + + workflowItem.getCollection().getID() + ",old_state=" + + taskstate + ",new_state=" + workflowItem.getState())); return archived; } @Override public void unclaim(Context context, BasicWorkflowItem workflowItem, EPerson e) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { int taskstate = workflowItem.getState(); - switch (taskstate) - { - case WFSTATE_STEP1: + switch (taskstate) { + case WFSTATE_STEP1: - doState(context, workflowItem, WFSTATE_STEP1POOL, e); + doState(context, workflowItem, WFSTATE_STEP1POOL, e); - break; + break; - case WFSTATE_STEP2: + case WFSTATE_STEP2: - doState(context, workflowItem, WFSTATE_STEP2POOL, e); + doState(context, workflowItem, WFSTATE_STEP2POOL, e); - break; + break; - case WFSTATE_STEP3: + case WFSTATE_STEP3: - doState(context, workflowItem, WFSTATE_STEP3POOL, e); + doState(context, workflowItem, WFSTATE_STEP3POOL, e); - break; - default: - throw new IllegalStateException("WorkflowItem reach an unknown state."); + break; + default: + throw new IllegalStateException("WorkflowItem reach an unknown state."); } log.info(LogManager.getHeader(context, "unclaim_workflow", - "workflow_item_id=" + workflowItem.getID() + ",item_id=" - + workflowItem.getItem().getID() + ",collection_id=" - + workflowItem.getCollection().getID() + ",old_state=" - + taskstate + ",new_state=" + workflowItem.getState())); + "workflow_item_id=" + workflowItem.getID() + ",item_id=" + + workflowItem.getItem().getID() + ",collection_id=" + + workflowItem.getCollection().getID() + ",old_state=" + + taskstate + ",new_state=" + workflowItem.getState())); } @Override public WorkspaceItem abort(Context context, BasicWorkflowItem workflowItem, EPerson e) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { // authorize a DSpaceActions.ABORT - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( - "You must be an admin to abort a workflow"); + "You must be an admin to abort a workflow"); } // stop workflow regardless of its state taskListItemService.deleteByWorkflowItem(context, workflowItem); log.info(LogManager.getHeader(context, "abort_workflow", "workflow_item_id=" - + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() - + "collection_id=" + workflowItem.getCollection().getID() + "eperson_id=" - + e.getID())); + + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() + + "collection_id=" + workflowItem.getCollection().getID() + "eperson_id=" + + e.getID())); // convert into personal workspace return returnToWorkspace(context, workflowItem); } - protected boolean doState(Context context, BasicWorkflowItem workflowItem, int newstate, - EPerson newowner) throws SQLException, IOException, - AuthorizeException - { + protected boolean doState(Context context, BasicWorkflowItem workflowItem, int newstate, + EPerson newowner) throws SQLException, IOException, + AuthorizeException { Collection collection = workflowItem.getCollection(); //Gather our old data for launching the workflow event int oldState = workflowItem.getState(); - + // in case we don't want to inform reviewers about tasks returned to // the pool by other reviewers, we'll ne to know whether they were owned // before. => keep this information before setting the new owner. EPerson oldOwner = workflowItem.getOwner(); - switch (newstate) - { - case WFSTATE_STEP1POOL: - return pool(context, workflowItem, 1); + switch (newstate) { + case WFSTATE_STEP1POOL: + return pool(context, workflowItem, 1); - case WFSTATE_STEP1: - assignToReviewer(context, workflowItem, 1, newowner); - return false; + case WFSTATE_STEP1: + assignToReviewer(context, workflowItem, 1, newowner); + return false; - case WFSTATE_STEP2POOL: - return pool(context, workflowItem, 2); + case WFSTATE_STEP2POOL: + return pool(context, workflowItem, 2); - case WFSTATE_STEP2: - assignToReviewer(context, workflowItem, 2, newowner); - return false; + case WFSTATE_STEP2: + assignToReviewer(context, workflowItem, 2, newowner); + return false; - case WFSTATE_STEP3POOL: - return pool(context, workflowItem, 3); + case WFSTATE_STEP3POOL: + return pool(context, workflowItem, 3); - case WFSTATE_STEP3: - assignToReviewer(context, workflowItem, 3, newowner); - return false; + case WFSTATE_STEP3: + assignToReviewer(context, workflowItem, 3, newowner); + return false; - case WFSTATE_ARCHIVE: - // put in archive in one transaction - // remove workflow tasks - taskListItemService.deleteByWorkflowItem(context, workflowItem); + case WFSTATE_ARCHIVE: + // put in archive in one transaction + // remove workflow tasks + taskListItemService.deleteByWorkflowItem(context, workflowItem); - collection = workflowItem.getCollection(); + collection = workflowItem.getCollection(); - Item myitem = archive(context, workflowItem); + Item myitem = archive(context, workflowItem); - // now email notification - notifyOfArchive(context, myitem, collection); + // now email notification + notifyOfArchive(context, myitem, collection); - // remove any workflow policies left - try - { - context.turnOffAuthorisationSystem(); - revokeReviewerPolicies(context, myitem); - } finally { - context.restoreAuthSystemState(); - } + // remove any workflow policies left + try { + context.turnOffAuthorisationSystem(); + revokeReviewerPolicies(context, myitem); + } finally { + context.restoreAuthSystemState(); + } - logWorkflowEvent(context, workflowItem.getItem(), workflowItem, context.getCurrentUser(), newstate, newowner, collection, oldState, null); + logWorkflowEvent(context, workflowItem.getItem(), workflowItem, context.getCurrentUser(), newstate, + newowner, collection, oldState, null); - return true; + return true; - default: - throw new IllegalArgumentException("BasicWorkflowService cannot handle workflowItemState " + newstate); + default: + throw new IllegalArgumentException("BasicWorkflowService cannot handle workflowItemState " + newstate); } } @@ -556,20 +537,20 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService * Don't use this method directly. Instead: use {@link #start(Context, WorkspaceItem)} to start a workflow and * {@link #claim(Context, BasicWorkflowItem, EPerson)} as those methods handles the internal states and checks for * the appropriate permissions. - * @param context DSpace context object + * + * @param context DSpace context object * @param workflowItem The item that shall be pooled. - * @param step The step (1-3) of the pool the item should be put to. - * @param newowner The EPerson that should do the review. - * @return True if the item was archived because no reviewers were assigned to any of the following workflow steps, false otherwise. + * @param step The step (1-3) of the pool the item should be put to. + * @param newowner The EPerson that should do the review. + * @return True if the item was archived because no reviewers were assigned to any of the following workflow + * steps, false otherwise. * @throws SQLException * @throws AuthorizeException * @throws IOException * @throws IllegalArgumentException If {@code param} has another value than either 1, 2, or 3. - */ protected void assignToReviewer(Context context, BasicWorkflowItem workflowItem, int step, EPerson newowner) - throws AuthorizeException, SQLException - { + throws AuthorizeException, SQLException { // shortcut to the collection Collection collection = workflowItem.getCollection(); @@ -595,9 +576,8 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // if there is a workflow state group and it contains any members, // then we have to check permissions first if ((collectionService.getWorkflowGroup(collection, step) != null) - && !(groupService.isEmpty(collectionService.getWorkflowGroup(collection, step))) - && newowner != null) - { + && !(groupService.isEmpty(collectionService.getWorkflowGroup(collection, step))) + && newowner != null) { authorizeService.authorizeAction(context, newowner, collection, correspondingAction, true); } @@ -618,27 +598,30 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService workflowItem.setState(newState); workflowItem.setOwner(newowner); - logWorkflowEvent(context, workflowItem.getItem(), workflowItem, context.getCurrentUser(), newState, newowner, collection, oldState, null); + logWorkflowEvent(context, workflowItem.getItem(), workflowItem, context.getCurrentUser(), newState, newowner, + collection, oldState, null); } /** * Helper method that manages state, policies, owner, notifies, tasklistitems and so on whenever an WorkflowItem * should be added to a workflow step pool. Don't use this method directly. Either use * {@link #unclaim(Context, BasicWorkflowItem, EPerson)} if the item is claimed, - * {@link #start(Context, WorkspaceItem)} to start the workflow or {@link #advance(Context, BasicWorkflowItem, EPerson)} + * {@link #start(Context, WorkspaceItem)} to start the workflow or + * {@link #advance(Context, BasicWorkflowItem, EPerson)} * to move an item to the next state. - * @param context DSpace context object + * + * @param context DSpace context object * @param workflowItem The item that shall be pooled. - * @param step The step (1-3) of the pool the item should be put to. - * @return True if the item was archived because no reviewers were assigned to any of the following workflow steps, false otherwise. + * @param step The step (1-3) of the pool the item should be put to. + * @return True if the item was archived because no reviewers were assigned to any of the following workflow + * steps, false otherwise. * @throws SQLException * @throws AuthorizeException * @throws IOException * @throws IllegalArgumentException If {@code param} has another value than either 1, 2, or 3. */ protected boolean pool(Context context, BasicWorkflowItem workflowItem, int step) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { // shortcut to the collection Collection collection = workflowItem.getCollection(); @@ -674,14 +657,12 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // if not, skip to next state Group workflowStepGroup = collectionService.getWorkflowGroup(collection, step); - if ((workflowStepGroup != null) && !(groupService.isEmpty(workflowStepGroup))) - { + if ((workflowStepGroup != null) && !(groupService.isEmpty(workflowStepGroup))) { // set new item state workflowItem.setState(newState); // revoke previously granted reviewer policies and grant read permissions - try - { + try { context.turnOffAuthorisationSystem(); // revoke previously granted policies revokeReviewerPolicies(context, workflowItem.getItem()); @@ -689,19 +670,20 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // JSPUI offers a preview to every task before a reviewer claims it. // So we need to grant permissions in advance, so that all possible reviewers can read the item and all // bitstreams in the bundle "ORIGINAL". - authorizeService.addPolicy(context, workflowItem.getItem(), Constants.READ, workflowStepGroup, ResourcePolicy.TYPE_WORKFLOW); + authorizeService.addPolicy(context, workflowItem.getItem(), Constants.READ, workflowStepGroup, + ResourcePolicy.TYPE_WORKFLOW); Bundle originalBundle; try { originalBundle = itemService.getBundles(workflowItem.getItem(), "ORIGINAL").get(0); } catch (IndexOutOfBoundsException ex) { originalBundle = null; } - if (originalBundle != null) - { - authorizeService.addPolicy(context, originalBundle, Constants.READ, workflowStepGroup, ResourcePolicy.TYPE_WORKFLOW); - for (Bitstream bitstream : originalBundle.getBitstreams()) - { - authorizeService.addPolicy(context, bitstream, Constants.READ, workflowStepGroup, ResourcePolicy.TYPE_WORKFLOW); + if (originalBundle != null) { + authorizeService.addPolicy(context, originalBundle, Constants.READ, workflowStepGroup, + ResourcePolicy.TYPE_WORKFLOW); + for (Bitstream bitstream : originalBundle.getBitstreams()) { + authorizeService.addPolicy(context, bitstream, Constants.READ, workflowStepGroup, + ResourcePolicy.TYPE_WORKFLOW); } } } finally { @@ -716,22 +698,19 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService createTasks(context, workflowItem, epa); if (configurationService.getBooleanProperty("workflow.notify.returned.tasks", true) - || oldState != correspondingState - || oldOwner == null) - { + || oldState != correspondingState + || oldOwner == null) { // email notification notifyGroupOfTask(context, workflowItem, workflowStepGroup, epa); } - logWorkflowEvent(context, workflowItem.getItem(), workflowItem, context.getCurrentUser(), newState, null, collection, oldState, workflowStepGroup); + logWorkflowEvent(context, workflowItem.getItem(), workflowItem, context.getCurrentUser(), newState, null, + collection, oldState, workflowStepGroup); return false; - } - else - { + } else { // no reviewers, skip ahead workflowItem.setState(correspondingState); boolean archived = advance(context, workflowItem, null, true, false); - if (archived) - { + if (archived) { // remove any workflow policies that may have left over try { context.turnOffAuthorisationSystem(); @@ -744,25 +723,29 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService } } - protected void logWorkflowEvent(Context context, Item item, BasicWorkflowItem workflowItem, EPerson actor, int newstate, EPerson newOwner, Collection mycollection, int oldState, Group newOwnerGroup) { - if(newstate == WFSTATE_ARCHIVE || newstate == WFSTATE_STEP1POOL || newstate == WFSTATE_STEP2POOL || newstate == WFSTATE_STEP3POOL){ + protected void logWorkflowEvent(Context context, Item item, BasicWorkflowItem workflowItem, EPerson actor, + int newstate, EPerson newOwner, Collection mycollection, int oldState, + Group newOwnerGroup) { + if (newstate == WFSTATE_ARCHIVE || newstate == WFSTATE_STEP1POOL || newstate == WFSTATE_STEP2POOL || newstate + == WFSTATE_STEP3POOL) { //Clear the newowner variable since this one isn't owned anymore ! newOwner = null; } - UsageWorkflowEvent usageWorkflowEvent = new UsageWorkflowEvent(context, item, workflowItem, workflowText[newstate], workflowText[oldState], mycollection, actor); - if(newOwner != null){ + UsageWorkflowEvent usageWorkflowEvent = new UsageWorkflowEvent(context, item, workflowItem, + workflowText[newstate], workflowText[oldState], + mycollection, actor); + if (newOwner != null) { usageWorkflowEvent.setEpersonOwners(newOwner); } - if(newOwnerGroup != null){ + if (newOwnerGroup != null) { usageWorkflowEvent.setGroupOwners(newOwnerGroup); } DSpaceServicesFactory.getInstance().getEventService().fireEvent(usageWorkflowEvent); } @Override - public String getWorkflowText(int state) - { + public String getWorkflowText(int state) { if (state > -1 && state < workflowText.length) { return workflowText[state]; } @@ -775,34 +758,28 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService * with the relevant collection, added to the search index, and any other * tasks such as assigning dates are performed. * - * @param context - * The relevant DSpace Context. - * @param workflowItem - * which workflow item to archive + * @param context The relevant DSpace Context. + * @param workflowItem which workflow item to archive * @return the fully archived item. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ protected Item archive(Context context, BasicWorkflowItem workflowItem) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { Item item = workflowItem.getItem(); Collection collection = workflowItem.getCollection(); log.info(LogManager.getHeader(context, "archive_item", "workflow_item_id=" - + workflowItem.getID() + "item_id=" + item.getID() + "collection_id=" - + collection.getID())); + + workflowItem.getID() + "item_id=" + item.getID() + "collection_id=" + + collection.getID())); installItemService.installItem(context, workflowItem); // Log the event log.info(LogManager.getHeader(context, "install_item", "workflow_id=" - + workflowItem.getID() + ", item_id=" + item.getID() + "handle=FIXME")); + + workflowItem.getID() + ", item_id=" + item.getID() + "handle=FIXME")); return item; } @@ -810,22 +787,15 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService /** * notify the submitter that the item is archived * - * @param context - * The relevant DSpace Context. - * @param item - * which item was archived - * @param coll - * collection name to display in template - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param context The relevant DSpace Context. + * @param item which item was archived + * @param coll collection name to display in template + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ protected void notifyOfArchive(Context context, Item item, Collection coll) - throws SQLException, IOException - { - try - { + throws SQLException, IOException { + try { // Get submitter EPerson ep = item.getSubmitter(); // Get the Locale @@ -837,14 +807,10 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // Get title String title = item.getName(); - if (StringUtils.isBlank(title)) - { - try - { + if (StringUtils.isBlank(title)) { + try { title = I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled"); - } - catch (MissingResourceException e) - { + } catch (MissingResourceException e) { title = "Untitled"; } } @@ -855,12 +821,10 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService email.addArgument(handleService.getCanonicalForm(handle)); email.send(); - } - catch (MessagingException e) - { + } catch (MessagingException e) { log.warn(LogManager.getHeader(context, "notifyOfArchive", - "cannot email user; item_id=" + item.getID() - + ": " + e.getMessage())); + "cannot email user; item_id=" + item.getID() + + ": " + e.getMessage())); } } @@ -868,22 +832,16 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService * Return the workflow item to the workspace of the submitter. The workflow * item is removed, and a workspace item created. * - * @param c - * Context - * @param wfi - * WorkflowItem to be 'dismantled' + * @param c Context + * @param wfi WorkflowItem to be 'dismantled' * @return the workspace item - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ protected WorkspaceItem returnToWorkspace(Context c, BasicWorkflowItem wfi) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { // Regarding auth: this method is protected. // Authorization should be checked in all public methods calling this one. // FIXME: How should this interact with the workflow system? @@ -899,8 +857,8 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService //myitem.update(); log.info(LogManager.getHeader(c, "return_to_workspace", - "workflow_item_id=" + wfi.getID() + "workspace_item_id=" - + workspaceItem.getID())); + "workflow_item_id=" + wfi.getID() + "workspace_item_id=" + + workspaceItem.getID())); // Now remove the workflow object manually from the database workflowItemService.deleteWrapper(c, wfi); @@ -909,24 +867,26 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService } - @Override - public WorkspaceItem sendWorkflowItemBackSubmission(Context context, BasicWorkflowItem workflowItem, EPerson ePerson, - String provenancePrefix, String rejection_message) throws SQLException, AuthorizeException, - IOException - { + public WorkspaceItem sendWorkflowItemBackSubmission(Context context, BasicWorkflowItem workflowItem, + EPerson ePerson, + String provenancePrefix, String rejection_message) + throws SQLException, AuthorizeException, + IOException { int oldState = workflowItem.getState(); - switch(oldState) - { + switch (oldState) { case WFSTATE_STEP1: - authorizeService.authorizeActionBoolean(context, ePerson, workflowItem.getItem(), Constants.WORKFLOW_STEP_1, true); + authorizeService + .authorizeActionBoolean(context, ePerson, workflowItem.getItem(), Constants.WORKFLOW_STEP_1, true); break; case WFSTATE_STEP2: - authorizeService.authorizeActionBoolean(context, ePerson, workflowItem.getItem(), Constants.WORKFLOW_STEP_2, true); + authorizeService + .authorizeActionBoolean(context, ePerson, workflowItem.getItem(), Constants.WORKFLOW_STEP_2, true); break; case WFSTATE_STEP3: - authorizeService.authorizeActionBoolean(context, ePerson, workflowItem.getItem(), Constants.WORKFLOW_STEP_3, true); + authorizeService + .authorizeActionBoolean(context, ePerson, workflowItem.getItem(), Constants.WORKFLOW_STEP_3, true); break; default: throw new IllegalArgumentException("Workflow Step " + oldState + " is out of range."); @@ -947,10 +907,11 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // Here's what happened String provDescription = "Rejected by " + usersName + ", reason: " - + rejection_message + " on " + now + " (GMT) "; + + rejection_message + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService + .addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); itemService.update(context, myitem); // convert into personal workspace @@ -960,11 +921,12 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService notifyOfReject(context, workflowItem, ePerson, rejection_message); log.info(LogManager.getHeader(context, "reject_workflow", "workflow_item_id=" - + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() - + "collection_id=" + workflowItem.getCollection().getID() + "eperson_id=" - + ePerson.getID())); + + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() + + "collection_id=" + workflowItem.getCollection().getID() + "eperson_id=" + + ePerson.getID())); - logWorkflowEvent(context, wsi.getItem(), workflowItem, ePerson, WFSTATE_SUBMIT, null, wsi.getCollection(), oldState, null); + logWorkflowEvent(context, wsi.getItem(), workflowItem, ePerson, WFSTATE_SUBMIT, null, wsi.getCollection(), + oldState, null); return wsi; } @@ -972,8 +934,7 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // creates workflow tasklist entries for a workflow // for all the given EPeople protected void createTasks(Context c, BasicWorkflowItem wi, List epa) - throws SQLException - { + throws SQLException { // create a tasklist entry for each eperson for (EPerson anEpa : epa) { // can we get away without creating a tasklistitem class? @@ -985,10 +946,8 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // send notices of curation activity @Override public void notifyOfCuration(Context c, BasicWorkflowItem wi, List ePeople, - String taskName, String action, String message) throws SQLException, IOException - { - try - { + String taskName, String action, String message) throws SQLException, IOException { + try { // Get the item title String title = getItemTitle(wi); @@ -998,11 +957,10 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // Get the collection Collection coll = wi.getCollection(); - for (EPerson epa : ePeople) - { + for (EPerson epa : ePeople) { Locale supportedLocale = I18nUtil.getEPersonLocale(epa); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, - "flowtask_notify")); + "flowtask_notify")); email.addArgument(title); email.addArgument(coll.getName()); email.addArgument(submitter); @@ -1012,32 +970,25 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService email.addRecipient(epa.getEmail()); email.send(); } - } - catch (MessagingException e) - { + } catch (MessagingException e) { log.warn(LogManager.getHeader(c, "notifyOfCuration", - "cannot email users of workflow_item_id " + wi.getID() - + ": " + e.getMessage())); + "cannot email users of workflow_item_id " + wi.getID() + + ": " + e.getMessage())); } } protected void notifyGroupOfTask(Context c, BasicWorkflowItem wi, - Group mygroup, List epa) throws SQLException, IOException - { + Group mygroup, List epa) throws SQLException, IOException { // check to see if notification is turned off // and only do it once - delete key after notification has // been suppressed for the first time UUID myID = wi.getItem().getID(); - if (noEMail.containsKey(myID)) - { + if (noEMail.containsKey(myID)) { // suppress email, and delete key noEMail.remove(myID); - } - else - { - try - { + } else { + try { // Get the item title String title = getItemTitle(wi); @@ -1049,8 +1000,7 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService String message = ""; - for (EPerson anEpa : epa) - { + for (EPerson anEpa : epa) { Locale supportedLocale = I18nUtil.getEPersonLocale(anEpa); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "submit_task")); email.addArgument(title); @@ -1058,21 +1008,19 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService email.addArgument(submitter); ResourceBundle messages = ResourceBundle.getBundle("Messages", supportedLocale); - switch (wi.getState()) - { + switch (wi.getState()) { case WFSTATE_STEP1POOL: message = messages.getString("org.dspace.workflow.WorkflowManager.step1"); - break; case WFSTATE_STEP2POOL: message = messages.getString("org.dspace.workflow.WorkflowManager.step2"); - break; case WFSTATE_STEP3POOL: message = messages.getString("org.dspace.workflow.WorkflowManager.step3"); - + break; + default: break; } email.addArgument(message); @@ -1080,30 +1028,25 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService email.addRecipient(anEpa.getEmail()); email.send(); } - } - catch (MessagingException e) - { + } catch (MessagingException e) { String gid = (mygroup != null) ? - String.valueOf(mygroup.getID()) : "none"; + String.valueOf(mygroup.getID()) : "none"; log.warn(LogManager.getHeader(c, "notifyGroupofTask", - "cannot email user group_id=" + gid - + " workflow_item_id=" + wi.getID() - + ": " + e.getMessage())); + "cannot email user group_id=" + gid + + " workflow_item_id=" + wi.getID() + + ": " + e.getMessage())); } } } @Override - public String getMyDSpaceLink() - { + public String getMyDSpaceLink() { return configurationService.getProperty("dspace.url") + "/mydspace"; } protected void notifyOfReject(Context context, BasicWorkflowItem workflowItem, EPerson e, - String reason) - { - try - { + String reason) { + try { // Get the item title String title = getItemTitle(workflowItem); @@ -1113,7 +1056,7 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // Get rejector's name String rejector = getEPersonName(e); Locale supportedLocale = I18nUtil.getEPersonLocale(e); - Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale,"submit_reject")); + Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "submit_reject")); email.addRecipient(workflowItem.getSubmitter().getEmail()); email.addArgument(title); @@ -1123,58 +1066,47 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService email.addArgument(getMyDSpaceLink()); email.send(); - } - catch (RuntimeException re) - { + } catch (RuntimeException re) { // log this email error log.warn(LogManager.getHeader(context, "notify_of_reject", - "cannot email user eperson_id=" + e.getID() - + " eperson_email=" + e.getEmail() - + " workflow_item_id=" + workflowItem.getID() - + ": " + re.getMessage())); + "cannot email user eperson_id=" + e.getID() + + " eperson_email=" + e.getEmail() + + " workflow_item_id=" + workflowItem.getID() + + ": " + re.getMessage())); throw re; - } - catch (Exception ex) - { + } catch (Exception ex) { // log this email error log.warn(LogManager.getHeader(context, "notify_of_reject", - "cannot email user eperson_id=" + e.getID() - + " eperson_email=" + e.getEmail() - + " workflow_item_id=" + workflowItem.getID() - + ": " + ex.getMessage())); + "cannot email user eperson_id=" + e.getID() + + " eperson_email=" + e.getEmail() + + " workflow_item_id=" + workflowItem.getID() + + ": " + ex.getMessage())); } } @Override - public String getItemTitle(BasicWorkflowItem wi) throws SQLException - { + public String getItemTitle(BasicWorkflowItem wi) throws SQLException { Item myitem = wi.getItem(); String title = myitem.getName(); // only return the first element, or "Untitled" - if (StringUtils.isNotBlank(title)) - { + if (StringUtils.isNotBlank(title)) { return title; - } - else - { + } else { return I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled "); } } @Override - public String getSubmitterName(BasicWorkflowItem wi) throws SQLException - { + public String getSubmitterName(BasicWorkflowItem wi) throws SQLException { EPerson e = wi.getSubmitter(); return getEPersonName(e); } - protected String getEPersonName(EPerson e) throws SQLException - { - if (e == null) - { + protected String getEPersonName(EPerson e) throws SQLException { + if (e == null) { return "Unknown"; } String submitter = e.getFullName(); @@ -1186,8 +1118,7 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // Record approval provenance statement protected void recordApproval(Context context, BasicWorkflowItem workflowItem, EPerson e) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { Item item = workflowItem.getItem(); // Get user's name + email address @@ -1198,49 +1129,48 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService // Here's what happened String provDescription = "Approved for entry into archive by " - + usersName + " on " + now + " (GMT) "; + + usersName + " on " + now + " (GMT) "; // add bitstream descriptions (name, size, checksums) provDescription += installItemService.getBitstreamProvenanceMessage(context, item); // Add to item as a DC field - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService + .addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); itemService.update(context, item); } // Create workflow start provenance message protected void recordStart(Context context, Item myitem) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { // get date DCDate now = DCDate.getCurrent(); // Create provenance description String provmessage; - if (myitem.getSubmitter() != null) - { + if (myitem.getSubmitter() != null) { provmessage = "Submitted by " + myitem.getSubmitter().getFullName() - + " (" + myitem.getSubmitter().getEmail() + ") on " - + now.toString() + "\n"; - } - else - // null submitter - { + + " (" + myitem.getSubmitter().getEmail() + ") on " + + now.toString() + "\n"; + } else { + // else, null submitter provmessage = "Submitted by unknown (probably automated) on" - + now.toString() + "\n"; + + now.toString() + "\n"; } // add sizes and checksums of bitstreams provmessage += installItemService.getBitstreamProvenanceMessage(context, myitem); // Add message to the DC - itemService.addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provmessage); + itemService + .addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provmessage); itemService.update(context, myitem); } @Override - public void deleteCollection(Context context, Collection collection) throws SQLException, IOException, AuthorizeException { + public void deleteCollection(Context context, Collection collection) + throws SQLException, IOException, AuthorizeException { authorizeService.authorizeAction(context, collection, Constants.WRITE); collection.setWorkflowGroup(context, 1, null); collection.setWorkflowGroup(context, 2, null); @@ -1252,38 +1182,35 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService public List getEPersonDeleteConstraints(Context context, EPerson ePerson) throws SQLException { List resultList = new ArrayList<>(); List workflowItems = workflowItemService.findByOwner(context, ePerson); - if(CollectionUtils.isNotEmpty(workflowItems)) - { + if (CollectionUtils.isNotEmpty(workflowItems)) { resultList.add("workflowitem"); } List taskListItems = taskListItemService.findByEPerson(context, ePerson); - if(CollectionUtils.isNotEmpty(taskListItems)) - { + if (CollectionUtils.isNotEmpty(taskListItems)) { resultList.add("tasklistitem"); } return resultList; } @Override - public Group getWorkflowRoleGroup(Context context, Collection collection, String roleName, Group roleGroup) throws SQLException, AuthorizeException { - if ("WF_STEP1".equals(roleName)) - { + public Group getWorkflowRoleGroup(Context context, Collection collection, String roleName, Group roleGroup) + throws SQLException, AuthorizeException { + if ("WF_STEP1".equals(roleName)) { roleGroup = collection.getWorkflowStep1(); - if (roleGroup == null) + if (roleGroup == null) { roleGroup = collectionService.createWorkflowGroup(context, collection, 1); + } - } - else if ("WF_STEP2".equals(roleName)) - { + } else if ("WF_STEP2".equals(roleName)) { roleGroup = collection.getWorkflowStep2(); - if (roleGroup == null) + if (roleGroup == null) { roleGroup = collectionService.createWorkflowGroup(context, collection, 2); - } - else if ("WF_STEP3".equals(roleName)) - { + } + } else if ("WF_STEP3".equals(roleName)) { roleGroup = collection.getWorkflowStep3(); - if (roleGroup == null) + if (roleGroup == null) { roleGroup = collectionService.createWorkflowGroup(context, collection, 3); + } } return roleGroup; diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/TaskListItem.java b/dspace-api/src/main/java/org/dspace/workflowbasic/TaskListItem.java index 3a70f6edf0..82a9438f68 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/TaskListItem.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/TaskListItem.java @@ -7,12 +7,21 @@ */ package org.dspace.workflowbasic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.dspace.eperson.EPerson; -import javax.persistence.*; - /** * Database entity representation of the TaskListItem table * @@ -24,8 +33,8 @@ public class TaskListItem implements ReloadableEntity { @Id @Column(name = "tasklist_id", unique = true, nullable = false) - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="tasklistitem_seq") - @SequenceGenerator(name="tasklistitem_seq", sequenceName="tasklistitem_seq", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tasklistitem_seq") + @SequenceGenerator(name = "tasklistitem_seq", sequenceName = "tasklistitem_seq", allocationSize = 1) private int taskListItemId; @ManyToOne(fetch = FetchType.LAZY) @@ -39,10 +48,8 @@ public class TaskListItem implements ReloadableEntity { /** * Protected constructor, create object using: * {@link org.dspace.workflowbasic.service.TaskListItemService#create(Context, BasicWorkflowItem, EPerson)} - * */ - protected TaskListItem() - { + protected TaskListItem() { } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/TaskListItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/TaskListItemServiceImpl.java index 94ff2ea5f1..d064600191 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/TaskListItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/TaskListItemServiceImpl.java @@ -7,15 +7,15 @@ */ package org.dspace.workflowbasic; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflowbasic.dao.TaskListItemDAO; import org.dspace.workflowbasic.service.TaskListItemService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.List; - /** * Service implementation for the TaskListItem object. * This class is responsible for all business logic calls for the TaskListItem object and is autowired by spring. @@ -28,8 +28,7 @@ public class TaskListItemServiceImpl implements TaskListItemService { @Autowired(required = true) protected TaskListItemDAO taskListItemDAO; - protected TaskListItemServiceImpl() - { + protected TaskListItemServiceImpl() { } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/BasicWorkflowItemDAO.java b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/BasicWorkflowItemDAO.java index 8a29b61199..b8540d98fb 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/BasicWorkflowItemDAO.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/BasicWorkflowItemDAO.java @@ -7,6 +7,9 @@ */ package org.dspace.workflowbasic.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.core.Context; @@ -14,12 +17,10 @@ import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; import org.dspace.workflowbasic.BasicWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the BasicWorkflowItem object. - * The implementation of this class is responsible for all database calls for the BasicWorkflowItem object and is autowired by spring + * The implementation of this class is responsible for all database calls for the BasicWorkflowItem object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/TaskListItemDAO.java b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/TaskListItemDAO.java index 10e0663ceb..b09cac72e0 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/TaskListItemDAO.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/TaskListItemDAO.java @@ -7,18 +7,19 @@ */ package org.dspace.workflowbasic.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; import org.dspace.workflowbasic.BasicWorkflowItem; import org.dspace.workflowbasic.TaskListItem; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the TaskListItem object. - * The implementation of this class is responsible for all database calls for the TaskListItem object and is autowired by spring + * The implementation of this class is responsible for all database calls for the TaskListItem object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/BasicWorkflowItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/BasicWorkflowItemDAOImpl.java index d241b3a013..d3ae4ba884 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/BasicWorkflowItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/BasicWorkflowItemDAOImpl.java @@ -7,20 +7,24 @@ */ package org.dspace.workflowbasic.dao.impl; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; + import org.dspace.content.Collection; import org.dspace.content.Item; -import org.dspace.core.Context; +import org.dspace.content.Item_; import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflowbasic.BasicWorkflowItem; +import org.dspace.workflowbasic.BasicWorkflowItem_; import org.dspace.workflowbasic.dao.BasicWorkflowItemDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the BasicWorkflowItem object. @@ -29,45 +33,56 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class BasicWorkflowItemDAOImpl extends AbstractHibernateDAO implements BasicWorkflowItemDAO -{ - protected BasicWorkflowItemDAOImpl() - { +public class BasicWorkflowItemDAOImpl extends AbstractHibernateDAO implements BasicWorkflowItemDAO { + protected BasicWorkflowItemDAOImpl() { super(); } @Override public BasicWorkflowItem findByItem(Context context, Item i) throws SQLException { - Criteria criteria = createCriteria(context, BasicWorkflowItem.class); - criteria.add(Restrictions.eq("item", i)); - // Look for the unique WorkflowItem entry where 'item_id' references this item - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BasicWorkflowItem.class); + Root basicWorkflowItemRoot = criteriaQuery.from(BasicWorkflowItem.class); + criteriaQuery.select(basicWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(basicWorkflowItemRoot.get(BasicWorkflowItem_.item), i)); + return uniqueResult(context, criteriaQuery, false, BasicWorkflowItem.class, -1, -1); } @Override - public List findBySubmitter(Context context, EPerson ep) throws SQLException - { - Criteria criteria = createCriteria(context, BasicWorkflowItem.class); - criteria.createAlias("item", "i"); - criteria.add(Restrictions.eq("i.submitter", ep)); - criteria.addOrder(Order.asc("workflowitemId")); - return list(criteria); + public List findBySubmitter(Context context, EPerson ep) throws SQLException { + + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BasicWorkflowItem.class); + Root basicWorkflowItemRoot = criteriaQuery.from(BasicWorkflowItem.class); + Join join = basicWorkflowItemRoot.join("item"); + criteriaQuery.select(basicWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(join.get(Item_.submitter), ep)); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(basicWorkflowItemRoot.get(BasicWorkflowItem_.workflowitemId))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, BasicWorkflowItem.class, -1, -1); } @Override - public List findByCollection(Context context, Collection c) throws SQLException - { - Criteria criteria = createCriteria(context, BasicWorkflowItem.class); - criteria.add(Restrictions.eq("collection", c)); - return list(criteria); + public List findByCollection(Context context, Collection c) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BasicWorkflowItem.class); + Root basicWorkflowItemRoot = criteriaQuery.from(BasicWorkflowItem.class); + criteriaQuery.select(basicWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(basicWorkflowItemRoot.get(BasicWorkflowItem_.collection), c)); + return list(context, criteriaQuery, false, BasicWorkflowItem.class, -1, -1); } @Override - public List findByPooledTasks(Context context, EPerson ePerson) throws SQLException - { - String queryString = "select wf from TaskListItem as tli join tli.workflowItem wf where tli.ePerson = :eperson ORDER BY wf.workflowitemId"; + public List findByPooledTasks(Context context, EPerson ePerson) throws SQLException { + String queryString = "select wf from TaskListItem as tli join tli.workflowItem wf where tli.ePerson = " + + ":eperson ORDER BY wf.workflowitemId"; Query query = createQuery(context, queryString); query.setParameter("eperson", ePerson); return list(query); @@ -75,9 +90,12 @@ public class BasicWorkflowItemDAOImpl extends AbstractHibernateDAO findByOwner(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, BasicWorkflowItem.class); - criteria.add(Restrictions.eq("owner", ePerson)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BasicWorkflowItem.class); + Root basicWorkflowItemRoot = criteriaQuery.from(BasicWorkflowItem.class); + criteriaQuery.select(basicWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(basicWorkflowItemRoot.get(BasicWorkflowItem_.owner), ePerson)); + return list(context, criteriaQuery, false, BasicWorkflowItem.class, -1, -1); } @Override diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/TaskListItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/TaskListItemDAOImpl.java index 5240cc4275..ec92faec03 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/TaskListItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/TaskListItemDAOImpl.java @@ -7,18 +7,20 @@ */ package org.dspace.workflowbasic.dao.impl; -import org.dspace.core.Context; +import java.sql.SQLException; +import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflowbasic.BasicWorkflowItem; import org.dspace.workflowbasic.TaskListItem; +import org.dspace.workflowbasic.TaskListItem_; import org.dspace.workflowbasic.dao.TaskListItemDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the TaskListItem object. @@ -27,10 +29,8 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class TaskListItemDAOImpl extends AbstractHibernateDAO implements TaskListItemDAO -{ - protected TaskListItemDAOImpl() - { +public class TaskListItemDAOImpl extends AbstractHibernateDAO implements TaskListItemDAO { + protected TaskListItemDAOImpl() { super(); } @@ -44,8 +44,11 @@ public class TaskListItemDAOImpl extends AbstractHibernateDAO impl @Override public List findByEPerson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, TaskListItem.class); - criteria.add(Restrictions.eq("ePerson", ePerson)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, TaskListItem.class); + Root taskListItemRoot = criteriaQuery.from(TaskListItem.class); + criteriaQuery.select(taskListItemRoot); + criteriaQuery.where(criteriaBuilder.equal(taskListItemRoot.get(TaskListItem_.ePerson), ePerson)); + return list(context, criteriaQuery, false, TaskListItem.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/factory/BasicWorkflowServiceFactory.java b/dspace-api/src/main/java/org/dspace/workflowbasic/factory/BasicWorkflowServiceFactory.java index 63c5897e52..22e5766ab5 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/factory/BasicWorkflowServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/factory/BasicWorkflowServiceFactory.java @@ -14,7 +14,8 @@ import org.dspace.workflowbasic.service.BasicWorkflowService; import org.dspace.workflowbasic.service.TaskListItemService; /** - * Abstract factory to get services for the workflowbasic package, use BasicWorkflowServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the workflowbasic package, use BasicWorkflowServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -26,8 +27,8 @@ public abstract class BasicWorkflowServiceFactory extends WorkflowServiceFactory public abstract TaskListItemService getTaskListItemService(); - public static BasicWorkflowServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("workflowServiceFactory", BasicWorkflowServiceFactory.class); + public static BasicWorkflowServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("workflowServiceFactory", BasicWorkflowServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/factory/BasicWorkflowServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/factory/BasicWorkflowServiceFactoryImpl.java index 79e7b1a747..839bdff3cc 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/factory/BasicWorkflowServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/factory/BasicWorkflowServiceFactoryImpl.java @@ -15,7 +15,8 @@ import org.dspace.workflowbasic.service.TaskListItemService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the workflowbasic package, use BasicWorkflowServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the workflowbasic package, use BasicWorkflowServiceFactory.getInstance + * () to retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/service/BasicWorkflowItemService.java b/dspace-api/src/main/java/org/dspace/workflowbasic/service/BasicWorkflowItemService.java index 2ae77efc0a..9d0e8f82fd 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/service/BasicWorkflowItemService.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/service/BasicWorkflowItemService.java @@ -7,34 +7,32 @@ */ package org.dspace.workflowbasic.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflow.WorkflowItemService; import org.dspace.workflowbasic.BasicWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the BasicWorkflowItem object. - * The implementation of this class is responsible for all business logic calls for the BasicWorkflowItem object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the BasicWorkflowItem object and + * is autowired by spring * * @author kevinvandevelde at atmire.com */ -public interface BasicWorkflowItemService extends WorkflowItemService -{ +public interface BasicWorkflowItemService extends WorkflowItemService { public List findPooledTasks(Context context, EPerson ePerson) throws SQLException; /** * Retrieve the list of BasicWorkflowItems that the given EPerson is owner of (owner == claimed for review) - * @param context - * The relevant DSpace Context. - * @param ePerson - * The DSpace EPerson object. + * + * @param context The relevant DSpace Context. + * @param ePerson The DSpace EPerson object. * @return a list of BasicWorkflowItem objects - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List findByOwner(Context context, EPerson ePerson) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/service/BasicWorkflowService.java b/dspace-api/src/main/java/org/dspace/workflowbasic/service/BasicWorkflowService.java index f26af1a893..c1027b85f4 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/service/BasicWorkflowService.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/service/BasicWorkflowService.java @@ -7,16 +7,16 @@ */ package org.dspace.workflowbasic.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflow.WorkflowService; import org.dspace.workflowbasic.BasicWorkflowItem; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * Workflow state machine * @@ -44,37 +44,38 @@ import java.util.List; * getStateEPeople( WorkflowItem wi, int state ) could return people affected by * the item's current state. */ -public interface BasicWorkflowService extends WorkflowService{ +public interface BasicWorkflowService extends WorkflowService { // states to store in WorkflowItem for the GUI to report on // fits our current set of workflow states (stored in WorkflowItem.state) public static final int WFSTATE_SUBMIT = 0; // hmm, probably don't need public static final int WFSTATE_STEP1POOL = 1; // waiting for a reviewer to - // claim it + // claim it public static final int WFSTATE_STEP1 = 2; // task - reviewer has claimed it public static final int WFSTATE_STEP2POOL = 3; // waiting for an admin to - // claim it + // claim it public static final int WFSTATE_STEP2 = 4; // task - admin has claimed item public static final int WFSTATE_STEP3POOL = 5; // waiting for an editor to - // claim it + // claim it public static final int WFSTATE_STEP3 = 6; // task - editor has claimed the - // item + // item public static final int WFSTATE_ARCHIVE = 7; // probably don't need this one - // either + // either /** * Translate symbolic name of workflow state into number. * The name is case-insensitive. Returns -1 when name cannot * be matched. + * * @param state symbolic name of workflow state, must be one of - * the elements of workflowText array. + * the elements of workflowText array. * @return numeric workflow state or -1 for error. */ public int getWorkflowID(String state); @@ -84,50 +85,38 @@ public interface BasicWorkflowService extends WorkflowService * claimed and owned by an EPerson. The GUI displays this info on the * MyDSpace page. * - * @param context - * The relevant DSpace Context. - * @param e - * The EPerson we want to fetch owned tasks for. + * @param context The relevant DSpace Context. + * @param e The EPerson we want to fetch owned tasks for. * @return list of basic workflow items - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List getOwnedTasks(Context context, EPerson e) - throws java.sql.SQLException; + throws java.sql.SQLException; /** * getPooledTasks() returns a List of WorkflowItems an EPerson could claim * (as a reviewer, etc.) for display on a user's MyDSpace page. * - * @param context - * The relevant DSpace Context. - * @param e - * The Eperson we want to fetch the pooled tasks for. + * @param context The relevant DSpace Context. + * @param e The Eperson we want to fetch the pooled tasks for. * @return list of basic workflow items - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public List getPooledTasks(Context context, EPerson e) throws SQLException; /** * claim() claims a workflow task for an EPerson * - * @param context - * The relevant DSpace Context. - * @param workflowItem - * WorkflowItem to do the claim on - * @param e - * The EPerson doing the claim - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param workflowItem WorkflowItem to do the claim on + * @param e The EPerson doing the claim + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void claim(Context context, BasicWorkflowItem workflowItem, EPerson e) - throws SQLException, IOException, AuthorizeException; + throws SQLException, IOException, AuthorizeException; /** @@ -137,22 +126,16 @@ public interface BasicWorkflowService extends WorkflowService * call the archive() method to put it in the archive, and email notify the * submitter of a successful submission * - * @param context - * The relevant DSpace Context. - * @param workflowItem - * WorkflowItem do do the approval on - * @param e - * EPerson doing the approval - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context The relevant DSpace Context. + * @param workflowItem WorkflowItem do do the approval on + * @param e EPerson doing the approval + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void advance(Context context, BasicWorkflowItem workflowItem, EPerson e) - throws SQLException, IOException, AuthorizeException; + throws SQLException, IOException, AuthorizeException; /** * advance() sends an item forward in the workflow (reviewers, @@ -161,48 +144,34 @@ public interface BasicWorkflowService extends WorkflowService * call the archive() method to put it in the archive, and email notify the * submitter of a successful submission * - * @param context - * The relevant DSpace Context. - * @param workflowItem - * WorkflowItem do do the approval on - * @param e - * EPerson doing the approval - * @param curate - * boolean indicating whether curation tasks should be done - * @param record - * boolean indicating whether to record action + * @param context The relevant DSpace Context. + * @param workflowItem WorkflowItem do do the approval on + * @param e EPerson doing the approval + * @param curate boolean indicating whether curation tasks should be done + * @param record boolean indicating whether to record action * @return true if the item was successfully archived - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public boolean advance(Context context, BasicWorkflowItem workflowItem, EPerson e, - boolean curate, boolean record) - throws SQLException, IOException, AuthorizeException; + boolean curate, boolean record) + throws SQLException, IOException, AuthorizeException; /** * unclaim() returns an owned task/item to the pool * - * @param context - * Context - * @param workflowItem - * WorkflowItem to operate on - * @param e - * EPerson doing the operation - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param context Context + * @param workflowItem WorkflowItem to operate on + * @param e EPerson doing the operation + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ public void unclaim(Context context, BasicWorkflowItem workflowItem, EPerson e) - throws SQLException, IOException, AuthorizeException; + throws SQLException, IOException, AuthorizeException; /** * Get the text representing the given workflow state @@ -213,27 +182,25 @@ public interface BasicWorkflowService extends WorkflowService public String getWorkflowText(int state); - // send notices of curation activity + // send notices of curation activity public void notifyOfCuration(Context c, BasicWorkflowItem wi, List ePeople, - String taskName, String action, String message) throws SQLException, IOException; + String taskName, String action, String message) throws SQLException, IOException; /** * get the title of the item in this workflow * - * @param wi the workflow item object + * @param wi the workflow item object * @return item title - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public String getItemTitle(BasicWorkflowItem wi) throws SQLException; /** * get the name of the eperson who started this workflow * - * @param wi the workflow item + * @param wi the workflow item * @return submitter's name - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public String getSubmitterName(BasicWorkflowItem wi) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/service/TaskListItemService.java b/dspace-api/src/main/java/org/dspace/workflowbasic/service/TaskListItemService.java index bea5e2de4d..4ce605f87f 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/service/TaskListItemService.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/service/TaskListItemService.java @@ -7,17 +7,18 @@ */ package org.dspace.workflowbasic.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflowbasic.BasicWorkflowItem; import org.dspace.workflowbasic.TaskListItem; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the TaskListItem object. - * The implementation of this class is responsible for all business logic calls for the TaskListItem object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the TaskListItem object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/Role.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/Role.java index 4cbeed6abc..3c137179eb 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/Role.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/Role.java @@ -7,19 +7,21 @@ */ package org.dspace.xmlworkflow; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.GroupService; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; -import org.dspace.xmlworkflow.storedcomponents.*; +import org.dspace.xmlworkflow.storedcomponents.CollectionRole; +import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService; import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; -import java.sql.SQLException; -import java.util.List; - /** * The role that is responsible for a certain step * Can either be on a group in the repo, or a collection group @@ -33,21 +35,23 @@ import java.util.List; public class Role { private GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - private CollectionRoleService collectionRoleService = XmlWorkflowServiceFactory.getInstance().getCollectionRoleService(); - private WorkflowItemRoleService workflowItemRoleService = XmlWorkflowServiceFactory.getInstance().getWorkflowItemRoleService(); + private CollectionRoleService collectionRoleService = XmlWorkflowServiceFactory.getInstance() + .getCollectionRoleService(); + private WorkflowItemRoleService workflowItemRoleService = XmlWorkflowServiceFactory.getInstance() + .getWorkflowItemRoleService(); private String id; private String name; private String description; private boolean isInternal; private Scope scope; - public static enum Scope{ + public static enum Scope { REPOSITORY, COLLECTION, ITEM } - public Role(String id, String name, String description, boolean isInternal, Scope scope){ + public Role(String id, String name, String description, boolean isInternal, Scope scope) { this.id = id; this.name = name; this.description = description; @@ -78,35 +82,36 @@ public class Role { } public RoleMembers getMembers(Context context, XmlWorkflowItem wfi) throws SQLException { - if(scope == Scope.REPOSITORY){ + if (scope == Scope.REPOSITORY) { Group group = groupService.findByName(context, name); - if(group == null) + if (group == null) { return new RoleMembers(); - else{ - RoleMembers assignees = new RoleMembers(); + } else { + RoleMembers assignees = new RoleMembers(); assignees.addGroup(group); return assignees; } - } else - if(scope == Scope.COLLECTION){ - CollectionRole collectionRole = collectionRoleService.find(context,wfi.getCollection(),id); - if(collectionRole != null){ - RoleMembers assignees = new RoleMembers(); + } else if (scope == Scope.COLLECTION) { + CollectionRole collectionRole = collectionRoleService.find(context, wfi.getCollection(), id); + if (collectionRole != null) { + RoleMembers assignees = new RoleMembers(); assignees.addGroup(collectionRole.getGroup()); return assignees; } return new RoleMembers(); - }else{ + } else { List roles = workflowItemRoleService.find(context, wfi, id); RoleMembers assignees = new RoleMembers(); - for (WorkflowItemRole itemRole : roles){ + for (WorkflowItemRole itemRole : roles) { EPerson user = itemRole.getEPerson(); - if(user != null) + if (user != null) { assignees.addEPerson(user); + } Group group = itemRole.getGroup(); - if(group != null) + if (group != null) { assignees.addGroup(group); + } } return assignees; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/RoleMembers.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/RoleMembers.java index cbb307bca9..39e3110d63 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/RoleMembers.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/RoleMembers.java @@ -7,21 +7,21 @@ */ package org.dspace.xmlworkflow; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.UUID; + import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.GroupService; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.UUID; - /** * The members from a role, can either * contains a list of epersons or groups - * + * * @author Bram De Schouwer (bram.deschouwer at dot com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -33,37 +33,42 @@ public class RoleMembers { private ArrayList groups; private ArrayList epersons; - public RoleMembers(){ + public RoleMembers() { this.groups = new ArrayList<>(); this.epersons = new ArrayList<>(); } - public ArrayList getGroups(){ + public ArrayList getGroups() { return groups; } - public ArrayList getEPersons(){ + + public ArrayList getEPersons() { return epersons; } - public void addGroup(Group group){ + public void addGroup(Group group) { groups.add(group); } - public void addEPerson(EPerson eperson){ + + public void addEPerson(EPerson eperson) { epersons.add(eperson); } - public void removeEperson(EPerson epersonToRemove){ - for(EPerson eperson: epersons){ - if(eperson.equals(epersonToRemove)) + + public void removeEperson(EPerson epersonToRemove) { + for (EPerson eperson : epersons) { + if (eperson.equals(epersonToRemove)) { epersons.remove(eperson); + } } } + public ArrayList getAllUniqueMembers(Context context) throws SQLException { HashMap epersonsMap = new HashMap(); - for(EPerson eperson: epersons){ + for (EPerson eperson : epersons) { epersonsMap.put(eperson.getID(), eperson); } - for(Group group: groups){ - for(EPerson eperson: groupService.allMembers(context, group)){ + for (Group group : groups) { + for (EPerson eperson : groupService.allMembers(context, group)) { epersonsMap.put(eperson.getID(), eperson); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowConfigurationException.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowConfigurationException.java index 5cdb66bbe3..5c2e1af487 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowConfigurationException.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowConfigurationException.java @@ -15,15 +15,15 @@ package org.dspace.xmlworkflow; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class WorkflowConfigurationException extends Exception{ +public class WorkflowConfigurationException extends Exception { private String error; - public WorkflowConfigurationException(String error){ + public WorkflowConfigurationException(String error) { this.error = error; } - public String toString(){ + public String toString() { return this.error; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowRequirementsServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowRequirementsServiceImpl.java index 8c2eeb6abd..c7cb8f05d4 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowRequirementsServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowRequirementsServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.xmlworkflow; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.service.ItemService; import org.dspace.core.Context; @@ -16,17 +21,14 @@ import org.dspace.xmlworkflow.service.WorkflowRequirementsService; import org.dspace.xmlworkflow.service.XmlWorkflowService; import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.Workflow; -import org.dspace.xmlworkflow.storedcomponents.*; +import org.dspace.xmlworkflow.storedcomponents.InProgressUser; +import org.dspace.xmlworkflow.storedcomponents.PoolTask; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService; import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService; import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * A class that contains utililty methods related to the workflow * The adding/removing from claimed users and ensuring that @@ -53,17 +55,17 @@ public class WorkflowRequirementsServiceImpl implements WorkflowRequirementsServ @Autowired(required = true) protected XmlWorkflowService xmlWorkflowService; - protected WorkflowRequirementsServiceImpl() - { + protected WorkflowRequirementsServiceImpl() { } @Override - public void addClaimedUser(Context context, XmlWorkflowItem wfi, Step step, EPerson user) throws SQLException, AuthorizeException, IOException { + public void addClaimedUser(Context context, XmlWorkflowItem wfi, Step step, EPerson user) + throws SQLException, AuthorizeException, IOException { //Make sure we delete the pooled task for our current user if the task is not a group pooltask - PoolTask task = poolTaskService.findByWorkflowIdAndEPerson(context,wfi,user); - if(task != null && task.getEperson() != null){ + PoolTask task = poolTaskService.findByWorkflowIdAndEPerson(context, wfi, user); + if (task != null && task.getEperson() != null) { xmlWorkflowService.deletePooledTask(context, wfi, task); } @@ -76,9 +78,10 @@ public class WorkflowRequirementsServiceImpl implements WorkflowRequirementsServ //Make sure the user has the necessary rights to update the item after the tasks is removed from the pool xmlWorkflowService.grantUserAllItemPolicies(context, wfi.getItem(), user); - int totalUsers = inProgressUserService.getNumberOfInProgressUsers(context, wfi) + inProgressUserService.getNumberOfFinishedUsers(context, wfi); + int totalUsers = inProgressUserService.getNumberOfInProgressUsers(context, wfi) + inProgressUserService + .getNumberOfFinishedUsers(context, wfi); - if(totalUsers == step.getRequiredUsers()){ + if (totalUsers == step.getRequiredUsers()) { //If enough users have claimed/finished this step then remove the tasks xmlWorkflowService.deleteAllPooledTasks(context, wfi); } @@ -87,9 +90,11 @@ public class WorkflowRequirementsServiceImpl implements WorkflowRequirementsServ } @Override - public void removeClaimedUser(Context context, XmlWorkflowItem wfi, EPerson user, String stepID) throws SQLException, IOException, WorkflowConfigurationException, AuthorizeException { + public void removeClaimedUser(Context context, XmlWorkflowItem wfi, EPerson user, String stepID) + throws SQLException, IOException, WorkflowConfigurationException, AuthorizeException { //Check if we had reached our max number @ this moment - int totalUsers = inProgressUserService.getNumberOfInProgressUsers(context, wfi) + inProgressUserService.getNumberOfFinishedUsers(context, wfi); + int totalUsers = inProgressUserService.getNumberOfInProgressUsers(context, wfi) + inProgressUserService + .getNumberOfFinishedUsers(context, wfi); //Then remove the current user from the inProgressUsers inProgressUserService.delete(context, inProgressUserService.findByWorkflowItemAndEPerson(context, wfi, user)); @@ -102,7 +107,7 @@ public class WorkflowRequirementsServiceImpl implements WorkflowRequirementsServ // WorkflowManager.deleteOwnedTask(c, user, wfi, step, step.getActionConfig()); //We had reached our total user, so recreate tasks for the user who don't have one - if(totalUsers == step.getRequiredUsers()){ + if (totalUsers == step.getRequiredUsers()) { //Create a list of the users we are to ignore List toIgnore = inProgressUserService.findByWorkflowItem(context, wfi); @@ -110,21 +115,23 @@ public class WorkflowRequirementsServiceImpl implements WorkflowRequirementsServ //Remove the users to ignore RoleMembers roleMembers = step.getRole().getMembers(context, wfi); //Create a list out all the users we are to pool a task for - for (InProgressUser ipu: toIgnore) { + for (InProgressUser ipu : toIgnore) { roleMembers.removeEperson(ipu.getUser()); } step.getUserSelectionMethod().getProcessingAction().regenerateTasks(context, wfi, roleMembers); - }else{ - //If the user previously had a personal PoolTask, this must be regenerated. Therefore we call the regeneration method + } else { + //If the user previously had a personal PoolTask, this must be regenerated. Therefore we call the + // regeneration method //with only one EPerson RoleMembers role = step.getRole().getMembers(context, wfi); List epersons = role.getEPersons(); - for(EPerson eperson: epersons){ - if(eperson.getID().equals(user.getID())){ + for (EPerson eperson : epersons) { + if (eperson.getID().equals(user.getID())) { RoleMembers memberToRegenerateTasksFor = new RoleMembers(); memberToRegenerateTasksFor.addEPerson(user); - step.getUserSelectionMethod().getProcessingAction().regenerateTasks(context, wfi, memberToRegenerateTasksFor); + step.getUserSelectionMethod().getProcessingAction() + .regenerateTasks(context, wfi, memberToRegenerateTasksFor); break; } } @@ -144,8 +151,7 @@ public class WorkflowRequirementsServiceImpl implements WorkflowRequirementsServ @Override public void clearInProgressUsers(Context c, XmlWorkflowItem wfi) throws AuthorizeException, SQLException { Iterator ipus = inProgressUserService.findByWorkflowItem(c, wfi).iterator(); - while(ipus.hasNext()) - { + while (ipus.hasNext()) { InProgressUser ipu = ipus.next(); ipus.remove(); inProgressUserService.delete(c, ipu); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowUtils.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowUtils.java index f2a02ca5fa..872ff2b21c 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowUtils.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/WorkflowUtils.java @@ -7,15 +7,25 @@ */ package org.dspace.xmlworkflow; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.sql.SQLException; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedHashMap; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; -import org.dspace.core.Context; import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; import org.dspace.core.Email; import org.dspace.core.I18nUtil; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.GroupService; @@ -25,14 +35,6 @@ import org.dspace.xmlworkflow.state.Workflow; import org.dspace.xmlworkflow.storedcomponents.CollectionRole; import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService; -import javax.servlet.http.HttpServletRequest; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; -import java.io.StringWriter; -import java.io.PrintWriter; - /** * Utilty methods for the xml workflow * @@ -41,24 +43,31 @@ import java.io.PrintWriter; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class WorkflowUtils extends Util{ - /** log4j category */ +public class WorkflowUtils extends Util { + /** + * log4j category + */ public static Logger log = Logger.getLogger(WorkflowUtils.class); - protected static final CollectionRoleService collectionRoleService = XmlWorkflowServiceFactory.getInstance().getCollectionRoleService(); + protected static final CollectionRoleService collectionRoleService = + XmlWorkflowServiceFactory.getInstance().getCollectionRoleService(); protected static final GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - protected static final XmlWorkflowFactory xmlWorkflowFactory = XmlWorkflowServiceFactory.getInstance().getWorkflowFactory(); + protected static final XmlWorkflowFactory xmlWorkflowFactory = XmlWorkflowServiceFactory.getInstance() + .getWorkflowFactory(); + + /** + * Default constructor + */ + private WorkflowUtils() { } /** * Return a string for logging, containing useful information about the * current request - the URL, the method and parameters. * - * @param request - * the request object. + * @param request the request object. * @return a multi-line string containing information about the request. */ - public static String getRequestLogInfo(HttpServletRequest request) - { + public static String getRequestLogInfo(HttpServletRequest request) { String report; report = "-- URL Was: " + getOriginalURL(request) + "\n"; @@ -69,20 +78,16 @@ public class WorkflowUtils extends Util{ Enumeration e = request.getParameterNames(); - while (e.hasMoreElements()) - { + while (e.hasMoreElements()) { String name = (String) e.nextElement(); - if (name.equals("login_password")) - { + if (name.equals("login_password")) { // We don't want to write a clear text password // to the log, even if it's wrong! report = report + "-- " + name + ": *not logged*\n"; - } - else - { + } else { report = report + "-- " + name + ": \"" - + request.getParameter(name) + "\"\n"; + + request.getParameter(name) + "\"\n"; } } @@ -90,17 +95,13 @@ public class WorkflowUtils extends Util{ } - /** * Get the original request URL. * - * @param request - * the HTTP request - * + * @param request the HTTP request * @return the original request URL */ - public static String getOriginalURL(HttpServletRequest request) - { + public static String getOriginalURL(HttpServletRequest request) { // Make sure there's a URL in the attribute storeOriginalURL(request); @@ -108,26 +109,21 @@ public class WorkflowUtils extends Util{ } - /** * Put the original request URL into the request object as an attribute for * later use. This is necessary because forwarding a request removes this * information. The attribute is only written if it hasn't been before; thus * it can be called after a forward safely. * - * @param request - * Servlet's HTTP request object. + * @param request Servlet's HTTP request object. */ - public static void storeOriginalURL(HttpServletRequest request) - { + public static void storeOriginalURL(HttpServletRequest request) { String orig = (String) request.getAttribute("dspace.original.url"); - if (orig == null) - { + if (orig == null) { String fullURL = request.getRequestURL().toString(); - if (request.getQueryString() != null) - { + if (request.getQueryString() != null) { fullURL = fullURL + "?" + request.getQueryString(); } @@ -149,53 +145,43 @@ public class WorkflowUtils extends Util{ * logged. This is because this method will usually be invoked as part of an * error handling routine anyway. * - * @param request - * the HTTP request leading to the error - * @param exception - * the exception causing the error, or null + * @param request the HTTP request leading to the error + * @param exception the exception causing the error, or null */ - public static void sendAlert(HttpServletRequest request, Exception exception) - { + public static void sendAlert(HttpServletRequest request, Exception exception) { String logInfo = WorkflowUtils.getRequestLogInfo(request); Context c = (Context) request.getAttribute("dspace.context"); - try - { + try { String recipient = ConfigurationManager - .getProperty("alert.recipient"); + .getProperty("alert.recipient"); - if (StringUtils.isNotBlank(recipient)) - { + if (StringUtils.isNotBlank(recipient)) { Email email = Email.getEmail(I18nUtil.getEmailFilename(c.getCurrentLocale(), "internal_error")); email.addRecipient(recipient); email.addArgument(ConfigurationManager - .getProperty("dspace.url")); + .getProperty("dspace.url")); email.addArgument(new Date()); email.addArgument(request.getSession().getId()); email.addArgument(logInfo); String stackTrace; - if (exception != null) - { + if (exception != null) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); exception.printStackTrace(pw); pw.flush(); stackTrace = sw.toString(); - } - else - { + } else { stackTrace = "No exception"; } email.addArgument(stackTrace); email.send(); } - } - catch (Exception e) - { + } catch (Exception e) { // Not much we can do here! log.warn("Unable to send email alert", e); } @@ -209,23 +195,16 @@ public class WorkflowUtils extends Util{ /** * Creates a role for a collection by linking a group of epersons to a role ID * - * @param context - * The relevant DSpace Context. - * @param collection - * the target collection - * @param roleId - * the role to be linked. - * @param group - * group of EPersons - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param context The relevant DSpace Context. + * @param collection the target collection + * @param roleId the role to be linked. + * @param group group of EPersons + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public static void createCollectionWorkflowRole(Context context, Collection collection, String roleId, Group group) - throws AuthorizeException, SQLException - { + throws AuthorizeException, SQLException { CollectionRole ass = collectionRoleService.create(context, collection, roleId, group); collectionRoleService.update(context, ass); } @@ -236,9 +215,9 @@ public class WorkflowUtils extends Util{ * @param context * The relevant DSpace Context. * @param collection - * + * * @param roleId - * + * * @throws SQLException * An exception that provides information on a database access error or other errors. * @throws IOException @@ -247,8 +226,7 @@ public class WorkflowUtils extends Util{ * occurs if there is a configuration error in the workflow */ public static void deleteRoleGroup(Context context, Collection collection, String roleID) - throws SQLException, IOException, WorkflowConfigurationException - { + throws SQLException, IOException, WorkflowConfigurationException { Workflow workflow = xmlWorkflowFactory.getWorkflow(collection); Role role = workflow.getRoles().get(roleID); if (role.getScope() == Role.Scope.COLLECTION) { @@ -258,7 +236,8 @@ public class WorkflowUtils extends Util{ } - public static HashMap getCollectionRoles(Collection thisCollection) throws IOException, WorkflowConfigurationException, SQLException { + public static HashMap getCollectionRoles(Collection thisCollection) + throws IOException, WorkflowConfigurationException, SQLException { Workflow workflow = xmlWorkflowFactory.getWorkflow(thisCollection); LinkedHashMap result = new LinkedHashMap(); if (workflow != null) { @@ -278,7 +257,8 @@ public class WorkflowUtils extends Util{ } - public static HashMap getCollectionAndRepositoryRoles(Collection thisCollection) throws IOException, WorkflowConfigurationException, SQLException { + public static HashMap getCollectionAndRepositoryRoles(Collection thisCollection) + throws IOException, WorkflowConfigurationException, SQLException { Workflow workflow = xmlWorkflowFactory.getWorkflow(thisCollection); LinkedHashMap result = new LinkedHashMap(); if (workflow != null) { @@ -288,7 +268,8 @@ public class WorkflowUtils extends Util{ for (String roleId : allRoles.keySet()) { Role role = allRoles.get(roleId); // We just require the roles which have a scope of collection - if ((role.getScope() == Role.Scope.COLLECTION || role.getScope() == Role.Scope.REPOSITORY) && !role.isInternal()) { + if ((role.getScope() == Role.Scope.COLLECTION || role.getScope() == Role.Scope.REPOSITORY) && !role + .isInternal()) { result.put(roleId, role); } } @@ -298,7 +279,8 @@ public class WorkflowUtils extends Util{ } - public static HashMap getAllExternalRoles(Collection thisCollection) throws IOException, WorkflowConfigurationException, SQLException { + public static HashMap getAllExternalRoles(Collection thisCollection) + throws IOException, WorkflowConfigurationException, SQLException { Workflow workflow = xmlWorkflowFactory.getWorkflow(thisCollection); LinkedHashMap result = new LinkedHashMap(); if (workflow != null) { @@ -320,22 +302,22 @@ public class WorkflowUtils extends Util{ public static Group getRoleGroup(Context context, Collection collection, Role role) throws SQLException { if (role.getScope() == Role.Scope.REPOSITORY) { return groupService.findByName(context, role.getName()); - } else - if (role.getScope() == Role.Scope.COLLECTION) { - CollectionRole collectionRole = collectionRoleService.find(context, collection, role.getId()); - if (collectionRole == null) - return null; - - return collectionRole.getGroup(); - } else - if (role.getScope() == Role.Scope.ITEM) { - + } else if (role.getScope() == Role.Scope.COLLECTION) { + CollectionRole collectionRole = collectionRoleService.find(context, collection, role.getId()); + if (collectionRole == null) { + return null; } + + return collectionRole.getGroup(); + } else if (role.getScope() == Role.Scope.ITEM) { + + } return null; } // public static List getAllUsedStepIdentifiers(Context context) throws SQLException { -// TableRowIterator tri = DatabaseManager.queryTable(context, "cwf_claimtask", "SELECT DISTINCT step_id FROM cwf_pooltask UNION SELECT DISTINCT step_id FROM cwf_claimtask"); +// TableRowIterator tri = DatabaseManager.queryTable(context, "cwf_claimtask", "SELECT DISTINCT step_id FROM +// cwf_pooltask UNION SELECT DISTINCT step_id FROM cwf_claimtask"); // List result = new ArrayList(); // while(tri.hasNext()) { // TableRow row = tri.next(); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowFactoryImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowFactoryImpl.java index bdcd395d20..7f1076b206 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowFactoryImpl.java @@ -7,6 +7,17 @@ */ package org.dspace.xmlworkflow; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.PostConstruct; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.TransformerException; + import org.apache.log4j.Logger; import org.apache.xpath.XPathAPI; import org.dspace.content.Collection; @@ -14,21 +25,14 @@ import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.xmlworkflow.factory.XmlWorkflowFactory; import org.dspace.xmlworkflow.state.Step; -import org.dspace.xmlworkflow.state.actions.UserSelectionActionConfig; import org.dspace.xmlworkflow.state.Workflow; +import org.dspace.xmlworkflow.state.actions.UserSelectionActionConfig; import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig; import org.springframework.beans.factory.annotation.Autowired; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import javax.annotation.PostConstruct; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.TransformerException; -import java.io.File; -import java.io.IOException; -import java.util.*; - /** * The workflowfactory is responsible for parsing the * workflow xml file and is used to retrieve the workflow for @@ -49,115 +53,134 @@ public class XmlWorkflowFactoryImpl implements XmlWorkflowFactory { protected String path; @PostConstruct - protected void init() - { - path = configurationService.getProperty("dspace.dir")+ File.separator + "config" + File.separator + "workflow.xml"; + protected void init() { + path = configurationService + .getProperty("dspace.dir") + File.separator + "config" + File.separator + "workflow.xml"; } // private static String pathActions = ConfigurationManager.getProperty("dspace.dir")+"/config/workflow-actions.xml"; - protected XmlWorkflowFactoryImpl() - { + protected XmlWorkflowFactoryImpl() { } @Override public Workflow getWorkflow(Collection collection) throws IOException, WorkflowConfigurationException { //Initialize our cache if we have none - if(workflowCache == null) + if (workflowCache == null) { workflowCache = new HashMap<>(); + } // Attempt to retrieve our workflow object - if(workflowCache.get(collection.getHandle())==null){ - try{ + if (workflowCache.get(collection.getHandle()) == null) { + try { // No workflow cache found for the collection, check if we have a workflowId for this collection File xmlFile = new File(path); Document input = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile); Node mainNode = input.getFirstChild(); - Node workflowMap = XPathAPI.selectSingleNode(mainNode, "//workflow-map/name-map[@collection='"+collection.getHandle()+"']"); - if(workflowMap==null){ + Node workflowMap = XPathAPI.selectSingleNode(mainNode, + "//workflow-map/name-map[@collection='" + collection + .getHandle() + "']"); + if (workflowMap == null) { //No workflowId found for this collection, so retrieve & use the default workflow - if(workflowCache.get("default")==null){ - String workflowID = XPathAPI.selectSingleNode(mainNode, "//workflow-map/name-map[@collection='default']").getAttributes().getNamedItem("workflow").getTextContent(); - if(workflowID==null){ - throw new WorkflowConfigurationException("No mapping is present for collection with handle:" + collection.getHandle()); + if (workflowCache.get("default") == null) { + String workflowID = XPathAPI + .selectSingleNode(mainNode, "//workflow-map/name-map[@collection='default']") + .getAttributes().getNamedItem("workflow").getTextContent(); + if (workflowID == null) { + throw new WorkflowConfigurationException( + "No mapping is present for collection with handle:" + collection.getHandle()); } - Node workflowNode = XPathAPI.selectSingleNode(mainNode, "//workflow[@id='"+workflowID+"']"); + Node workflowNode = XPathAPI.selectSingleNode(mainNode, "//workflow[@id='" + workflowID + "']"); Workflow wf = new Workflow(workflowID, getRoles(workflowNode)); Step step = createFirstStep(wf, workflowNode); wf.setFirstStep(step); workflowCache.put("default", wf); workflowCache.put(collection.getHandle(), wf); return wf; - }else{ + } else { return workflowCache.get("default"); } - }else{ + } else { //We have a workflowID so retrieve it & resolve it to a workflow, also store it in our cache String workflowID = workflowMap.getAttributes().getNamedItem("workflow").getTextContent(); - Node workflowNode = XPathAPI.selectSingleNode(mainNode, "//workflow[@id='"+workflowID+"']"); + Node workflowNode = XPathAPI.selectSingleNode(mainNode, "//workflow[@id='" + workflowID + "']"); Workflow wf = new Workflow(workflowID, getRoles(workflowNode)); Step step = createFirstStep(wf, workflowNode); wf.setFirstStep(step); workflowCache.put(collection.getHandle(), wf); return wf; } - } catch (Exception e){ + } catch (Exception e) { log.error("Error while retrieving workflow for collection: " + collection.getHandle(), e); - throw new WorkflowConfigurationException("Error while retrieving workflow for the following collection: " + collection.getHandle()); + throw new WorkflowConfigurationException( + "Error while retrieving workflow for the following collection: " + collection.getHandle()); } - }else{ + } else { return workflowCache.get(collection.getHandle()); } } - protected Step createFirstStep(Workflow workflow, Node workflowNode) throws TransformerException, WorkflowConfigurationException { + protected Step createFirstStep(Workflow workflow, Node workflowNode) + throws TransformerException, WorkflowConfigurationException { String firstStepID = workflowNode.getAttributes().getNamedItem("start").getTextContent(); - Node stepNode = XPathAPI.selectSingleNode(workflowNode, "step[@id='"+firstStepID+"']"); - if(stepNode == null){ - throw new WorkflowConfigurationException("First step does not exist for workflow: "+workflowNode.getAttributes().getNamedItem("id").getTextContent()); + Node stepNode = XPathAPI.selectSingleNode(workflowNode, "step[@id='" + firstStepID + "']"); + if (stepNode == null) { + throw new WorkflowConfigurationException( + "First step does not exist for workflow: " + workflowNode.getAttributes().getNamedItem("id") + .getTextContent()); } Node roleNode = stepNode.getAttributes().getNamedItem("role"); Role role = null; - if(roleNode != null) + if (roleNode != null) { role = workflow.getRoles().get(roleNode.getTextContent()); + } String userSelectionActionID = stepNode.getAttributes().getNamedItem("userSelectionMethod").getTextContent(); UserSelectionActionConfig userSelection = createUserAssignmentActionConfig(userSelectionActionID); - return new Step(firstStepID, workflow, role, userSelection, getStepActionConfigs(stepNode), getStepOutcomes(stepNode), getNbRequiredUser(stepNode)); + return new Step(firstStepID, workflow, role, userSelection, getStepActionConfigs(stepNode), + getStepOutcomes(stepNode), getNbRequiredUser(stepNode)); } - - protected Map getStepOutcomes(Node stepNode) throws TransformerException, WorkflowConfigurationException { - try{ + protected Map getStepOutcomes(Node stepNode) + throws TransformerException, WorkflowConfigurationException { + try { NodeList outcomesNodeList = XPathAPI.selectNodeList(stepNode, "outcomes/step"); Map outcomes = new HashMap(); //Add our outcome, should it be null it will be interpreted as the end of the line (last step) - for(int i = 0; i < outcomesNodeList.getLength(); i++){ + for (int i = 0; i < outcomesNodeList.getLength(); i++) { Node outcomeNode = outcomesNodeList.item(i); int index = Integer.parseInt(outcomeNode.getAttributes().getNamedItem("status").getTextContent()); - if(index < 0){ - throw new WorkflowConfigurationException("Outcome configuration error for step: "+stepNode.getAttributes().getNamedItem("id").getTextContent()); + if (index < 0) { + throw new WorkflowConfigurationException( + "Outcome configuration error for step: " + stepNode.getAttributes().getNamedItem("id") + .getTextContent()); } outcomes.put(index, outcomeNode.getTextContent()); } return outcomes; - }catch(Exception e){ - log.error("Outcome configuration error for step: " + stepNode.getAttributes().getNamedItem("id").getTextContent(), e); - throw new WorkflowConfigurationException("Outcome configuration error for step: "+stepNode.getAttributes().getNamedItem("id").getTextContent()); + } catch (Exception e) { + log.error( + "Outcome configuration error for step: " + stepNode.getAttributes().getNamedItem("id").getTextContent(), + e); + throw new WorkflowConfigurationException( + "Outcome configuration error for step: " + stepNode.getAttributes().getNamedItem("id") + .getTextContent()); } } - protected int getNbRequiredUser(Node stepnode){ - if(stepnode.getAttributes().getNamedItem("requiredUsers")!=null){ + + protected int getNbRequiredUser(Node stepnode) { + if (stepnode.getAttributes().getNamedItem("requiredUsers") != null) { return Integer.parseInt(stepnode.getAttributes().getNamedItem("requiredUsers").getTextContent()); } return 1; } + private static List getStepActionConfigs(Node stepNode) throws TransformerException { NodeList actionConfigNodes = XPathAPI.selectNodeList(stepNode, "actions/action"); List actionConfigIDs = new ArrayList(); - for(int i = 0; i < actionConfigNodes.getLength(); i++){ + for (int i = 0; i < actionConfigNodes.getLength(); i++) { actionConfigIDs.add(actionConfigNodes.item(i).getAttributes().getNamedItem("id").getTextContent()); } return actionConfigIDs; @@ -165,83 +188,93 @@ public class XmlWorkflowFactoryImpl implements XmlWorkflowFactory { @Override public Step createStep(Workflow workflow, String stepID) throws WorkflowConfigurationException, IOException { - try{ + try { File xmlFile = new File(path); Document input = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile); Node mainNode = input.getFirstChild(); - Node stepNode = XPathAPI.selectSingleNode(mainNode, "//workflow[@id='"+workflow.getID()+"']/step[@id='"+stepID+"']"); + Node stepNode = XPathAPI + .selectSingleNode(mainNode, "//workflow[@id='" + workflow.getID() + "']/step[@id='" + stepID + "']"); - if(stepNode == null){ - throw new WorkflowConfigurationException("Step does not exist for workflow: "+workflow.getID()); + if (stepNode == null) { + throw new WorkflowConfigurationException("Step does not exist for workflow: " + workflow.getID()); } Node roleNode = stepNode.getAttributes().getNamedItem("role"); Role role = null; - if(roleNode != null) + if (roleNode != null) { role = workflow.getRoles().get(roleNode.getTextContent()); - String userSelectionActionID = stepNode.getAttributes().getNamedItem("userSelectionMethod").getTextContent(); + } + String userSelectionActionID = stepNode.getAttributes().getNamedItem("userSelectionMethod") + .getTextContent(); UserSelectionActionConfig userSelection = createUserAssignmentActionConfig(userSelectionActionID); - return new Step(stepID, workflow, role, userSelection, getStepActionConfigs(stepNode), getStepOutcomes(stepNode), getNbRequiredUser(stepNode)); + return new Step(stepID, workflow, role, userSelection, getStepActionConfigs(stepNode), + getStepOutcomes(stepNode), getNbRequiredUser(stepNode)); - }catch (Exception e){ + } catch (Exception e) { log.error("Error while creating step with :" + stepID, e); - throw new WorkflowConfigurationException("Step: " + stepID + " does not exist for workflow: "+workflow.getID()); + throw new WorkflowConfigurationException( + "Step: " + stepID + " does not exist for workflow: " + workflow.getID()); } } - protected UserSelectionActionConfig createUserAssignmentActionConfig(String userSelectionActionID) { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(userSelectionActionID, UserSelectionActionConfig.class); + + protected UserSelectionActionConfig createUserAssignmentActionConfig(String userSelectionActionID) { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(userSelectionActionID, UserSelectionActionConfig.class); } @Override - public WorkflowActionConfig createWorkflowActionConfig(String actionID){ - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(actionID, WorkflowActionConfig.class); + public WorkflowActionConfig createWorkflowActionConfig(String actionID) { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(actionID, WorkflowActionConfig.class); } protected LinkedHashMap getRoles(Node workflowNode) throws WorkflowConfigurationException { NodeList roleNodes = null; - try{ + try { roleNodes = XPathAPI.selectNodeList(workflowNode, "roles/role"); - }catch (Exception e){ + } catch (Exception e) { log.error("Error while resolving nodes", e); throw new WorkflowConfigurationException("Error while retrieving roles"); } LinkedHashMap roles = new LinkedHashMap(); - for(int i = 0; i < roleNodes.getLength(); i++){ + for (int i = 0; i < roleNodes.getLength(); i++) { String roleID = roleNodes.item(i).getAttributes().getNamedItem("id").getTextContent(); String roleName = roleNodes.item(i).getAttributes().getNamedItem("name").getTextContent(); Node descriptionNode = roleNodes.item(i).getAttributes().getNamedItem("description"); String roleDescription = null; - if(descriptionNode != null) + if (descriptionNode != null) { roleDescription = descriptionNode.getTextContent(); + } Node scopeNode = roleNodes.item(i).getAttributes().getNamedItem("scope"); String roleScope = null; - if(scopeNode != null) + if (scopeNode != null) { roleScope = scopeNode.getTextContent(); + } Node internalNode = roleNodes.item(i).getAttributes().getNamedItem("internal"); String roleInternal; boolean internal = false; - if(internalNode != null){ + if (internalNode != null) { roleInternal = internalNode.getTextContent(); internal = Boolean.parseBoolean(roleInternal); } Role.Scope scope; - if(roleScope == null || roleScope.equalsIgnoreCase("collection")) + if (roleScope == null || roleScope.equalsIgnoreCase("collection")) { scope = Role.Scope.COLLECTION; - else - if(roleScope.equalsIgnoreCase("item")) + } else if (roleScope.equalsIgnoreCase("item")) { scope = Role.Scope.ITEM; - else - if(roleScope.equalsIgnoreCase("repository")) + } else if (roleScope.equalsIgnoreCase("repository")) { scope = Role.Scope.REPOSITORY; - else - throw new WorkflowConfigurationException("An invalid role scope has been specified it must either be item or collection."); + } else { + throw new WorkflowConfigurationException( + "An invalid role scope has been specified it must either be item or collection."); + } - Role role = new Role(roleID, roleName, roleDescription,internal, scope); + Role role = new Role(roleID, roleName, roleDescription, internal, scope); roles.put(roleID, role); } return roles; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java index e39a560eb7..a6cbf73007 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java @@ -7,17 +7,42 @@ */ package org.dspace.xmlworkflow; -import org.apache.commons.collections.CollectionUtils; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.UUID; +import javax.mail.MessagingException; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.collections4.CollectionUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.service.AuthorizeService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; +import org.dspace.content.WorkspaceItem; import org.dspace.content.service.InstallItemService; import org.dspace.content.service.ItemService; import org.dspace.content.service.WorkspaceItemService; -import org.dspace.core.*; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Email; +import org.dspace.core.I18nUtil; +import org.dspace.core.LogManager; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.service.GroupService; @@ -30,17 +55,19 @@ import org.dspace.xmlworkflow.service.WorkflowRequirementsService; import org.dspace.xmlworkflow.service.XmlWorkflowService; import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.Workflow; -import org.dspace.xmlworkflow.state.actions.*; -import org.dspace.xmlworkflow.storedcomponents.*; -import org.dspace.xmlworkflow.storedcomponents.service.*; +import org.dspace.xmlworkflow.state.actions.Action; +import org.dspace.xmlworkflow.state.actions.ActionResult; +import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig; +import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; +import org.dspace.xmlworkflow.storedcomponents.PoolTask; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService; +import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; +import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; import org.springframework.beans.factory.annotation.Autowired; -import javax.mail.MessagingException; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; - /** * When an item is submitted and is somewhere in a workflow, it has a row in the * WorkflowItem table pointing to it. @@ -86,14 +113,14 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { @Autowired(required = true) protected GroupService groupService; - protected XmlWorkflowServiceImpl() - { + protected XmlWorkflowServiceImpl() { } @Override - public void deleteCollection(Context context, Collection collection) throws SQLException, IOException, AuthorizeException { + public void deleteCollection(Context context, Collection collection) + throws SQLException, IOException, AuthorizeException { xmlWorkflowItemService.deleteByCollection(context, collection); collectionRoleService.deleteByCollection(context, collection); } @@ -101,43 +128,41 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { @Override public List getEPersonDeleteConstraints(Context context, EPerson ePerson) throws SQLException { List constraints = new ArrayList(); - if (CollectionUtils.isNotEmpty(claimedTaskService.findByEperson(context, ePerson))) - { + if (CollectionUtils.isNotEmpty(claimedTaskService.findByEperson(context, ePerson))) { constraints.add("cwf_claimtask"); } - if (CollectionUtils.isNotEmpty(poolTaskService.findByEPerson(context, ePerson))) - { + if (CollectionUtils.isNotEmpty(poolTaskService.findByEPerson(context, ePerson))) { constraints.add("cwf_pooltask"); } - if (CollectionUtils.isNotEmpty(workflowItemRoleService.findByEPerson(context, ePerson))) - { + if (CollectionUtils.isNotEmpty(workflowItemRoleService.findByEPerson(context, ePerson))) { constraints.add("cwf_workflowitemrole"); } return constraints; } @Override - public Group getWorkflowRoleGroup(Context context, Collection collection, String roleName, Group roleGroup) throws SQLException, IOException, WorkflowException, AuthorizeException { + public Group getWorkflowRoleGroup(Context context, Collection collection, String roleName, Group roleGroup) + throws SQLException, IOException, WorkflowException, AuthorizeException { try { Role role = WorkflowUtils.getCollectionAndRepositoryRoles(collection).get(roleName); - if (role.getScope() == Role.Scope.COLLECTION || role.getScope() == Role.Scope.REPOSITORY){ + if (role.getScope() == Role.Scope.COLLECTION || role.getScope() == Role.Scope.REPOSITORY) { roleGroup = WorkflowUtils.getRoleGroup(context, collection, role); - if (roleGroup == null){ + if (roleGroup == null) { authorizeService.authorizeAction(context, collection, Constants.WRITE); roleGroup = groupService.create(context); - if (role.getScope() == Role.Scope.COLLECTION){ + if (role.getScope() == Role.Scope.COLLECTION) { groupService.setName(roleGroup, - "COLLECTION_" + collection.getID().toString() - + "_WORKFLOW_ROLE_" + roleName); - }else{ - groupService.setName(roleGroup, role.getName()); + "COLLECTION_" + collection.getID().toString() + + "_WORKFLOW_ROLE_" + roleName); + } else { + groupService.setName(roleGroup, role.getName()); } groupService.update(context, roleGroup); authorizeService.addPolicy(context, collection, Constants.ADD, roleGroup); - if (role.getScope() == Role.Scope.COLLECTION){ + if (role.getScope() == Role.Scope.COLLECTION) { WorkflowUtils.createCollectionWorkflowRole(context, collection, roleName, roleGroup); } - } + } } return roleGroup; } catch (WorkflowConfigurationException e) { @@ -151,7 +176,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } @Override - public XmlWorkflowItem start(Context context, WorkspaceItem wsi) throws SQLException, AuthorizeException, IOException, WorkflowException { + public XmlWorkflowItem start(Context context, WorkspaceItem wsi) + throws SQLException, AuthorizeException, IOException, WorkflowException { try { Item myitem = wsi.getItem(); Collection collection = wsi.getCollection(); @@ -167,14 +193,14 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { context.turnOffAuthorisationSystem(); Step firstStep = wf.getFirstStep(); - if (firstStep.isValidStep(context, wfi)){ - activateFirstStep(context, wf, firstStep, wfi); + if (firstStep.isValidStep(context, wfi)) { + activateFirstStep(context, wf, firstStep, wfi); } else { //Get our next step, if none is found, archive our item firstStep = wf.getNextStep(context, wfi, firstStep, ActionResult.OUTCOME_COMPLETE); - if (firstStep == null){ + if (firstStep == null) { archive(context, wfi); - }else{ + } else { activateFirstStep(context, wf, firstStep, wfi); } @@ -189,6 +215,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } //TODO: this is currently not used in our notifications. Look at the code used by the original WorkflowManager + /** * startWithoutNotify() starts the workflow normally, but disables * notifications (useful for large imports,) for the first workflow step - @@ -196,7 +223,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { */ @Override public XmlWorkflowItem startWithoutNotify(Context context, WorkspaceItem wsi) - throws SQLException, AuthorizeException, IOException, WorkflowException { + throws SQLException, AuthorizeException, IOException, WorkflowException { // make a hash table entry with item ID for no notify // notify code checks no notify hash for item id noEMail.put(wsi.getItem().getID(), Boolean.TRUE); @@ -205,7 +232,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } @Override - public void alertUsersOnTaskActivation(Context c, XmlWorkflowItem wfi, String emailTemplate, List epa, String ...arguments) throws IOException, SQLException, MessagingException { + public void alertUsersOnTaskActivation(Context c, XmlWorkflowItem wfi, String emailTemplate, List epa, + String... arguments) throws IOException, SQLException, MessagingException { if (noEMail.containsKey(wfi.getItem().getID())) { // suppress email, and delete key noEMail.remove(wfi.getItem().getID()); @@ -223,37 +251,40 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } protected void grantSubmitterReadPolicies(Context context, Item item) throws SQLException, AuthorizeException { - //A list of policies the user has for this item - List userHasPolicies = new ArrayList(); + //A list of policies the user has for this item + List userHasPolicies = new ArrayList(); List itempols = authorizeService.getPolicies(context, item); EPerson submitter = item.getSubmitter(); for (ResourcePolicy resourcePolicy : itempols) { - if (submitter.equals(resourcePolicy.getEPerson())){ + if (submitter.equals(resourcePolicy.getEPerson())) { //The user has already got this policy so add it to the list userHasPolicies.add(resourcePolicy.getAction()); } } //Make sure we don't add duplicate policies - if (!userHasPolicies.contains(Constants.READ)) - addPolicyToItem(context, item, Constants.READ, submitter); + if (!userHasPolicies.contains(Constants.READ)) { + addPolicyToItem(context, item, Constants.READ, submitter, ResourcePolicy.TYPE_SUBMISSION); + } } - protected void activateFirstStep(Context context, Workflow wf, Step firstStep, XmlWorkflowItem wfi) throws AuthorizeException, IOException, SQLException, WorkflowException, WorkflowConfigurationException{ + protected void activateFirstStep(Context context, Workflow wf, Step firstStep, XmlWorkflowItem wfi) + throws AuthorizeException, IOException, SQLException, WorkflowException, WorkflowConfigurationException { WorkflowActionConfig firstActionConfig = firstStep.getUserSelectionMethod(); firstActionConfig.getProcessingAction().activate(context, wfi); - log.info(LogManager.getHeader(context, "start_workflow", firstActionConfig.getProcessingAction() + " workflow_item_id=" - + wfi.getID() + "item_id=" + wfi.getItem().getID() + "collection_id=" - + wfi.getCollection().getID())); + log.info(LogManager.getHeader(context, "start_workflow", + firstActionConfig.getProcessingAction() + " workflow_item_id=" + + wfi.getID() + "item_id=" + wfi.getItem().getID() + "collection_id=" + + wfi.getCollection().getID())); // record the start of the workflow w/provenance message recordStart(context, wfi.getItem(), firstActionConfig.getProcessingAction()); //Fire an event ! - logWorkflowEvent(context, firstStep.getWorkflow().getID(), null, null, wfi, null, firstStep, firstActionConfig); + logWorkflowEvent(context, firstStep.getWorkflow().getID(), null, null, wfi, null, firstStep, firstActionConfig); //If we don't have a UI activate it - if (!firstActionConfig.requiresUI()){ + if (!firstActionConfig.requiresUI()) { ActionResult outcome = firstActionConfig.getProcessingAction().execute(context, wfi, firstStep, null); processOutcome(context, null, wf, firstStep, firstActionConfig, outcome, wfi, true); } @@ -263,42 +294,50 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { * Executes an action and returns the next. */ @Override - public WorkflowActionConfig doState(Context c, EPerson user, HttpServletRequest request, int workflowItemId, Workflow workflow, WorkflowActionConfig currentActionConfig) throws SQLException, AuthorizeException, IOException, MessagingException, WorkflowException { + public WorkflowActionConfig doState(Context c, EPerson user, HttpServletRequest request, int workflowItemId, + Workflow workflow, WorkflowActionConfig currentActionConfig) + throws SQLException, AuthorizeException, IOException, MessagingException, WorkflowException { try { XmlWorkflowItem wi = xmlWorkflowItemService.find(c, workflowItemId); Step currentStep = currentActionConfig.getStep(); - if (currentActionConfig.getProcessingAction().isAuthorized(c, request, wi)){ + if (currentActionConfig.getProcessingAction().isAuthorized(c, request, wi)) { ActionResult outcome = currentActionConfig.getProcessingAction().execute(c, wi, currentStep, request); return processOutcome(c, user, workflow, currentStep, currentActionConfig, outcome, wi, false); - }else{ + } else { throw new AuthorizeException("You are not allowed to to perform this task."); } } catch (WorkflowConfigurationException e) { - log.error(LogManager.getHeader(c, "error while executing state", "workflow: " + workflow.getID() + " action: " + currentActionConfig.getId() + " workflowItemId: " + workflowItemId), e); + log.error(LogManager.getHeader(c, "error while executing state", + "workflow: " + workflow.getID() + " action: " + currentActionConfig + .getId() + " workflowItemId: " + workflowItemId), e); WorkflowUtils.sendAlert(request, e); throw new WorkflowException(e); } } @Override - public WorkflowActionConfig processOutcome(Context c, EPerson user, Workflow workflow, Step currentStep, WorkflowActionConfig currentActionConfig, ActionResult currentOutcome, XmlWorkflowItem wfi, boolean enteredNewStep) throws IOException, AuthorizeException, SQLException, WorkflowException { - if (currentOutcome.getType() == ActionResult.TYPE.TYPE_PAGE || currentOutcome.getType() == ActionResult.TYPE.TYPE_ERROR){ + public WorkflowActionConfig processOutcome(Context c, EPerson user, Workflow workflow, Step currentStep, + WorkflowActionConfig currentActionConfig, ActionResult currentOutcome, + XmlWorkflowItem wfi, boolean enteredNewStep) + throws IOException, AuthorizeException, SQLException, WorkflowException { + if (currentOutcome.getType() == ActionResult.TYPE.TYPE_PAGE || currentOutcome + .getType() == ActionResult.TYPE.TYPE_ERROR) { //Our outcome is a page or an error, so return our current action c.restoreAuthSystemState(); return currentActionConfig; - }else - if (currentOutcome.getType() == ActionResult.TYPE.TYPE_CANCEL || currentOutcome.getType() == ActionResult.TYPE.TYPE_SUBMISSION_PAGE){ - //We either pressed the cancel button or got an order to return to the submission page, so don't return an action + } else if (currentOutcome.getType() == ActionResult.TYPE.TYPE_CANCEL || currentOutcome + .getType() == ActionResult.TYPE.TYPE_SUBMISSION_PAGE) { + //We either pressed the cancel button or got an order to return to the submission page, so don't return + // an action //By not returning an action we ensure ourselfs that we go back to the submission page c.restoreAuthSystemState(); return null; - }else - if (currentOutcome.getType() == ActionResult.TYPE.TYPE_OUTCOME) { + } else if (currentOutcome.getType() == ActionResult.TYPE.TYPE_OUTCOME) { Step nextStep = null; WorkflowActionConfig nextActionConfig = null; try { //We have completed our action search & retrieve the next action - if (currentOutcome.getResult() == ActionResult.OUTCOME_COMPLETE){ + if (currentOutcome.getResult() == ActionResult.OUTCOME_COMPLETE) { nextActionConfig = currentStep.getNextAction(currentActionConfig); } @@ -309,24 +348,28 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { if (nextActionConfig.requiresUI() && !enteredNewStep) { createOwnedTask(c, wfi, currentStep, nextActionConfig, user); return nextActionConfig; - } else if ( nextActionConfig.requiresUI() && enteredNewStep){ - //We have entered a new step and have encountered a UI, return null since the current user doesn't have anything to do with this + } else if (nextActionConfig.requiresUI() && enteredNewStep) { + //We have entered a new step and have encountered a UI, return null since the current user + // doesn't have anything to do with this c.restoreAuthSystemState(); return null; } else { - ActionResult newOutcome = nextActionConfig.getProcessingAction().execute(c, wfi, currentStep, null); - return processOutcome(c, user, workflow, currentStep, nextActionConfig, newOutcome, wfi, enteredNewStep); + ActionResult newOutcome = nextActionConfig.getProcessingAction() + .execute(c, wfi, currentStep, null); + return processOutcome(c, user, workflow, currentStep, nextActionConfig, newOutcome, wfi, + enteredNewStep); } - }else - if (enteredNewStep){ - // If the user finished his/her step, we keep processing until there is a UI step action or no step at all + } else if (enteredNewStep) { + // If the user finished his/her step, we keep processing until there is a UI step action or no + // step at all nextStep = workflow.getNextStep(c, wfi, currentStep, currentOutcome.getResult()); c.turnOffAuthorisationSystem(); nextActionConfig = processNextStep(c, user, workflow, currentOutcome, wfi, nextStep); - //If we require a user interface return null so that the user is redirected to the "submissions page" - if (nextActionConfig == null || nextActionConfig.requiresUI()){ + //If we require a user interface return null so that the user is redirected to the "submissions + // page" + if (nextActionConfig == null || nextActionConfig.requiresUI()) { return null; - }else{ + } else { return nextActionConfig; } } else { @@ -337,7 +380,9 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { workflowRequirementsService.addFinishedUser(c, wfi, user); c.turnOffAuthorisationSystem(); //Check if our requirements have been met - if ((currentStep.isFinished(c, wfi) && currentOutcome.getResult() == ActionResult.OUTCOME_COMPLETE) || currentOutcome.getResult() != ActionResult.OUTCOME_COMPLETE){ + if ((currentStep.isFinished(c, wfi) && currentOutcome + .getResult() == ActionResult.OUTCOME_COMPLETE) || currentOutcome + .getResult() != ActionResult.OUTCOME_COMPLETE) { //Delete all the table rows containing the users who performed this task workflowRequirementsService.clearInProgressUsers(c, wfi); //Remove all the tasks @@ -347,14 +392,16 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { nextStep = workflow.getNextStep(c, wfi, currentStep, currentOutcome.getResult()); nextActionConfig = processNextStep(c, user, workflow, currentOutcome, wfi, nextStep); - //If we require a user interface return null so that the user is redirected to the "submissions page" - if (nextActionConfig == null || nextActionConfig.requiresUI()){ + //If we require a user interface return null so that the user is redirected to the + // "submissions page" + if (nextActionConfig == null || nextActionConfig.requiresUI()) { return null; - }else{ + } else { return nextActionConfig; } - }else{ - //We are done with our actions so go to the submissions page but remove action ClaimedAction first + } else { + //We are done with our actions so go to the submissions page but remove action ClaimedAction + // first deleteClaimedTask(c, wfi, task); c.restoreAuthSystemState(); nextStep = currentStep; @@ -362,13 +409,15 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { return null; } } - }catch (Exception e){ + } catch (Exception e) { log.error("error while processing workflow outcome", e); e.printStackTrace(); - } - finally { - if ((nextStep != null && currentStep != null && nextActionConfig != null) || (wfi.getItem().isArchived() && currentStep != null)){ - logWorkflowEvent(c, currentStep.getWorkflow().getID(), currentStep.getId(), currentActionConfig.getId(), wfi, user, nextStep, nextActionConfig); + } finally { + if ((nextStep != null && currentStep != null && nextActionConfig != null) || (wfi.getItem() + .isArchived() && + currentStep != null)) { + logWorkflowEvent(c, currentStep.getWorkflow().getID(), currentStep.getId(), + currentActionConfig.getId(), wfi, user, nextStep, nextActionConfig); } } @@ -378,7 +427,9 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { throw new WorkflowException("Invalid step outcome"); } - protected void logWorkflowEvent(Context c, String workflowId, String previousStepId, String previousActionConfigId, XmlWorkflowItem wfi, EPerson actor, Step newStep, WorkflowActionConfig newActionConfig) throws SQLException { + protected void logWorkflowEvent(Context c, String workflowId, String previousStepId, String previousActionConfigId, + XmlWorkflowItem wfi, EPerson actor, Step newStep, + WorkflowActionConfig newActionConfig) throws SQLException { try { //Fire an event so we can log our action ! Item item = wfi.getItem(); @@ -388,16 +439,16 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { List currentEpersonOwners = new ArrayList(); List currentGroupOwners = new ArrayList(); //These are only null if our item is sent back to the submission - if (newStep != null && newActionConfig != null){ + if (newStep != null && newActionConfig != null) { workflowStepString = workflowId + "." + newStep.getId() + "." + newActionConfig.getId(); //Retrieve the current owners of the task List claimedTasks = claimedTaskService.find(c, wfi, newStep.getId()); List pooledTasks = poolTaskService.find(c, wfi); - for (PoolTask poolTask : pooledTasks){ - if (poolTask.getEperson() != null){ + for (PoolTask poolTask : pooledTasks) { + if (poolTask.getEperson() != null) { currentEpersonOwners.add(poolTask.getEperson()); - }else{ + } else { currentGroupOwners.add(poolTask.getGroup()); } } @@ -406,12 +457,14 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } } String previousWorkflowStepString = null; - if (previousStepId != null && previousActionConfigId != null){ + if (previousStepId != null && previousActionConfigId != null) { previousWorkflowStepString = workflowId + "." + previousStepId + "." + previousActionConfigId; } //Fire our usage event ! - UsageWorkflowEvent usageWorkflowEvent = new UsageWorkflowEvent(c, item, wfi, workflowStepString, previousWorkflowStepString, myCollection, actor); + UsageWorkflowEvent usageWorkflowEvent = new UsageWorkflowEvent(c, item, wfi, workflowStepString, + previousWorkflowStepString, myCollection, + actor); usageWorkflowEvent.setEpersonOwners(currentEpersonOwners.toArray(new EPerson[currentEpersonOwners.size()])); usageWorkflowEvent.setGroupOwners(currentGroupOwners.toArray(new Group[currentGroupOwners.size()])); @@ -419,13 +472,16 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { DSpaceServicesFactory.getInstance().getEventService().fireEvent(usageWorkflowEvent); } catch (Exception e) { //Catch all errors we do not want our workflow to crash because the logging threw an exception - log.error(LogManager.getHeader(c, "Error while logging workflow event", "Workflow Item: " + wfi.getID()), e); + log.error(LogManager.getHeader(c, "Error while logging workflow event", "Workflow Item: " + wfi.getID()), + e); } } - protected WorkflowActionConfig processNextStep(Context c, EPerson user, Workflow workflow, ActionResult currentOutcome, XmlWorkflowItem wfi, Step nextStep) throws SQLException, IOException, AuthorizeException, WorkflowException, WorkflowConfigurationException { + protected WorkflowActionConfig processNextStep(Context c, EPerson user, Workflow workflow, + ActionResult currentOutcome, XmlWorkflowItem wfi, Step nextStep) + throws SQLException, IOException, AuthorizeException, WorkflowException, WorkflowConfigurationException { WorkflowActionConfig nextActionConfig; - if (nextStep!=null){ + if (nextStep != null) { nextActionConfig = nextStep.getUserSelectionMethod(); nextActionConfig.getProcessingAction().activate(c, wfi); // nextActionConfig.getProcessingAction().generateTasks(); @@ -439,8 +495,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { c.restoreAuthSystemState(); return processOutcome(c, user, workflow, nextStep, nextActionConfig, newOutcome, wfi, true); } - }else{ - if (currentOutcome.getResult() != ActionResult.OUTCOME_COMPLETE){ + } else { + if (currentOutcome.getResult() != ActionResult.OUTCOME_COMPLETE) { c.restoreAuthSystemState(); throw new WorkflowException("No alternate step was found for outcome: " + currentOutcome.getResult()); } @@ -456,21 +512,16 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { * with the relevant collection, added to the search index, and any other * tasks such as assigning dates are performed. * - * @param context - * The relevant DSpace Context. - * @param wfi - * workflow item + * @param context The relevant DSpace Context. + * @param wfi workflow item * @return the fully archived item. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ protected Item archive(Context context, XmlWorkflowItem wfi) - throws SQLException, IOException, AuthorizeException { + throws SQLException, IOException, AuthorizeException { // FIXME: Check auth Item item = wfi.getItem(); Collection collection = wfi.getCollection(); @@ -479,8 +530,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { workflowItemRoleService.deleteForWorkflowItem(context, wfi); log.info(LogManager.getHeader(context, "archive_item", "workflow_item_id=" - + wfi.getID() + "item_id=" + item.getID() + "collection_id=" - + collection.getID())); + + wfi.getID() + "item_id=" + item.getID() + "collection_id=" + + collection.getID())); installItemService.installItem(context, wfi); @@ -488,12 +539,13 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { notifyOfArchive(context, item, collection); //Clear any remaining workflow metadata - itemService.clearMetadata(context, item, WorkflowRequirementsService.WORKFLOW_SCHEMA, Item.ANY, Item.ANY, Item.ANY); + itemService + .clearMetadata(context, item, WorkflowRequirementsService.WORKFLOW_SCHEMA, Item.ANY, Item.ANY, Item.ANY); itemService.update(context, item); // Log the event log.info(LogManager.getHeader(context, "install_item", "workflow_item_id=" - + wfi.getID() + ", item_id=" + item.getID() + "handle=FIXME")); + + wfi.getID() + ", item_id=" + item.getID() + "handle=FIXME")); return item; } @@ -501,19 +553,14 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { /** * notify the submitter that the item is archived * - * @param context - * The relevant DSpace Context. - * @param item - * which item was archived - * @param coll - * collection name to display in template - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param context The relevant DSpace Context. + * @param item which item was archived + * @param coll collection name to display in template + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ protected void notifyOfArchive(Context context, Item item, Collection coll) - throws SQLException, IOException { + throws SQLException, IOException { try { // Get submitter EPerson ep = item.getSubmitter(); @@ -525,12 +572,12 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { String handle = handleService.findHandle(context, item); // Get title - List titles = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + List titles = itemService + .getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); String title = ""; try { title = I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled"); - } - catch (MissingResourceException e) { + } catch (MissingResourceException e) { title = "Untitled"; } if (titles.size() > 0) { @@ -543,10 +590,9 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { email.addArgument(handleService.getCanonicalForm(handle)); email.send(); - } - catch (MessagingException e) { + } catch (MessagingException e) { log.warn(LogManager.getHeader(context, "notifyOfArchive", - "cannot email user" + " item_id=" + item.getID())); + "cannot email user" + " item_id=" + item.getID())); } } @@ -555,19 +601,18 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { **********************************/ /** * Deletes all tasks from this workflowflowitem + * * @param context the dspace context - * @param wi the workflow item for which we are to delete the tasks - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @param wi the workflow item for which we are to delete the tasks + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ @Override public void deleteAllTasks(Context context, XmlWorkflowItem wi) throws SQLException, AuthorizeException { deleteAllPooledTasks(context, wi); - Iterator allClaimedTasks = claimedTaskService.findByWorkflowItem(context,wi).iterator(); + Iterator allClaimedTasks = claimedTaskService.findByWorkflowItem(context, wi).iterator(); while (allClaimedTasks.hasNext()) { ClaimedTask task = allClaimedTasks.next(); allClaimedTasks.remove(); @@ -589,11 +634,12 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { * Deletes an eperson from the taskpool of a step */ @Override - public void deletePooledTask(Context context, XmlWorkflowItem wi, PoolTask task) throws SQLException, AuthorizeException { - if (task != null){ - if (task.getEperson() != null){ + public void deletePooledTask(Context context, XmlWorkflowItem wi, PoolTask task) + throws SQLException, AuthorizeException { + if (task != null) { + if (task.getEperson() != null) { removeUserItemPolicies(context, wi.getItem(), task.getEperson()); - }else{ + } else { removeGroupItemPolicies(context, wi.getItem(), task.getGroup()); } poolTaskService.delete(context, task); @@ -601,8 +647,9 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } @Override - public void deleteClaimedTask(Context c, XmlWorkflowItem wi, ClaimedTask task) throws SQLException, AuthorizeException { - if (task != null){ + public void deleteClaimedTask(Context c, XmlWorkflowItem wi, ClaimedTask task) + throws SQLException, AuthorizeException { + if (task != null) { removeUserItemPolicies(c, wi.getItem(), task.getOwner()); claimedTaskService.delete(c, task); } @@ -612,8 +659,9 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { * Creates a task pool for a given step */ @Override - public void createPoolTasks(Context context, XmlWorkflowItem wi, RoleMembers assignees, Step step, WorkflowActionConfig action) - throws SQLException, AuthorizeException { + public void createPoolTasks(Context context, XmlWorkflowItem wi, RoleMembers assignees, Step step, + WorkflowActionConfig action) + throws SQLException, AuthorizeException { // create a tasklist entry for each eperson for (EPerson anEpa : assignees.getEPersons()) { PoolTask task = poolTaskService.create(context); @@ -626,7 +674,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { //Make sure this user has a task grantUserAllItemPolicies(context, wi.getItem(), anEpa); } - for(Group group: assignees.getGroups()){ + for (Group group : assignees.getGroups()) { PoolTask task = poolTaskService.create(context); task.setStepID(step.getId()); task.setWorkflowID(step.getWorkflow().getID()); @@ -643,7 +691,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { * Claims an action for a given eperson */ @Override - public void createOwnedTask(Context context, XmlWorkflowItem wi, Step step, WorkflowActionConfig action, EPerson e) throws SQLException, AuthorizeException { + public void createOwnedTask(Context context, XmlWorkflowItem wi, Step step, WorkflowActionConfig action, EPerson e) + throws SQLException, AuthorizeException { ClaimedTask task = claimedTaskService.create(context); task.setWorkflowItem(wi); task.setStepID(step.getId()); @@ -655,72 +704,92 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { grantUserAllItemPolicies(context, wi.getItem(), e); } - public void grantUserAllItemPolicies(Context context, Item item, EPerson epa) throws AuthorizeException, SQLException { - if (epa != null){ + public void grantUserAllItemPolicies(Context context, Item item, EPerson epa) + throws AuthorizeException, SQLException { + if (epa != null) { //A list of policies the user has for this item - List userHasPolicies = new ArrayList(); + List userHasPolicies = new ArrayList(); List itempols = authorizeService.getPolicies(context, item); for (ResourcePolicy resourcePolicy : itempols) { - if (epa.equals(resourcePolicy.getEPerson())){ + if (epa.equals(resourcePolicy.getEPerson())) { //The user has already got this policy so it it to the list userHasPolicies.add(resourcePolicy.getAction()); } } //Make sure we don't add duplicate policies - if (!userHasPolicies.contains(Constants.READ)) + if (!userHasPolicies.contains(Constants.READ)) { addPolicyToItem(context, item, Constants.READ, epa); - if (!userHasPolicies.contains(Constants.WRITE)) + } + if (!userHasPolicies.contains(Constants.WRITE)) { addPolicyToItem(context, item, Constants.WRITE, epa); - if (!userHasPolicies.contains(Constants.DELETE)) + } + if (!userHasPolicies.contains(Constants.DELETE)) { addPolicyToItem(context, item, Constants.DELETE, epa); - if (!userHasPolicies.contains(Constants.ADD)) + } + if (!userHasPolicies.contains(Constants.ADD)) { addPolicyToItem(context, item, Constants.ADD, epa); - if (!userHasPolicies.contains(Constants.REMOVE)) + } + if (!userHasPolicies.contains(Constants.REMOVE)) { addPolicyToItem(context, item, Constants.REMOVE, epa); + } } } - protected void grantGroupAllItemPolicies(Context context, Item item, Group group) throws AuthorizeException, SQLException { - if (group != null){ + protected void grantGroupAllItemPolicies(Context context, Item item, Group group) + throws AuthorizeException, SQLException { + if (group != null) { //A list of policies the user has for this item - List groupHasPolicies = new ArrayList(); + List groupHasPolicies = new ArrayList(); List itempols = authorizeService.getPolicies(context, item); for (ResourcePolicy resourcePolicy : itempols) { - if (group.equals(resourcePolicy.getGroup())){ + if (group.equals(resourcePolicy.getGroup())) { //The user has already got this policy so it it to the list groupHasPolicies.add(resourcePolicy.getAction()); } } //Make sure we don't add duplicate policies - if (!groupHasPolicies.contains(Constants.READ)) + if (!groupHasPolicies.contains(Constants.READ)) { addGroupPolicyToItem(context, item, Constants.READ, group); - if (!groupHasPolicies.contains(Constants.WRITE)) + } + if (!groupHasPolicies.contains(Constants.WRITE)) { addGroupPolicyToItem(context, item, Constants.WRITE, group); - if (!groupHasPolicies.contains(Constants.DELETE)) + } + if (!groupHasPolicies.contains(Constants.DELETE)) { addGroupPolicyToItem(context, item, Constants.DELETE, group); - if (!groupHasPolicies.contains(Constants.ADD)) + } + if (!groupHasPolicies.contains(Constants.ADD)) { addGroupPolicyToItem(context, item, Constants.ADD, group); - if (!groupHasPolicies.contains(Constants.REMOVE)) + } + if (!groupHasPolicies.contains(Constants.REMOVE)) { addGroupPolicyToItem(context, item, Constants.REMOVE, group); + } } } - protected void addPolicyToItem(Context context, Item item, int type, EPerson epa) throws AuthorizeException, SQLException { - if (epa != null){ - authorizeService.addPolicy(context, item, type, epa); + protected void addPolicyToItem(Context context, Item item, int type, EPerson epa) + throws AuthorizeException, SQLException { + addPolicyToItem(context, item, type, epa, null); + } + + protected void addPolicyToItem(Context context, Item item, int type, EPerson epa, String policyType) + throws AuthorizeException, SQLException { + if (epa != null) { + authorizeService.addPolicy(context, item, type, epa, policyType); List bundles = item.getBundles(); for (Bundle bundle : bundles) { - authorizeService.addPolicy(context, bundle, type, epa); + authorizeService.addPolicy(context, bundle, type, epa, policyType); List bits = bundle.getBitstreams(); for (Bitstream bit : bits) { - authorizeService.addPolicy(context, bit, type, epa); + authorizeService.addPolicy(context, bit, type, epa, policyType); } } } } - protected void addGroupPolicyToItem(Context context, Item item, int type, Group group) throws AuthorizeException, SQLException { - if (group != null){ + + protected void addGroupPolicyToItem(Context context, Item item, int type, Group group) + throws AuthorizeException, SQLException { + if (group != null) { authorizeService.addPolicy(context, item, type, group); List bundles = item.getBundles(); for (Bundle bundle : bundles) { @@ -734,7 +803,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } public void removeUserItemPolicies(Context context, Item item, EPerson e) throws SQLException, AuthorizeException { - if (e != null){ + if (e != null) { //Also remove any lingering authorizations from this user authorizeService.removeEPersonPolicies(context, item, e); //Remove the bundle rights @@ -747,15 +816,16 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } } // Ensure that the submitter always retains his resource policies - if (e.getID().equals(item.getSubmitter().getID())){ + if (e.getID().equals(item.getSubmitter().getID())) { grantSubmitterReadPolicies(context, item); } } } - protected void removeGroupItemPolicies(Context context, Item item, Group e) throws SQLException, AuthorizeException { - if (e != null){ + protected void removeGroupItemPolicies(Context context, Item item, Group e) + throws SQLException, AuthorizeException { + if (e != null) { //Also remove any lingering authorizations from this user authorizeService.removeGroupPolicies(context, item, e); //Remove the bundle rights @@ -771,16 +841,17 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } @Override - public WorkspaceItem sendWorkflowItemBackSubmission(Context context, XmlWorkflowItem wi, EPerson e, String provenance, - String rejection_message) throws SQLException, AuthorizeException, - IOException - { + public WorkspaceItem sendWorkflowItemBackSubmission(Context context, XmlWorkflowItem wi, EPerson e, + String provenance, + String rejection_message) + throws SQLException, AuthorizeException, + IOException { String workflowID = null; String currentStepId = null; String currentActionConfigId = null; ClaimedTask claimedTask = claimedTaskService.findByWorkflowIdAndEPerson(context, wi, e); - if (claimedTask != null){ + if (claimedTask != null) { //Log it workflowID = claimedTask.getWorkflowID(); currentStepId = claimedTask.getStepID(); @@ -799,13 +870,15 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { // Here's what happened String provDescription = provenance + " Rejected by " + usersName + ", reason: " - + rejection_message + " on " + now + " (GMT) "; + + rejection_message + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService + .addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); //Clear any workflow schema related metadata - itemService.clearMetadata(context, myitem, WorkflowRequirementsService.WORKFLOW_SCHEMA, Item.ANY, Item.ANY, Item.ANY); + itemService + .clearMetadata(context, myitem, WorkflowRequirementsService.WORKFLOW_SCHEMA, Item.ANY, Item.ANY, Item.ANY); itemService.update(context, myitem); @@ -815,9 +888,9 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { // notify that it's been rejected notifyOfReject(context, wi, e, rejection_message); log.info(LogManager.getHeader(context, "reject_workflow", "workflow_item_id=" - + wi.getID() + "item_id=" + wi.getItem().getID() - + "collection_id=" + wi.getCollection().getID() + "eperson_id=" - + e.getID())); + + wi.getID() + "item_id=" + wi.getItem().getID() + + "collection_id=" + wi.getCollection().getID() + "eperson_id=" + + e.getID())); logWorkflowEvent(context, workflowID, currentStepId, currentActionConfigId, wi, e, null, null); @@ -826,11 +899,11 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } @Override - public WorkspaceItem abort(Context c, XmlWorkflowItem wi, EPerson e) throws AuthorizeException, SQLException, IOException { - if (!authorizeService.isAdmin(c)) - { + public WorkspaceItem abort(Context c, XmlWorkflowItem wi, EPerson e) + throws AuthorizeException, SQLException, IOException { + if (!authorizeService.isAdmin(c)) { throw new AuthorizeException( - "You must be an admin to abort a workflow"); + "You must be an admin to abort a workflow"); } c.turnOffAuthorisationSystem(); @@ -839,9 +912,9 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { WorkspaceItem wsi = returnToWorkspace(c, wi); log.info(LogManager.getHeader(c, "abort_workflow", "workflow_item_id=" - + wi.getID() + "item_id=" + wsi.getItem().getID() - + "collection_id=" + wi.getCollection().getID() + "eperson_id=" - + e.getID())); + + wi.getID() + "item_id=" + wsi.getItem().getID() + + "collection_id=" + wi.getCollection().getID() + "eperson_id=" + + e.getID())); c.restoreAuthSystemState(); @@ -852,19 +925,16 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { * Return the workflow item to the workspace of the submitter. The workflow * item is removed, and a workspace item created. * - * @param c - * Context - * @param wfi - * WorkflowItem to be 'dismantled' + * @param c Context + * @param wfi WorkflowItem to be 'dismantled' * @return the workspace item - * @throws java.io.IOException ... - * @throws java.sql.SQLException ... + * @throws java.io.IOException ... + * @throws java.sql.SQLException ... * @throws org.dspace.authorize.AuthorizeException ... */ protected WorkspaceItem returnToWorkspace(Context c, XmlWorkflowItem wfi) - throws SQLException, IOException, AuthorizeException - { - // authorize a DSpaceActions.REJECT + throws SQLException, IOException, AuthorizeException { + // authorize a DSpaceActions.REJECT // stop workflow deleteAllTasks(c, wfi); @@ -891,8 +961,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { //myitem.update(); log.info(LogManager.getHeader(c, "return_to_workspace", - "workflow_item_id=" + wfi.getID() + "workspace_item_id=" - + workspaceItem.getID())); + "workflow_item_id=" + wfi.getID() + "workspace_item_id=" + + workspaceItem.getID())); // Now remove the workflow object manually from the database xmlWorkflowItemService.deleteWrapper(c, wfi); @@ -900,8 +970,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { } @Override - public String getEPersonName(EPerson ePerson) - { + public String getEPersonName(EPerson ePerson) { String submitter = ePerson.getFullName(); submitter = submitter + "(" + ePerson.getEmail() + ")"; @@ -911,40 +980,35 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { // Create workflow start provenance message protected void recordStart(Context context, Item myitem, Action action) - throws SQLException, IOException, AuthorizeException - { + throws SQLException, IOException, AuthorizeException { // get date DCDate now = DCDate.getCurrent(); // Create provenance description String provmessage = ""; - if (myitem.getSubmitter() != null) - { + if (myitem.getSubmitter() != null) { provmessage = "Submitted by " + myitem.getSubmitter().getFullName() - + " (" + myitem.getSubmitter().getEmail() + ") on " - + now.toString() + " workflow start=" + action.getProvenanceStartId() + "\n"; - } - else - // null submitter - { + + " (" + myitem.getSubmitter().getEmail() + ") on " + + now.toString() + " workflow start=" + action.getProvenanceStartId() + "\n"; + } else { + // else, null submitter provmessage = "Submitted by unknown (probably automated) on" - + now.toString() + " workflow start=" + action.getProvenanceStartId() + "\n"; + + now.toString() + " workflow start=" + action.getProvenanceStartId() + "\n"; } // add sizes and checksums of bitstreams provmessage += installItemService.getBitstreamProvenanceMessage(context, myitem); // Add message to the DC - itemService.addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provmessage); + itemService + .addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provmessage); itemService.update(context, myitem); } protected void notifyOfReject(Context c, XmlWorkflowItem wi, EPerson e, - String reason) - { - try - { + String reason) { + try { // Get the item title String title = wi.getItem().getName(); @@ -954,7 +1018,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { // Get rejector's name String rejector = getEPersonName(e); Locale supportedLocale = I18nUtil.getEPersonLocale(e); - Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale,"submit_reject")); + Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "submit_reject")); email.addRecipient(wi.getSubmitter().getEmail()); email.addArgument(title); @@ -964,14 +1028,12 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { email.addArgument(ConfigurationManager.getProperty("dspace.url") + "/mydspace"); email.send(); - } - catch (Exception ex) - { + } catch (Exception ex) { // log this email error log.warn(LogManager.getHeader(c, "notify_of_reject", - "cannot email user" + " eperson_id" + e.getID() - + " eperson_email" + e.getEmail() - + " workflow_item_id" + wi.getID())); + "cannot email user" + " eperson_id" + e.getID() + + " eperson_email" + e.getEmail() + + " workflow_item_id" + wi.getID())); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowFactory.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowFactory.java index 4cdb863c41..75c2a451ce 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowFactory.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowFactory.java @@ -7,15 +7,15 @@ */ package org.dspace.xmlworkflow.factory; +import java.io.IOException; +import java.sql.SQLException; + import org.dspace.content.Collection; import org.dspace.xmlworkflow.WorkflowConfigurationException; import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.Workflow; import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig; -import java.io.IOException; -import java.sql.SQLException; - /** * The xmlworkflowfactory is responsible for parsing the * workflow xml file and is used to retrieve the workflow for diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowServiceFactory.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowServiceFactory.java index d19ffa4407..639a8d3770 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowServiceFactory.java @@ -11,10 +11,16 @@ import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.workflow.factory.WorkflowServiceFactory; import org.dspace.xmlworkflow.service.WorkflowRequirementsService; import org.dspace.xmlworkflow.service.XmlWorkflowService; -import org.dspace.xmlworkflow.storedcomponents.service.*; +import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService; +import org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService; +import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; +import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; /** - * Abstract factory to get services for the xmlworkflow package, use XmlWorkflowServiceFactory.getInstance() to retrieve an implementation + * Abstract factory to get services for the xmlworkflow package, use XmlWorkflowServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ @@ -38,8 +44,8 @@ public abstract class XmlWorkflowServiceFactory extends WorkflowServiceFactory { public abstract XmlWorkflowItemService getXmlWorkflowItemService(); - public static XmlWorkflowServiceFactory getInstance() - { - return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("workflowServiceFactory", XmlWorkflowServiceFactory.class); + public static XmlWorkflowServiceFactory getInstance() { + return DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName("workflowServiceFactory", XmlWorkflowServiceFactory.class); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowServiceFactoryImpl.java index 7ecd7cacbc..5f36285d86 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/factory/XmlWorkflowServiceFactoryImpl.java @@ -11,11 +11,17 @@ import org.dspace.workflow.WorkflowItemService; import org.dspace.workflow.WorkflowService; import org.dspace.xmlworkflow.service.WorkflowRequirementsService; import org.dspace.xmlworkflow.service.XmlWorkflowService; -import org.dspace.xmlworkflow.storedcomponents.service.*; +import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService; +import org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService; +import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; +import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; import org.springframework.beans.factory.annotation.Autowired; /** - * Factory implementation to get services for the xmlworkflow package, use XmlWorkflowServiceFactory.getInstance() to retrieve an implementation + * Factory implementation to get services for the xmlworkflow package, use XmlWorkflowServiceFactory.getInstance() to + * retrieve an implementation * * @author kevinvandevelde at atmire.com */ diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/migration/RestartWorkflow.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/migration/RestartWorkflow.java index 7c0270b707..d64fa66843 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/migration/RestartWorkflow.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/migration/RestartWorkflow.java @@ -7,7 +7,14 @@ */ package org.dspace.xmlworkflow.migration; -import org.apache.commons.cli.*; +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.log4j.Logger; import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; @@ -20,9 +27,6 @@ import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.WorkflowService; import org.dspace.workflow.factory.WorkflowServiceFactory; -import java.util.List; -import java.util.UUID; - /** * A utility class that will send all the worklfow items * back to their submitters @@ -43,6 +47,11 @@ public class RestartWorkflow { private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); + /** + * Default constructor + */ + private RestartWorkflow() { } + public static void main(String[] args) { try { System.out.println("All workflowitems will be sent back to the first workflow step."); @@ -53,11 +62,11 @@ public class RestartWorkflow { Options options = new Options(); options.addOption("e", "eperson", true, - "email of eperson doing importing"); + "email of eperson doing importing"); options.addOption("n", "notify", false, - "if sending submissions through the workflow, send notification emails"); + "if sending submissions through the workflow, send notification emails"); options.addOption("p", "provenance", true, - "the provenance description to be added to the item"); + "the provenance description to be added to the item"); options.addOption("h", "help", false, "help"); CommandLine line = parser.parse(options, args); @@ -72,10 +81,10 @@ public class RestartWorkflow { if (line.hasOption('n')) { useWorkflowSendEmail = true; } - if (line.hasOption('e')) // eperson - { + // eperson + if (line.hasOption('e')) { eperson = line.getOptionValue('e'); - }else{ + } else { System.out.println("The -e (eperson) option is mandatory !"); System.exit(1); } @@ -96,7 +105,7 @@ public class RestartWorkflow { } String provenance = null; - if(line.hasOption('p')){ + if (line.hasOption('p')) { provenance = line.getOptionValue('p'); } @@ -125,11 +134,12 @@ public class RestartWorkflow { // tasklog.update(); // convert into personal workspace - WorkspaceItem wsi = workflowService.sendWorkflowItemBackSubmission(context, workflowItem, myEPerson, provenance, ""); + WorkspaceItem wsi = workflowService + .sendWorkflowItemBackSubmission(context, workflowItem, myEPerson, provenance, ""); log.info(LogManager.getHeader(context, "restart_workflow", "workflow_item_id=" - + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() - + "collection_id=" + workflowItem.getCollection().getID())); + + workflowItem.getID() + "item_id=" + workflowItem.getItem().getID() + + "collection_id=" + workflowItem.getCollection().getID())); if (useWorkflowSendEmail) { diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/service/WorkflowRequirementsService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/service/WorkflowRequirementsService.java index a4d888054d..29d29dbcda 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/service/WorkflowRequirementsService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/service/WorkflowRequirementsService.java @@ -7,6 +7,9 @@ */ package org.dspace.xmlworkflow.service; +import java.io.IOException; +import java.sql.SQLException; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -14,9 +17,6 @@ import org.dspace.xmlworkflow.WorkflowConfigurationException; import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.io.IOException; -import java.sql.SQLException; - /** * A class that contains utililty methods related to the workflow * The adding/removing from claimed users and ensuring that @@ -37,28 +37,33 @@ public interface WorkflowRequirementsService { * Adds a claimed user in the metadata * if enough users have claimed this task (claimed or finished) to meet the required number * the pooled tasks will be deleted + * * @param context the dspace context - * @param wfi the workflow item - * @param step the step for which we are accepting - * @param user the current user - * @throws SQLException ... + * @param wfi the workflow item + * @param step the step for which we are accepting + * @param user the current user + * @throws SQLException ... * @throws AuthorizeException ... - * @throws IOException ... + * @throws IOException ... */ - public void addClaimedUser(Context context, XmlWorkflowItem wfi, Step step, EPerson user) throws SQLException, AuthorizeException, IOException; + public void addClaimedUser(Context context, XmlWorkflowItem wfi, Step step, EPerson user) + throws SQLException, AuthorizeException, IOException; - public void removeClaimedUser(Context context, XmlWorkflowItem wfi, EPerson user, String stepID) throws SQLException, IOException, WorkflowConfigurationException, AuthorizeException; + public void removeClaimedUser(Context context, XmlWorkflowItem wfi, EPerson user, String stepID) + throws SQLException, IOException, WorkflowConfigurationException, AuthorizeException; /** * Adds a finished user in the metadata * this method will also remove the user from the inprogress metadata + * * @param context the dspace context - * @param wfi the workflow item - * @param user the current user + * @param wfi the workflow item + * @param user the current user * @throws AuthorizeException ... - * @throws SQLException ... + * @throws SQLException ... */ - public void addFinishedUser(Context context, XmlWorkflowItem wfi, EPerson user) throws AuthorizeException, SQLException; + public void addFinishedUser(Context context, XmlWorkflowItem wfi, EPerson user) + throws AuthorizeException, SQLException; public void clearInProgressUsers(Context context, XmlWorkflowItem wfi) throws AuthorizeException, SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/service/XmlWorkflowService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/service/XmlWorkflowService.java index 9eea8e671e..83e2812956 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/service/XmlWorkflowService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/service/XmlWorkflowService.java @@ -7,12 +7,18 @@ */ package org.dspace.xmlworkflow.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import javax.mail.MessagingException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import org.dspace.workflow.WorkflowService; import org.dspace.workflow.WorkflowException; +import org.dspace.workflow.WorkflowService; import org.dspace.xmlworkflow.RoleMembers; import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.Workflow; @@ -22,12 +28,6 @@ import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; import org.dspace.xmlworkflow.storedcomponents.PoolTask; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import javax.mail.MessagingException; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * When an item is submitted and is somewhere in a workflow, it has a row in the * WorkflowItem table pointing to it. @@ -41,26 +41,37 @@ import java.util.List; */ public interface XmlWorkflowService extends WorkflowService { - public void alertUsersOnTaskActivation(Context c, XmlWorkflowItem wfi, String emailTemplate, List epa, String ...arguments) throws IOException, SQLException, MessagingException; + public void alertUsersOnTaskActivation(Context c, XmlWorkflowItem wfi, String emailTemplate, List epa, + String... arguments) throws IOException, SQLException, MessagingException; - public WorkflowActionConfig doState(Context c, EPerson user, HttpServletRequest request, int workflowItemId, Workflow workflow, WorkflowActionConfig currentActionConfig) throws SQLException, AuthorizeException, IOException, MessagingException, WorkflowException; + public WorkflowActionConfig doState(Context c, EPerson user, HttpServletRequest request, int workflowItemId, + Workflow workflow, WorkflowActionConfig currentActionConfig) + throws SQLException, AuthorizeException, IOException, MessagingException, WorkflowException; - public WorkflowActionConfig processOutcome(Context c, EPerson user, Workflow workflow, Step currentStep, WorkflowActionConfig currentActionConfig, ActionResult currentOutcome, XmlWorkflowItem wfi, boolean enteredNewStep) throws IOException, AuthorizeException, SQLException, WorkflowException; + public WorkflowActionConfig processOutcome(Context c, EPerson user, Workflow workflow, Step currentStep, + WorkflowActionConfig currentActionConfig, ActionResult currentOutcome, + XmlWorkflowItem wfi, boolean enteredNewStep) + throws IOException, AuthorizeException, SQLException, WorkflowException; public void deleteAllTasks(Context context, XmlWorkflowItem wi) throws SQLException, AuthorizeException; public void deleteAllPooledTasks(Context c, XmlWorkflowItem wi) throws SQLException, AuthorizeException; - public void deletePooledTask(Context context, XmlWorkflowItem wi, PoolTask task) throws SQLException, AuthorizeException; + public void deletePooledTask(Context context, XmlWorkflowItem wi, PoolTask task) + throws SQLException, AuthorizeException; - public void deleteClaimedTask(Context c, XmlWorkflowItem wi, ClaimedTask task) throws SQLException, AuthorizeException; + public void deleteClaimedTask(Context c, XmlWorkflowItem wi, ClaimedTask task) + throws SQLException, AuthorizeException; - public void createPoolTasks(Context context, XmlWorkflowItem wi, RoleMembers assignees, Step step, WorkflowActionConfig action) - throws SQLException, AuthorizeException; + public void createPoolTasks(Context context, XmlWorkflowItem wi, RoleMembers assignees, Step step, + WorkflowActionConfig action) + throws SQLException, AuthorizeException; - public void createOwnedTask(Context context, XmlWorkflowItem wi, Step step, WorkflowActionConfig action, EPerson e) throws SQLException, AuthorizeException; + public void createOwnedTask(Context context, XmlWorkflowItem wi, Step step, WorkflowActionConfig action, EPerson e) + throws SQLException, AuthorizeException; - public void grantUserAllItemPolicies(Context context, Item item, EPerson epa) throws AuthorizeException, SQLException; + public void grantUserAllItemPolicies(Context context, Item item, EPerson epa) + throws AuthorizeException, SQLException; public void removeUserItemPolicies(Context context, Item item, EPerson e) throws SQLException, AuthorizeException; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/Step.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/Step.java index b1c8bba5d4..01a83d9bb3 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/Step.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/Step.java @@ -7,22 +7,23 @@ */ package org.dspace.xmlworkflow.state; -import org.dspace.core.Context; -import org.dspace.workflow.WorkflowException; -import org.dspace.xmlworkflow.factory.XmlWorkflowFactory; -import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; -import org.dspace.xmlworkflow.state.actions.UserSelectionActionConfig; -import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import org.dspace.xmlworkflow.*; -import org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService; - import java.io.IOException; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.dspace.core.Context; +import org.dspace.workflow.WorkflowException; +import org.dspace.xmlworkflow.Role; +import org.dspace.xmlworkflow.WorkflowConfigurationException; +import org.dspace.xmlworkflow.factory.XmlWorkflowFactory; +import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; +import org.dspace.xmlworkflow.state.actions.UserSelectionActionConfig; +import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService; + /** * A class that contains all the data of an xlworkflow step * @@ -34,7 +35,8 @@ import java.util.Map; public class Step { - protected InProgressUserService inProgressUserService = XmlWorkflowServiceFactory.getInstance().getInProgressUserService(); + protected InProgressUserService inProgressUserService = XmlWorkflowServiceFactory.getInstance() + .getInProgressUserService(); protected XmlWorkflowFactory xmlWorkflowFactory = XmlWorkflowServiceFactory.getInstance().getWorkflowFactory(); @@ -47,7 +49,8 @@ public class Step { private Workflow workflow; private int requiredUsers; - public Step(String id, Workflow workflow, Role role, UserSelectionActionConfig userSelectionMethod, List actionConfigsList, Map outcomes, int requiredUsers) { + public Step(String id, Workflow workflow, Role role, UserSelectionActionConfig userSelectionMethod, + List actionConfigsList, Map outcomes, int requiredUsers) { this.actionConfigsMap = new HashMap<>(); this.outcomes = outcomes; this.userSelectionMethod = userSelectionMethod; @@ -61,7 +64,7 @@ public class Step { } public WorkflowActionConfig getActionConfig(String actionID) { - if (actionConfigsMap.get(actionID)!=null) { + if (actionConfigsMap.get(actionID) != null) { return actionConfigsMap.get(actionID); } else { WorkflowActionConfig action = xmlWorkflowFactory.createWorkflowActionConfig(actionID); @@ -73,6 +76,7 @@ public class Step { /** * Boolean that returns whether or not the actions in this step have a ui + * * @return a boolean */ public boolean hasUI() { @@ -85,25 +89,29 @@ public class Step { return false; } - public String getNextStepID(int outcome) throws WorkflowException, IOException, WorkflowConfigurationException, SQLException { + public String getNextStepID(int outcome) + throws WorkflowException, IOException, WorkflowConfigurationException, SQLException { return outcomes.get(outcome); } - public boolean isValidStep(Context context, XmlWorkflowItem wfi) throws WorkflowConfigurationException, SQLException { + public boolean isValidStep(Context context, XmlWorkflowItem wfi) + throws WorkflowConfigurationException, SQLException { //Check if our next step has a UI, if not then the step is valid, no need for a group - return !(getUserSelectionMethod() == null || getUserSelectionMethod().getProcessingAction() == null) && getUserSelectionMethod().getProcessingAction().isValidUserSelection(context, wfi, hasUI()); + return !(getUserSelectionMethod() == null || getUserSelectionMethod() + .getProcessingAction() == null) && getUserSelectionMethod().getProcessingAction() + .isValidUserSelection(context, wfi, hasUI()); } public UserSelectionActionConfig getUserSelectionMethod() { - return userSelectionMethod; + return userSelectionMethod; } public WorkflowActionConfig getNextAction(WorkflowActionConfig currentAction) { int index = actionConfigsList.indexOf(currentAction.getId()); - if (index < actionConfigsList.size()-1) { - return getActionConfig(actionConfigsList.get(index+1)); + if (index < actionConfigsList.size() - 1) { + return getActionConfig(actionConfigsList.get(index + 1)); } else { return null; } @@ -120,13 +128,11 @@ public class Step { /** * Check if enough users have finished this step for it to continue - * @param c - * The relevant DSpace Context. - * @param wfi - * the workflow item to check + * + * @param c The relevant DSpace Context. + * @param wfi the workflow item to check * @return if enough users have finished this task - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public boolean isFinished(Context c, XmlWorkflowItem wfi) throws SQLException { return inProgressUserService.getNumberOfFinishedUsers(c, wfi) == requiredUsers; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/Workflow.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/Workflow.java index 99094aaa39..99ff7391dd 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/Workflow.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/Workflow.java @@ -7,19 +7,19 @@ */ package org.dspace.xmlworkflow.state; -import org.dspace.core.Context; -import org.dspace.xmlworkflow.Role; -import org.dspace.xmlworkflow.WorkflowConfigurationException; -import org.dspace.workflow.WorkflowException; -import org.dspace.xmlworkflow.factory.XmlWorkflowFactory; -import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; - import java.io.IOException; import java.sql.SQLException; import java.util.HashMap; import java.util.LinkedHashMap; +import org.dspace.core.Context; +import org.dspace.workflow.WorkflowException; +import org.dspace.xmlworkflow.Role; +import org.dspace.xmlworkflow.WorkflowConfigurationException; +import org.dspace.xmlworkflow.factory.XmlWorkflowFactory; +import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; + /** * Class that contains all the steps and roles involved in a certain * configured workflow @@ -57,31 +57,34 @@ public class Workflow { * Return a step with a given id */ public Step getStep(String stepID) throws WorkflowConfigurationException, IOException { - if (steps.get(id)!=null) { + if (steps.get(id) != null) { return steps.get(id); } else { Step step = xmlWorkflowFactory.createStep(this, stepID); - if (step== null){ - throw new WorkflowConfigurationException("Step definition not found for: "+stepID); + if (step == null) { + throw new WorkflowConfigurationException("Step definition not found for: " + stepID); } steps.put(stepID, step); return step; } } - public Step getNextStep(Context context, XmlWorkflowItem wfi, Step currentStep, int outcome) throws IOException, WorkflowConfigurationException, WorkflowException, SQLException { + public Step getNextStep(Context context, XmlWorkflowItem wfi, Step currentStep, int outcome) + throws IOException, WorkflowConfigurationException, WorkflowException, SQLException { String nextStepID = currentStep.getNextStepID(outcome); if (nextStepID != null) { Step nextStep = getStep(nextStepID); - if (nextStep == null) - throw new WorkflowException("Error while processing outcome, the following action was undefined: " + nextStepID); + if (nextStep == null) { + throw new WorkflowException( + "Error while processing outcome, the following action was undefined: " + nextStepID); + } if (nextStep.isValidStep(context, wfi)) { return nextStep; } else { return getNextStep(context, wfi, nextStep, 0); } - }else{ + } else { //No next step, archive it return null; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/Action.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/Action.java index ef6a94df01..ba481be3d9 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/Action.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/Action.java @@ -7,26 +7,26 @@ */ package org.dspace.xmlworkflow.state.actions; -import org.dspace.authorize.AuthorizeException; -import org.dspace.core.Context; -import org.dspace.xmlworkflow.RoleMembers; -import org.dspace.xmlworkflow.WorkflowConfigurationException; -import org.dspace.workflow.WorkflowException; -import org.dspace.xmlworkflow.state.Step; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; - -import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.core.Context; +import org.dspace.workflow.WorkflowException; +import org.dspace.xmlworkflow.RoleMembers; +import org.dspace.xmlworkflow.WorkflowConfigurationException; +import org.dspace.xmlworkflow.state.Step; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; /** * This abstract class represents an api action * Each step in the xml workflow consists of a number of actions * this abstract action contains some utility methods and the methods * that each of these actions must implement including: - * activating, execution, ... + * activating, execution, ... * * @author Bram De Schouwer (bram.deschouwer at dot com) * @author Kevin Van de Velde (kevin at atmire dot com) @@ -39,9 +39,11 @@ public abstract class Action { private static String ERROR_FIELDS_ATTRIBUTE = "dspace.workflow.error_fields"; - public abstract void activate(Context c, XmlWorkflowItem wf) throws SQLException, IOException, AuthorizeException, WorkflowException; + public abstract void activate(Context c, XmlWorkflowItem wf) + throws SQLException, IOException, AuthorizeException, WorkflowException; - public abstract ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException, WorkflowException; + public abstract ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException, WorkflowException; public WorkflowActionConfig getParent() { return parent; @@ -51,15 +53,17 @@ public abstract class Action { this.parent = parent; } - public String getProvenanceStartId(){ + public String getProvenanceStartId() { return "Step: " + getParent().getStep().getId() + " - action:" + getParent().getId(); } - public void alertUsersOnActivation(Context c, XmlWorkflowItem wfi, RoleMembers members) throws SQLException, IOException { + public void alertUsersOnActivation(Context c, XmlWorkflowItem wfi, RoleMembers members) + throws SQLException, IOException { } - public abstract boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) throws SQLException, AuthorizeException, IOException, WorkflowConfigurationException; + public abstract boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) + throws SQLException, AuthorizeException, IOException, WorkflowConfigurationException; /** @@ -67,17 +71,15 @@ public abstract class Action { * step processing. This list is for usage in generating the appropriate * error message(s) in the UI. * - * @param request - * current servlet request object - * @param errorFields - * List of all fields (as Strings) which had errors + * @param request current servlet request object + * @param errorFields List of all fields (as Strings) which had errors */ - private void setErrorFields(HttpServletRequest request, List errorFields) - { - if(errorFields==null) + private void setErrorFields(HttpServletRequest request, List errorFields) { + if (errorFields == null) { request.removeAttribute(ERROR_FIELDS_ATTRIBUTE); - else + } else { request.setAttribute(ERROR_FIELDS_ATTRIBUTE, errorFields); + } } /** @@ -85,15 +87,14 @@ public abstract class Action { * workflow processing. This list is for usage in generating the appropriate * error message(s) in the UI. * - * @param request - * current servlet request object + * @param request current servlet request object * @return List of error fields (as Strings) */ - public static List getErrorFields(HttpServletRequest request) - { + public static List getErrorFields(HttpServletRequest request) { List result = new ArrayList(); - if(request.getAttribute(ERROR_FIELDS_ATTRIBUTE) != null) + if (request.getAttribute(ERROR_FIELDS_ATTRIBUTE) != null) { result = (List) request.getAttribute(ERROR_FIELDS_ATTRIBUTE); + } return result; } @@ -101,18 +102,14 @@ public abstract class Action { * Add a single UI field to the list of all error fields (which can * later be retrieved using getErrorFields()) * - * @param request - * current servlet request object - * @param fieldName - * the name of the field which had an error + * @param request current servlet request object + * @param fieldName the name of the field which had an error */ - protected void addErrorField(HttpServletRequest request, String fieldName) - { + protected void addErrorField(HttpServletRequest request, String fieldName) { //get current list List errorFields = getErrorFields(request); - if (errorFields == null) - { + if (errorFields == null) { errorFields = new ArrayList(); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/ActionResult.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/ActionResult.java index 8582d7da60..e51d52b211 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/ActionResult.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/ActionResult.java @@ -25,7 +25,7 @@ package org.dspace.xmlworkflow.state.actions; */ public class ActionResult { - public static enum TYPE{ + public static enum TYPE { TYPE_OUTCOME, TYPE_PAGE, TYPE_ERROR, @@ -35,9 +35,14 @@ public class ActionResult { public static final int OUTCOME_COMPLETE = 0; - /** The type is used to send the user to the submission page, to another page in the step, to move to another step, ... */ + /** + * The type is used to send the user to the submission page, to another page in the step, to move to another + * step, ... + */ private TYPE type; - /** The result int will determine what our next step is */ + /** + * The result int will determine what our next step is + */ private int result; public ActionResult(TYPE type, int result) { diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/UserSelectionActionConfig.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/UserSelectionActionConfig.java index ddd6804d4d..d4029c73f0 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/UserSelectionActionConfig.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/UserSelectionActionConfig.java @@ -17,13 +17,13 @@ import org.dspace.xmlworkflow.state.actions.userassignment.UserSelectionAction; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class UserSelectionActionConfig extends WorkflowActionConfig{ +public class UserSelectionActionConfig extends WorkflowActionConfig { public UserSelectionActionConfig(String id) { super(id); } - public void setProcessingAction(UserSelectionAction processingAction){ + public void setProcessingAction(UserSelectionAction processingAction) { this.processingAction = processingAction; processingAction.setParent(this); @@ -31,7 +31,7 @@ public class UserSelectionActionConfig extends WorkflowActionConfig{ @Override - public UserSelectionAction getProcessingAction(){ + public UserSelectionAction getProcessingAction() { return (UserSelectionAction) processingAction; } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/WorkflowActionConfig.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/WorkflowActionConfig.java index 81618b1c5b..8b6a3dc880 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/WorkflowActionConfig.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/WorkflowActionConfig.java @@ -28,12 +28,11 @@ public class WorkflowActionConfig { private ActionInterface actionUI; - - public WorkflowActionConfig(String id){ + public WorkflowActionConfig(String id) { this.id = id; } - public void setProcessingAction(Action processingAction){ + public void setProcessingAction(Action processingAction) { this.processingAction = processingAction; processingAction.setParent(this); @@ -56,7 +55,6 @@ public class WorkflowActionConfig { } - public void setStep(Step step) { this.step = step; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java index a3102768f1..072e2289d7 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java @@ -7,6 +7,10 @@ */ package org.dspace.xmlworkflow.state.actions.processingaction; +import java.io.IOException; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; @@ -14,12 +18,8 @@ import org.dspace.content.MetadataSchema; import org.dspace.core.Context; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; import org.dspace.xmlworkflow.state.Step; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.state.actions.ActionResult; - -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; /** * Processing class of an action that allows users to @@ -43,27 +43,28 @@ public class AcceptEditRejectAction extends ProcessingAction { } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { int page = Util.getIntParameter(request, "page"); - switch (page){ + switch (page) { case MAIN_PAGE: return processMainPage(c, wfi, step, request); case REJECT_PAGE: return processRejectPage(c, wfi, step, request); - + default: + return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } - - return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } - public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException { - if(request.getParameter("submit_approve") != null){ + public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException { + if (request.getParameter("submit_approve") != null) { //Delete the tasks addApprovedProvenance(c, wfi); return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); - } else if(request.getParameter("submit_reject") != null){ + } else if (request.getParameter("submit_reject") != null) { // Make sure we indicate which page we want to process request.setAttribute("page", REJECT_PAGE); // We have pressed reject item, so take the user to a page where he can reject @@ -74,21 +75,24 @@ public class AcceptEditRejectAction extends ProcessingAction { } } - public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { - if(request.getParameter("submit_reject") != null){ + public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { + if (request.getParameter("submit_reject") != null) { String reason = request.getParameter("reason"); - if(reason == null || 0 == reason.trim().length()){ + if (reason == null || 0 == reason.trim().length()) { addErrorField(request, "reason"); request.setAttribute("page", REJECT_PAGE); return new ActionResult(ActionResult.TYPE.TYPE_ERROR); } //We have pressed reject, so remove the task the user has & put it back to a workspace item - XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), this.getProvenanceStartId(), reason); + XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), + this.getProvenanceStartId(), reason); return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); - }else{ + } else { //Cancel, go back to the main task page request.setAttribute("page", MAIN_PAGE); @@ -101,13 +105,15 @@ public class AcceptEditRejectAction extends ProcessingAction { String now = DCDate.getCurrent().toString(); // Get user's name + email address - String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().getEPersonName(c.getCurrentUser()); + String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .getEPersonName(c.getCurrentUser()); String provDescription = getProvenanceStartId() + " Approved for entry into archive by " - + usersName + " on " + now + " (GMT) "; + + usersName + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + provDescription); itemService.update(c, wfi.getItem()); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java index 17d71f1247..2b05f3d0d1 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java @@ -7,6 +7,10 @@ */ package org.dspace.xmlworkflow.state.actions.processingaction; +import java.io.IOException; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; import org.dspace.content.MetadataSchema; @@ -16,10 +20,6 @@ import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.actions.ActionResult; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; - /** * Processing class of an action that allows users to * accept/reject a workflow item @@ -38,12 +38,14 @@ public class FinalEditAction extends ProcessingAction { } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { return processMainPage(c, wfi, step, request); } - public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException { - if(request.getParameter("submit_approve") != null){ + public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException { + if (request.getParameter("submit_approve") != null) { //Delete the tasks addApprovedProvenance(c, wfi); @@ -59,16 +61,17 @@ public class FinalEditAction extends ProcessingAction { String now = DCDate.getCurrent().toString(); // Get user's name + email address - String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().getEPersonName(c.getCurrentUser()); + String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .getEPersonName(c.getCurrentUser()); String provDescription = getProvenanceStartId() + " Approved for entry into archive by " - + usersName + " on " + now + " (GMT) "; + + usersName + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + provDescription); itemService.update(c, wfi.getItem()); } - } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ProcessingAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ProcessingAction.java index e14aa04de0..1fbb02710d 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ProcessingAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ProcessingAction.java @@ -7,16 +7,17 @@ */ package org.dspace.xmlworkflow.state.actions.processingaction; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.xmlworkflow.state.actions.Action; -import org.dspace.xmlworkflow.storedcomponents.*; +import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService; import org.springframework.beans.factory.annotation.Autowired; -import javax.servlet.http.HttpServletRequest; -import java.sql.SQLException; - /** * A class that that extends the action to support the common * isAuthorized method @@ -37,12 +38,13 @@ public abstract class ProcessingAction extends Action { @Override public boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) throws SQLException { ClaimedTask task = null; - if(context.getCurrentUser() != null) + if (context.getCurrentUser() != null) { task = claimedTaskService.findByWorkflowIdAndEPerson(context, wfi, context.getCurrentUser()); + } //Check if we have claimed the current task return task != null && - task.getWorkflowID().equals(getParent().getStep().getWorkflow().getID()) && - task.getStepID().equals(getParent().getStep().getId()) && - task.getActionID().equals(getParent().getId()); + task.getWorkflowID().equals(getParent().getStep().getWorkflow().getID()) && + task.getStepID().equals(getParent().getStep().getId()) && + task.getActionID().equals(getParent().getId()); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java index 81e3e900d5..1db060d39d 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java @@ -7,6 +7,10 @@ */ package org.dspace.xmlworkflow.state.actions.processingaction; +import java.io.IOException; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; @@ -14,12 +18,8 @@ import org.dspace.content.MetadataSchema; import org.dspace.core.Context; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; import org.dspace.xmlworkflow.state.Step; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.state.actions.ActionResult; - -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; /** * Processing class of an accept/reject action @@ -41,26 +41,28 @@ public class ReviewAction extends ProcessingAction { } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { int page = Util.getIntParameter(request, "page"); - switch (page){ + switch (page) { case MAIN_PAGE: return processMainPage(c, wfi, step, request); case REJECT_PAGE: return processRejectPage(c, wfi, step, request); + default: + return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } - - return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } - public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException { - if(request.getParameter("submit_approve") != null){ + public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException { + if (request.getParameter("submit_approve") != null) { //Delete the tasks addApprovedProvenance(c, wfi); return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); - } else if(request.getParameter("submit_reject") != null){ + } else if (request.getParameter("submit_reject") != null) { // Make sure we indicate which page we want to process request.setAttribute("page", REJECT_PAGE); // We have pressed reject item, so take the user to a page where he can reject @@ -76,31 +78,36 @@ public class ReviewAction extends ProcessingAction { String now = DCDate.getCurrent().toString(); // Get user's name + email address - String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().getEPersonName(c.getCurrentUser()); + String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .getEPersonName(c.getCurrentUser()); String provDescription = getProvenanceStartId() + " Approved for entry into archive by " - + usersName + " on " + now + " (GMT) "; + + usersName + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + provDescription); itemService.update(c, wfi.getItem()); } - public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { - if(request.getParameter("submit_reject") != null){ + public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { + if (request.getParameter("submit_reject") != null) { String reason = request.getParameter("reason"); - if(reason == null || 0 == reason.trim().length()){ + if (reason == null || 0 == reason.trim().length()) { request.setAttribute("page", REJECT_PAGE); addErrorField(request, "reason"); return new ActionResult(ActionResult.TYPE.TYPE_ERROR); } //We have pressed reject, so remove the task the user has & put it back to a workspace item - XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), this.getProvenanceStartId(), reason); + XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), + this.getProvenanceStartId(), reason); return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); - }else{ + } else { //Cancel, go back to the main task page request.setAttribute("page", MAIN_PAGE); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreEvaluationAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreEvaluationAction.java index 1b8cf30cf5..97f26eb3c7 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreEvaluationAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreEvaluationAction.java @@ -7,10 +7,15 @@ */ package org.dspace.xmlworkflow.state.actions.processingaction; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import javax.servlet.http.HttpServletRequest; + import org.dspace.authorize.AuthorizeException; -import org.dspace.content.MetadataValue; import org.dspace.content.Item; import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataValue; import org.dspace.core.Context; import org.dspace.workflow.WorkflowException; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; @@ -19,11 +24,6 @@ import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.actions.ActionResult; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * Processing class for the score evaluation action * This action will allow multiple users to rate a certain item @@ -35,21 +35,24 @@ import java.util.List; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class ScoreEvaluationAction extends ProcessingAction{ +public class ScoreEvaluationAction extends ProcessingAction { private int minimumAcceptanceScore; @Override - public void activate(Context c, XmlWorkflowItem wf) throws SQLException, IOException, AuthorizeException, WorkflowException { + public void activate(Context c, XmlWorkflowItem wf) + throws SQLException, IOException, AuthorizeException, WorkflowException { } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException, WorkflowException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException, WorkflowException { boolean hasPassed = false; //Retrieve all our scores from the metadata & add em up - List scores = itemService.getMetadata(wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, Item.ANY); - if(0 < scores.size()){ + List scores = itemService + .getMetadata(wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, Item.ANY); + if (0 < scores.size()) { int totalScoreCount = 0; for (MetadataValue score : scores) { totalScoreCount += Integer.parseInt(score.getValue()); @@ -58,17 +61,23 @@ public class ScoreEvaluationAction extends ProcessingAction{ //We have passed if we have at least gained our minimum score hasPassed = getMinimumAcceptanceScore() <= scoreMean; //Wether or not we have passed, clear our score information - itemService.clearMetadata(c, wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, Item.ANY); + itemService + .clearMetadata(c, wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, Item.ANY); - String provDescription = getProvenanceStartId() + " Approved for entry into archive with a score of: " + scoreMean; - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + String provDescription = getProvenanceStartId() + " Approved for entry into archive with a score of: " + + scoreMean; + itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + provDescription); itemService.update(c, wfi.getItem()); } - if(hasPassed){ + if (hasPassed) { return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); - }else{ + } else { //We haven't passed, reject our item - XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), this.getProvenanceStartId(), "The item was reject due to a bad review score."); + XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), + this.getProvenanceStartId(), + "The item was reject due to a bad review score."); return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreReviewAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreReviewAction.java index ba80d1af7d..07780704bc 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreReviewAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreReviewAction.java @@ -7,6 +7,10 @@ */ package org.dspace.xmlworkflow.state.actions.processingaction; +import java.io.IOException; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; @@ -16,12 +20,7 @@ import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.actions.ActionResult; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; - /** - * * This action will allow multiple users to rate a certain item * if the mean of this score is higher then the minimum score the * item will be sent to the next action/step else it will be rejected @@ -31,23 +30,26 @@ import java.sql.SQLException; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class ScoreReviewAction extends ProcessingAction{ +public class ScoreReviewAction extends ProcessingAction { @Override - public void activate(Context c, XmlWorkflowItem wf) throws SQLException, IOException, AuthorizeException, WorkflowException { + public void activate(Context c, XmlWorkflowItem wf) + throws SQLException, IOException, AuthorizeException, WorkflowException { } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException, WorkflowException { - if(request.getParameter("submit_score") != null){ + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException, WorkflowException { + if (request.getParameter("submit_score") != null) { int score = Util.getIntParameter(request, "score"); //Add our score to the metadata - itemService.addMetadata(c, wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, null, String.valueOf(score)); + itemService.addMetadata(c, wfi.getItem(), WorkflowRequirementsService.WORKFLOW_SCHEMA, "score", null, null, + String.valueOf(score)); itemService.update(c, wfi.getItem()); return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); - }else{ + } else { //We have pressed the leave button so return to our submission page return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SelectReviewerAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SelectReviewerAction.java index 4b85b5ad26..f1ddcd8e6f 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SelectReviewerAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SelectReviewerAction.java @@ -7,6 +7,12 @@ */ package org.dspace.xmlworkflow.state.actions.processingaction; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; + import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; @@ -20,12 +26,6 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; import org.springframework.beans.factory.annotation.Autowired; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; - /** * Processing class for an action where an assigned user can * assign another user to review the item @@ -35,7 +35,7 @@ import java.util.UUID; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class SelectReviewerAction extends ProcessingAction{ +public class SelectReviewerAction extends ProcessingAction { public static final int MAIN_PAGE = 0; public static final int SEARCH_RESULTS_PAGE = 1; @@ -51,30 +51,31 @@ public class SelectReviewerAction extends ProcessingAction{ protected WorkflowItemRoleService workflowItemRoleService; @Override - public void activate(Context c, XmlWorkflowItem wf) throws SQLException, IOException, AuthorizeException, WorkflowException { + public void activate(Context c, XmlWorkflowItem wf) + throws SQLException, IOException, AuthorizeException, WorkflowException { } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException, WorkflowException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException, WorkflowException { String submitButton = Util.getSubmitButton(request, "submit_cancel"); //Check if our user has pressed cancel - if(submitButton.equals("submit_cancel")){ + if (submitButton.equals("submit_cancel")) { //Send us back to the submissions page return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); - }else - if(submitButton.equals("submit_search")){ + } else if (submitButton.equals("submit_search")) { //Perform the search String query = request.getParameter("query"); int page = Util.getIntParameter(request, "result-page"); - if(page == -1){ + if (page == -1) { page = 0; } int resultCount = ePersonService.searchResultCount(c, query); - List epeople = ePersonService.search(c, query, page*RESULTS_PER_PAGE, RESULTS_PER_PAGE); + List epeople = ePersonService.search(c, query, page * RESULTS_PER_PAGE, RESULTS_PER_PAGE); request.setAttribute("eperson-result-count", resultCount); @@ -82,8 +83,7 @@ public class SelectReviewerAction extends ProcessingAction{ request.setAttribute("result-page", page); request.setAttribute("page", SEARCH_RESULTS_PAGE); return new ActionResult(ActionResult.TYPE.TYPE_PAGE, SEARCH_RESULTS_PAGE); - }else - if(submitButton.startsWith("submit_select_reviewer_")){ + } else if (submitButton.startsWith("submit_select_reviewer_")) { //Retrieve the identifier of the eperson which will do the reviewing UUID reviewerId = UUID.fromString(submitButton.substring(submitButton.lastIndexOf("_") + 1)); EPerson reviewer = ePersonService.find(c, reviewerId); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SingleUserReviewAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SingleUserReviewAction.java index 2185581ee9..74eea2d448 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SingleUserReviewAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SingleUserReviewAction.java @@ -7,6 +7,10 @@ */ package org.dspace.xmlworkflow.state.actions.processingaction; +import java.io.IOException; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; @@ -17,10 +21,6 @@ import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.actions.ActionResult; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; - /** * Processing class of an action where a single user has * been assigned and he can either accept/reject the workflow item @@ -31,7 +31,7 @@ import java.sql.SQLException; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class SingleUserReviewAction extends ProcessingAction{ +public class SingleUserReviewAction extends ProcessingAction { public static final int MAIN_PAGE = 0; public static final int REJECT_PAGE = 1; @@ -44,34 +44,36 @@ public class SingleUserReviewAction extends ProcessingAction{ } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { int page = Util.getIntParameter(request, "page"); - switch (page){ + switch (page) { case MAIN_PAGE: return processMainPage(c, wfi, step, request); case REJECT_PAGE: return processRejectPage(c, wfi, step, request); + default: + return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } - - return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } - public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException { - if(request.getParameter("submit_approve") != null){ + public ActionResult processMainPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException { + if (request.getParameter("submit_approve") != null) { //Delete the tasks addApprovedProvenance(c, wfi); return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); - } else if(request.getParameter("submit_reject") != null){ + } else if (request.getParameter("submit_reject") != null) { // Make sure we indicate which page we want to process request.setAttribute("page", REJECT_PAGE); // We have pressed reject item, so take the user to a page where he can reject return new ActionResult(ActionResult.TYPE.TYPE_PAGE); - } else if(request.getParameter("submit_decline_task") != null){ + } else if (request.getParameter("submit_decline_task") != null) { return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, OUTCOME_REJECT); - }else{ + } else { //We pressed the leave button so return to our submissions page return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); } @@ -82,31 +84,36 @@ public class SingleUserReviewAction extends ProcessingAction{ String now = DCDate.getCurrent().toString(); // Get user's name + email address - String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().getEPersonName(c.getCurrentUser()); + String usersName = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .getEPersonName(c.getCurrentUser()); String provDescription = getProvenanceStartId() + " Approved for entry into archive by " - + usersName + " on " + now + " (GMT) "; + + usersName + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + provDescription); itemService.update(c, wfi.getItem()); } - public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { - if(request.getParameter("submit_reject") != null){ + public ActionResult processRejectPage(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { + if (request.getParameter("submit_reject") != null) { String reason = request.getParameter("reason"); - if(reason == null || 0 == reason.trim().length()){ + if (reason == null || 0 == reason.trim().length()) { request.setAttribute("page", REJECT_PAGE); addErrorField(request, "reason"); return new ActionResult(ActionResult.TYPE.TYPE_ERROR); } //We have pressed reject, so remove the task the user has & put it back to a workspace item - XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), this.getProvenanceStartId(), reason); + XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .sendWorkflowItemBackSubmission(c, wfi, c.getCurrentUser(), + this.getProvenanceStartId(), reason); return new ActionResult(ActionResult.TYPE.TYPE_SUBMISSION_PAGE); - }else{ + } else { //Cancel, go back to the main task page request.setAttribute("page", MAIN_PAGE); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AssignAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AssignAction.java index 0cdf4ae0be..5b8d9b08b8 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AssignAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AssignAction.java @@ -7,15 +7,15 @@ */ package org.dspace.xmlworkflow.state.actions.userassignment; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.core.Context; import org.dspace.xmlworkflow.RoleMembers; -import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.WorkflowConfigurationException; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.actions.ActionResult; - -import javax.servlet.http.HttpServletRequest; -import java.sql.SQLException; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; /** * @author Bram De Schouwer (bram.deschouwer at dot com) @@ -43,11 +43,12 @@ public class AssignAction extends UserSelectionAction { } @Override - public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException { + public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException { } @Override - public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) throws WorkflowConfigurationException, SQLException { + public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) + throws WorkflowConfigurationException, SQLException { return false; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AssignOriginalSubmitterAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AssignOriginalSubmitterAction.java index 24d3021739..5786515a81 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AssignOriginalSubmitterAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AssignOriginalSubmitterAction.java @@ -7,27 +7,28 @@ */ package org.dspace.xmlworkflow.state.actions.userassignment; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Arrays; +import javax.mail.MessagingException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.eperson.EPerson; import org.dspace.workflow.WorkflowException; +import org.dspace.xmlworkflow.RoleMembers; +import org.dspace.xmlworkflow.WorkflowConfigurationException; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; import org.dspace.xmlworkflow.service.WorkflowRequirementsService; import org.dspace.xmlworkflow.service.XmlWorkflowService; -import org.dspace.xmlworkflow.state.actions.ActionResult; import org.dspace.xmlworkflow.state.Step; -import org.dspace.xmlworkflow.*; +import org.dspace.xmlworkflow.state.actions.ActionResult; import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.springframework.beans.factory.annotation.Autowired; -import javax.mail.MessagingException; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Arrays; - /** * A user selection action that assigns the original submitter * to the workflowitem @@ -37,7 +38,7 @@ import java.util.Arrays; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class AssignOriginalSubmitterAction extends UserSelectionAction{ +public class AssignOriginalSubmitterAction extends UserSelectionAction { @Autowired(required = true) protected WorkflowRequirementsService workflowRequirementsService; @@ -53,7 +54,8 @@ public class AssignOriginalSubmitterAction extends UserSelectionAction{ } @Override - public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) throws WorkflowConfigurationException, SQLException { + public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) + throws WorkflowConfigurationException, SQLException { return wfi.getSubmitter() != null; } @@ -68,36 +70,39 @@ public class AssignOriginalSubmitterAction extends UserSelectionAction{ } @Override - public void alertUsersOnActivation(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws IOException, SQLException { - try{ + public void alertUsersOnActivation(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) + throws IOException, SQLException { + try { XmlWorkflowService xmlWorkflowService = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService(); xmlWorkflowService.alertUsersOnTaskActivation(c, wfi, "submit_task", Arrays.asList(wfi.getSubmitter()), - //The arguments - wfi.getItem().getName(), - wfi.getCollection().getName(), - wfi.getSubmitter().getFullName(), - //TODO: message - "New task available.", - xmlWorkflowService.getMyDSpaceLink() + //The arguments + wfi.getItem().getName(), + wfi.getCollection().getName(), + wfi.getSubmitter().getFullName(), + //TODO: message + "New task available.", + xmlWorkflowService.getMyDSpaceLink() ); } catch (MessagingException e) { - log.info(LogManager.getHeader(c, "error emailing user(s) for claimed task", "step: " + getParent().getStep().getId() + " workflowitem: " + wfi.getID())); + log.info(LogManager.getHeader(c, "error emailing user(s) for claimed task", + "step: " + getParent().getStep().getId() + " workflowitem: " + wfi.getID())); } } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException, WorkflowException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException, WorkflowException { EPerson submitter = wfi.getSubmitter(); WorkflowActionConfig nextAction = getParent().getStep().getNextAction(this.getParent()); //Retrieve the action which has a user interface - while(nextAction != null && !nextAction.requiresUI()){ + while (nextAction != null && !nextAction.requiresUI()) { nextAction = nextAction.getStep().getNextAction(nextAction); } - if(nextAction == null) - { + if (nextAction == null) { //Should never occur, but just in case - log.error("Could not find next action for step with id: " + step.getId() + " to assign a submitter to. Aborting the action."); + log.error("Could not find next action for step with id: " + step + .getId() + " to assign a submitter to. Aborting the action."); throw new IllegalStateException(); } @@ -107,21 +112,24 @@ public class AssignOriginalSubmitterAction extends UserSelectionAction{ return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); } -/** + /** * Create a claimed task for the user IF this user doesn't have a claimed action for this workflow item - * @param c the dspace context - * @param wfi the workflow item - * @param step the current step + * + * @param c the dspace context + * @param wfi the workflow item + * @param step the current step * @param actionConfig the action - * @param user the user to create the action for - * @throws SQLException ... + * @param user the user to create the action for + * @throws SQLException ... * @throws AuthorizeException ... - * @throws IOException ... + * @throws IOException ... */ - protected void createTaskForEPerson(Context c, XmlWorkflowItem wfi, Step step, WorkflowActionConfig actionConfig, EPerson user) throws SQLException, AuthorizeException, IOException { - if(claimedTaskService.find(c, wfi, step.getId(), actionConfig.getId()) != null){ + protected void createTaskForEPerson(Context c, XmlWorkflowItem wfi, Step step, WorkflowActionConfig actionConfig, + EPerson user) throws SQLException, AuthorizeException, IOException { + if (claimedTaskService.find(c, wfi, step.getId(), actionConfig.getId()) != null) { workflowRequirementsService.addClaimedUser(c, wfi, step, c.getCurrentUser()); - XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().createOwnedTask(c, wfi, step, actionConfig, user); + XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .createOwnedTask(c, wfi, step, actionConfig, user); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AutoAssignAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AutoAssignAction.java index 496b3b09b8..d77ac39aaf 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AutoAssignAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/AutoAssignAction.java @@ -7,27 +7,29 @@ */ package org.dspace.xmlworkflow.state.actions.userassignment; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import javax.servlet.http.HttpServletRequest; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.eperson.EPerson; import org.dspace.eperson.service.GroupService; -import org.dspace.xmlworkflow.*; +import org.dspace.xmlworkflow.Role; +import org.dspace.xmlworkflow.RoleMembers; +import org.dspace.xmlworkflow.WorkflowConfigurationException; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; import org.dspace.xmlworkflow.service.WorkflowRequirementsService; import org.dspace.xmlworkflow.state.Step; +import org.dspace.xmlworkflow.state.actions.ActionResult; import org.dspace.xmlworkflow.state.actions.WorkflowActionConfig; import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import org.dspace.xmlworkflow.state.actions.ActionResult; import org.springframework.beans.factory.annotation.Autowired; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * A user selection action that will create pooled tasks * for all the user who have a workflowItemRole for this @@ -49,26 +51,27 @@ public class AutoAssignAction extends UserSelectionAction { @Override public void activate(Context c, XmlWorkflowItem wfItem) { - + } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { try { Role role = getParent().getStep().getRole(); - if(role != null){ + if (role != null) { WorkflowActionConfig nextAction = getParent().getStep().getNextAction(this.getParent()); //Retrieve the action which has a user interface - while(nextAction != null && !nextAction.requiresUI()){ + while (nextAction != null && !nextAction.requiresUI()) { nextAction = nextAction.getStep().getNextAction(nextAction); } - if(nextAction != null){ + if (nextAction != null) { List workflowItemRoles = workflowItemRoleService.find(c, wfi, role.getId()); for (WorkflowItemRole workflowItemRole : workflowItemRoles) { - if(workflowItemRole.getEPerson() != null){ + if (workflowItemRole.getEPerson() != null) { createTaskForEPerson(c, wfi, step, nextAction, workflowItemRole.getEPerson()); - }else{ + } else { List members = groupService.allMembers(c, workflowItemRole.getGroup()); for (EPerson member : members) { createTaskForEPerson(c, wfi, step, nextAction, member); @@ -77,18 +80,25 @@ public class AutoAssignAction extends UserSelectionAction { //Delete our workflow item role since the users have been assigned workflowItemRoleService.delete(c, workflowItemRole); } - }else{ - log.warn(LogManager.getHeader(c, "Error while executing auto assign action", "No valid next action. Workflow item:" + wfi.getID())); + } else { + log.warn(LogManager.getHeader(c, "Error while executing auto assign action", + "No valid next action. Workflow item:" + wfi.getID())); } } } catch (SQLException e) { - log.error(LogManager.getHeader(c, "Error while executing auto assign action", "Workflow item: " + wfi.getID() + " step :" + getParent().getStep().getId()), e); + log.error(LogManager.getHeader(c, "Error while executing auto assign action", + "Workflow item: " + wfi.getID() + " step :" + getParent().getStep().getId()), + e); throw e; } catch (AuthorizeException e) { - log.error(LogManager.getHeader(c, "Error while executing auto assign action", "Workflow item: " + wfi.getID() + " step :" + getParent().getStep().getId()), e); + log.error(LogManager.getHeader(c, "Error while executing auto assign action", + "Workflow item: " + wfi.getID() + " step :" + getParent().getStep().getId()), + e); throw e; } catch (IOException e) { - log.error(LogManager.getHeader(c, "Error while executing auto assign action", "Workflow item: " + wfi.getID() + " step :" + getParent().getStep().getId()), e); + log.error(LogManager.getHeader(c, "Error while executing auto assign action", + "Workflow item: " + wfi.getID() + " step :" + getParent().getStep().getId()), + e); throw e; } @@ -98,19 +108,22 @@ public class AutoAssignAction extends UserSelectionAction { /** * Create a claimed task for the user IF this user doesn't have a claimed action for this workflow item - * @param c the dspace context - * @param wfi the workflow item - * @param step the current step + * + * @param c the dspace context + * @param wfi the workflow item + * @param step the current step * @param actionConfig the action - * @param user the user to create the action for - * @throws SQLException ... + * @param user the user to create the action for + * @throws SQLException ... * @throws AuthorizeException ... - * @throws IOException ... + * @throws IOException ... */ - protected void createTaskForEPerson(Context c, XmlWorkflowItem wfi, Step step, WorkflowActionConfig actionConfig, EPerson user) throws SQLException, AuthorizeException, IOException { - if(claimedTaskService.find(c, wfi, step.getId(), actionConfig.getId()) != null){ + protected void createTaskForEPerson(Context c, XmlWorkflowItem wfi, Step step, WorkflowActionConfig actionConfig, + EPerson user) throws SQLException, AuthorizeException, IOException { + if (claimedTaskService.find(c, wfi, step.getId(), actionConfig.getId()) != null) { workflowRequirementsService.addClaimedUser(c, wfi, step, c.getCurrentUser()); - XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().createOwnedTask(c, wfi, step, actionConfig, user); + XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .createOwnedTask(c, wfi, step, actionConfig, user); } } @@ -120,21 +133,23 @@ public class AutoAssignAction extends UserSelectionAction { } @Override - public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException { + public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException { } @Override - public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) throws WorkflowConfigurationException, SQLException { + public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) + throws WorkflowConfigurationException, SQLException { //This is an automatic assign action, it can never have a user interface Role role = getParent().getStep().getRole(); - if(role != null){ + if (role != null) { List workflowItemRoles = workflowItemRoleService.find(context, wfi, role.getId()); - if(workflowItemRoles.size() == 0){ - throw new WorkflowConfigurationException("The next step is invalid, since it doesn't have any individual item roles"); + if (workflowItemRoles.size() == 0) { + throw new WorkflowConfigurationException( + "The next step is invalid, since it doesn't have any individual item roles"); } return true; - }else{ + } else { throw new WorkflowConfigurationException("The next step is invalid, since it doesn't have a valid role"); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/ClaimAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/ClaimAction.java index fc32009282..bf4eecb77d 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/ClaimAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/ClaimAction.java @@ -7,26 +7,30 @@ */ package org.dspace.xmlworkflow.state.actions.userassignment; -import org.dspace.authorize.AuthorizeException; -import org.dspace.core.*; -import org.dspace.eperson.EPerson; -import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; -import org.dspace.xmlworkflow.service.XmlWorkflowService; -import org.dspace.xmlworkflow.state.Step; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import org.dspace.xmlworkflow.*; -import org.dspace.xmlworkflow.state.actions.ActionResult; - -import javax.mail.MessagingException; -import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; +import javax.mail.MessagingException; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.core.LogManager; +import org.dspace.eperson.EPerson; +import org.dspace.xmlworkflow.Role; +import org.dspace.xmlworkflow.RoleMembers; +import org.dspace.xmlworkflow.WorkflowConfigurationException; +import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; +import org.dspace.xmlworkflow.service.XmlWorkflowService; +import org.dspace.xmlworkflow.state.Step; +import org.dspace.xmlworkflow.state.actions.ActionResult; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; /** * Processing class for an action where x number of users * have to accept a task from a designated pool - * + * * @author Bram De Schouwer (bram.deschouwer at dot com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) @@ -40,62 +44,73 @@ public class ClaimAction extends UserSelectionAction { RoleMembers allroleMembers = getParent().getStep().getRole().getMembers(context, wfItem); // Create pooled tasks for each member of our group - if(allroleMembers != null && (allroleMembers.getGroups().size() > 0 || allroleMembers.getEPersons().size() > 0)){ - XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().createPoolTasks(context, wfItem, allroleMembers, owningStep, getParent()); + if (allroleMembers != null && (allroleMembers.getGroups().size() > 0 || allroleMembers.getEPersons() + .size() > 0)) { + XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .createPoolTasks(context, wfItem, allroleMembers, owningStep, getParent()); alertUsersOnActivation(context, wfItem, allroleMembers); + } else { + log.info(LogManager.getHeader(context, "warning while activating claim action", + "No group or person was found for the following roleid: " + getParent() + .getStep().getRole().getId())); } - else - log.info(LogManager.getHeader(context, "warning while activating claim action", "No group or person was found for the following roleid: " + getParent().getStep().getRole().getId())); } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { //Check if we are accept this task, or accepting multiple tasks - if(request.getParameter("submit_take_task") != null || request.getParameter("submit_take_tasks") != null){ + if (request.getParameter("submit_take_task") != null || request.getParameter("submit_take_tasks") != null) { //Add a claimed user to our task - XmlWorkflowServiceFactory.getInstance().getWorkflowRequirementsService().addClaimedUser(c, wfi, step, c.getCurrentUser()); + XmlWorkflowServiceFactory.getInstance().getWorkflowRequirementsService() + .addClaimedUser(c, wfi, step, c.getCurrentUser()); return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); - }else{ + } else { return new ActionResult(ActionResult.TYPE.TYPE_CANCEL); } } @Override - public void alertUsersOnActivation(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws IOException, SQLException { - try{ + public void alertUsersOnActivation(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) + throws IOException, SQLException { + try { XmlWorkflowService xmlWorkflowService = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService(); xmlWorkflowService.alertUsersOnTaskActivation(c, wfi, "submit_task", roleMembers.getAllUniqueMembers(c), - //The arguments - wfi.getItem().getName(), - wfi.getCollection().getName(), - wfi.getSubmitter().getFullName(), - //TODO: message - "New task available.", - xmlWorkflowService.getMyDSpaceLink() + //The arguments + wfi.getItem().getName(), + wfi.getCollection().getName(), + wfi.getSubmitter().getFullName(), + //TODO: message + "New task available.", + xmlWorkflowService.getMyDSpaceLink() ); } catch (MessagingException e) { - log.info(LogManager.getHeader(c, "error emailing user(s) for claimed task", "step: " + getParent().getStep().getId() + " workflowitem: " + wfi.getID())); + log.info(LogManager.getHeader(c, "error emailing user(s) for claimed task", + "step: " + getParent().getStep().getId() + " workflowitem: " + wfi.getID())); } } @Override - public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException, AuthorizeException, IOException { - if(roleMembers != null && (roleMembers.getEPersons().size() > 0 || roleMembers.getGroups().size() >0)){ + public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) + throws SQLException, AuthorizeException, IOException { + if (roleMembers != null && (roleMembers.getEPersons().size() > 0 || roleMembers.getGroups().size() > 0)) { //Create task for the users left - XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService().createPoolTasks(c, wfi, roleMembers, getParent().getStep(), getParent()); - if(ConfigurationManager.getBooleanProperty("workflow", "notify.returned.tasks", true)) - { + XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService() + .createPoolTasks(c, wfi, roleMembers, getParent().getStep(), getParent()); + if (ConfigurationManager.getBooleanProperty("workflow", "notify.returned.tasks", true)) { alertUsersOnActivation(c, wfi, roleMembers); } + } else { + log.info(LogManager.getHeader(c, "warning while activating claim action", + "No group or person was found for the following roleid: " + getParent() + .getStep().getId())); } - else - log.info(LogManager.getHeader(c, "warning while activating claim action", "No group or person was found for the following roleid: " + getParent().getStep().getId())); } @@ -105,13 +120,14 @@ public class ClaimAction extends UserSelectionAction { } @Override - public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) throws WorkflowConfigurationException, SQLException { + public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) + throws WorkflowConfigurationException, SQLException { //A user claim action always needs to have a UI, since somebody needs to be able to claim it - if(hasUI){ + if (hasUI) { Step step = getParent().getStep(); //First of all check if our step has a role Role role = step.getRole(); - if(role != null){ + if (role != null) { //We have a role, check if we have a group to with that role RoleMembers roleMembers = role.getMembers(context, wfi); @@ -119,10 +135,12 @@ public class ClaimAction extends UserSelectionAction { return !(epersons.size() == 0 || step.getRequiredUsers() > epersons.size()); } else { // We don't have a role and do have a UI so throw a workflow exception - throw new WorkflowConfigurationException("The next step is invalid, since it doesn't have a valid role"); + throw new WorkflowConfigurationException( + "The next step is invalid, since it doesn't have a valid role"); } - }else + } else { return true; + } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/InheritUsersAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/InheritUsersAction.java index d5b3cab38b..5e134855a7 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/InheritUsersAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/InheritUsersAction.java @@ -7,15 +7,15 @@ */ package org.dspace.xmlworkflow.state.actions.userassignment; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.dspace.core.Context; import org.dspace.xmlworkflow.RoleMembers; -import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.WorkflowConfigurationException; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.state.Step; import org.dspace.xmlworkflow.state.actions.ActionResult; - -import javax.servlet.http.HttpServletRequest; -import java.sql.SQLException; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; /** * A user selection action that inherits user @@ -43,11 +43,12 @@ public class InheritUsersAction extends UserSelectionAction { } @Override - public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException { + public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException { } @Override - public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) throws WorkflowConfigurationException, SQLException { + public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) + throws WorkflowConfigurationException, SQLException { return false; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/NoUserSelectionAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/NoUserSelectionAction.java index e6b6fc9c35..35eeaf1a0e 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/NoUserSelectionAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/NoUserSelectionAction.java @@ -7,17 +7,17 @@ */ package org.dspace.xmlworkflow.state.actions.userassignment; -import org.dspace.authorize.AuthorizeException; -import org.dspace.core.Context; -import org.dspace.xmlworkflow.state.actions.ActionResult; -import org.dspace.xmlworkflow.state.Step; -import org.dspace.xmlworkflow.RoleMembers; -import org.dspace.xmlworkflow.WorkflowConfigurationException; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; - -import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.core.Context; +import org.dspace.xmlworkflow.RoleMembers; +import org.dspace.xmlworkflow.WorkflowConfigurationException; +import org.dspace.xmlworkflow.state.Step; +import org.dspace.xmlworkflow.state.actions.ActionResult; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; /** * A user selection action that does not assign any users @@ -27,18 +27,19 @@ import java.sql.SQLException; * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) */ -public class NoUserSelectionAction extends UserSelectionAction{ +public class NoUserSelectionAction extends UserSelectionAction { @Override public boolean isFinished(XmlWorkflowItem wfi) { return true; } @Override - public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException { + public void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException { } @Override - public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) throws WorkflowConfigurationException, SQLException { + public boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) + throws WorkflowConfigurationException, SQLException { return true; } @@ -52,7 +53,8 @@ public class NoUserSelectionAction extends UserSelectionAction{ } @Override - public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) throws SQLException, AuthorizeException, IOException { + public ActionResult execute(Context c, XmlWorkflowItem wfi, Step step, HttpServletRequest request) + throws SQLException, AuthorizeException, IOException { return new ActionResult(ActionResult.TYPE.TYPE_OUTCOME, ActionResult.OUTCOME_COMPLETE); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/UserSelectionAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/UserSelectionAction.java index 19193ac996..b80496ab4a 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/UserSelectionAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/userassignment/UserSelectionAction.java @@ -7,22 +7,23 @@ */ package org.dspace.xmlworkflow.state.actions.userassignment; +import java.io.IOException; +import java.sql.SQLException; +import javax.servlet.http.HttpServletRequest; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; -import org.dspace.xmlworkflow.state.actions.Action; -import org.dspace.xmlworkflow.storedcomponents.*; import org.dspace.xmlworkflow.RoleMembers; import org.dspace.xmlworkflow.WorkflowConfigurationException; +import org.dspace.xmlworkflow.state.actions.Action; +import org.dspace.xmlworkflow.storedcomponents.PoolTask; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService; import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService; import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; import org.springframework.beans.factory.annotation.Autowired; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; - /** * An abstract class representing the processing side of * a user selection action. @@ -47,46 +48,51 @@ public abstract class UserSelectionAction extends Action { protected WorkflowItemRoleService workflowItemRoleService; @Override - public boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) throws SQLException, AuthorizeException, IOException, WorkflowConfigurationException { + public boolean isAuthorized(Context context, HttpServletRequest request, XmlWorkflowItem wfi) + throws SQLException, AuthorizeException, IOException, WorkflowConfigurationException { PoolTask task = null; - if(context.getCurrentUser() != null) + if (context.getCurrentUser() != null) { task = poolTaskService.findByWorkflowIdAndEPerson(context, wfi, context.getCurrentUser()); + } //Check if we have pooled the current task return task != null && - task.getWorkflowID().equals(getParent().getStep().getWorkflow().getID()) && - task.getStepID().equals(getParent().getStep().getId()) && - task.getActionID().equals(getParent().getId()); + task.getWorkflowID().equals(getParent().getStep().getWorkflow().getID()) && + task.getStepID().equals(getParent().getStep().getId()) && + task.getActionID().equals(getParent().getId()); } /** * Should a person have the option to repool the task the tasks will have to be regenerated - * @param c the dspace context - * @param wfi the workflowitem + * + * @param c the dspace context + * @param wfi the workflowitem * @param roleMembers the list of users for which tasks must be regenerated * @throws AuthorizeException thrown if the current user isn't authorized - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ - public abstract void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) throws SQLException, AuthorizeException, IOException; + public abstract void regenerateTasks(Context c, XmlWorkflowItem wfi, RoleMembers roleMembers) + throws SQLException, AuthorizeException, IOException; /** * Verifies if the user selection action is valid * User constraints will be checked (enough users, group exists, ...) + * * @param context the dspace context - * @param wfi the workflow item - * @param hasUI boolean indicating whether or not the action has a user interface + * @param wfi the workflow item + * @param hasUI boolean indicating whether or not the action has a user interface * @return if the action is valid * @throws WorkflowConfigurationException occurs if there is a configuration error in the workflow - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or + * other errors. */ - public abstract boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) throws WorkflowConfigurationException, SQLException; + public abstract boolean isValidUserSelection(Context context, XmlWorkflowItem wfi, boolean hasUI) + throws WorkflowConfigurationException, SQLException; /** * A boolean indicating wether or not the task pool is used for this type of user selection + * * @return a boolean */ public abstract boolean usesTaskPool(); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/ClaimedTask.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/ClaimedTask.java index b57779c959..fe64bae0fd 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/ClaimedTask.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/ClaimedTask.java @@ -7,12 +7,21 @@ */ package org.dspace.xmlworkflow.storedcomponents; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.dspace.eperson.EPerson; -import javax.persistence.*; - /** * Claimed task representing the database representation of an action claimed by an eperson * @@ -22,33 +31,33 @@ import javax.persistence.*; * @author Mark Diggory (markd at atmire dot com) */ @Entity -@Table(name="cwf_claimtask") +@Table(name = "cwf_claimtask") public class ClaimedTask implements ReloadableEntity { @Id - @Column(name="claimtask_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="cwf_claimtask_seq") - @SequenceGenerator(name="cwf_claimtask_seq", sequenceName="cwf_claimtask_seq", allocationSize = 1) + @Column(name = "claimtask_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cwf_claimtask_seq") + @SequenceGenerator(name = "cwf_claimtask_seq", sequenceName = "cwf_claimtask_seq", allocationSize = 1) private Integer id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "workflowitem_id") private XmlWorkflowItem workflowItem; -// @Column(name = "workflow_id") + // @Column(name = "workflow_id") // @Lob - @Column(name="workflow_id", columnDefinition = "text") + @Column(name = "workflow_id", columnDefinition = "text") private String workflowId; -// @Column(name = "step_id") + // @Column(name = "step_id") // @Lob - @Column(name="step_id", columnDefinition = "text") + @Column(name = "step_id", columnDefinition = "text") private String stepId; -// @Column(name = "action_id") + // @Column(name = "action_id") // @Lob - @Column(name="action_id", columnDefinition = "text") + @Column(name = "action_id", columnDefinition = "text") private String actionId; @ManyToOne(fetch = FetchType.LAZY) @@ -58,10 +67,8 @@ public class ClaimedTask implements ReloadableEntity { /** * Protected constructor, create object using: * {@link org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService#create(Context)} - * */ - protected ClaimedTask() - { + protected ClaimedTask() { } @@ -69,43 +76,43 @@ public class ClaimedTask implements ReloadableEntity { return id; } - public void setOwner(EPerson owner){ + public void setOwner(EPerson owner) { this.owner = owner; } - public EPerson getOwner(){ + public EPerson getOwner() { return owner; } - public void setWorkflowItem(XmlWorkflowItem workflowItem){ + public void setWorkflowItem(XmlWorkflowItem workflowItem) { this.workflowItem = workflowItem; } - public XmlWorkflowItem getWorkflowItem(){ + public XmlWorkflowItem getWorkflowItem() { return workflowItem; } - public void setActionID(String actionID){ + public void setActionID(String actionID) { this.actionId = actionID; } - public String getActionID(){ + public String getActionID() { return actionId; } - public void setStepID(String stepID){ + public void setStepID(String stepID) { this.stepId = stepID; } - public String getStepID(){ + public String getStepID() { return stepId; } - public void setWorkflowID(String workflowID){ + public void setWorkflowID(String workflowID) { this.workflowId = workflowID; } - public String getWorkflowID(){ + public String getWorkflowID() { return workflowId; } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/ClaimedTaskServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/ClaimedTaskServiceImpl.java index 127a2eafdc..50e0e10efc 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/ClaimedTaskServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/ClaimedTaskServiceImpl.java @@ -7,7 +7,12 @@ */ package org.dspace.xmlworkflow.storedcomponents; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -15,12 +20,6 @@ import org.dspace.xmlworkflow.storedcomponents.dao.ClaimedTaskDAO; import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - /** * Service implementation for the ClaimedTask object. * This class is responsible for all business logic calls for the ClaimedTask object and is autowired by spring. @@ -28,14 +27,12 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class ClaimedTaskServiceImpl implements ClaimedTaskService -{ +public class ClaimedTaskServiceImpl implements ClaimedTaskService { @Autowired(required = true) protected ClaimedTaskDAO claimedTaskDAO; - protected ClaimedTaskServiceImpl() - { + protected ClaimedTaskServiceImpl() { } @@ -56,7 +53,7 @@ public class ClaimedTaskServiceImpl implements ClaimedTaskService @Override public void update(Context context, List claimedTasks) throws SQLException, AuthorizeException { - if(CollectionUtils.isNotEmpty(claimedTasks)) { + if (CollectionUtils.isNotEmpty(claimedTasks)) { for (ClaimedTask claimedTask : claimedTasks) { claimedTaskDAO.save(context, claimedTask); } @@ -74,7 +71,8 @@ public class ClaimedTaskServiceImpl implements ClaimedTaskService } @Override - public ClaimedTask findByWorkflowIdAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException { + public ClaimedTask findByWorkflowIdAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException { return claimedTaskDAO.findByWorkflowItemAndEPerson(context, workflowItem, ePerson); } @@ -89,13 +87,16 @@ public class ClaimedTaskServiceImpl implements ClaimedTaskService } @Override - public ClaimedTask find(Context context, EPerson ePerson, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException { - return claimedTaskDAO.findByEPersonAndWorkflowItemAndStepIdAndActionId(context, ePerson,workflowItem,stepID,actionID); + public ClaimedTask find(Context context, EPerson ePerson, XmlWorkflowItem workflowItem, String stepID, + String actionID) throws SQLException { + return claimedTaskDAO + .findByEPersonAndWorkflowItemAndStepIdAndActionId(context, ePerson, workflowItem, stepID, actionID); } @Override - public List find(Context context, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException { - return claimedTaskDAO.findByWorkflowItemAndStepIdAndActionId(context, workflowItem,stepID, actionID); + public List find(Context context, XmlWorkflowItem workflowItem, String stepID, String actionID) + throws SQLException { + return claimedTaskDAO.findByWorkflowItemAndStepIdAndActionId(context, workflowItem, stepID, actionID); } @Override @@ -109,7 +110,8 @@ public class ClaimedTaskServiceImpl implements ClaimedTaskService } @Override - public void deleteByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException, AuthorizeException { + public void deleteByWorkflowItem(Context context, XmlWorkflowItem workflowItem) + throws SQLException, AuthorizeException { List claimedTasks = findByWorkflowItem(context, workflowItem); //Use an iterator to remove the tasks ! Iterator iterator = claimedTasks.iterator(); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/CollectionRole.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/CollectionRole.java index 030cbfa783..114db17087 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/CollectionRole.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/CollectionRole.java @@ -7,39 +7,46 @@ */ package org.dspace.xmlworkflow.storedcomponents; +import java.sql.SQLException; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.dspace.eperson.Group; -import javax.persistence.*; -import java.sql.SQLException; - /** -/* * Represents a workflow assignments database representation. * These assignments describe roles and the groups connected * to these roles for each collection - * + * * @author Bram De Schouwer (bram.deschouwer at dot com) * @author Kevin Van de Velde (kevin at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Mark Diggory (markd at atmire dot com) - */ @Entity -@Table(name="cwf_collectionrole") +@Table(name = "cwf_collectionrole") public class CollectionRole implements ReloadableEntity { @Id - @Column(name="collectionrole_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="cwf_collectionrole_seq") - @SequenceGenerator(name="cwf_collectionrole_seq", sequenceName="cwf_collectionrole_seq", allocationSize = 1) + @Column(name = "collectionrole_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cwf_collectionrole_seq") + @SequenceGenerator(name = "cwf_collectionrole_seq", sequenceName = "cwf_collectionrole_seq", allocationSize = 1) private Integer id; -// @Column(name = "role_id") -// @Lob - @Column(name="role_id", columnDefinition = "text") + // @Column(name = "role_id") + // @Lob + @Column(name = "role_id", columnDefinition = "text") private String roleId; @ManyToOne(fetch = FetchType.LAZY) @@ -52,31 +59,31 @@ public class CollectionRole implements ReloadableEntity { /** * Protected constructor, create object using: - * {@link org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService#create(Context, Collection, String, Group)} - * + * {@link + * org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService#create(Context, Collection, String, Group) + * } */ - protected CollectionRole() - { + protected CollectionRole() { } - public void setRoleId(String id){ + public void setRoleId(String id) { this.roleId = id; } - public String getRoleId(){ + public String getRoleId() { return roleId; } - public void setCollection(Collection collection){ + public void setCollection(Collection collection) { this.collection = collection; } - public Collection getCollection(){ + public Collection getCollection() { return collection; } - public void setGroup(Group group){ + public void setGroup(Group group) { this.group = group; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/CollectionRoleServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/CollectionRoleServiceImpl.java index 6ebf545ca2..fbca3d47e7 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/CollectionRoleServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/CollectionRoleServiceImpl.java @@ -7,6 +7,9 @@ */ package org.dspace.xmlworkflow.storedcomponents; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.eperson.Group; @@ -14,9 +17,6 @@ import org.dspace.xmlworkflow.storedcomponents.dao.CollectionRoleDAO; import org.dspace.xmlworkflow.storedcomponents.service.CollectionRoleService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.List; - /** * Service implementation for the CollectionRole object. * This class is responsible for all business logic calls for the CollectionRole object and is autowired by spring. @@ -29,8 +29,7 @@ public class CollectionRoleServiceImpl implements CollectionRoleService { @Autowired(required = true) protected CollectionRoleDAO collectionRoleDAO; - protected CollectionRoleServiceImpl() - { + protected CollectionRoleServiceImpl() { } @@ -51,7 +50,8 @@ public class CollectionRoleServiceImpl implements CollectionRoleService { } @Override - public CollectionRole create(Context context, Collection collection, String roleId, Group group) throws SQLException { + public CollectionRole create(Context context, Collection collection, String roleId, Group group) + throws SQLException { CollectionRole collectionRole = collectionRoleDAO.create(context, new CollectionRole()); collectionRole.setCollection(collection); collectionRole.setRoleId(roleId); diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/InProgressUser.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/InProgressUser.java index 9479f51664..5cd714345e 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/InProgressUser.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/InProgressUser.java @@ -7,12 +7,21 @@ */ package org.dspace.xmlworkflow.storedcomponents; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.dspace.eperson.EPerson; -import javax.persistence.*; - /** * Claimed task representing the database representation of an action claimed by an eperson * @@ -22,33 +31,31 @@ import javax.persistence.*; * @author Mark Diggory (markd at atmire dot com) */ @Entity -@Table(name="cwf_in_progress_user") +@Table(name = "cwf_in_progress_user") public class InProgressUser implements ReloadableEntity { @Id - @Column(name="in_progress_user_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="cwf_in_progress_user_seq") - @SequenceGenerator(name="cwf_in_progress_user_seq", sequenceName="cwf_in_progress_user_seq", allocationSize = 1) + @Column(name = "in_progress_user_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cwf_in_progress_user_seq") + @SequenceGenerator(name = "cwf_in_progress_user_seq", sequenceName = "cwf_in_progress_user_seq", allocationSize = 1) private Integer id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name="user_id") + @JoinColumn(name = "user_id") private EPerson ePerson; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name="workflowitem_id") + @JoinColumn(name = "workflowitem_id") private XmlWorkflowItem workflowItem; - @Column(name ="finished") + @Column(name = "finished") private boolean finished = false; /** * Protected constructor, create object using: * {@link org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService#create(Context)} - * */ - protected InProgressUser() - { + protected InProgressUser() { } @@ -56,24 +63,27 @@ public class InProgressUser implements ReloadableEntity { return id; } - public void setUser(EPerson user){ + public void setUser(EPerson user) { this.ePerson = user; } - public EPerson getUser(){ + + public EPerson getUser() { return this.ePerson; } - public void setWorkflowItem(XmlWorkflowItem workflowItem){ + + public void setWorkflowItem(XmlWorkflowItem workflowItem) { this.workflowItem = workflowItem; } - public XmlWorkflowItem getWorkflowItem(){ + + public XmlWorkflowItem getWorkflowItem() { return this.workflowItem; } - public boolean isFinished(){ + public boolean isFinished() { return finished; } - public void setFinished(boolean finished){ + public void setFinished(boolean finished) { this.finished = finished; } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/InProgressUserServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/InProgressUserServiceImpl.java index 7df5381a1c..a2b5e718eb 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/InProgressUserServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/InProgressUserServiceImpl.java @@ -7,7 +7,11 @@ */ package org.dspace.xmlworkflow.storedcomponents; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -15,10 +19,6 @@ import org.dspace.xmlworkflow.storedcomponents.dao.InProgressUserDAO; import org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Collections; -import java.util.List; - /** * Service implementation for the InProgressUser object. * This class is responsible for all business logic calls for the InProgressUser object and is autowired by spring. @@ -31,13 +31,13 @@ public class InProgressUserServiceImpl implements InProgressUserService { @Autowired(required = true) protected InProgressUserDAO inProgressUserDAO; - protected InProgressUserServiceImpl() - { + protected InProgressUserServiceImpl() { } @Override - public InProgressUser findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException { + public InProgressUser findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException { return inProgressUserDAO.findByWorkflowItemAndEPerson(context, workflowItem, ePerson); } @@ -78,7 +78,7 @@ public class InProgressUserServiceImpl implements InProgressUserService { @Override public void update(Context context, List inProgressUsers) throws SQLException, AuthorizeException { - if(CollectionUtils.isNotEmpty(inProgressUsers)) { + if (CollectionUtils.isNotEmpty(inProgressUsers)) { for (InProgressUser inProgressUser : inProgressUsers) { inProgressUserDAO.save(context, inProgressUser); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/PoolTask.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/PoolTask.java index c20253faa9..0edff5fb94 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/PoolTask.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/PoolTask.java @@ -7,14 +7,24 @@ */ package org.dspace.xmlworkflow.storedcomponents; +import java.sql.SQLException; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import javax.persistence.*; -import java.sql.SQLException; - /** * Pool task representing the database representation of a pool task for a step and an eperson * @@ -24,36 +34,36 @@ import java.sql.SQLException; * @author Mark Diggory (markd at atmire dot com) */ @Entity -@Table(name="cwf_pooltask") +@Table(name = "cwf_pooltask") public class PoolTask implements ReloadableEntity { @Id - @Column(name="pooltask_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="cwf_pooltask_seq") - @SequenceGenerator(name="cwf_pooltask_seq", sequenceName="cwf_pooltask_seq", allocationSize = 1) + @Column(name = "pooltask_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cwf_pooltask_seq") + @SequenceGenerator(name = "cwf_pooltask_seq", sequenceName = "cwf_pooltask_seq", allocationSize = 1) private Integer id; @OneToOne @JoinColumn(name = "workflowitem_id") private XmlWorkflowItem workflowItem; -// @Column(name = "workflow_id") + // @Column(name = "workflow_id") // @Lob - @Column(name="workflow_id", columnDefinition = "text") + @Column(name = "workflow_id", columnDefinition = "text") private String workflowId; -// @Column(name = "step_id") + // @Column(name = "step_id") // @Lob - @Column(name="step_id", columnDefinition = "text") + @Column(name = "step_id", columnDefinition = "text") private String stepId; -// @Column(name = "action_id") + // @Column(name = "action_id") // @Lob - @Column(name="action_id", columnDefinition = "text") + @Column(name = "action_id", columnDefinition = "text") private String actionId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name="eperson_id") + @JoinColumn(name = "eperson_id") private EPerson ePerson; @ManyToOne(fetch = FetchType.LAZY) @@ -64,10 +74,8 @@ public class PoolTask implements ReloadableEntity { /** * Protected constructor, create object using: * {@link org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService#create(Context)} - * */ - protected PoolTask() - { + protected PoolTask() { } @@ -75,39 +83,39 @@ public class PoolTask implements ReloadableEntity { return id; } - public void setEperson(EPerson eperson){ + public void setEperson(EPerson eperson) { this.ePerson = eperson; } - public EPerson getEperson(){ + public EPerson getEperson() { return ePerson; } - public void setGroup(Group group){ + public void setGroup(Group group) { this.group = group; } - public Group getGroup(){ + public Group getGroup() { return this.group; } - public void setWorkflowID(String id){ + public void setWorkflowID(String id) { this.workflowId = id; } - public String getWorkflowID(){ + public String getWorkflowID() { return workflowId; } - public void setWorkflowItem(XmlWorkflowItem xmlWorkflowItem){ + public void setWorkflowItem(XmlWorkflowItem xmlWorkflowItem) { this.workflowItem = xmlWorkflowItem; } - public XmlWorkflowItem getWorkflowItem(){ + public XmlWorkflowItem getWorkflowItem() { return this.workflowItem; } - public void setStepID(String stepID){ + public void setStepID(String stepID) { this.stepId = stepID; } @@ -115,11 +123,11 @@ public class PoolTask implements ReloadableEntity { return stepId; } - public void setActionID(String actionID){ + public void setActionID(String actionID) { this.actionId = actionID; } - public String getActionID(){ + public String getActionID() { return this.actionId; } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/PoolTaskServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/PoolTaskServiceImpl.java index c92c770235..d6ca9fdc1c 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/PoolTaskServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/PoolTaskServiceImpl.java @@ -7,7 +7,15 @@ */ package org.dspace.xmlworkflow.storedcomponents; -import org.apache.commons.collections.CollectionUtils; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.commons.collections4.CollectionUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -18,10 +26,6 @@ import org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService; import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; - /** * Service implementation for the PoolTask object. * This class is responsible for all business logic calls for the PoolTask object and is autowired by spring. @@ -39,13 +43,13 @@ public class PoolTaskServiceImpl implements PoolTaskService { @Autowired(required = true) protected InProgressUserService inProgressUserService; - protected PoolTaskServiceImpl() - { + protected PoolTaskServiceImpl() { } @Override - public List findByEperson(Context context, EPerson ePerson) throws SQLException, AuthorizeException, IOException { + public List findByEperson(Context context, EPerson ePerson) + throws SQLException, AuthorizeException, IOException { List result = poolTaskDAO.findByEPerson(context, ePerson); //Get all PoolTasks for groups of which this eperson is a member List groups = groupService.allMemberGroups(context, ePerson); @@ -59,7 +63,7 @@ public class PoolTaskServiceImpl implements PoolTaskService { List groupTasks = poolTaskDAO.findByGroup(context, group); for (PoolTask poolTask : groupTasks) { XmlWorkflowItem workflowItem = poolTask.getWorkflowItem(); - if(inProgressUserService.findByWorkflowItemAndEPerson(context, workflowItem, ePerson) == null){ + if (inProgressUserService.findByWorkflowItemAndEPerson(context, workflowItem, ePerson) == null) { result.add(poolTask); } } @@ -74,26 +78,26 @@ public class PoolTaskServiceImpl implements PoolTaskService { } @Override - public PoolTask findByWorkflowIdAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException, AuthorizeException, IOException { + public PoolTask findByWorkflowIdAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException, AuthorizeException, IOException { PoolTask poolTask = poolTaskDAO.findByWorkflowItemAndEPerson(context, workflowItem, ePerson); //If there is a pooltask for this eperson, return it - if(poolTask != null) + if (poolTask != null) { return poolTask; - else{ - //If the user has a is processing or has finished the step for a workflowitem, there is no need to look for pooltasks for one of his + } else { + //If the user has a is processing or has finished the step for a workflowitem, there is no need to look + // for pooltasks for one of his //groups because the user already has the task claimed - if(inProgressUserService.findByWorkflowItemAndEPerson(context, workflowItem, ePerson)!=null){ + if (inProgressUserService.findByWorkflowItemAndEPerson(context, workflowItem, ePerson) != null) { return null; - } - else{ + } else { //If the user does not have a claimedtask yet, see whether one of the groups of the user has pooltasks //for this workflow item Set groups = groupService.allMemberGroupsSet(context, ePerson); for (Group group : groups) { poolTask = poolTaskDAO.findByWorkflowItemAndGroup(context, group, workflowItem); - if(poolTask != null) - { + if (poolTask != null) { return poolTask; } @@ -104,7 +108,8 @@ public class PoolTaskServiceImpl implements PoolTaskService { } @Override - public void deleteByWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) throws SQLException, AuthorizeException { + public void deleteByWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) + throws SQLException, AuthorizeException { List tasks = find(context, xmlWorkflowItem); //Use an iterator to remove the tasks ! Iterator iterator = tasks.iterator(); @@ -137,7 +142,7 @@ public class PoolTaskServiceImpl implements PoolTaskService { @Override public void update(Context context, List poolTasks) throws SQLException, AuthorizeException { - if(CollectionUtils.isNotEmpty(poolTasks)) { + if (CollectionUtils.isNotEmpty(poolTasks)) { for (PoolTask poolTask : poolTasks) { poolTaskDAO.save(context, poolTask); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/WorkflowItemRole.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/WorkflowItemRole.java index 13c33fa3a8..9a7e5a034c 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/WorkflowItemRole.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/WorkflowItemRole.java @@ -7,14 +7,23 @@ */ package org.dspace.xmlworkflow.storedcomponents; +import java.sql.SQLException; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import javax.persistence.*; -import java.sql.SQLException; - /** * Represents a workflow assignments database representation. * These assignments describe roles and the groups connected @@ -26,18 +35,18 @@ import java.sql.SQLException; * @author Mark Diggory (markd at atmire dot com) */ @Entity -@Table(name="cwf_workflowitemrole") +@Table(name = "cwf_workflowitemrole") public class WorkflowItemRole implements ReloadableEntity { @Id - @Column(name="workflowitemrole_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="cwf_workflowitemrole_seq") - @SequenceGenerator(name="cwf_workflowitemrole_seq", sequenceName="cwf_workflowitemrole_seq", allocationSize = 1) + @Column(name = "workflowitemrole_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cwf_workflowitemrole_seq") + @SequenceGenerator(name = "cwf_workflowitemrole_seq", sequenceName = "cwf_workflowitemrole_seq", allocationSize = 1) private Integer id; -// @Column(name = "role_id") + // @Column(name = "role_id") // @Lob - @Column(name="role_id", columnDefinition = "text") + @Column(name = "role_id", columnDefinition = "text") private String roleId; @OneToOne(fetch = FetchType.LAZY) @@ -55,10 +64,8 @@ public class WorkflowItemRole implements ReloadableEntity { /** * Protected constructor, create object using: * {@link org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService#create(Context)} - * */ - protected WorkflowItemRole() - { + protected WorkflowItemRole() { } @@ -67,23 +74,23 @@ public class WorkflowItemRole implements ReloadableEntity { return id; } - public void setRoleId(String id){ + public void setRoleId(String id) { this.roleId = id; } - public String getRoleId(){ + public String getRoleId() { return this.roleId; } - public void setWorkflowItem(XmlWorkflowItem xmlWorkflowItem){ + public void setWorkflowItem(XmlWorkflowItem xmlWorkflowItem) { this.workflowItem = xmlWorkflowItem; } - public XmlWorkflowItem getWorkflowItem(){ + public XmlWorkflowItem getWorkflowItem() { return workflowItem; } - public void setEPerson(EPerson eperson){ + public void setEPerson(EPerson eperson) { this.ePerson = eperson; } @@ -91,7 +98,7 @@ public class WorkflowItemRole implements ReloadableEntity { return ePerson; } - public void setGroup(Group group){ + public void setGroup(Group group) { this.group = group; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/WorkflowItemRoleServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/WorkflowItemRoleServiceImpl.java index a23ffd61e4..c96bcd032d 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/WorkflowItemRoleServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/WorkflowItemRoleServiceImpl.java @@ -7,7 +7,12 @@ */ package org.dspace.xmlworkflow.storedcomponents; -import org.apache.commons.collections.CollectionUtils; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -15,11 +20,6 @@ import org.dspace.xmlworkflow.storedcomponents.dao.WorkflowItemRoleDAO; import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - /** * Service implementation for the WorkflowItemRole object. * This class is responsible for all business logic calls for the WorkflowItemRole object and is autowired by spring. @@ -32,8 +32,7 @@ public class WorkflowItemRoleServiceImpl implements WorkflowItemRoleService { @Autowired(required = true) private WorkflowItemRoleDAO workflowItemRoleDAO; - protected WorkflowItemRoleServiceImpl() - { + protected WorkflowItemRoleServiceImpl() { } @@ -43,12 +42,14 @@ public class WorkflowItemRoleServiceImpl implements WorkflowItemRoleService { } @Override - public List findByWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) throws SQLException { + public List findByWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) + throws SQLException { return workflowItemRoleDAO.findByWorkflowItem(context, xmlWorkflowItem); } @Override - public void deleteForWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) throws SQLException, AuthorizeException { + public void deleteForWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) + throws SQLException, AuthorizeException { Iterator workflowItemRoles = findByWorkflowItem(context, xmlWorkflowItem).iterator(); while (workflowItemRoles.hasNext()) { WorkflowItemRole workflowItemRole = workflowItemRoles.next(); @@ -78,8 +79,9 @@ public class WorkflowItemRoleServiceImpl implements WorkflowItemRoleService { } @Override - public void update(Context context, List workflowItemRoles) throws SQLException, AuthorizeException { - if(CollectionUtils.isNotEmpty(workflowItemRoles)) { + public void update(Context context, List workflowItemRoles) + throws SQLException, AuthorizeException { + if (CollectionUtils.isNotEmpty(workflowItemRoles)) { for (WorkflowItemRole workflowItemRole : workflowItemRoles) { workflowItemRoleDAO.save(context, workflowItemRole); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItem.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItem.java index 587198cbdc..7cde578356 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItem.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItem.java @@ -7,6 +7,19 @@ */ package org.dspace.xmlworkflow.storedcomponents; +import java.sql.SQLException; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.core.Context; @@ -14,9 +27,6 @@ import org.dspace.core.ReloadableEntity; import org.dspace.eperson.EPerson; import org.dspace.workflow.WorkflowItem; -import javax.persistence.*; -import java.sql.SQLException; - /** * Class representing an item going through the workflow process in DSpace * @@ -26,13 +36,13 @@ import java.sql.SQLException; * @author Mark Diggory (markd at atmire dot com) */ @Entity -@Table(name="cwf_workflowitem") +@Table(name = "cwf_workflowitem") public class XmlWorkflowItem implements WorkflowItem, ReloadableEntity { @Id - @Column(name="workflowitem_id") - @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="cwf_workflowitem_seq") - @SequenceGenerator(name="cwf_workflowitem_seq", sequenceName="cwf_workflowitem_seq", allocationSize = 1) + @Column(name = "workflowitem_id") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cwf_workflowitem_seq") + @SequenceGenerator(name = "cwf_workflowitem_seq", sequenceName = "cwf_workflowitem_seq", allocationSize = 1) private Integer id; @ManyToOne(fetch = FetchType.LAZY) @@ -55,10 +65,8 @@ public class XmlWorkflowItem implements WorkflowItem, ReloadableEntity /** * Protected constructor, create object using: * {@link org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService#create(Context, Item, Collection)} - * */ - protected XmlWorkflowItem() - { + protected XmlWorkflowItem() { } @@ -68,70 +76,61 @@ public class XmlWorkflowItem implements WorkflowItem, ReloadableEntity * @return the internal identifier */ @Override - public Integer getID() - { + public Integer getID() { return id; } @Override - public Collection getCollection(){ + public Collection getCollection() { return this.collection; } - public void setCollection(Collection collection){ + public void setCollection(Collection collection) { this.collection = collection; } @Override - public Item getItem() - { + public Item getItem() { return item; } - public void setItem(Item item){ + public void setItem(Item item) { this.item = item; } @Override - public EPerson getSubmitter() throws SQLException - { + public EPerson getSubmitter() throws SQLException { return item.getSubmitter(); } @Override - public boolean hasMultipleFiles() - { + public boolean hasMultipleFiles() { return multipleFiles; } @Override - public void setMultipleFiles(boolean b) - { + public void setMultipleFiles(boolean b) { this.multipleFiles = b; } @Override - public boolean hasMultipleTitles() - { + public boolean hasMultipleTitles() { return this.multipleTitles; } @Override - public void setMultipleTitles(boolean b) - { + public void setMultipleTitles(boolean b) { this.multipleTitles = b; } @Override - public boolean isPublishedBefore() - { + public boolean isPublishedBefore() { return this.publishedBefore; } @Override - public void setPublishedBefore(boolean b) - { + public void setPublishedBefore(boolean b) { this.publishedBefore = b; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItemServiceImpl.java index edfe94b0a7..975719e800 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItemServiceImpl.java @@ -7,6 +7,11 @@ */ package org.dspace.xmlworkflow.storedcomponents; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; @@ -22,11 +27,6 @@ import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - /** * Service implementation for the XmlWorkflowItem object. * This class is responsible for all business logic calls for the XmlWorkflowItem object and is autowired by spring. @@ -49,19 +49,19 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { @Autowired(required = true) protected WorkflowItemRoleService workflowItemRoleService; - /* + /* * The current step in the workflow system in which this workflow item is present */ private Logger log = Logger.getLogger(XmlWorkflowItemServiceImpl.class); - protected XmlWorkflowItemServiceImpl() - { + protected XmlWorkflowItemServiceImpl() { } @Override - public XmlWorkflowItem create(Context context, Item item, Collection collection) throws SQLException, AuthorizeException { + public XmlWorkflowItem create(Context context, Item item, Collection collection) + throws SQLException, AuthorizeException { XmlWorkflowItem xmlWorkflowItem = xmlWorkflowItemDAO.create(context, new XmlWorkflowItem()); xmlWorkflowItem.setItem(item); xmlWorkflowItem.setCollection(collection); @@ -73,20 +73,15 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { XmlWorkflowItem workflowItem = xmlWorkflowItemDAO.findByID(context, XmlWorkflowItem.class, id); - if (workflowItem == null) - { - if (log.isDebugEnabled()) - { + if (workflowItem == null) { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_workflow_item", - "not_found,workflowitem_id=" + id)); + "not_found,workflowitem_id=" + id)); } - } - else - { - if (log.isDebugEnabled()) - { + } else { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "find_workflow_item", - "workflowitem_id=" + id)); + "workflowitem_id=" + id)); } } return workflowItem; @@ -103,7 +98,8 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { } @Override - public List findAllInCollection(Context context, Integer offset, Integer pagesize, Collection collection) throws SQLException { + public List findAllInCollection(Context context, Integer offset, Integer pagesize, + Collection collection) throws SQLException { return xmlWorkflowItemDAO.findAllInCollection(context, offset, pagesize, collection); } @@ -123,7 +119,8 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { } @Override - public void deleteByCollection(Context context, Collection collection) throws SQLException, IOException, AuthorizeException { + public void deleteByCollection(Context context, Collection collection) + throws SQLException, IOException, AuthorizeException { List xmlWorkflowItems = findByCollection(context, collection); Iterator iterator = xmlWorkflowItems.iterator(); while (iterator.hasNext()) { @@ -134,7 +131,8 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { } @Override - public void delete(Context context, XmlWorkflowItem workflowItem) throws SQLException, AuthorizeException, IOException { + public void delete(Context context, XmlWorkflowItem workflowItem) + throws SQLException, AuthorizeException, IOException { Item item = workflowItem.getItem(); // Need to delete the workspaceitem row first since it refers // to item ID @@ -156,9 +154,9 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { @Override public void update(Context context, XmlWorkflowItem workflowItem) throws SQLException, AuthorizeException { - // FIXME check auth + // FIXME check auth log.info(LogManager.getHeader(context, "update_workflow_item", - "workflowitem_id=" + workflowItem.getID())); + "workflowitem_id=" + workflowItem.getID())); // Update the item itemService.update(context, workflowItem.getItem()); @@ -170,8 +168,7 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { public void deleteWrapper(Context context, XmlWorkflowItem workflowItem) throws SQLException, AuthorizeException { List roles = workflowItemRoleService.findByWorkflowItem(context, workflowItem); Iterator workflowItemRoleIterator = roles.iterator(); - while (workflowItemRoleIterator.hasNext()) - { + while (workflowItemRoleIterator.hasNext()) { WorkflowItemRole workflowItemRole = workflowItemRoleIterator.next(); workflowItemRoleIterator.remove(); workflowItemRoleService.delete(context, workflowItemRole); @@ -183,4 +180,11 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { // FIXME - auth? xmlWorkflowItemDAO.delete(context, workflowItem); } + + + @Override + public void move(Context context, XmlWorkflowItem inProgressSubmission, Collection fromCollection, + Collection toCollection) { + // TODO not implemented yet + } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/ClaimedTaskDAO.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/ClaimedTaskDAO.java index c8224ac682..7f97e14006 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/ClaimedTaskDAO.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/ClaimedTaskDAO.java @@ -7,18 +7,19 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the ClaimedTask object. - * The implementation of this class is responsible for all database calls for the ClaimedTask object and is autowired by spring + * The implementation of this class is responsible for all database calls for the ClaimedTask object and is autowired + * by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -27,15 +28,20 @@ public interface ClaimedTaskDAO extends GenericDAO { public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException; - public ClaimedTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException; + public ClaimedTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException; public List findByEperson(Context context, EPerson ePerson) throws SQLException; - public List findByWorkflowItemAndStepId(Context context, XmlWorkflowItem workflowItem, String stepID) throws SQLException; + public List findByWorkflowItemAndStepId(Context context, XmlWorkflowItem workflowItem, String stepID) + throws SQLException; - public ClaimedTask findByEPersonAndWorkflowItemAndStepIdAndActionId(Context context, EPerson ePerson, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException; + public ClaimedTask findByEPersonAndWorkflowItemAndStepIdAndActionId(Context context, EPerson ePerson, + XmlWorkflowItem workflowItem, String stepID, + String actionID) throws SQLException; - public List findByWorkflowItemAndStepIdAndActionId(Context c, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException; + public List findByWorkflowItemAndStepIdAndActionId(Context c, XmlWorkflowItem workflowItem, + String stepID, String actionID) throws SQLException; public List findByStep(Context context, String stepID) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/CollectionRoleDAO.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/CollectionRoleDAO.java index c2cdf70fac..5c4d4a16b4 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/CollectionRoleDAO.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/CollectionRoleDAO.java @@ -7,17 +7,18 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.xmlworkflow.storedcomponents.CollectionRole; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the CollectionRole object. - * The implementation of this class is responsible for all database calls for the CollectionRole object and is autowired by spring + * The implementation of this class is responsible for all database calls for the CollectionRole object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -26,7 +27,8 @@ public interface CollectionRoleDAO extends GenericDAO { public List findByCollection(Context context, Collection collection) throws SQLException; - public CollectionRole findByCollectionAndRole(Context context, Collection collection, String role) throws SQLException; + public CollectionRole findByCollectionAndRole(Context context, Collection collection, String role) + throws SQLException; public void deleteByCollection(Context context, Collection collection) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/InProgressUserDAO.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/InProgressUserDAO.java index 89277758dd..b08d5afc21 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/InProgressUserDAO.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/InProgressUserDAO.java @@ -7,25 +7,27 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; import org.dspace.xmlworkflow.storedcomponents.InProgressUser; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the InProgressUser object. - * The implementation of this class is responsible for all database calls for the InProgressUser object and is autowired by spring + * The implementation of this class is responsible for all database calls for the InProgressUser object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com */ public interface InProgressUserDAO extends GenericDAO { - public InProgressUser findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException; + public InProgressUser findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException; public List findByEperson(Context context, EPerson ePerson) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/PoolTaskDAO.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/PoolTaskDAO.java index 6e5a925ef4..55aed546d9 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/PoolTaskDAO.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/PoolTaskDAO.java @@ -7,6 +7,9 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; @@ -14,12 +17,10 @@ import org.dspace.eperson.Group; import org.dspace.xmlworkflow.storedcomponents.PoolTask; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the PoolTask object. - * The implementation of this class is responsible for all database calls for the PoolTask object and is autowired by spring + * The implementation of this class is responsible for all database calls for the PoolTask object and is autowired by + * spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com @@ -32,7 +33,9 @@ public interface PoolTaskDAO extends GenericDAO { public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException; - public PoolTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException; + public PoolTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException; - public PoolTask findByWorkflowItemAndGroup(Context context, Group group, XmlWorkflowItem workflowItem) throws SQLException; + public PoolTask findByWorkflowItemAndGroup(Context context, Group group, XmlWorkflowItem workflowItem) + throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/WorkflowItemRoleDAO.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/WorkflowItemRoleDAO.java index 435d967b58..8ee9e4e4c0 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/WorkflowItemRoleDAO.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/WorkflowItemRoleDAO.java @@ -7,25 +7,27 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the WorkflowItemRole object. - * The implementation of this class is responsible for all database calls for the WorkflowItemRole object and is autowired by spring + * The implementation of this class is responsible for all database calls for the WorkflowItemRole object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com */ public interface WorkflowItemRoleDAO extends GenericDAO { - public List findByWorkflowItemAndRole(Context context, XmlWorkflowItem workflowItem, String role) throws SQLException; + public List findByWorkflowItemAndRole(Context context, XmlWorkflowItem workflowItem, String role) + throws SQLException; public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/XmlWorkflowItemDAO.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/XmlWorkflowItemDAO.java index 559a920575..fddf215da1 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/XmlWorkflowItemDAO.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/XmlWorkflowItemDAO.java @@ -7,6 +7,9 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.core.Context; @@ -14,19 +17,18 @@ import org.dspace.core.GenericDAO; import org.dspace.eperson.EPerson; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Database Access Object interface class for the XmlWorkflowItem object. - * The implementation of this class is responsible for all database calls for the XmlWorkflowItem object and is autowired by spring + * The implementation of this class is responsible for all database calls for the XmlWorkflowItem object and is + * autowired by spring * This class should only be accessed from a single service and should never be exposed outside of the API * * @author kevinvandevelde at atmire.com */ public interface XmlWorkflowItemDAO extends GenericDAO { - public List findAllInCollection(Context context, Integer offset, Integer limit, Collection collection) throws SQLException; + public List findAllInCollection(Context context, Integer offset, Integer limit, + Collection collection) throws SQLException; public int countAll(Context context) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/ClaimedTaskDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/ClaimedTaskDAOImpl.java index 6df57785f8..bb5a167237 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/ClaimedTaskDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/ClaimedTaskDAOImpl.java @@ -7,17 +7,19 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao.impl; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.eperson.EPerson; -import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import org.dspace.xmlworkflow.storedcomponents.dao.ClaimedTaskDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; +import org.dspace.xmlworkflow.storedcomponents.ClaimedTask_; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.dao.ClaimedTaskDAO; /** * Hibernate implementation of the Database Access Object interface class for the ClaimedTask object. @@ -26,82 +28,106 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class ClaimedTaskDAOImpl extends AbstractHibernateDAO implements ClaimedTaskDAO -{ - protected ClaimedTaskDAOImpl() - { +public class ClaimedTaskDAOImpl extends AbstractHibernateDAO implements ClaimedTaskDAO { + protected ClaimedTaskDAOImpl() { super(); } @Override public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.eq("workflowItem", workflowItem)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem)); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override - public ClaimedTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("owner", ePerson) - )); + public ClaimedTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.owner), ePerson) + ) + ); + return uniqueResult(context, criteriaQuery, false, ClaimedTask.class, -1, -1); + - return uniqueResult(criteria); } @Override public List findByEperson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.eq("owner", ePerson)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.owner), ePerson)); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override - public List findByWorkflowItemAndStepId(Context context, XmlWorkflowItem workflowItem, String stepID) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("stepId", stepID) - )); - - return list(criteria); + public List findByWorkflowItemAndStepId(Context context, XmlWorkflowItem workflowItem, String stepID) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.stepId), stepID) + ) + ); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override - public ClaimedTask findByEPersonAndWorkflowItemAndStepIdAndActionId(Context context, EPerson ePerson, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("owner", ePerson), - Restrictions.eq("stepId", stepID), - Restrictions.eq("actionId", actionID) - )); - - return uniqueResult(criteria); + public ClaimedTask findByEPersonAndWorkflowItemAndStepIdAndActionId(Context context, EPerson ePerson, + XmlWorkflowItem workflowItem, String stepID, + String actionID) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.stepId), stepID), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.owner), ePerson), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.actionId), actionID) + ) + ); + return uniqueResult(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override - public List findByWorkflowItemAndStepIdAndActionId(Context context, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("stepId", stepID), - Restrictions.eq("actionId", actionID) - )); - - return list(criteria); + public List findByWorkflowItemAndStepIdAndActionId(Context context, XmlWorkflowItem workflowItem, + String stepID, String actionID) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.stepId), stepID), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.actionId), actionID) + ) + ); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override public List findByStep(Context context, String stepID) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.eq("stepId", stepID)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.stepId), stepID)); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/CollectionRoleDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/CollectionRoleDAOImpl.java index 190092ec5c..c4218d7109 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/CollectionRoleDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/CollectionRoleDAOImpl.java @@ -7,17 +7,19 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao.impl; -import org.dspace.content.Collection; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.xmlworkflow.storedcomponents.CollectionRole; -import org.dspace.xmlworkflow.storedcomponents.dao.CollectionRoleDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.content.Collection; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.xmlworkflow.storedcomponents.CollectionRole; +import org.dspace.xmlworkflow.storedcomponents.CollectionRole_; +import org.dspace.xmlworkflow.storedcomponents.dao.CollectionRoleDAO; /** * Hibernate implementation of the Database Access Object interface class for the CollectionRole object. @@ -26,31 +28,34 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class CollectionRoleDAOImpl extends AbstractHibernateDAO implements CollectionRoleDAO -{ - protected CollectionRoleDAOImpl() - { +public class CollectionRoleDAOImpl extends AbstractHibernateDAO implements CollectionRoleDAO { + protected CollectionRoleDAOImpl() { super(); } @Override public List findByCollection(Context context, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, CollectionRole.class); - criteria.add(Restrictions.eq("collection", collection)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, CollectionRole.class); + Root collectionRoleRoot = criteriaQuery.from(CollectionRole.class); + criteriaQuery.select(collectionRoleRoot); + criteriaQuery.where(criteriaBuilder.equal(collectionRoleRoot.get(CollectionRole_.collection), collection)); + return list(context, criteriaQuery, false, CollectionRole.class, -1, -1); } @Override - public CollectionRole findByCollectionAndRole(Context context, Collection collection, String role) throws SQLException { - Criteria criteria = createCriteria(context, CollectionRole.class); - criteria.add(Restrictions.and( - Restrictions.eq("collection", collection), - Restrictions.eq("roleId", role) - ) + public CollectionRole findByCollectionAndRole(Context context, Collection collection, String role) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, CollectionRole.class); + Root collectionRoleRoot = criteriaQuery.from(CollectionRole.class); + criteriaQuery.select(collectionRoleRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(collectionRoleRoot.get(CollectionRole_.collection), collection), + criteriaBuilder.equal(collectionRoleRoot.get(CollectionRole_.roleId), role) + ) ); - - return uniqueResult(criteria); + return uniqueResult(context, criteriaQuery, false, CollectionRole.class, -1, -1); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/InProgressUserDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/InProgressUserDAOImpl.java index 5633ac9203..cdba1600a8 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/InProgressUserDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/InProgressUserDAOImpl.java @@ -7,17 +7,19 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao.impl; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.eperson.EPerson; -import org.dspace.xmlworkflow.storedcomponents.InProgressUser; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import org.dspace.xmlworkflow.storedcomponents.dao.InProgressUserDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.xmlworkflow.storedcomponents.InProgressUser; +import org.dspace.xmlworkflow.storedcomponents.InProgressUser_; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.dao.InProgressUserDAO; /** * Hibernate implementation of the Database Access Object interface class for the InProgressUser object. @@ -26,63 +28,78 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class InProgressUserDAOImpl extends AbstractHibernateDAO implements InProgressUserDAO -{ - protected InProgressUserDAOImpl() - { +public class InProgressUserDAOImpl extends AbstractHibernateDAO implements InProgressUserDAO { + protected InProgressUserDAOImpl() { super(); } @Override - public InProgressUser findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("ePerson", ePerson) - ) + public InProgressUser findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException { + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, InProgressUser.class); + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + criteriaQuery.select(inProgressUserRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.workflowItem), workflowItem), + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.ePerson), ePerson) + ) ); - return uniqueResult(criteria); + return uniqueResult(context, criteriaQuery, false, InProgressUser.class, -1, -1); + } @Override public List findByEperson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add(Restrictions.eq("ePerson", ePerson)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, InProgressUser.class); + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + criteriaQuery.select(inProgressUserRoot); + criteriaQuery.where(criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.ePerson), ePerson)); + return list(context, criteriaQuery, false, InProgressUser.class, -1, -1); } @Override public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add(Restrictions.eq("workflowItem", workflowItem)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, InProgressUser.class); + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + criteriaQuery.select(inProgressUserRoot); + criteriaQuery.where(criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.workflowItem), workflowItem)); + return list(context, criteriaQuery, false, InProgressUser.class, -1, -1); } @Override public int countInProgressUsers(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("finished", false) - ) - ); - return count(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.workflowItem), workflowItem), + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.finished), false) + ) + ); + return count(context, criteriaQuery, criteriaBuilder, inProgressUserRoot); } @Override public int countFinishedUsers(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("finished", true) - ) + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.workflowItem), workflowItem), + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.finished), true) + ) ); - return count(criteria); + return count(context, criteriaQuery, criteriaBuilder, inProgressUserRoot); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/PoolTaskDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/PoolTaskDAOImpl.java index 56ee84da73..b38041da39 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/PoolTaskDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/PoolTaskDAOImpl.java @@ -7,18 +7,20 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao.impl; -import org.dspace.core.Context; +import java.sql.SQLException; +import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.xmlworkflow.storedcomponents.PoolTask; +import org.dspace.xmlworkflow.storedcomponents.PoolTask_; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.dao.PoolTaskDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - -import java.sql.SQLException; -import java.util.List; /** * Hibernate implementation of the Database Access Object interface class for the PoolTask object. @@ -27,60 +29,69 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class PoolTaskDAOImpl extends AbstractHibernateDAO implements PoolTaskDAO -{ - protected PoolTaskDAOImpl() - { +public class PoolTaskDAOImpl extends AbstractHibernateDAO implements PoolTaskDAO { + protected PoolTaskDAOImpl() { super(); } @Override public List findByEPerson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add(Restrictions.eq("ePerson", ePerson)); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.ePerson), ePerson)); + return list(context, criteriaQuery, false, PoolTask.class, -1, -1); - return list(criteria); } @Override public List findByGroup(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add(Restrictions.eq("group", group)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.group), group)); + return list(context, criteriaQuery, false, PoolTask.class, -1, -1); } @Override public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add(Restrictions.eq("workflowItem", workflowItem)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.workflowItem), workflowItem)); + return list(context, criteriaQuery, false, PoolTask.class, -1, -1); } @Override - public PoolTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("ePerson", ePerson) - ) + public PoolTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.workflowItem), workflowItem), + criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.ePerson), ePerson) + ) ); - - return uniqueResult(criteria); + return uniqueResult(context, criteriaQuery, false, PoolTask.class, -1, -1); } @Override - public PoolTask findByWorkflowItemAndGroup(Context context, Group group, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("group", group) - ) + public PoolTask findByWorkflowItemAndGroup(Context context, Group group, XmlWorkflowItem workflowItem) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.workflowItem), workflowItem), + criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.group), group) + ) ); - - return uniqueResult(criteria); + return uniqueResult(context, criteriaQuery, false, PoolTask.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/WorkflowItemRoleDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/WorkflowItemRoleDAOImpl.java index 75a36a2e41..fdc2413b5f 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/WorkflowItemRoleDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/WorkflowItemRoleDAOImpl.java @@ -7,17 +7,19 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao.impl; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.eperson.EPerson; -import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import org.dspace.xmlworkflow.storedcomponents.dao.WorkflowItemRoleDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole; +import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole_; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.dao.WorkflowItemRoleDAO; /** * Hibernate implementation of the Database Access Object interface class for the WorkflowItemRole object. @@ -26,38 +28,50 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class WorkflowItemRoleDAOImpl extends AbstractHibernateDAO implements WorkflowItemRoleDAO -{ - protected WorkflowItemRoleDAOImpl() - { +public class WorkflowItemRoleDAOImpl extends AbstractHibernateDAO implements WorkflowItemRoleDAO { + + protected WorkflowItemRoleDAOImpl() { super(); } @Override - public List findByWorkflowItemAndRole(Context context, XmlWorkflowItem workflowItem, String role) throws SQLException { - Criteria criteria = createCriteria(context, WorkflowItemRole.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("role", role) - ) + public List findByWorkflowItemAndRole(Context context, + XmlWorkflowItem workflowItem, + String role) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkflowItemRole.class); + Root workflowItemRoleRoot = criteriaQuery.from(WorkflowItemRole.class); + criteriaQuery.select(workflowItemRoleRoot); + criteriaQuery.where(criteriaBuilder.and(criteriaBuilder + .equal(workflowItemRoleRoot.get(WorkflowItemRole_.workflowItem), + workflowItem), + criteriaBuilder + .equal(workflowItemRoleRoot.get(WorkflowItemRole_.roleId), + role) + ) ); - - return list(criteria); + return list(context, criteriaQuery, false, WorkflowItemRole.class, -1, -1); } @Override - public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, WorkflowItemRole.class); - criteria.add(Restrictions.eq("workflowItem", workflowItem)); - - return list(criteria); + public List findByWorkflowItem(Context context, + XmlWorkflowItem workflowItem) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkflowItemRole.class); + Root workflowItemRoleRoot = criteriaQuery.from(WorkflowItemRole.class); + criteriaQuery.select(workflowItemRoleRoot); + criteriaQuery.where(criteriaBuilder.equal(workflowItemRoleRoot.get(WorkflowItemRole_.workflowItem), + workflowItem)); + return list(context, criteriaQuery, false, WorkflowItemRole.class, -1, -1); } @Override public List findByEPerson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, WorkflowItemRole.class); - criteria.add(Restrictions.eq("ePerson", ePerson)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkflowItemRole.class); + Root workflowItemRoleRoot = criteriaQuery.from(WorkflowItemRole.class); + criteriaQuery.select(workflowItemRoleRoot); + criteriaQuery.where(criteriaBuilder.equal(workflowItemRoleRoot.get(WorkflowItemRole_.ePerson), ePerson)); + return list(context, criteriaQuery, false, WorkflowItemRole.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/XmlWorkflowItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/XmlWorkflowItemDAOImpl.java index ee131ed585..3c14e42a5b 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/XmlWorkflowItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/XmlWorkflowItemDAOImpl.java @@ -7,19 +7,24 @@ */ package org.dspace.xmlworkflow.storedcomponents.dao.impl; -import org.dspace.content.Collection; -import org.dspace.content.Item; -import org.dspace.core.Context; -import org.dspace.core.AbstractHibernateDAO; -import org.dspace.eperson.EPerson; -import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import org.dspace.xmlworkflow.storedcomponents.dao.XmlWorkflowItemDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; - import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; + +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.content.Item_; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem_; +import org.dspace.xmlworkflow.storedcomponents.dao.XmlWorkflowItemDAO; + /** * Hibernate implementation of the Database Access Object interface class for the XmlWorkflowItem object. * This class is responsible for all database calls for the XmlWorkflowItem object and is autowired by spring @@ -27,32 +32,31 @@ import java.util.List; * * @author kevinvandevelde at atmire.com */ -public class XmlWorkflowItemDAOImpl extends AbstractHibernateDAO implements XmlWorkflowItemDAO -{ +public class XmlWorkflowItemDAOImpl extends AbstractHibernateDAO implements XmlWorkflowItemDAO { - protected XmlWorkflowItemDAOImpl() - { + protected XmlWorkflowItemDAOImpl() { super(); } @Override - public List findAllInCollection(Context context, Integer offset, Integer limit, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, XmlWorkflowItem.class); - if(collection != null) - { - criteria.add(Restrictions.eq("collection", collection)); + public List findAllInCollection(Context context, Integer offset, + Integer limit, + Collection collection) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, XmlWorkflowItem.class); + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + criteriaQuery.select(xmlWorkflowItemRoot); + if (collection != null) { + criteriaQuery.where(criteriaBuilder.equal(xmlWorkflowItemRoot.get(XmlWorkflowItem_.collection), + collection)); } - - if(offset != null) - { - criteria.setFirstResult(offset); + if (offset == null) { + offset = -1; } - if(limit != null) - { - criteria.setMaxResults(limit); + if (limit == null) { + limit = -1; } - - return list(criteria); + return list(context, criteriaQuery, false, XmlWorkflowItem.class, limit, offset); } @Override @@ -62,36 +66,48 @@ public class XmlWorkflowItemDAOImpl extends AbstractHibernateDAO criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + if (collection != null) { + criteriaQuery.where(criteriaBuilder.equal(xmlWorkflowItemRoot.get(XmlWorkflowItem_.collection), + collection)); } - return count(criteria); + return count(context, criteriaQuery, criteriaBuilder, xmlWorkflowItemRoot); } @Override public List findBySubmitter(Context context, EPerson ep) throws SQLException { - Criteria criteria = createCriteria(context, XmlWorkflowItem.class); - criteria.createAlias("item", "i"); - criteria.add(Restrictions.eq("i.submitter", ep)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, XmlWorkflowItem.class); + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + Join join = xmlWorkflowItemRoot.join("item"); + criteriaQuery.select(xmlWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(join.get(Item_.submitter), ep)); + return list(context, criteriaQuery, false, XmlWorkflowItem.class, -1, -1); } @Override public List findByCollection(Context context, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, XmlWorkflowItem.class); - criteria.add(Restrictions.eq("collection", collection)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, XmlWorkflowItem.class); + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + criteriaQuery.select(xmlWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(xmlWorkflowItemRoot.get(XmlWorkflowItem_.collection), collection)); + return list(context, criteriaQuery, false, XmlWorkflowItem.class, -1, -1); } @Override public XmlWorkflowItem findByItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, XmlWorkflowItem.class); - criteria.add(Restrictions.eq("item", item)); - - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, XmlWorkflowItem.class); + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + criteriaQuery.select(xmlWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(xmlWorkflowItemRoot.get(XmlWorkflowItem_.item), item)); + return uniqueResult(context, criteriaQuery, false, XmlWorkflowItem.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/ClaimedTaskService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/ClaimedTaskService.java index 8555a9be63..cfa6d3b613 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/ClaimedTaskService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/ClaimedTaskService.java @@ -7,6 +7,9 @@ */ package org.dspace.xmlworkflow.storedcomponents.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -14,12 +17,10 @@ import org.dspace.service.DSpaceCRUDService; import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the ClaimedTask object. - * The implementation of this class is responsible for all business logic calls for the ClaimedTask object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the ClaimedTask object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -28,19 +29,22 @@ public interface ClaimedTaskService extends DSpaceCRUDService { public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException; public ClaimedTask findByWorkflowIdAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) - throws SQLException; + throws SQLException; public List findByEperson(Context context, EPerson ePerson) throws SQLException; public List find(Context context, XmlWorkflowItem workflowItem, String stepID) throws SQLException; - public ClaimedTask find(Context context, EPerson ePerson, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException; + public ClaimedTask find(Context context, EPerson ePerson, XmlWorkflowItem workflowItem, String stepID, + String actionID) throws SQLException; - public List find(Context context, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException; + public List find(Context context, XmlWorkflowItem workflowItem, String stepID, String actionID) + throws SQLException; public List find(Context context, XmlWorkflowItem workflowItem) throws SQLException; public List findAllInStep(Context context, String stepID) throws SQLException; - public void deleteByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException, AuthorizeException; + public void deleteByWorkflowItem(Context context, XmlWorkflowItem workflowItem) + throws SQLException, AuthorizeException; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/CollectionRoleService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/CollectionRoleService.java index f66ce7196a..bc7930a13b 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/CollectionRoleService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/CollectionRoleService.java @@ -7,17 +7,18 @@ */ package org.dspace.xmlworkflow.storedcomponents.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.eperson.Group; import org.dspace.xmlworkflow.storedcomponents.CollectionRole; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the CollectionRole object. - * The implementation of this class is responsible for all business logic calls for the CollectionRole object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the CollectionRole object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -29,7 +30,8 @@ public interface CollectionRoleService { public List findByCollection(Context context, Collection collection) throws SQLException; - public CollectionRole create(Context context, Collection collection, String roleId, Group group) throws SQLException; + public CollectionRole create(Context context, Collection collection, String roleId, Group group) + throws SQLException; public void update(Context context, CollectionRole collectionRole) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/InProgressUserService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/InProgressUserService.java index 404bae5f69..d90d73e7c9 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/InProgressUserService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/InProgressUserService.java @@ -7,25 +7,25 @@ */ package org.dspace.xmlworkflow.storedcomponents.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.service.DSpaceCRUDService; import org.dspace.xmlworkflow.storedcomponents.InProgressUser; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the InProgressUser object. - * The implementation of this class is responsible for all business logic calls for the InProgressUser object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the InProgressUser object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ -public interface InProgressUserService extends DSpaceCRUDService -{ +public interface InProgressUserService extends DSpaceCRUDService { public InProgressUser findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) - throws SQLException; + throws SQLException; public List findByEperson(Context context, EPerson ePerson) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/PoolTaskService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/PoolTaskService.java index 5c140b4c60..5006760453 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/PoolTaskService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/PoolTaskService.java @@ -7,6 +7,10 @@ */ package org.dspace.xmlworkflow.storedcomponents.service; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -14,26 +18,24 @@ import org.dspace.service.DSpaceCRUDService; import org.dspace.xmlworkflow.storedcomponents.PoolTask; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the PoolTask object. - * The implementation of this class is responsible for all business logic calls for the PoolTask object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the PoolTask object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ -public interface PoolTaskService extends DSpaceCRUDService -{ - public List findByEperson(Context context, EPerson ePerson) throws SQLException, AuthorizeException, IOException; +public interface PoolTaskService extends DSpaceCRUDService { + public List findByEperson(Context context, EPerson ePerson) + throws SQLException, AuthorizeException, IOException; public List find(Context context, XmlWorkflowItem workflowItem) throws SQLException; public PoolTask findByWorkflowIdAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) - throws SQLException, AuthorizeException, IOException; + throws SQLException, AuthorizeException, IOException; - public void deleteByWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) throws SQLException, AuthorizeException; + public void deleteByWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) + throws SQLException, AuthorizeException; public List findByEPerson(Context context, EPerson ePerson) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/WorkflowItemRoleService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/WorkflowItemRoleService.java index 6c03f7140f..62c661f02a 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/WorkflowItemRoleService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/WorkflowItemRoleService.java @@ -7,6 +7,9 @@ */ package org.dspace.xmlworkflow.storedcomponents.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -14,12 +17,10 @@ import org.dspace.service.DSpaceCRUDService; import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the WorkflowItemRole object. - * The implementation of this class is responsible for all business logic calls for the WorkflowItemRole object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the WorkflowItemRole object and + * is autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -27,7 +28,8 @@ public interface WorkflowItemRoleService extends DSpaceCRUDService find(Context context, XmlWorkflowItem workflowItem, String role) throws SQLException; - public List findByWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) throws SQLException; + public List findByWorkflowItem(Context context, XmlWorkflowItem xmlWorkflowItem) + throws SQLException; public void deleteForWorkflowItem(Context context, XmlWorkflowItem wfi) throws SQLException, AuthorizeException; diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/XmlWorkflowItemService.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/XmlWorkflowItemService.java index cfa033091a..bc65b230a5 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/XmlWorkflowItemService.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/service/XmlWorkflowItemService.java @@ -7,17 +7,18 @@ */ package org.dspace.xmlworkflow.storedcomponents.service; +import java.sql.SQLException; +import java.util.List; + import org.dspace.content.Collection; import org.dspace.core.Context; import org.dspace.workflow.WorkflowItemService; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; -import java.sql.SQLException; -import java.util.List; - /** * Service interface class for the XmlWorkflowItem object. - * The implementation of this class is responsible for all business logic calls for the XmlWorkflowItem object and is autowired by spring + * The implementation of this class is responsible for all business logic calls for the XmlWorkflowItem object and is + * autowired by spring * * @author kevinvandevelde at atmire.com */ @@ -26,56 +27,43 @@ public interface XmlWorkflowItemService extends WorkflowItemService findAll(Context context, Integer page, Integer pagesize) throws SQLException; /** * return all workflowitems for a certain page with a certain collection * - * @param context - * The relevant DSpace Context. - * @param page - * paging: page number - * @param pagesize - * paging: items per page - * @param collection - * restrict to this collection + * @param context The relevant DSpace Context. + * @param page paging: page number + * @param pagesize paging: items per page + * @param collection restrict to this collection * @return WorkflowItem list of all the workflow items in system - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ - public List findAllInCollection(Context context, Integer page, Integer pagesize, Collection collection) throws SQLException; + public List findAllInCollection(Context context, Integer page, Integer pagesize, + Collection collection) throws SQLException; /** * return how many workflow items appear in the database * - * @param context - * The relevant DSpace Context. + * @param context The relevant DSpace Context. * @return the number of workflow items - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public int countAll(Context context) throws SQLException; /** * return how many workflow items that appear in the collection * - * @param context - * The relevant DSpace Context. - * @param collection - * restrict to this collection + * @param context The relevant DSpace Context. + * @param collection restrict to this collection * @return the number of workflow items - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @throws SQLException An exception that provides information on a database access error or other errors. */ public int countAllInCollection(Context context, Collection collection) throws SQLException; diff --git a/dspace-api/src/main/resources/Messages.properties b/dspace-api/src/main/resources/Messages.properties index 1fa4693efd..bf1b475375 100644 --- a/dspace-api/src/main/resources/Messages.properties +++ b/dspace-api/src/main/resources/Messages.properties @@ -78,7 +78,7 @@ itemlist.dc.type.degree = Degree itemlist.et-al = et al itemlist.thumbnail = Preview -itemlist.title.undefined = Undefined +itemlist.title.undefined = Undefined jsp.adminhelp = jsp.administer = Administer @@ -304,20 +304,20 @@ jsp.dspace-admin.group-eperson-select.title = Select EPerson jsp.dspace-admin.group-group-select.add = Add Group jsp.dspace-admin.group-group-select.heading = Select Group to Add to Group {0} jsp.dspace-admin.group-group-select.title = Select Group -jsp.dspace-admin.batchmetadataimport.title = Batch import metadata (BTE) -jsp.dspace-admin.batchmetadataimport.success = The job was taken over, an email will be sent as soon as it's finished -jsp.dspace-admin.batchmetadataimport.genericerror = An error occurred! Please, try again! -jsp.dspace-admin.batchmetadataimport.selectfile = Select data file to upload -jsp.dspace-admin.batchmetadataimport.selectinputfile = Select the type of the input data -jsp.dspace-admin.batchmetadataimport.selectcollection = Select the collection the items will be imported to -jsp.dspace-admin.batchimport.info.success = The job was taken over, an email will be sent as soon as it's finished. In the meanwhile, you can check the progress of your batch import in the 'My DSpace' section. -jsp.dspace-admin.batchimport.saf.remote = Simple Archive Format (zip file via remote URL) -jsp.dspace-admin.batchimport.saf.upload = Simple Archive Format (zip file via upload) -jsp.dspace-admin.batchimport.hide = hide -jsp.dspace-admin.batchimport.show = show more -jsp.dspace-admin.batchimport.hideitems = hide items -jsp.dspace-admin.batchimport.showitems = show items -jsp.dspace-admin.batchimport.errormsg = Error Message +jsp.dspace-admin.batchmetadataimport.title = Batch import metadata (BTE) +jsp.dspace-admin.batchmetadataimport.success = The job was taken over, an email will be sent as soon as it's finished +jsp.dspace-admin.batchmetadataimport.genericerror = An error occurred! Please, try again! +jsp.dspace-admin.batchmetadataimport.selectfile = Select data file to upload +jsp.dspace-admin.batchmetadataimport.selectinputfile = Select the type of the input data +jsp.dspace-admin.batchmetadataimport.selectcollection = Select the collection the items will be imported to +jsp.dspace-admin.batchimport.info.success = The job was taken over, an email will be sent as soon as it's finished. In the meanwhile, you can check the progress of your batch import in the 'My DSpace' section. +jsp.dspace-admin.batchimport.saf.remote = Simple Archive Format (zip file via remote URL) +jsp.dspace-admin.batchimport.saf.upload = Simple Archive Format (zip file via upload) +jsp.dspace-admin.batchimport.hide = hide +jsp.dspace-admin.batchimport.show = show more +jsp.dspace-admin.batchimport.hideitems = hide items +jsp.dspace-admin.batchimport.showitems = show items +jsp.dspace-admin.batchimport.errormsg = Error Message jsp.dspace-admin.metadataimport.title = Import metadata jsp.dspace-admin.metadataimport.apply = Apply changes jsp.dspace-admin.metadataimport.unknownerror = An unknown error has occurred @@ -488,7 +488,7 @@ jsp.dspace-admin.wizard-permissions.text5 = Who is respons jsp.dspace-admin.wizard-permissions.text6 = Who are the collection administrators for this collection? They will be able to decide who can submit items to the collection, withdraw items, edit item metadata (after submission), and add (map) existing items from other collections to this collection (subject to authorization from that collection). jsp.dspace-admin.wizard-permissions.title = Collection Authorization jsp.dspace-admin.wizard-questions.check1 = New items should be publicly readable -jsp.dspace-admin.wizard-questions.check1-disabled = Only System Admin can change this +jsp.dspace-admin.wizard-questions.check1-disabled = Only System Admin can change this jsp.dspace-admin.wizard-questions.check2 = Some users will be able to submit to this collection jsp.dspace-admin.wizard-questions.check3 = The submission workflow will include an accept/reject step jsp.dspace-admin.wizard-questions.check4 = The submission workflow will include an accept/reject/edit metadata step @@ -553,7 +553,7 @@ jsp.feedback.form.text1 = Thanks for tak jsp.feedback.form.text2 = Please fill out all of the information below. jsp.feedback.form.title = Feedback Form jsp.general.authors.button = Authors -jsp.general.browse = Browse +jsp.general.browse = Browse jsp.general.date.button = By Date jsp.general.edit.button = Edit... jsp.general.genericScope = All of DSpace @@ -600,11 +600,11 @@ jsp.home.search2 = Enter some tex jsp.home.title = Home jsp.layout.footer-default.feedback = Feedback jsp.layout.footer-default.text = DSpace Software Copyright © 2002-2013  Duraspace -jsp.layout.footer-default.theme-by = Theme by +jsp.layout.footer-default.theme-by = Theme by jsp.layout.header-default.about = About DSpace Software jsp.layout.header-default.alt = DSpace -jsp.layout.header-default.brand.heading = DSpace JSPUI -jsp.layout.header-default.brand.description =

    DSpace preserves and enables easy and open access to all types of digital content including text, images, moving images, mpegs and data sets

    Learn More +jsp.layout.header-default.brand.heading = DSpace JSPUI +jsp.layout.header-default.brand.description =

    DSpace preserves and enables easy and open access to all types of digital content including text, images, moving images, mpegs and data sets

    Learn More jsp.layout.navbar-admin.authorization = Authorization jsp.layout.navbar-admin.communities-collections = Communities & Collections jsp.layout.navbar-admin.curate = Curation Tasks @@ -618,7 +618,7 @@ jsp.layout.navbar-admin.items = Items jsp.layout.navbar-admin.logout = Log Out jsp.layout.navbar-admin.privateitems = Private Items jsp.layout.navbar-admin.metadataimport = Import metadata -jsp.layout.navbar-admin.batchmetadataimport = Batch import metadata (BTE) +jsp.layout.navbar-admin.batchmetadataimport = Batch import metadata (BTE) jsp.layout.navbar-admin.metadataregistry = Metadata
    Registry jsp.layout.navbar-admin.statistics = Statistics jsp.layout.navbar-admin.supervisors = Supervisors @@ -848,17 +848,17 @@ jsp.search.advanced.type = Search type: jsp.search.advanced.type.abstract = Abstract jsp.search.advanced.type.author = Author jsp.search.advanced.type.identifier = Identifier -jsp.search.advanced.type.ANY = Keyword +jsp.search.advanced.type.ANY = Keyword jsp.search.advanced.type.language = Language (ISO) jsp.search.advanced.type.series = Series jsp.search.advanced.type.sponsor = Sponsor jsp.search.advanced.type.keyword = Subject jsp.search.advanced.type.title = Title -jsp.search.didyoumean = Did you mean: {0} +jsp.search.didyoumean = Did you mean: {0} jsp.search.error.invalid-search-string = Invalid search string jsp.search.error.number-format-exception = Number format exception jsp.search.error.query-too-broad = Your query was too broad. Try a narrower query. -jsp.search.general.new-search = Start a new search +jsp.search.general.new-search = Start a new search jsp.search.general.next = next jsp.search.general.noresults = Search produced no results. jsp.search.general.previous = previous @@ -869,34 +869,34 @@ jsp.search.results.results = Results {0}-{1 jsp.search.results.searchfor = for jsp.search.results.searchin = Search: jsp.search.results.title = Search Results -jsp.search.title = Search -jsp.search.error.discovery = An error has occurred. Your query is invalid or the search engine is down. -jsp.search.facet.refine = Discover -jsp.search.facet.refine.author = Author -jsp.search.facet.refine.subject = Subject -jsp.search.facet.refine.dateIssued = Date issued -jsp.search.facet.refine.has_content_in_original_bundle = Has File(s) -jsp.search.facet.refine.value_has_content_in_original_bundle_true = Yes -jsp.search.facet.refine.value.has_content_in_original_bundle_false = False -jsp.search.facet.refine.previous = < previous -jsp.search.facet.refine.next = next > -jsp.search.facet.narrow = Filter by {0} -jsp.search.filter.heading = Add filters: -jsp.search.filter.hint = Use filters to refine the search results. -jsp.search.filter.add = Add -jsp.search.filter.applied = Current filters: -jsp.search.filter.any = Any fields -jsp.search.filter.title = Title -jsp.search.filter.author = Author -jsp.search.filter.subject = Subject -jsp.search.filter.dateIssued = Date Issued -jsp.search.filter.op.equals = Equals -jsp.search.filter.op.notequals = Not Equals -jsp.search.filter.op.contains = Contains -jsp.search.filter.op.notcontains = Not Contains -jsp.search.filter.op.authority = ID -jsp.search.filter.op.notauthority = Not ID -jsp.search.filter.has_content_in_original_bundle = Has File(s) +jsp.search.title = Search +jsp.search.error.discovery = An error has occurred. Your query is invalid or the search engine is down. +jsp.search.facet.refine = Discover +jsp.search.facet.refine.author = Author +jsp.search.facet.refine.subject = Subject +jsp.search.facet.refine.dateIssued = Date issued +jsp.search.facet.refine.has_content_in_original_bundle = Has File(s) +jsp.search.facet.refine.value_has_content_in_original_bundle_true = Yes +jsp.search.facet.refine.value.has_content_in_original_bundle_false = False +jsp.search.facet.refine.previous = < previous +jsp.search.facet.refine.next = next > +jsp.search.facet.narrow = Filter by {0} +jsp.search.filter.heading = Add filters: +jsp.search.filter.hint = Use filters to refine the search results. +jsp.search.filter.add = Add +jsp.search.filter.applied = Current filters: +jsp.search.filter.any = Any fields +jsp.search.filter.title = Title +jsp.search.filter.author = Author +jsp.search.filter.subject = Subject +jsp.search.filter.dateIssued = Date Issued +jsp.search.filter.op.equals = Equals +jsp.search.filter.op.notequals = Not Equals +jsp.search.filter.op.contains = Contains +jsp.search.filter.op.notcontains = Not Contains +jsp.search.filter.op.authority = ID +jsp.search.filter.op.notauthority = Not ID +jsp.search.filter.has_content_in_original_bundle = Has File(s) jsp.sherpa.title = SHERPA/RoMEO Publisher Policy Database jsp.sherpa.loading =

    Fetching policy information from the SHERPA/RoMEO database

    loading jsp.sherpa.heading =

    SHERPA/RoMEO Database All SHERPA/RoMEO information is correct to the best of our knowledge but should not be relied upon for legal advice. SHERPA cannot be held responsible for the re-use of RoMEO data, or for alternative interpretations which are derived from this information.

    @@ -905,7 +905,7 @@ jsp.sherpa.noresult =

    Sorry, there are not data in the jsp.sherpa.oneresult =

    The SHERPA/RoMEO Database provide the following data for the journal that you have entered.

    jsp.sherpa.moreresults =

    The ISSNs that you have entered match with multiple journals, please review them. You can find the publisher policy for these journals below.

    jsp.sherpa.jornaltitle =

    Journal: {0} -jsp.sherpa.jornalissn = (ISSN\: {0})

    +jsp.sherpa.jornalissn = (ISSN\: {0})

    jsp.sherpa.publisher =

    Publisher: {0}

    jsp.sherpa.publisher.onlyname =

    Publisher: {0}

    jsp.sherpa.publisher.unknow =

    Publisher: Unknown

    @@ -956,15 +956,15 @@ jsp.submit.access.private_setting.help = If selected, t jsp.submit.access.private_setting.label = Private\: jsp.submit.access.private_setting.review.discoverable = The item will be searchable jsp.submit.access.private_setting.review.notdiscoverable = The item will not be searchable -jsp.submit.access.review.button = Edit access settings -jsp.submit.access.review.embargoed = Access is allowed from {0} +jsp.submit.access.review.button = Edit access settings +jsp.submit.access.review.embargoed = Access is allowed from {0} jsp.submit.access.embargo_setting.heading = Embargo -jsp.submit.access.policy_setting.help = Policies listed in this section override any default policies for the collection you're submitting to. If you wish to set an embargo but the target collection allows access for any user, you must set a policy that allows access for the Anonymous group only from a specific date onwards. -jsp.submit.access.policy_setting.label_name = Name\: -jsp.submit.access.policy_setting.label_group = Group\: -jsp.submit.access.policy_setting.label_date = Embargo Access until Specific Date\: +jsp.submit.access.policy_setting.help = Policies listed in this section override any default policies for the collection you're submitting to. If you wish to set an embargo but the target collection allows access for any user, you must set a policy that allows access for the Anonymous group only from a specific date onwards. +jsp.submit.access.policy_setting.label_name = Name\: +jsp.submit.access.policy_setting.label_group = Group\: +jsp.submit.access.policy_setting.label_date = Embargo Access until Specific Date\: jsp.submit.access.policy_setting.label_date.help = Accepted format: yyyy, yyyy-mm, yyyy-mm-dd -jsp.submit.access.policy_setting.label_reason = Reason\: +jsp.submit.access.policy_setting.label_reason = Reason\: jsp.submit.access.submit_add_policy.button = Confirm Policy & add another jsp.submit.access.edit_policy.heading = Edit Policy jsp.submit.cancel.continue.button = Oops, continue submission @@ -991,16 +991,16 @@ jsp.submit.choose-file.info7 = Information ab jsp.submit.choose-file.info9 = Please give a brief description of the contents of this file, for example "Main article", or "Experiment data readings". jsp.submit.choose-file.title = Upload a File jsp.submit.choose-file.skip = Skip file upload > -jsp.submit.choose-file.upload-ajax.button.cancel = Cancel -jsp.submit.choose-file.upload-ajax.button.select-file = Select a file... -jsp.submit.choose-file.upload-ajax.dialog.close = Ok -jsp.submit.choose-file.upload-ajax.fileRequired.title = File required -jsp.submit.choose-file.upload-ajax.fileRequired.info = You must upload at least one file for this item -jsp.submit.choose-file.upload-ajax.uploadInit = Upload is starting... -jsp.submit.choose-file.upload-ajax.uploadInProgress = Upload in progress... {0}% [{1} bytes of {2}] -jsp.submit.choose-file.upload-ajax.uploadCompleted = Upload completed. +jsp.submit.choose-file.upload-ajax.button.cancel = Cancel +jsp.submit.choose-file.upload-ajax.button.select-file = Select a file... +jsp.submit.choose-file.upload-ajax.dialog.close = Ok +jsp.submit.choose-file.upload-ajax.fileRequired.title = File required +jsp.submit.choose-file.upload-ajax.fileRequired.info = You must upload at least one file for this item +jsp.submit.choose-file.upload-ajax.uploadInit = Upload is starting... +jsp.submit.choose-file.upload-ajax.uploadInProgress = Upload in progress... {0}% [{1} bytes of {2}] +jsp.submit.choose-file.upload-ajax.uploadCompleted = Upload completed. jsp.submit.choose-file.upload-resumable.unsupported = Your browser, unfortunately, does not support enhanced file upload. Use a browser that supports the HTML5 File API along with file slicing for an enhanced upload. -jsp.submit.choose-file.upload-resumable.button.select-file = Select a file or drag & drop files ... +jsp.submit.choose-file.upload-resumable.button.select-file = Select a file or drag & drop files ... jsp.submit.complete.heading = Submit: Submission Complete! jsp.submit.complete.info = Your submission will now go through the workflow process designated for the collection to which you are submitting. You will receive e-mail notification as soon as your submission has become a part of the collection, or if for some reason there is a problem with your submission. You can also check on the status of your submission by going to the My DSpace page. jsp.submit.complete.again = Submit another item to the same collection @@ -1012,7 +1012,7 @@ jsp.submit.creative-commons.title = Use a Creative jsp.submit.creative-commons.license = License Type jsp.submit.creative-commons.select_change = Select or modify your license ... -jsp.submit.creative-commons.no_license = No Creative Commons License +jsp.submit.creative-commons.no_license = No Creative Commons License jsp.submit.creative-commons.license.current = Current license jsp.submit.edit-bitstream-access.title = Edit Bitstream Access @@ -1106,9 +1106,9 @@ jsp.submit.review.title = Verify Submiss jsp.submit.review.unknown = (Unknown) jsp.submit.review.upload1 = Uploaded Files: jsp.submit.review.upload2 = Uploaded File: -jsp.submit.review.policies.founded = Found {0} access settings -jsp.submit.review.policies.openaccess = Open Access -jsp.submit.review.policies.embargoed = Access is allowed from {0} +jsp.submit.review.policies.founded = Found {0} access settings +jsp.submit.review.policies.openaccess = Open Access +jsp.submit.review.policies.embargoed = Access is allowed from {0} jsp.submit.saved.info = Your submission has been saved for you to finish later. You can continue the submission by going to your "My DSpace" page and clicking on the relevant "Resume" button. jsp.submit.saved.title = Submission Saved jsp.submit.select-collection.collection = Collection @@ -1259,8 +1259,8 @@ jsp.tools.curate.select-group.tag = Choose from th jsp.tools.curate.select-task.tag = Task jsp.tools.curate.task.name = Task: {0} jsp.tools.edit-collection.button.delete = Delete this Collection... -jsp.tools.edit-collection.form.basic-metadata = Collection's Metadata -jsp.tools.edit-collection.form.collection-settings = Collection's settings +jsp.tools.edit-collection.form.basic-metadata = Collection's Metadata +jsp.tools.edit-collection.form.collection-settings = Collection's settings jsp.tools.edit-collection.form.button.add-logo = Upload new logo... jsp.tools.edit-collection.form.button.cancel = Cancel jsp.tools.edit-collection.form.button.create = Create... @@ -1284,8 +1284,8 @@ jsp.tools.edit-collection.form.label18 = This collectio jsp.tools.edit-collection.form.label19 = OAI Provider jsp.tools.edit-collection.form.label20 = OAI Set Id jsp.tools.edit-collection.form.label21 = Metadata Format -jsp.tools.edit-collection.form.label21.select.qdc = Qualified Dublin Core -jsp.tools.edit-collection.form.label21.select.dc = Dublin Core +jsp.tools.edit-collection.form.label21.select.qdc = Qualified Dublin Core +jsp.tools.edit-collection.form.label21.select.dc = Dublin Core jsp.tools.edit-collection.form.label21.select.dim = DSpace Intermediate Format jsp.tools.edit-collection.form.label22 = Content
    being
    Harvested jsp.tools.edit-collection.form.label23 = Harvest metadata only. @@ -1308,12 +1308,12 @@ jsp.tools.edit-collection.wf-role1 = Accept/Reject jsp.tools.edit-collection.wf-role2 = Accept/Reject/Edit Metadata jsp.tools.edit-collection.wf-role3 = Edit Metadata jsp.tools.edit-community.button.delete = Delete this Community... -jsp.tools.edit-community.form.basic-metadata = Community's metadata -jsp.tools.edit-community.form.community-settings = Community's settings +jsp.tools.edit-community.form.basic-metadata = Community's metadata +jsp.tools.edit-community.form.community-settings = Community's settings jsp.tools.edit-community.form.button.add-logo = Upload new logo... jsp.tools.edit-community.form.button.cancel = Cancel jsp.tools.edit-community.form.button.create = Create -jsp.tools.edit-community.form.button.remove = Remove +jsp.tools.edit-community.form.button.remove = Remove jsp.tools.edit-community.form.button.delete-logo = Delete (no logo) jsp.tools.edit-community.form.button.edit = Edit... jsp.tools.edit-community.form.button.set-logo = Upload a logo... @@ -1326,7 +1326,7 @@ jsp.tools.edit-community.form.label4 = Copyright text jsp.tools.edit-community.form.label5 = Side bar text (HTML): jsp.tools.edit-community.form.label6 = Logo: jsp.tools.edit-community.form.label7 = Community's Authorizations: -jsp.tools.edit-community.form.label8 = Community Administrators: +jsp.tools.edit-community.form.label8 = Community Administrators: jsp.tools.edit-community.form.label9 = Community's Curations: jsp.tools.edit-community.heading1 = Create Community jsp.tools.edit-community.heading2 = Edit Community {0} @@ -1445,9 +1445,9 @@ jsp.tools.itemmap-browse.th.date = Date jsp.tools.itemmap-browse.th.remove = Unmap jsp.tools.itemmap-browse.th.title = Title jsp.tools.itemmap-browse.title = Browse Items -jsp.tools.itemmap-browse.info.change-page = Your query returned a lot of results. You can navigate the results using the following buttons. Please note that the selected items will be mapped only after clicking the ''Add'' button. -jsp.tools.itemmap-browse.previous.button = Previous page -jsp.tools.itemmap-browse.next.button = Next page +jsp.tools.itemmap-browse.info.change-page = Your query returned a lot of results. You can navigate the results using the following buttons. Please note that the selected items will be mapped only after clicking the ''Add'' button. +jsp.tools.itemmap-browse.previous.button = Previous page +jsp.tools.itemmap-browse.next.button = Next page jsp.tools.itemmap-info.button.continue = Continue jsp.tools.itemmap-info.heading = Item Map Info jsp.tools.itemmap-info.msg.added = Add item {0} @@ -1655,9 +1655,9 @@ search.sort-by.title search.sort-by.dateissued = Issue Date search.sort-by.dateaccessioned = Submit Date # used by discovery (standard sort index _sort) -search.sort-by.dc.title_sort = Title +search.sort-by.dc.title_sort = Title # used by discovery (date sort index _dt) -search.sort-by.dc.date.issued_dt = Issue Date +search.sort-by.dc.date.issued_dt = Issue Date search.update = Update # authority-control confidence levels, descriptions: @@ -1701,17 +1701,17 @@ jsp.dspace-admin.eperson-main.ResetPassword-error.errormsg = Sorry, an error has jsp.dspace-admin.eperson-main.ResetPassword.returntoedit = Return to the Administer EPeople page # login as -jsp.dspace-admin.eperson-main.LoginAs.submit = Login As +jsp.dspace-admin.eperson-main.LoginAs.submit = Login As jsp.dspace-admin.eperson-main.loginAs.authorize.errormsg = Reason: you may not assume the login as another administrator. jsp.dspace-admin.eperson-main.loginAs.authorize.title = Authorization Error jsp.dspace-admin.eperson-main.loginAs.backtoeditpeople = Back to E-people Admin page org.dspace.app.webui.jsptag.access-setting.legend = Embargo -org.dspace.app.webui.jsptag.access-setting.label_name = Name\: -org.dspace.app.webui.jsptag.access-setting.label_group = Groups\: -org.dspace.app.webui.jsptag.access-setting.label_embargo = Access for selected group: -org.dspace.app.webui.jsptag.access-setting.label_reason = Reason\: -org.dspace.app.webui.jsptag.access-setting.label_date = Embargo Date\: +org.dspace.app.webui.jsptag.access-setting.label_name = Name\: +org.dspace.app.webui.jsptag.access-setting.label_group = Groups\: +org.dspace.app.webui.jsptag.access-setting.label_embargo = Access for selected group: +org.dspace.app.webui.jsptag.access-setting.label_reason = Reason\: +org.dspace.app.webui.jsptag.access-setting.label_date = Embargo Date\: org.dspace.app.webui.jsptag.access-setting.radio0 = Allow access once item is accepted into archive org.dspace.app.webui.jsptag.access-setting.radio1 = Embargo until specific date org.dspace.app.webui.jsptag.access-setting.radio_help = The first day from which access is allowed. Accepted format: yyyy, yyyy-mm, yyyy-mm-dd @@ -1721,14 +1721,14 @@ org.dspace.app.webui.jsptag.policies-list.label_action = Action org.dspace.app.webui.jsptag.policies-list.label_group = Group org.dspace.app.webui.jsptag.policies-list.label_sdate = Start Date org.dspace.app.webui.jsptag.policies-list.label_edate = End Date -org.dspace.app.webui.jsptag.policies-list.no_policies = No group policies have been set up for this item +org.dspace.app.webui.jsptag.policies-list.no_policies = No group policies have been set up for this item org.dspace.app.webui.jsptag.access-setting.name_help = A short, descriptive name for the policy (up to 30 characters). May be shown to end users. Example: "Staff-only". Optional but recommended. org.dspace.app.webui.jsptag.access-setting.reason_help = The reason for the embargo, typically for internal use only. Optional. -jsp.layout.navbar-admin.accesscontrol = Access Control -jsp.layout.navbar-admin.contents = Content -jsp.layout.navbar-admin.settings = General Settings +jsp.layout.navbar-admin.accesscontrol = Access Control +jsp.layout.navbar-admin.contents = Content +jsp.layout.navbar-admin.settings = General Settings jsp.submit.start-lookup-submission.title = New submission jsp.submit.start-lookup-submission.heading = New submission: get data from bibliographic external service @@ -1737,7 +1737,7 @@ jsp.submit.start-lookup-submission.tabs.result = Results jsp.submit.start-lookup-submission.identifiers = Search for identifier jsp.submit.start-lookup-submission.identifiers.hints = Fill in publication identifiers (DOI is preferable) and then press "Search". A list of all matching publications will be shown to you to select in order to proceed with the submission process. -jsp.submit.start-lookup-submission.identifier-doi = DOI (Digital Object Identifier) +jsp.submit.start-lookup-submission.identifier-doi = DOI (Digital Object Identifier) jsp.submit.start-lookup-submission.identifier-doi.hint = e.g. 10.1021/ac0354342 jsp.submit.start-lookup-submission.identifier-pubmed = PubMed ID jsp.submit.start-lookup-submission.identifier-pubmed.hint = e.g. 20524090 @@ -1750,13 +1750,13 @@ jsp.submit.start-lookup-submission.search = Free search jsp.submit.start-lookup-submission.search.hints = Insert base info about publication: either title or author/year is required.
    If you know any unique identifier about publication like DOI, Pubmed, or arXiv you can switch on the identifier search mode. jsp.submit.start-lookup-submission.search.title = Title jsp.submit.start-lookup-submission.search.year = Year -jsp.submit.start-lookup-submission.search.authors = Authors/Publishers +jsp.submit.start-lookup-submission.search.authors = Authors/Publishers jsp.submit.start-lookup-submission.identifier.lookup = Search jsp.submit.start-lookup-submission.search-go = Search jsp.submit.start-lookup-submission.exit = Exit jsp.submit.start-lookup-submission.search-loading.title = Loading... -jsp.submit.start-lookup-submission.search-loading.hint = Quering the external service to retrieve the requested publications. Please, wait for the request to complete. If you close this window, the request will be aborted. -jsp.submit.edit-metadata.affiliation.select = Multiple possible matches, please select one to proceed! +jsp.submit.start-lookup-submission.search-loading.hint = Quering the external service to retrieve the requested publications. Please, wait for the request to complete. If you close this window, the request will be aborted. +jsp.submit.edit-metadata.affiliation.select = Multiple possible matches, please select one to proceed! jsp.submit.edit-metadata.affiliation.other = Other jsp.submit.start-lookup-submission.no-collection = No collection selected jsp.submit.start-lookup-submission.no-collection-warn.title = Warning, no collection @@ -1823,7 +1823,7 @@ itemRequest.response.body.approve = Dear {0},\n\ In response to your request I have the pleasure to send you in attachment a copy of the file(s) concerning the document: "{2}" ({1}), of which I am author (or co-author).\n\n\ Best regards,\n\ {3} <{4}> - + itemRequest.response.subject.reject = Request copy of document itemRequest.response.body.reject = Dear {0},\n\ In response to your request I regret to inform you that it''s not possible to send you a copy of the file(s) you have requested, concerning the document: "{2}" ({1}), of which I am author (or co-author).\n\n\ @@ -1845,38 +1845,38 @@ itemRequest.response.body.contactRequester = Dear {0},\n\n\ Thanks for your interest! Since the author owns the copyright for this work, I will contact the author and ask permission to send you a copy. I''ll let you know as soon as I hear from the author.\n\n\ Thanks!\n\ {1} <{2}> -jsp.request.item.request-form.info2 = Request a document copy: {0} -jsp.request.item.request-form.problem = You must fill all the missing fields. -jsp.request.item.request-form.reqname = Requester name: -jsp.request.item.request-form.email = Requester e-mail: -jsp.request.item.request-form.coment = Message: +jsp.request.item.request-form.info2 = Request a document copy: {0} +jsp.request.item.request-form.problem = You must fill all the missing fields. +jsp.request.item.request-form.reqname = Requester name: +jsp.request.item.request-form.email = Requester e-mail: +jsp.request.item.request-form.coment = Message: jsp.request.item.request-form.go = Send jsp.request.item.request-form.cancel = Cancel -jsp.request.item.request-form.allfiles = Files: -jsp.request.item.request-form.yes = all files (of this document) in restricted access -jsp.request.item.request-form.no = the file(s) you requested -jsp.request.item.request-form.title = Request a document copy +jsp.request.item.request-form.allfiles = Files: +jsp.request.item.request-form.yes = all files (of this document) in restricted access +jsp.request.item.request-form.no = the file(s) you requested +jsp.request.item.request-form.title = Request a document copy jsp.request.item.request-information.info1 = Subject: Request a document copy jsp.request.item.request-information.info2 = IF YOU ARE AN AUTHOR OF THE DOCUMENT, {0}, use one of the buttons below to answer the request for a copy made by the user, {1}. jsp.request.item.request-information.note = This repository will propose an appropriate model reply, which you may edit. -jsp.request.item.request-information.yes = Send a copy -jsp.request.item.request-information.no = Don’t send a copy -jsp.request.item.request-information.title = Request a document copy +jsp.request.item.request-information.yes = Send a copy +jsp.request.item.request-information.no = Don’t send a copy +jsp.request.item.request-information.title = Request a document copy jsp.request.item.request-letter.accept.heading = Accept the request jsp.request.item.request-letter.accept.info = This is the email that will be sent to the requester along with the file(s). jsp.request.item.request-letter.reject.heading = Reject the request jsp.request.item.request-letter.reject.info = This is the email that will be sent to the requester. jsp.request.item.request-letter.subject = Subject: jsp.request.item.request-letter.message = Message: -jsp.request.item.request-letter.title = Copy of the requested document -jsp.request.item.request-letter.next = Send -jsp.request.item.request-letter.back = Back +jsp.request.item.request-letter.title = Copy of the requested document +jsp.request.item.request-letter.next = Send +jsp.request.item.request-letter.back = Back jsp.request.item.return-item = Return to the item -jsp.request.item.response-send.info1 = Your answer was sent successfully! -jsp.request.item.response-send.info2 = Your answer was sent successfully to the e-mail indicated by the requester.

    Thank you. +jsp.request.item.response-send.info1 = Your answer was sent successfully! +jsp.request.item.response-send.info2 = Your answer was sent successfully to the e-mail indicated by the requester.

    Thank you. jsp.request.item.response-send.title = Request a document copy -jsp.request.item.request-send.info1 = Your request was sent successfully! -jsp.request.item.request-send.info2 = Your request was sent successfully to the author(s).

    Thank you. +jsp.request.item.request-send.info1 = Your request was sent successfully! +jsp.request.item.request-send.info2 = Your request was sent successfully to the author(s).

    Thank you. jsp.request.item.request-send.title = Request a document copy jsp.request.item.request-free-acess.title = Your answer was sent successfully! jsp.request.item.request-free-acess.info1 = Your answer was sent successfully to the e-mail indicated by the requester. Thank you. diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2017.10.12__DS-3542-stateless-sessions.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2017.10.12__DS-3542-stateless-sessions.sql new file mode 100644 index 0000000000..30cfae91c8 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2017.10.12__DS-3542-stateless-sessions.sql @@ -0,0 +1,20 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +-- =============================================================== +-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +-- +-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED +-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE. +-- http://flywaydb.org/ +-- =============================================================== + +------------------------------------------------------------------------------------------------------------ +-- This adds an extra column to the eperson table where we save a salt for stateless authentication +------------------------------------------------------------------------------------------------------------ +ALTER TABLE eperson ADD session_salt varchar(32); \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2017.10.12__DS-3542-stateless-sessions.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2017.10.12__DS-3542-stateless-sessions.sql new file mode 100644 index 0000000000..30cfae91c8 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2017.10.12__DS-3542-stateless-sessions.sql @@ -0,0 +1,20 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +-- =============================================================== +-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +-- +-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED +-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE. +-- http://flywaydb.org/ +-- =============================================================== + +------------------------------------------------------------------------------------------------------------ +-- This adds an extra column to the eperson table where we save a salt for stateless authentication +------------------------------------------------------------------------------------------------------------ +ALTER TABLE eperson ADD session_salt varchar(32); \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2017.10.12__DS-3542-stateless-sessions.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2017.10.12__DS-3542-stateless-sessions.sql new file mode 100644 index 0000000000..30cfae91c8 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2017.10.12__DS-3542-stateless-sessions.sql @@ -0,0 +1,20 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +-- =============================================================== +-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +-- +-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED +-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE. +-- http://flywaydb.org/ +-- =============================================================== + +------------------------------------------------------------------------------------------------------------ +-- This adds an extra column to the eperson table where we save a salt for stateless authentication +------------------------------------------------------------------------------------------------------------ +ALTER TABLE eperson ADD session_salt varchar(32); \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/workflow/oracle/xmlworkflow/V6.0_2015.08.11__DS-2701_Xml_Workflow_Migration.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/workflow/oracle/xmlworkflow/V6.0_2015.08.11__DS-2701_Xml_Workflow_Migration.sql index 9193d3e2d2..7a992836ee 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/workflow/oracle/xmlworkflow/V6.0_2015.08.11__DS-2701_Xml_Workflow_Migration.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/workflow/oracle/xmlworkflow/V6.0_2015.08.11__DS-2701_Xml_Workflow_Migration.sql @@ -15,6 +15,8 @@ UPDATE collection SET workflow_step_3 = null; -- cwf_workflowitem +DROP INDEX cwf_workflowitem_coll_fk_idx; + ALTER TABLE cwf_workflowitem RENAME COLUMN item_id to item_legacy_id; ALTER TABLE cwf_workflowitem ADD item_id RAW(16) REFERENCES Item(uuid); UPDATE cwf_workflowitem SET item_id = (SELECT item.uuid FROM item WHERE cwf_workflowitem.item_legacy_id = item.item_id); @@ -29,7 +31,14 @@ UPDATE cwf_workflowitem SET multiple_titles = '0' WHERE multiple_titles IS NULL; UPDATE cwf_workflowitem SET published_before = '0' WHERE published_before IS NULL; UPDATE cwf_workflowitem SET multiple_files = '0' WHERE multiple_files IS NULL; +CREATE INDEX cwf_workflowitem_coll_fk_idx ON cwf_workflowitem(collection_id); + -- cwf_collectionrole + +ALTER TABLE cwf_collectionrole DROP CONSTRAINT cwf_collectionrole_unique; +DROP INDEX cwf_cr_coll_role_fk_idx; +DROP INDEX cwf_cr_coll_fk_idx; + ALTER TABLE cwf_collectionrole RENAME COLUMN collection_id to collection_legacy_id; ALTER TABLE cwf_collectionrole ADD collection_id RAW(16) REFERENCES Collection(uuid); UPDATE cwf_collectionrole SET collection_id = (SELECT collection.uuid FROM collection WHERE cwf_collectionrole.collection_legacy_id = collection.collection_id); @@ -40,8 +49,19 @@ ALTER TABLE cwf_collectionrole ADD group_id RAW(16) REFERENCES epersongroup(uuid UPDATE cwf_collectionrole SET group_id = (SELECT epersongroup.uuid FROM epersongroup WHERE cwf_collectionrole.group_legacy_id = epersongroup.eperson_group_id); ALTER TABLE cwf_collectionrole DROP COLUMN group_legacy_id; +ALTER TABLE cwf_collectionrole +ADD CONSTRAINT cwf_collectionrole_unique UNIQUE (role_id, collection_id, group_id); + +CREATE INDEX cwf_cr_coll_role_fk_idx ON cwf_collectionrole(collection_id,role_id); +CREATE INDEX cwf_cr_coll_fk_idx ON cwf_collectionrole(collection_id); + -- cwf_workflowitemrole + +ALTER TABLE cwf_workflowitemrole DROP CONSTRAINT cwf_workflowitemrole_unique; +DROP INDEX cwf_wfir_item_role_fk_idx; +DROP INDEX cwf_wfir_item_fk_idx; + ALTER TABLE cwf_workflowitemrole RENAME COLUMN group_id to group_legacy_id; ALTER TABLE cwf_workflowitemrole ADD group_id RAW(16) REFERENCES epersongroup(uuid); UPDATE cwf_workflowitemrole SET group_id = (SELECT epersongroup.uuid FROM epersongroup WHERE cwf_workflowitemrole.group_legacy_id = epersongroup.eperson_group_id); @@ -52,7 +72,18 @@ ALTER TABLE cwf_workflowitemrole ADD eperson_id RAW(16) REFERENCES eperson(uuid) UPDATE cwf_workflowitemrole SET eperson_id = (SELECT eperson.uuid FROM eperson WHERE cwf_workflowitemrole.eperson_legacy_id = eperson.eperson_id); ALTER TABLE cwf_workflowitemrole DROP COLUMN eperson_legacy_id; + +ALTER TABLE cwf_workflowitemrole +ADD CONSTRAINT cwf_workflowitemrole_unique UNIQUE (role_id, workflowitem_id, eperson_id, group_id); + +CREATE INDEX cwf_wfir_item_role_fk_idx ON cwf_workflowitemrole(workflowitem_id,role_id); +CREATE INDEX cwf_wfir_item_fk_idx ON cwf_workflowitemrole(workflowitem_id); + -- cwf_pooltask + +DROP INDEX cwf_pt_eperson_fk_idx; +DROP INDEX cwf_pt_workflow_eperson_fk_idx; + ALTER TABLE cwf_pooltask RENAME COLUMN group_id to group_legacy_id; ALTER TABLE cwf_pooltask ADD group_id RAW(16) REFERENCES epersongroup(uuid); UPDATE cwf_pooltask SET group_id = (SELECT epersongroup.uuid FROM epersongroup WHERE cwf_pooltask.group_legacy_id = epersongroup.eperson_group_id); @@ -63,17 +94,48 @@ ALTER TABLE cwf_pooltask ADD eperson_id RAW(16) REFERENCES eperson(uuid); UPDATE cwf_pooltask SET eperson_id = (SELECT eperson.uuid FROM eperson WHERE cwf_pooltask.eperson_legacy_id = eperson.eperson_id); ALTER TABLE cwf_pooltask DROP COLUMN eperson_legacy_id; +CREATE INDEX cwf_pt_eperson_fk_idx ON cwf_pooltask(eperson_id); +CREATE INDEX cwf_pt_workflow_eperson_fk_idx ON cwf_pooltask(eperson_id,workflowitem_id); + -- cwf_claimtask + +ALTER TABLE cwf_claimtask DROP CONSTRAINT cwf_claimtask_unique; +DROP INDEX cwf_ct_workflow_fk_idx; +DROP INDEX cwf_ct_workflow_eperson_fk_idx; +DROP INDEX cwf_ct_eperson_fk_idx; +DROP INDEX cwf_ct_wfs_fk_idx; +DROP INDEX cwf_ct_wfs_action_fk_idx; +DROP INDEX cwf_ct_wfs_action_e_fk_idx; + ALTER TABLE cwf_claimtask RENAME COLUMN owner_id to eperson_legacy_id; ALTER TABLE cwf_claimtask ADD owner_id RAW(16) REFERENCES eperson(uuid); UPDATE cwf_claimtask SET owner_id = (SELECT eperson.uuid FROM eperson WHERE cwf_claimtask.eperson_legacy_id = eperson.eperson_id); ALTER TABLE cwf_claimtask DROP COLUMN eperson_legacy_id; +ALTER TABLE cwf_claimtask +ADD CONSTRAINT cwf_claimtask_unique UNIQUE (step_id, workflowitem_id, workflow_id, owner_id, action_id); + +CREATE INDEX cwf_ct_workflow_fk_idx ON cwf_claimtask(workflowitem_id); +CREATE INDEX cwf_ct_workflow_eperson_fk_idx ON cwf_claimtask(workflowitem_id,owner_id); +CREATE INDEX cwf_ct_eperson_fk_idx ON cwf_claimtask(owner_id); +CREATE INDEX cwf_ct_wfs_fk_idx ON cwf_claimtask(workflowitem_id,step_id); +CREATE INDEX cwf_ct_wfs_action_fk_idx ON cwf_claimtask(workflowitem_id,step_id,action_id); +CREATE INDEX cwf_ct_wfs_action_e_fk_idx ON cwf_claimtask(workflowitem_id,step_id,action_id,owner_id); -- cwf_in_progress_user + +ALTER TABLE cwf_in_progress_user DROP CONSTRAINT cwf_in_progress_user_unique; +DROP INDEX cwf_ipu_workflow_fk_idx; +DROP INDEX cwf_ipu_eperson_fk_idx; + ALTER TABLE cwf_in_progress_user RENAME COLUMN user_id to eperson_legacy_id; ALTER TABLE cwf_in_progress_user ADD user_id RAW(16) REFERENCES eperson(uuid); UPDATE cwf_in_progress_user SET user_id = (SELECT eperson.uuid FROM eperson WHERE cwf_in_progress_user.eperson_legacy_id = eperson.eperson_id); ALTER TABLE cwf_in_progress_user DROP COLUMN eperson_legacy_id; UPDATE cwf_in_progress_user SET finished = '0' WHERE finished IS NULL; +ALTER TABLE cwf_in_progress_user +ADD CONSTRAINT cwf_in_progress_user_unique UNIQUE (workflowitem_id, user_id); + +CREATE INDEX cwf_ipu_workflow_fk_idx ON cwf_in_progress_user(workflowitem_id); +CREATE INDEX cwf_ipu_eperson_fk_idx ON cwf_in_progress_user(user_id); \ No newline at end of file diff --git a/dspace-api/src/main/resources/spring/spring-dspace-addon-import-services.xml b/dspace-api/src/main/resources/spring/spring-dspace-addon-import-services.xml index 997e658698..bbdf085619 100644 --- a/dspace-api/src/main/resources/spring/spring-dspace-addon-import-services.xml +++ b/dspace-api/src/main/resources/spring/spring-dspace-addon-import-services.xml @@ -17,7 +17,7 @@ http://www.springframework.org/schema/context/spring-context.xsd" default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> - + @@ -27,14 +27,15 @@ - + - + + default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> - + - - - + + + diff --git a/dspace-api/src/main/resources/spring/spring-dspace-addon-sherpa-configuration-services.xml b/dspace-api/src/main/resources/spring/spring-dspace-addon-sherpa-configuration-services.xml index 00bf02a2b9..c8197970a9 100644 --- a/dspace-api/src/main/resources/spring/spring-dspace-addon-sherpa-configuration-services.xml +++ b/dspace-api/src/main/resources/spring/spring-dspace-addon-sherpa-configuration-services.xml @@ -9,37 +9,37 @@ --> + default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> - + - - - - - - - dc.identifier.issn - - - - - - - + + + + + + + dc.identifier.issn + + + + + + + diff --git a/dspace-api/src/main/resources/spring/spring-dspace-addon-sherpa-services.xml b/dspace-api/src/main/resources/spring/spring-dspace-addon-sherpa-services.xml index a7af04c219..6fe8ddb07b 100644 --- a/dspace-api/src/main/resources/spring/spring-dspace-addon-sherpa-services.xml +++ b/dspace-api/src/main/resources/spring/spring-dspace-addon-sherpa-services.xml @@ -9,25 +9,26 @@ --> + default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> - + - - - - + + + + - - - - - + + + + + diff --git a/dspace-api/src/main/resources/spring/spring-dspace-core-services.xml b/dspace-api/src/main/resources/spring/spring-dspace-core-services.xml index 420fa295b8..dfdd1a2c8c 100644 --- a/dspace-api/src/main/resources/spring/spring-dspace-core-services.xml +++ b/dspace-api/src/main/resources/spring/spring-dspace-core-services.xml @@ -22,13 +22,17 @@ autowire="byType" scope="singleton"/> - + + + - diff --git a/dspace-api/src/test/data/dspaceFolder/config/controlled-vocabularies/farm.xml b/dspace-api/src/test/data/dspaceFolder/config/controlled-vocabularies/farm.xml index bfa9434f1c..c77d1c5ff2 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/controlled-vocabularies/farm.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/controlled-vocabularies/farm.xml @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml new file mode 100644 index 0000000000..de19ef7287 --- /dev/null +++ b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.dspace.app.rest.submit.step.CollectionStep + collection + submission + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.describe.steptwo + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.upload + org.dspace.app.rest.submit.step.UploadStep + upload + + + submit.progressbar.license + org.dspace.app.rest.submit.step.LicenseStep + license + submission + + + + + + + + + + + + + + + + + + + + + Sample + org.dspace.submit.step.SampleStep + sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace-api/src/test/data/dspaceFolder/config/local.cfg b/dspace-api/src/test/data/dspaceFolder/config/local.cfg index ca95ff081f..96ebb8b5e7 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/local.cfg +++ b/dspace-api/src/test/data/dspaceFolder/config/local.cfg @@ -105,8 +105,3 @@ plugin.sequence.java.util.Collection = \ java.util.LinkedList, \ java.util.Stack, \ java.util.TreeSet - -# Enable a test authority control on dc.language.iso field -choices.plugin.dc.language.iso = common_iso_languages -choices.presentation.dc.language.iso = select -authority.controlled.dc.language.iso = true \ No newline at end of file diff --git a/dspace-api/src/test/data/dspaceFolder/config/spring/api/identifier-service-test.xml b/dspace-api/src/test/data/dspaceFolder/config/spring/api/identifier-service-test.xml index 6f3e8be3c6..3efda0c73b 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/spring/api/identifier-service-test.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/spring/api/identifier-service-test.xml @@ -21,10 +21,10 @@ autowire="byType" scope="singleton"/> - + - - + + + class="org.dspace.identifier.DOIIdentifierProvider" + scope="singleton"> + ref="org.dspace.services.ConfigurationService"/> + ref="org.dspace.identifier.doi.DOIConnector"/> - + + + + + + + + + + + + + + diff --git a/dspace/config/input-forms.xml b/dspace-api/src/test/data/dspaceFolder/config/submission-forms.xml similarity index 90% rename from dspace/config/input-forms.xml rename to dspace-api/src/test/data/dspaceFolder/config/submission-forms.xml index 2d3124ba60..10e9578c88 100644 --- a/dspace/config/input-forms.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/submission-forms.xml @@ -1,23 +1,9 @@ - + - - - - - - - - - - - - - - @@ -35,9 +21,34 @@ - -
    - + + + + dc + title + + false + + onebox + Enter the name of the file. + You must enter a main title for this item. + + + + + dc + description + true + + textarea + Enter a description for the file + + + + + +
    + dc contributor @@ -48,7 +59,8 @@ Enter the names of the authors of this item. - + + dc title @@ -58,8 +70,10 @@ onebox Enter the main title of the item. You must enter a main title for this item. + - + + dc title @@ -70,13 +84,15 @@ If the item has any alternative titles, please enter them here. - + + dc date issued false + date Please give the date of previous publication or public distribution. You can leave out the day and/or month if they aren't @@ -90,11 +106,13 @@ false + onebox Enter the name of the publisher of the previously issued instance of this item. - + + dc identifier @@ -105,7 +123,8 @@ Enter the standard citation for the previously issued instance of this item. - + + dc relation @@ -116,7 +135,8 @@ Enter the series and number assigned to this item by your community. - + + dc identifier @@ -129,7 +149,8 @@ it, please enter the types and the actual numbers or codes. - + + dc type @@ -140,7 +161,8 @@ it, please enter the types and the actual numbers or codes. Select the type(s) of content of the item. To select more than one value in the list, you may have to hold down the "CTRL" or "Shift" key. - + + dc language @@ -151,9 +173,11 @@ it, please enter the types and the actual numbers or codes. Select the language of the main content of the item. If the language does not appear in the list, please select 'Other'. If the content does not really have a language (for example, if it is a dataset or an image) please select 'N/A'. - - - + +
    + +
    + dc subject @@ -166,7 +190,8 @@ it, please enter the types and the actual numbers or codes. srsc - + + dc description @@ -177,7 +202,8 @@ it, please enter the types and the actual numbers or codes. Enter the abstract of the item. - + + dc description @@ -188,7 +214,8 @@ it, please enter the types and the actual numbers or codes. Enter the names of any sponsors and/or funding codes in the box. - + + dc description @@ -199,23 +226,9 @@ it, please enter the types and the actual numbers or codes. Enter any other description or comments in this box. - +
    -
    - - - dc - contributor - author - true - - name - Enter the names of the authors of this item. - - - -
    diff --git a/dspace-api/src/test/java/org/dspace/AbstractDSpaceTest.java b/dspace-api/src/test/java/org/dspace/AbstractDSpaceTest.java index 12730b4e5a..f62db49e4c 100644 --- a/dspace-api/src/test/java/org/dspace/AbstractDSpaceTest.java +++ b/dspace-api/src/test/java/org/dspace/AbstractDSpaceTest.java @@ -7,23 +7,24 @@ */ package org.dspace; +import static org.junit.Assert.fail; + import java.io.IOException; import java.net.URL; import java.sql.SQLException; import java.util.Properties; import java.util.TimeZone; + +import mockit.integration.junit4.JMockit; import org.apache.log4j.Logger; import org.dspace.app.util.MockUtil; import org.dspace.servicemanager.DSpaceKernelImpl; import org.dspace.servicemanager.DSpaceKernelInit; import org.junit.AfterClass; -import static org.junit.Assert.fail; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.runner.RunWith; -import mockit.integration.junit4.JMockit; - /** * DSpace Unit Tests need to initialize the DSpace Kernel / Service Mgr * in order to have access to configurations, etc. This Abstract class only @@ -33,15 +34,22 @@ import mockit.integration.junit4.JMockit; *

    * Tests which also need an in-memory DB should extend AbstractUnitTest or AbstractIntegrationTest * + * @author Tim * @see AbstractUnitTest * @see AbstractIntegrationTest - * @author Tim */ @Ignore @RunWith(JMockit.class) -public class AbstractDSpaceTest -{ - /** log4j category */ +public class AbstractDSpaceTest { + + /** + * Default constructor + */ + protected AbstractDSpaceTest() { } + + /** + * log4j category + */ private static final Logger log = Logger.getLogger(AbstractDSpaceTest.class); /** @@ -63,32 +71,27 @@ public class AbstractDSpaceTest * and then starts the DSpace Kernel (which allows access to services). */ @BeforeClass - public static void initKernel() - { - try - { + public static void initKernel() { + try { //set a standard time zone for the tests TimeZone.setDefault(TimeZone.getTimeZone("Europe/Dublin")); //load the properties of the tests testProps = new Properties(); URL properties = AbstractUnitTest.class.getClassLoader() - .getResource("test-config.properties"); + .getResource("test-config.properties"); testProps.load(properties.openStream()); // Initialise the service manager kernel kernelImpl = DSpaceKernelInit.getKernel(null); - if (!kernelImpl.isRunning()) - { + if (!kernelImpl.isRunning()) { // NOTE: the "dspace.dir" system property MUST be specified via Maven - kernelImpl.start(System.getProperty("dspace.dir")); // init the kernel + kernelImpl.start(getDspaceDir()); // init the kernel } // Initialize mock Util class (allows Util.getSourceVersion() to work in Unit tests) new MockUtil(); - } - catch (IOException ex) - { + } catch (IOException ex) { log.error("Error initializing tests", ex); fail("Error initializing tests: " + ex.getMessage()); } @@ -111,4 +114,9 @@ public class AbstractDSpaceTest } kernelImpl = null; } + + public static String getDspaceDir() { + return System.getProperty("dspace.dir"); + + } } diff --git a/dspace-api/src/test/java/org/dspace/AbstractIntegrationTest.java b/dspace-api/src/test/java/org/dspace/AbstractIntegrationTest.java index fd7fb2375a..e6e8addb91 100644 --- a/dspace-api/src/test/java/org/dspace/AbstractIntegrationTest.java +++ b/dspace-api/src/test/java/org/dspace/AbstractIntegrationTest.java @@ -7,9 +7,7 @@ */ package org.dspace; -import org.databene.contiperf.junit.ContiPerfRule; import org.junit.Ignore; -import org.junit.Rule; /** * This is the base class for Integration Tests. It inherits from the class @@ -22,11 +20,6 @@ import org.junit.Rule; * @author pvillega */ @Ignore -public class AbstractIntegrationTest extends AbstractUnitTest -{ - - //We only enable contiperf in the integration tests, as it doesn't - //seem so useful to run them in isolated unit tests - @Rule - public ContiPerfRule contiperfRules = new ContiPerfRule(); +public class AbstractIntegrationTest extends AbstractUnitTest { + // This class intentionally left blank. } diff --git a/dspace-api/src/test/java/org/dspace/AbstractUnitTest.java b/dspace-api/src/test/java/org/dspace/AbstractUnitTest.java index f7877bf322..c008b76d17 100644 --- a/dspace-api/src/test/java/org/dspace/AbstractUnitTest.java +++ b/dspace-api/src/test/java/org/dspace/AbstractUnitTest.java @@ -7,6 +7,10 @@ */ package org.dspace; +import static org.junit.Assert.fail; + +import java.sql.SQLException; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.factory.AuthorizeServiceFactory; @@ -23,11 +27,6 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; -import java.sql.SQLException; - -import static org.junit.Assert.fail; - - /** * This is the base class for most Unit Tests. It contains some generic mocks and @@ -36,13 +35,14 @@ import static org.junit.Assert.fail; * NOTE: This base class also performs in-memory (H2) database initialization. * If your tests don't need that, you may wish to just use AbstractDSpaceTest. * - * @see AbstractDSpaceTest * @author pvillega + * @see AbstractDSpaceTest */ @Ignore -public class AbstractUnitTest extends AbstractDSpaceTest -{ - /** log4j category */ +public class AbstractUnitTest extends AbstractDSpaceTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(AbstractUnitTest.class); /** @@ -61,7 +61,7 @@ public class AbstractUnitTest extends AbstractDSpaceTest */ protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); - /** + /** * This method will be run before the first test as per @BeforeClass. It will * initialize shared resources required for all tests of this class. *

    @@ -72,23 +72,19 @@ public class AbstractUnitTest extends AbstractDSpaceTest * initializes the in-memory database for tests that need it. */ @BeforeClass - public static void initDatabase() - { + public static void initDatabase() { // Clear our old flyway object. Because this DB is in-memory, its // data is lost when the last connection is closed. So, we need // to (re)start Flyway from scratch for each Unit Test class. DatabaseUtils.clearFlywayDBCache(); - try - { + try { // Update/Initialize the database to latest version (via Flyway) DatabaseUtils.updateDatabase(); - } - catch(SQLException se) - { + } catch (SQLException se) { log.error("Error initializing database", se); fail("Error initializing database: " + se.getMessage() - + (se.getCause() == null ? "" : ": " + se.getCause().getMessage())); + + (se.getCause() == null ? "" : ": " + se.getCause().getMessage())); } // Initialize mock indexer (which does nothing, since Solr isn't running) @@ -104,8 +100,7 @@ public class AbstractUnitTest extends AbstractDSpaceTest */ @Before public void init() { - try - { + try { //Start a new context context = new Context(Context.Mode.BATCH_EDIT); context.turnOffAuthorisationSystem(); @@ -113,8 +108,7 @@ public class AbstractUnitTest extends AbstractDSpaceTest //Find our global test EPerson account. If it doesn't exist, create it. EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); eperson = ePersonService.findByEmail(context, "test@email.com"); - if(eperson == null) - { + if (eperson == null) { // This EPerson creation should only happen once (i.e. for first test run) log.info("Creating initial EPerson (email=test@email.com) for Unit Tests"); eperson = ePersonService.create(context); @@ -133,15 +127,11 @@ public class AbstractUnitTest extends AbstractDSpaceTest EPersonServiceFactory.getInstance().getGroupService().initDefaultGroupNames(context); context.restoreAuthSystemState(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Error creating initial eperson or default groups", ex); fail("Error creating initial eperson or default groups in AbstractUnitTest init()"); - } - catch (SQLException ex) - { - log.error(ex.getMessage(),ex); + } catch (SQLException ex) { + log.error(ex.getMessage(), ex); fail("SQL Error on AbstractUnitTest init()"); } } @@ -154,8 +144,7 @@ public class AbstractUnitTest extends AbstractDSpaceTest * but no execution order is guaranteed */ @After - public void destroy() - { + public void destroy() { // Cleanup our global context object try { cleanupContext(context); @@ -165,16 +154,18 @@ public class AbstractUnitTest extends AbstractDSpaceTest } /** - * Utility method to cleanup a created Context object (to save memory). - * This can also be used by individual tests to cleanup context objects they create. + * Utility method to cleanup a created Context object (to save memory). + * This can also be used by individual tests to cleanup context objects they create. */ protected void cleanupContext(Context c) throws SQLException { // If context still valid, abort it - if(c!=null && c.isValid()) - c.complete(); + if (c != null && c.isValid()) { + c.complete(); + } // Cleanup Context object by setting it to null - if(c!=null) - c = null; + if (c != null) { + c = null; + } } } diff --git a/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java b/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java index 44c6d82ad9..c4261f0b02 100644 --- a/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java +++ b/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java @@ -7,17 +7,20 @@ */ package org.dspace.app.bulkedit; -import java.io.*; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; -import org.dspace.AbstractUnitTest; - -import org.junit.*; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; - import org.apache.log4j.Logger; +import org.dspace.AbstractUnitTest; +import org.junit.Test; /** @@ -25,33 +28,37 @@ import org.apache.log4j.Logger; * * @author Stuart Lewis */ -public class DSpaceCSVTest extends AbstractUnitTest -{ - /** log4j category */ +public class DSpaceCSVTest extends AbstractUnitTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(DSpaceCSVTest.class); /** * Test the reading and parsing of CSV files */ @Test - public void testDSpaceCSV() - { - try - { + public void testDSpaceCSV() { + try { // Test the CSV parsing String[] csv = {"id,collection,\"dc.title[en]\",dc.contributor.author,dc.description.abstract", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Easy line,\"Lewis, Stuart\",A nice short abstract", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Two authors,\"Lewis, Stuart||Bloggs, Joe\",Two people wrote this item", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Three authors,\"Lewis, Stuart||Bloggs, Joe||Loaf, Meat\",Three people wrote this item", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"Two line\n\ntitle\",\"Lewis, Stuart\",abstract", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"Empty lines\n\nshould work too (DS-3245).\",\"Lewis, Stuart\",abstract", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"\"\"Embedded quotes\"\" here\",\"Lewis, Stuart\",\"Abstract with\ntwo\nnew lines\"", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"\"\"Unbalanced embedded\"\" quotes\"\" here\",\"Lewis, Stuart\",\"Abstract with\ntwo\nnew lines\"",}; + "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Easy line,\"Lewis, Stuart\",A nice short abstract", + "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Two authors,\"Lewis, Stuart||Bloggs, Joe\",Two people wrote " + + "this item", + "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Three authors,\"Lewis, Stuart||Bloggs, Joe||Loaf, Meat\"," + + "Three people wrote this item", + "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"Two line\n\ntitle\",\"Lewis, Stuart\",abstract", + "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"Empty lines\n\nshould work too (DS-3245).\",\"Lewis, " + + "Stuart\",abstract", + "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"\"\"Embedded quotes\"\" here\",\"Lewis, Stuart\",\"Abstract" + + " with\ntwo\nnew lines\"", + "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"\"\"Unbalanced embedded\"\" quotes\"\" here\",\"Lewis, " + + "Stuart\",\"Abstract with\ntwo\nnew lines\"",}; // Write the string to a file String filename = "test.csv"; BufferedWriter out = new BufferedWriter( - new OutputStreamWriter( - new FileOutputStream(filename), "UTF-8")); + new OutputStreamWriter( + new FileOutputStream(filename), "UTF-8")); for (String csvLine : csv) { out.write(csvLine + "\n"); } @@ -68,9 +75,9 @@ public class DSpaceCSVTest extends AbstractUnitTest List csvLines = dcsv.getCSVLines(); DSpaceCSVLine line = csvLines.get(5); List value = new ArrayList(); - value.add("Abstract with\ntwo\nnew lines"); + value.add("Abstract with\ntwo\nnew lines"); assertThat("testDSpaceCSV New lines", line.valueToCSV(value, dcsv.valueSeparator), - equalTo("\"Abstract with\ntwo\nnew lines\"")); + equalTo("\"Abstract with\ntwo\nnew lines\"")); line = null; // Test the CSV parsing with a bad heading element value @@ -78,8 +85,8 @@ public class DSpaceCSVTest extends AbstractUnitTest // Write the string to a file filename = "test.csv"; out = new BufferedWriter( - new OutputStreamWriter( - new FileOutputStream(filename), "UTF-8")); + new OutputStreamWriter( + new FileOutputStream(filename), "UTF-8")); for (String csvLine : csv) { out.write(csvLine + "\n"); } @@ -88,16 +95,14 @@ public class DSpaceCSVTest extends AbstractUnitTest out = null; // Test the CSV parsing was OK - try - { + try { dcsv = new DSpaceCSV(new File(filename), context); lines = dcsv.getCSVLinesAsStringArray(); fail("An exception should have been thrown due to bad CSV"); - } - catch (Exception e) - { - assertThat("testDSpaceCSV Bad heading CSV", e.getMessage(), equalTo("Unknown metadata element in column 4: dc.contributor.foobar")); + } catch (Exception e) { + assertThat("testDSpaceCSV Bad heading CSV", e.getMessage(), + equalTo("Unknown metadata element in column 4: dc.contributor.foobar")); } lines = dcsv.getCSVLinesAsStringArray(); assertThat("testDSpaceCSV Good CSV", lines.length, equalTo(8)); @@ -108,8 +113,8 @@ public class DSpaceCSVTest extends AbstractUnitTest // Write the string to a file filename = "test.csv"; out = new BufferedWriter( - new OutputStreamWriter( - new FileOutputStream(filename), "UTF-8")); + new OutputStreamWriter( + new FileOutputStream(filename), "UTF-8")); for (String csvLine : csv) { out.write(csvLine + "\n"); } @@ -118,28 +123,25 @@ public class DSpaceCSVTest extends AbstractUnitTest out = null; // Test the CSV parsing was OK - try - { + try { dcsv = new DSpaceCSV(new File(filename), context); lines = dcsv.getCSVLinesAsStringArray(); fail("An exception should have been thrown due to bad CSV"); - } - catch (Exception e) - { - assertThat("testDSpaceCSV Bad heading CSV", e.getMessage(), equalTo("Unknown metadata schema in column 3: dcdc.title")); + } catch (Exception e) { + assertThat("testDSpaceCSV Bad heading CSV", e.getMessage(), + equalTo("Unknown metadata schema in column 3: dcdc.title")); } // Delete the test file File toDelete = new File(filename); toDelete.delete(); toDelete = null; - + // Nullify resources so JUnit will clean them up dcsv = null; lines = null; - } - catch (Exception ex) { + } catch (Exception ex) { log.error("IO Error while creating test CSV file", ex); fail("IO Error while creating test CSV file"); } diff --git a/dspace-api/src/test/java/org/dspace/app/mediafilter/PoiWordFilterTest.java b/dspace-api/src/test/java/org/dspace/app/mediafilter/PoiWordFilterTest.java index f3b71c9abb..4d2353a29a 100644 --- a/dspace-api/src/test/java/org/dspace/app/mediafilter/PoiWordFilterTest.java +++ b/dspace-api/src/test/java/org/dspace/app/mediafilter/PoiWordFilterTest.java @@ -7,9 +7,12 @@ */ package org.dspace.app.mediafilter; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; + import org.dspace.content.Item; import org.junit.After; import org.junit.AfterClass; @@ -17,37 +20,30 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; - /** * Drive the POI-based MS Word filter. + * * @author mwood */ -public class PoiWordFilterTest -{ +public class PoiWordFilterTest { - public PoiWordFilterTest() - { + public PoiWordFilterTest() { } @BeforeClass - public static void setUpClass() - { + public static void setUpClass() { } @AfterClass - public static void tearDownClass() - { + public static void tearDownClass() { } @Before - public void setUp() - { + public void setUp() { } @After - public void tearDown() - { + public void tearDown() { } /** @@ -127,8 +123,7 @@ public class PoiWordFilterTest */ @Test public void testGetDestinationStreamDoc() - throws Exception - { + throws Exception { System.out.println("getDestinationStream"); Item currentItem = null; InputStream source; @@ -149,8 +144,7 @@ public class PoiWordFilterTest */ @Test public void testGetDestinationStreamDocx() - throws Exception - { + throws Exception { System.out.println("getDestinationStream"); Item currentItem = null; InputStream source; @@ -171,15 +165,15 @@ public class PoiWordFilterTest * @throws IOException */ private static String readAll(InputStream stream) - throws IOException - { - if (null == stream) return null; + throws IOException { + if (null == stream) { + return null; + } byte[] bytes = new byte[stream.available()]; - StringBuilder resultSb = new StringBuilder(bytes.length/2); // Guess: average 2 bytes per character + StringBuilder resultSb = new StringBuilder(bytes.length / 2); // Guess: average 2 bytes per character int howmany; - while((howmany = stream.read(bytes)) > 0) - { + while ((howmany = stream.read(bytes)) > 0) { resultSb.append(new String(bytes, 0, howmany, StandardCharsets.UTF_8)); } return resultSb.toString(); diff --git a/dspace-api/src/test/java/org/dspace/app/util/GoogleBitstreamComparatorTest.java b/dspace-api/src/test/java/org/dspace/app/util/GoogleBitstreamComparatorTest.java index 6fc066ae21..0fdf145ff2 100644 --- a/dspace-api/src/test/java/org/dspace/app/util/GoogleBitstreamComparatorTest.java +++ b/dspace-api/src/test/java/org/dspace/app/util/GoogleBitstreamComparatorTest.java @@ -7,6 +7,15 @@ */ package org.dspace.app.util; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + import org.dspace.AbstractUnitTest; import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; @@ -19,18 +28,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.when; - @RunWith(MockitoJUnitRunner.class) -public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ +public class GoogleBitstreamComparatorTest extends AbstractUnitTest { @Mock private Bundle bundle; @@ -59,6 +59,7 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ /** * Create a bundle with three bitstreams + * * @throws Exception */ @Before @@ -85,6 +86,7 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ /** * Create three pdf bitstreams and give them a different size, the largest one should come first + * * @throws Exception */ @Test @@ -92,9 +94,9 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ when(bitstreamFormat1.getMIMEType()).thenReturn("application/pdf"); when(bitstreamFormat2.getMIMEType()).thenReturn("application/pdf"); when(bitstreamFormat3.getMIMEType()).thenReturn("application/pdf"); - when(bitstream1.getSize()).thenReturn(new Long(100)); - when(bitstream2.getSize()).thenReturn(new Long(200)); - when(bitstream3.getSize()).thenReturn(new Long(300)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(100)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(300)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); @@ -105,6 +107,7 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ /** * Create three bitstreams with different mimetypes, order is defined in settings + * * @throws Exception */ @Test @@ -115,14 +118,17 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); - assertEquals("WORD should be first as its type has the highest priority", "bitstream2", toSort.get(0).getName()); - assertEquals("RTF should be second as its type priority is right after Word", "bitstream1", toSort.get(1).getName()); + assertEquals("WORD should be first as its type has the highest priority", "bitstream2", + toSort.get(0).getName()); + assertEquals("RTF should be second as its type priority is right after Word", "bitstream1", + toSort.get(1).getName()); assertEquals("PS should be last as it has the lowest type priority", "bitstream3", toSort.get(2).getName()); } /** * Test for two bitstreams with same mimetype, but different size. * Should be first ordered by mimetype and then by size (largest first) + * * @throws Exception */ @Test @@ -130,9 +136,9 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ when(bitstreamFormat1.getMIMEType()).thenReturn("text/richtext"); when(bitstreamFormat2.getMIMEType()).thenReturn("text/richtext"); when(bitstreamFormat3.getMIMEType()).thenReturn("application/postscript"); - when(bitstream1.getSize()).thenReturn(new Long(100)); - when(bitstream2.getSize()).thenReturn(new Long(200)); - when(bitstream3.getSize()).thenReturn(new Long(300)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(100)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(300)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); @@ -143,6 +149,7 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ /** * Test for same Mimetype and same Size, if this is the case, then ordering is just as it was before sorting + * * @throws Exception */ @Test @@ -150,19 +157,23 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ when(bitstreamFormat1.getMIMEType()).thenReturn("application/pdf"); when(bitstreamFormat2.getMIMEType()).thenReturn("application/pdf"); when(bitstreamFormat3.getMIMEType()).thenReturn("application/pdf"); - when(bitstream1.getSize()).thenReturn(new Long(200)); - when(bitstream2.getSize()).thenReturn(new Long(200)); - when(bitstream3.getSize()).thenReturn(new Long(200)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(200)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); - assertEquals("Bitstreams have same size and type, so order should remain unchanged", "bitstream1", toSort.get(0).getName()); - assertEquals("Bitstreams have same size and type, so order should remain unchanged", "bitstream2", toSort.get(1).getName()); - assertEquals("Bitstreams have same size and type, so order should remain unchanged", "bitstream3", toSort.get(2).getName()); + assertEquals("Bitstreams have same size and type, so order should remain unchanged", "bitstream1", + toSort.get(0).getName()); + assertEquals("Bitstreams have same size and type, so order should remain unchanged", "bitstream2", + toSort.get(1).getName()); + assertEquals("Bitstreams have same size and type, so order should remain unchanged", "bitstream3", + toSort.get(2).getName()); } /** * Test if sorting still works when there is an undefined Mimetype, undefined mimetypes have the lowest priority + * * @throws Exception */ @Test @@ -170,19 +181,21 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ when(bitstreamFormat1.getMIMEType()).thenReturn("unknown"); when(bitstreamFormat2.getMIMEType()).thenReturn("text/richtext"); when(bitstreamFormat3.getMIMEType()).thenReturn("text/richtext"); - when(bitstream1.getSize()).thenReturn(new Long(400)); - when(bitstream2.getSize()).thenReturn(new Long(200)); - when(bitstream3.getSize()).thenReturn(new Long(300)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(400)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(300)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); assertEquals("bitstream3", toSort.get(0).getName()); assertEquals("bitstream2", toSort.get(1).getName()); - assertEquals("Unknown mime-types should always have the lowest priority", "bitstream1",toSort.get(2).getName()); + assertEquals("Unknown mime-types should always have the lowest priority", "bitstream1", + toSort.get(2).getName()); } /** * Test with all unknown mimetypes, ordered by size if this is the case + * * @throws Exception */ @Test @@ -190,22 +203,25 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ when(bitstreamFormat1.getMIMEType()).thenReturn("unknown"); when(bitstreamFormat2.getMIMEType()).thenReturn("unknown"); when(bitstreamFormat3.getMIMEType()).thenReturn("unknown"); - when(bitstream1.getSize()).thenReturn(new Long(200)); - when(bitstream2.getSize()).thenReturn(new Long(300)); - when(bitstream3.getSize()).thenReturn(new Long(100)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(300)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(100)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); - assertEquals("bitstream2 should come first as it is the largest and all types are equal", "bitstream2", toSort.get(0).getName()); - assertEquals("bitstream1 should come second as it is the second largest and all types are equal", "bitstream1", toSort.get(1).getName()); - assertEquals("bitstream3 should come last as it is the smallest and all types are equal", "bitstream3", toSort.get(2).getName()); + assertEquals("bitstream2 should come first as it is the largest and all types are equal", "bitstream2", + toSort.get(0).getName()); + assertEquals("bitstream1 should come second as it is the second largest and all types are equal", "bitstream1", + toSort.get(1).getName()); + assertEquals("bitstream3 should come last as it is the smallest and all types are equal", "bitstream3", + toSort.get(2).getName()); } /** * Test to see if priority is configurable, order should change according to prioritized_types property */ @Test - public void testChangePriority() throws Exception{ + public void testChangePriority() throws Exception { settings.put("citation.prioritized_types", "Postscript, RTF, Microsoft Word, Adobe PDF"); when(bitstreamFormat1.getMIMEType()).thenReturn("text/richtext"); when(bitstreamFormat2.getMIMEType()).thenReturn("application/msword"); @@ -213,29 +229,36 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); - assertEquals("According to the updated type prioritization, PS should be first", "bitstream3", toSort.get(0).getName()); - assertEquals("According to the updated type prioritization, RTF should come second", "bitstream1", toSort.get(1).getName()); - assertEquals("According to the updated type prioritization, Word has to be last", "bitstream2", toSort.get(2).getName()); + assertEquals("According to the updated type prioritization, PS should be first", "bitstream3", + toSort.get(0).getName()); + assertEquals("According to the updated type prioritization, RTF should come second", "bitstream1", + toSort.get(1).getName()); + assertEquals("According to the updated type prioritization, Word has to be last", "bitstream2", + toSort.get(2).getName()); } /** * Test what happens when bitstreams have no mimetype, should be just ordered by size */ @Test - public void testNoMimeType() throws Exception{ - when(bitstream1.getSize()).thenReturn(new Long(200)); - when(bitstream2.getSize()).thenReturn(new Long(300)); - when(bitstream3.getSize()).thenReturn(new Long(100)); + public void testNoMimeType() throws Exception { + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(300)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(100)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); - assertEquals("bitstream2 should come first as it is the largest and there are no types", "bitstream2", toSort.get(0).getName()); - assertEquals("bitstream1 should come second as it is the second largest and there are no types", "bitstream1", toSort.get(1).getName()); - assertEquals("bitstream3 should come last as it is the smallest and there are no types", "bitstream3", toSort.get(2).getName()); + assertEquals("bitstream2 should come first as it is the largest and there are no types", "bitstream2", + toSort.get(0).getName()); + assertEquals("bitstream1 should come second as it is the second largest and there are no types", "bitstream1", + toSort.get(1).getName()); + assertEquals("bitstream3 should come last as it is the smallest and there are no types", "bitstream3", + toSort.get(2).getName()); } /** * Three bitstreams without a size, just the same ordering as given + * * @throws Exception */ @Test @@ -272,38 +295,42 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ when(bitstreamFormat1.getMIMEType()).thenReturn("text/richtext"); when(bitstreamFormat2.getMIMEType()).thenReturn("application/msword"); when(bitstreamFormat3.getMIMEType()).thenReturn("application/postscript"); - when(bitstream1.getSize()).thenReturn(new Long(100)); - when(bitstream2.getSize()).thenReturn(new Long(200)); - when(bitstream3.getSize()).thenReturn(new Long(300)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(100)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(300)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); assertEquals("PS should be first because it is the largest one and there is no type prioritization", - "bitstream3", toSort.get(0).getName()); + "bitstream3", toSort.get(0).getName()); assertEquals("RTF should come second because it is the second largest and there is no type prioritization", - "bitstream2", toSort.get(1).getName()); + "bitstream2", toSort.get(1).getName()); assertEquals("Word has to be last (third) as it is the smallest one and there is no type prioritization", - "bitstream1", toSort.get(2).getName()); + "bitstream1", toSort.get(2).getName()); } /** * Test to check for no crash when nothing is configured, just checks for size */ @Test - public void testNoConfig() throws Exception{ + public void testNoConfig() throws Exception { settings.remove("citation.prioritized_types"); when(bitstreamFormat1.getMIMEType()).thenReturn("text/richtext"); when(bitstreamFormat2.getMIMEType()).thenReturn("application/msword"); when(bitstreamFormat3.getMIMEType()).thenReturn("application/postscript"); - when(bitstream1.getSize()).thenReturn(new Long(100)); - when(bitstream2.getSize()).thenReturn(new Long(200)); - when(bitstream3.getSize()).thenReturn(new Long(300)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(100)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(300)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); - assertEquals("bitstream3 should come first as it is the largest and there is no type prioritization configured", "bitstream3", toSort.get(0).getName()); - assertEquals("bitstream2 should come second as it is the second largest and there is no type prioritization configured", "bitstream2", toSort.get(1).getName()); - assertEquals("bitstream1 should come last as it is the smallest and there is no type prioritization configured", "bitstream1", toSort.get(2).getName()); + assertEquals("bitstream3 should come first as it is the largest and there is no type prioritization configured", + "bitstream3", toSort.get(0).getName()); + assertEquals( + "bitstream2 should come second as it is the second largest and there is no type prioritization configured", + "bitstream2", toSort.get(1).getName()); + assertEquals("bitstream1 should come last as it is the smallest and there is no type prioritization configured", + "bitstream1", toSort.get(2).getName()); } /** @@ -315,9 +342,9 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ when(bitstreamFormat1.getMIMEType()).thenReturn("text/richtext"); when(bitstreamFormat2.getMIMEType()).thenReturn("application/msword"); when(bitstreamFormat3.getMIMEType()).thenReturn("application/postscript"); - when(bitstream1.getSize()).thenReturn(new Long(100)); - when(bitstream2.getSize()).thenReturn(new Long(200)); - when(bitstream3.getSize()).thenReturn(new Long(300)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(100)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(300)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); @@ -335,25 +362,27 @@ public class GoogleBitstreamComparatorTest extends AbstractUnitTest{ when(bitstreamFormat1.getMIMEType()).thenReturn("text/richtext"); when(bitstreamFormat2.getMIMEType()).thenReturn("application/msword"); when(bitstreamFormat3.getMIMEType()).thenReturn("audio/x-wav"); - when(bitstream1.getSize()).thenReturn(new Long(300)); - when(bitstream2.getSize()).thenReturn(new Long(200)); - when(bitstream3.getSize()).thenReturn(new Long(100)); + when(bitstream1.getSizeBytes()).thenReturn(Long.valueOf(300)); + when(bitstream2.getSizeBytes()).thenReturn(Long.valueOf(200)); + when(bitstream3.getSizeBytes()).thenReturn(Long.valueOf(100)); List toSort = bundle.getBitstreams(); Collections.sort(toSort, new GoogleBitstreamComparator(context, settings)); assertEquals("bitstream3 has the type with the highest priority (thus ignoring its size) and should come first", - "bitstream3", toSort.get(0).getName()); - assertEquals("bitstream2 has a type with a priority higher than bitstream1 (size is ignored) and should come second", - "bitstream2", toSort.get(1).getName()); - assertEquals("bitstream1 has a type with the lowest priority in this bundle eventhough it is the largest bitstream and should come last", - "bitstream1", toSort.get(2).getName()); + "bitstream3", toSort.get(0).getName()); + assertEquals( + "bitstream2 has a type with a priority higher than bitstream1 (size is ignored) and should come second", + "bitstream2", toSort.get(1).getName()); + assertEquals( + "bitstream1 has a type with the lowest priority in this bundle eventhough it is the largest bitstream and" + + " should come last", + "bitstream1", toSort.get(2).getName()); } - + @After - public void destroy() - { + public void destroy() { settings = null; super.destroy(); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/app/util/GoogleMetadataTest.java b/dspace-api/src/test/java/org/dspace/app/util/GoogleMetadataTest.java index c49336b1b1..a03b46ad57 100644 --- a/dspace-api/src/test/java/org/dspace/app/util/GoogleMetadataTest.java +++ b/dspace-api/src/test/java/org/dspace/app/util/GoogleMetadataTest.java @@ -7,11 +7,23 @@ */ package org.dspace.app.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.sql.SQLException; + import org.apache.commons.io.Charsets; import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.WorkspaceItem; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamService; @@ -20,16 +32,11 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.sql.SQLException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - public class GoogleMetadataTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(GoogleMetadataTest.class); /** @@ -54,14 +61,15 @@ public class GoogleMetadataTest extends AbstractUnitTest { */ @Before @Override - public void init(){ + public void init() { super.init(); - try - { + try { context.turnOffAuthorisationSystem(); community = ContentServiceFactory.getInstance().getCommunityService().create(null, context); - Collection collection = ContentServiceFactory.getInstance().getCollectionService().create(context, community); - WorkspaceItem wi = ContentServiceFactory.getInstance().getWorkspaceItemService().create(context, collection, true); + Collection collection = ContentServiceFactory.getInstance().getCollectionService() + .create(context, community); + WorkspaceItem wi = ContentServiceFactory.getInstance().getWorkspaceItemService() + .create(context, collection, true); Item item = wi.getItem(); ContentServiceFactory.getInstance().getInstallItemService().installItem(context, wi, null); context.restoreAuthSystemState(); @@ -70,14 +78,10 @@ public class GoogleMetadataTest extends AbstractUnitTest { bundleService = ContentServiceFactory.getInstance().getBundleService(); bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } catch (IOException e) { @@ -87,23 +91,27 @@ public class GoogleMetadataTest extends AbstractUnitTest { /** * Test to see the priorities work, the PDF should be returned + * * @throws Exception */ @Test public void testGetPDFURLDifferentMimeTypes() throws Exception { context.turnOffAuthorisationSystem(); Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL"); - Bitstream b = bitstreamService.create(context, new ByteArrayInputStream("Bitstream 1".getBytes(Charsets.UTF_8))); + Bitstream b = bitstreamService + .create(context, new ByteArrayInputStream("Bitstream 1".getBytes(Charsets.UTF_8))); b.setName(context, "Word"); b.setFormat(context, bitstreamFormatService.create(context)); b.getFormat(context).setMIMEType("application/msword"); bundleService.addBitstream(context, bundle, b); - Bitstream b2 = bitstreamService.create(context, new ByteArrayInputStream("Bitstream 2".getBytes(Charsets.UTF_8))); + Bitstream b2 = bitstreamService + .create(context, new ByteArrayInputStream("Bitstream 2".getBytes(Charsets.UTF_8))); b2.setName(context, "Pdf"); b2.setFormat(context, bitstreamFormatService.create(context)); b2.getFormat(context).setMIMEType("application/pdf"); bundleService.addBitstream(context, bundle, b2); - Bitstream b3 = bitstreamService.create(context, new ByteArrayInputStream("Bitstream 3".getBytes(Charsets.UTF_8))); + Bitstream b3 = bitstreamService + .create(context, new ByteArrayInputStream("Bitstream 3".getBytes(Charsets.UTF_8))); b3.setName(context, "Rtf"); b3.setFormat(context, bitstreamFormatService.create(context)); b3.getFormat(context).setMIMEType("text/richtext"); @@ -117,12 +125,14 @@ public class GoogleMetadataTest extends AbstractUnitTest { /** * When multiple bitstreams with the sametype are found, it returns the largest one + * * @throws Exception */ @Test public void testGetPDFURLSameMimeTypes() throws Exception { context.turnOffAuthorisationSystem(); - Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL");; + Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL"); + ; Bitstream b = bitstreamService.create(context, new ByteArrayInputStream("123456789".getBytes(Charsets.UTF_8))); b.setName(context, "size9"); b.setFormat(context, bitstreamFormatService.create(context)); @@ -147,12 +157,14 @@ public class GoogleMetadataTest extends AbstractUnitTest { /** * Multiple bitstreams with same mimetype and size, just returns the first one + * * @throws Exception */ @Test public void testGetPDFURLSameMimeTypesSameSize() throws Exception { context.turnOffAuthorisationSystem(); - Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL");; + Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL"); + ; Bitstream b = bitstreamService.create(context, new ByteArrayInputStream("1".getBytes(Charsets.UTF_8))); b.setName(context, "first"); b.setFormat(context, bitstreamFormatService.create(context)); @@ -177,18 +189,22 @@ public class GoogleMetadataTest extends AbstractUnitTest { /** * Test to see if that when an item is marked as primary, that it will still be the result of getPdfURL() + * * @throws Exception */ @Test public void testGetPDFURLWithPrimaryBitstream() throws Exception { context.turnOffAuthorisationSystem(); - Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL");; - Bitstream b = bitstreamService.create(context, new ByteArrayInputStream("Larger file than primary".getBytes(Charsets.UTF_8))); + Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL"); + ; + Bitstream b = bitstreamService + .create(context, new ByteArrayInputStream("Larger file than primary".getBytes(Charsets.UTF_8))); b.setName(context, "first"); b.setFormat(context, bitstreamFormatService.create(context)); b.getFormat(context).setMIMEType("unknown"); bundleService.addBitstream(context, bundle, b); - Bitstream b2 = bitstreamService.create(context, new ByteArrayInputStream("Bitstream with more prioritized mimetype than primary".getBytes(Charsets.UTF_8))); + Bitstream b2 = bitstreamService.create(context, new ByteArrayInputStream( + "Bitstream with more prioritized mimetype than primary".getBytes(Charsets.UTF_8))); b2.setName(context, "second"); b2.setFormat(context, bitstreamFormatService.create(context)); b2.getFormat(context).setMIMEType("application/pdf"); @@ -209,12 +225,14 @@ public class GoogleMetadataTest extends AbstractUnitTest { /** * Test to make sure mimetypes can be undefined in the property file, just give them lowest priority if * this is the case and return the largest. + * * @throws Exception */ @Test public void testGetPDFURLWithUndefinedMimeTypes() throws Exception { context.turnOffAuthorisationSystem(); - Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL");; + Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL"); + ; Bitstream b = bitstreamService.create(context, new ByteArrayInputStream("12".getBytes(Charsets.UTF_8))); b.setName(context, "small"); b.setFormat(context, bitstreamFormatService.create(context)); @@ -225,7 +243,8 @@ public class GoogleMetadataTest extends AbstractUnitTest { b2.setFormat(context, bitstreamFormatService.create(context)); b2.getFormat(context).setMIMEType("unknown type 2"); bundleService.addBitstream(context, bundle, b2); - Bitstream b3 = bitstreamService.create(context, new ByteArrayInputStream("12121212121212".getBytes(Charsets.UTF_8))); + Bitstream b3 = bitstreamService + .create(context, new ByteArrayInputStream("12121212121212".getBytes(Charsets.UTF_8))); b3.setName(context, "large"); b3.setFormat(context, bitstreamFormatService.create(context)); b3.getFormat(context).setMIMEType("unknown type 3"); @@ -240,6 +259,7 @@ public class GoogleMetadataTest extends AbstractUnitTest { /** * Test for crash when no bundle is given + * * @throws Exception */ @Test @@ -250,12 +270,14 @@ public class GoogleMetadataTest extends AbstractUnitTest { /** * Test for crash when no bitstreams are in the bundle + * * @throws Exception */ @Test public void testGetPDFURLWithNoBitstreams() throws Exception { context.turnOffAuthorisationSystem(); - Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL");; + Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL"); + ; context.restoreAuthSystemState(); context.commit(); GoogleMetadata gm = new GoogleMetadata(this.context, it); @@ -266,11 +288,12 @@ public class GoogleMetadataTest extends AbstractUnitTest { * Test empty bitstreams */ @Test - public void testGetPDFURLWithEmptyBitstreams() throws Exception{ + public void testGetPDFURLWithEmptyBitstreams() throws Exception { context.turnOffAuthorisationSystem(); - Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL");; + Bundle bundle = ContentServiceFactory.getInstance().getBundleService().create(context, it, "ORIGINAL"); + ; Bitstream b = bitstreamService.create(context, new ByteArrayInputStream("".getBytes(Charsets.UTF_8))); - b.setName(context,"small"); + b.setName(context, "small"); b.setFormat(context, bitstreamFormatService.create(context)); b.getFormat(context).setMIMEType("unknown type 1"); bundleService.addBitstream(context, bundle, b); @@ -293,12 +316,12 @@ public class GoogleMetadataTest extends AbstractUnitTest { @After @Override - public void destroy() - { + public void destroy() { try { context.turnOffAuthorisationSystem(); - //Context might have been committed in the test method, so best to reload to entity so we're sure that it is attached. + //Context might have been committed in the test method, so best to reload to entity so we're sure that it + // is attached. community = context.reloadEntity(community); ContentServiceFactory.getInstance().getCommunityService().delete(context, community); community = null; @@ -314,4 +337,4 @@ public class GoogleMetadataTest extends AbstractUnitTest { } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/app/util/IndexVersionTest.java b/dspace-api/src/test/java/org/dspace/app/util/IndexVersionTest.java index f93676fa0a..332ce49aae 100644 --- a/dspace-api/src/test/java/org/dspace/app/util/IndexVersionTest.java +++ b/dspace-api/src/test/java/org/dspace/app/util/IndexVersionTest.java @@ -7,30 +7,31 @@ */ package org.dspace.app.util; +import static org.junit.Assert.assertEquals; + import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; /** * @author Tim */ public class IndexVersionTest { - + @BeforeClass public static void setUpClass() { } - + @AfterClass public static void tearDownClass() { } - + @Before public void setUp() { } - + @After public void tearDown() { } @@ -40,10 +41,10 @@ public class IndexVersionTest { */ @Test public void testCompareSoftwareVersions() throws Exception { - + // Test various version comparisons. Remember, in software versions: // 4.1 < 4.4 < 4.5 < 4.10 < 4.21 < 4.51 - + // less than tests (return -1) assertEquals(IndexVersion.compareSoftwareVersions("5", "6"), -1); assertEquals(IndexVersion.compareSoftwareVersions("4.1", "6"), -1); @@ -51,13 +52,13 @@ public class IndexVersionTest { assertEquals(IndexVersion.compareSoftwareVersions("4.1", "4.10"), -1); assertEquals(IndexVersion.compareSoftwareVersions("4.4", "4.10"), -1); assertEquals(IndexVersion.compareSoftwareVersions("4.4", "5.1"), -1); - + // greater than tests (return 1) assertEquals(IndexVersion.compareSoftwareVersions("6", "5"), 1); assertEquals(IndexVersion.compareSoftwareVersions("6.10", "6.4"), 1); assertEquals(IndexVersion.compareSoftwareVersions("6.10", "6.1"), 1); assertEquals(IndexVersion.compareSoftwareVersions("5.3", "2.4"), 1); - + // equality tests (return 0) assertEquals(IndexVersion.compareSoftwareVersions("5", "5.0"), 0); assertEquals(IndexVersion.compareSoftwareVersions("6", "6"), 0); @@ -65,5 +66,5 @@ public class IndexVersionTest { // we ignore subminor versions, so these should be "equal" assertEquals(IndexVersion.compareSoftwareVersions("4.2.1", "4.2"), 0); } - + } diff --git a/dspace-api/src/test/java/org/dspace/app/util/MockUtil.java b/dspace-api/src/test/java/org/dspace/app/util/MockUtil.java index ad3b2b7dcb..6043f1b848 100644 --- a/dspace-api/src/test/java/org/dspace/app/util/MockUtil.java +++ b/dspace-api/src/test/java/org/dspace/app/util/MockUtil.java @@ -13,11 +13,10 @@ import mockit.MockUp; /** * Mocks the "Util" class, as the getSourceVersion() method in this class * is not usable in Unit Testing (since the final JAR is not yet created) + * * @author Tim Donohue - * */ -public class MockUtil extends MockUp -{ +public class MockUtil extends MockUp { /** * Override/Mock the default "getSourceVersion()" method. This method * relies on the "pom.properties" file which is generated by Maven ONLY @@ -29,8 +28,7 @@ public class MockUtil extends MockUp * @return "unit-testing" since this is only used during Unit Tests */ @Mock - public static String getSourceVersion() - { + public static String getSourceVersion() { return "unit-testing"; } } diff --git a/dspace-api/src/test/java/org/dspace/authenticate/IPMatcherTest.java b/dspace-api/src/test/java/org/dspace/authenticate/IPMatcherTest.java index 021182e79d..3f5a08a648 100644 --- a/dspace-api/src/test/java/org/dspace/authenticate/IPMatcherTest.java +++ b/dspace-api/src/test/java/org/dspace/authenticate/IPMatcherTest.java @@ -6,26 +6,25 @@ * http://www.dspace.org/license/ */ /** - * + * */ package org.dspace.authenticate; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; + import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import java.util.ArrayList; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - /** * @author Mark Wood * @author Ben Bosman * @author Roeland Dillen */ -public class IPMatcherTest -{ +public class IPMatcherTest { private static final String IP6_FULL_ADDRESS1 = "2001:18e8:3:171:218:8bff:fe2a:56a4"; private static final String IP6_FULL_ADDRESS2 = "2001:18e8:3:171:218:8bff:fe2a:56a3"; private static final String IP6_MASKED_ADDRESS = "2001:18e8:3::/48"; @@ -37,13 +36,12 @@ public class IPMatcherTest /** * This also tests instantiation of correct masked and unmasked IPv6 addresses. - * @throws IPMatcherException - * if there is an error parsing the specification (i.e. it is - * somehow malformed) + * + * @throws IPMatcherException if there is an error parsing the specification (i.e. it is + * somehow malformed) */ @BeforeClass - static public void setUp() throws IPMatcherException - { + static public void setUp() throws IPMatcherException { ip6FullMatcher = new IPMatcher(IP6_FULL_ADDRESS1); ip6MaskedMatcher = new IPMatcher(IP6_MASKED_ADDRESS); } @@ -51,40 +49,36 @@ public class IPMatcherTest /** * Test method for {@link org.dspace.authenticate.IPMatcher#IPMatcher(java.lang.String)}. */ - @Test(expected=IPMatcherException.class) + @Test(expected = IPMatcherException.class) public void testIPMatcherIp6Incomplete() - throws IPMatcherException - { + throws IPMatcherException { new IPMatcher("1234:5"); // Incomplete IPv6 address } /** * Test method for {@link org.dspace.authenticate.IPMatcher#IPMatcher(java.lang.String)}. */ - @Test(expected=IPMatcherException.class) + @Test(expected = IPMatcherException.class) public void testIPMatcherIp6MaskOutOfRange() - throws IPMatcherException - { + throws IPMatcherException { new IPMatcher("123::456/999"); // Mask bits out of range } /** * Test method for {@link org.dspace.authenticate.IPMatcher#IPMatcher(java.lang.String)}. */ - @Test(expected=IPMatcherException.class) + @Test(expected = IPMatcherException.class) public void testIPMatcherIp6MaskNotNumeric() - throws IPMatcherException - { + throws IPMatcherException { new IPMatcher("123::456/abc"); // Mask is not a number } /** * Test method for {@link org.dspace.authenticate.IPMatcher#IPMatcher(java.lang.String)}. */ - @Test(expected=IPMatcherException.class) + @Test(expected = IPMatcherException.class) public void testIPMatcherIp6TooManySlashes() - throws IPMatcherException - { + throws IPMatcherException { new IPMatcher("123::456/12/12"); // Too many slashes } @@ -94,10 +88,9 @@ public class IPMatcherTest */ @Test public void testIp6FullMatch() - throws IPMatcherException - { + throws IPMatcherException { assertTrue("IPv6 full match fails", ip6FullMatcher - .match(IP6_FULL_ADDRESS1)); + .match(IP6_FULL_ADDRESS1)); } /** @@ -106,10 +99,9 @@ public class IPMatcherTest */ @Test public void testIp6MisMatch() - throws IPMatcherException - { + throws IPMatcherException { assertFalse("IPv6 full nonmatch succeeds", ip6FullMatcher - .match(IP6_FULL_ADDRESS2)); + .match(IP6_FULL_ADDRESS2)); } /** @@ -118,15 +110,13 @@ public class IPMatcherTest */ @Test public void testIp6MaskedMatch() - throws IPMatcherException - { + throws IPMatcherException { assertTrue("IPv6 masked match fails", ip6MaskedMatcher - .match(IP6_FULL_ADDRESS2)); + .match(IP6_FULL_ADDRESS2)); } @Test - public void testIPv4MatchingSuccess() throws Exception - { + public void testIPv4MatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("1.1.1.1"); assertTrue(ipMatcher.match("1.1.1.1")); @@ -136,74 +126,64 @@ public class IPMatcherTest } @Test - public void testIPv4MatchingFailure() throws Exception - { + public void testIPv4MatchingFailure() throws Exception { final IPMatcher ipMatcher = new IPMatcher("1.1.1.1"); assertFalse(ipMatcher.match("1.1.1.0")); } @Test - public void testIPv6MatchingSuccess() throws Exception - { + public void testIPv6MatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("::2"); assertTrue(ipMatcher.match("0:0:0:0:0:0:0:2")); } @Test - public void testShortFormIPv6MatchingSuccess() throws Exception - { + public void testShortFormIPv6MatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("::2"); assertTrue(ipMatcher.match("::2")); } @Test - public void testIPv6MatchingFailure() throws Exception - { + public void testIPv6MatchingFailure() throws Exception { final IPMatcher ipMatcher = new IPMatcher("::2"); assertFalse(ipMatcher.match("0:0:0:0:0:0:0:1")); } - @Test - public void testAsteriskMatchingSuccess() throws Exception - { + public void testAsteriskMatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("172.16"); assertTrue(ipMatcher.match("172.16.1.1")); } @Test - public void testAsteriskMatchingFailure() throws Exception - { + public void testAsteriskMatchingFailure() throws Exception { final IPMatcher ipMatcher = new IPMatcher("172.16"); assertFalse(ipMatcher.match("172.15.255.255")); } @Test - public void testIPv4CIDRMatchingSuccess() throws Exception - { + public void testIPv4CIDRMatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("192.1.2.3/8"); assertTrue(ipMatcher.match("192.1.1.1")); } @Test - public void testIPv4CIDRMatchingFailure() throws Exception - { + public void testIPv4CIDRMatchingFailure() throws Exception { final IPMatcher ipMatcher = new IPMatcher("192.1.2.3/8"); assertTrue(ipMatcher.match("192.2.0.0")); } @Test - public void test2IPv4CIDRMatchingSuccess() throws Exception - { + public void test2IPv4CIDRMatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("192.86.100.72/29"); assertTrue(ipMatcher.match("192.86.100.75")); @@ -222,8 +202,7 @@ public class IPMatcherTest } @Test - public void test3IPv4CIDRMatchingSuccess() throws Exception - { + public void test3IPv4CIDRMatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("192.86.100.72/255.255.255.248"); assertTrue(ipMatcher.match("192.86.100.75")); @@ -242,81 +221,82 @@ public class IPMatcherTest } @Test - public void testIPv6CIDRMatchingSuccess() throws Exception - { + public void testIPv6CIDRMatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("0:0:0:1::/64"); assertTrue(ipMatcher.match("0:0:0:1:ffff:ffff:ffff:ffff")); } @Test - public void testIPv6CIDRMatchingFailure() throws Exception - { + public void testIPv6CIDRMatchingFailure() throws Exception { final IPMatcher ipMatcher = new IPMatcher("0:0:0:1::/64"); assertFalse(ipMatcher.match("0:0:0:2::")); } - @Test - public void testIPv4IPv6Matching() throws Exception - { + public void testIPv4IPv6Matching() throws Exception { final IPMatcher ipMatcher = new IPMatcher("0.0.0.1"); assertTrue(ipMatcher.match("::1")); } - @Test - public void testSubnetZeroIPv6CIDRMatching() throws Exception - { + public void testSubnetZeroIPv6CIDRMatching() throws Exception { final IPMatcher ipMatcher = new IPMatcher("::1/0"); assertTrue(ipMatcher.match("::2")); } @Test - public void testAllOnesSubnetIPv4CIDRMatchingSuccess() throws Exception - { + public void testAllOnesSubnetIPv4CIDRMatchingSuccess() throws Exception { final IPMatcher ipMatcher = new IPMatcher("192.1.2.3/32"); assertTrue(ipMatcher.match("192.1.2.3")); } @Test - public void testAllOnesSubnetIPv4CIDRMatchingFailure() throws Exception - { + public void testAllOnesSubnetIPv4CIDRMatchingFailure() throws Exception { final IPMatcher ipMatcher = new IPMatcher("192.1.2.3/32"); assertFalse(ipMatcher.match("192.1.2.2")); } - private ArrayList getAllIp4Except(ArrayList exceptions) { - int d1 = 0, d2 = 0, d3 = 0, d4 = 0; + int d1 = 0; + int d2 = 0; + int d3 = 0; + int d4 = 0; ArrayList ips = new ArrayList(); - for (d1 = 0; d1 <= 255; d1+=increment) - for (d2 = 0; d2 <= 255; d2+=increment) - for (d3 = 0; d3 <= 255; d3+=increment) - for (d4 = 0; d4 <= 255; d4+=increment) { - String IP = d1+"."+d2+"."+d3+"."+d4; + for (d1 = 0; d1 <= 255; d1 += increment) { + for (d2 = 0; d2 <= 255; d2 += increment) { + for (d3 = 0; d3 <= 255; d3 += increment) { + for (d4 = 0; d4 <= 255; d4 += increment) { + String IP = d1 + "." + d2 + "." + d3 + "." + d4; if (exceptions == null || !exceptions.contains(IP)) { ips.add(IP); } } + } + } + } return ips; } - private void verifyAllIp4Except(ArrayList exceptions, boolean asserted, IPMatcher ipMatcher) throws IPMatcherException { - int d1 = 0, d2 = 0, d3 = 0, d4 = 0; - for (d1 = 0; d1 <= 255; d1+=increment) - for (d2 = 0; d2 <= 255; d2+=increment) - for (d3 = 0; d3 <= 255; d3+=increment) - for (d4 = 0; d4 <= 255; d4+=increment) { - String IP = d1+"."+d2+"."+d3+"."+d4; + private void verifyAllIp4Except(ArrayList exceptions, boolean asserted, IPMatcher ipMatcher) + throws IPMatcherException { + int d1 = 0; + int d2 = 0; + int d3 = 0; + int d4 = 0; + for (d1 = 0; d1 <= 255; d1 += increment) { + for (d2 = 0; d2 <= 255; d2 += increment) { + for (d3 = 0; d3 <= 255; d3 += increment) { + for (d4 = 0; d4 <= 255; d4 += increment) { + String IP = d1 + "." + d2 + "." + d3 + "." + d4; if (exceptions != null && exceptions.contains(IP)) { if (asserted) { assertFalse(ipMatcher.match(IP)); @@ -332,15 +312,14 @@ public class IPMatcherTest } } + } + } + } } - - - @AfterClass - static public void cleanup() - { + static public void cleanup() { ip6FullMatcher = null; ip6MaskedMatcher = null; } diff --git a/dspace-api/src/test/java/org/dspace/authorize/AuthorizeServiceTest.java b/dspace-api/src/test/java/org/dspace/authorize/AuthorizeServiceTest.java index 527207b1a5..7cd5873e06 100644 --- a/dspace-api/src/test/java/org/dspace/authorize/AuthorizeServiceTest.java +++ b/dspace-api/src/test/java/org/dspace/authorize/AuthorizeServiceTest.java @@ -8,6 +8,8 @@ package org.dspace.authorize; +import java.sql.SQLException; + import org.dspace.AbstractUnitTest; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.ResourcePolicyService; @@ -23,33 +25,29 @@ import org.dspace.eperson.service.GroupService; import org.junit.Assert; import org.junit.Test; -import java.sql.SQLException; - /** * Created by pbecker as he wanted to write a test against DS-3572. * This definitely needs to be extended, but it's at least a start. */ -public class AuthorizeServiceTest extends AbstractUnitTest -{ +public class AuthorizeServiceTest extends AbstractUnitTest { protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); + protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance() + .getResourcePolicyService(); protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); - public AuthorizeServiceTest() - {} + public AuthorizeServiceTest() { + } @Test - public void testauthorizeMethodDoesNotConfuseEPersonWithCurrentUser() - { + public void testauthorizeMethodDoesNotConfuseEPersonWithCurrentUser() { Community dso; EPerson eperson1; EPerson eperson2; Group group; - try - { + try { context.turnOffAuthorisationSystem(); // create two epersons: one to test a permission the other one to be used as currentUser @@ -73,13 +71,9 @@ public class AuthorizeServiceTest extends AbstractUnitTest // set the other eperson as the current user // Notice that it is not a member of the group, and does not have write permission context.setCurrentUser(eperson2); - } - catch (SQLException | AuthorizeException ex) - { + } catch (SQLException | AuthorizeException ex) { throw new RuntimeException(ex); - } - finally - { + } finally { context.restoreAuthSystemState(); } @@ -88,24 +82,20 @@ public class AuthorizeServiceTest extends AbstractUnitTest Assert.assertTrue(authorizeService.authorizeActionBoolean(context, eperson1, dso, Constants.WRITE, true)); // person2 shouldn't have write access Assert.assertFalse(authorizeService.authorizeActionBoolean(context, eperson2, dso, Constants.WRITE, true)); - } - catch (SQLException ex) - { + } catch (SQLException ex) { throw new RuntimeException(ex); } } @Test - public void testauthorizeMethodRespectSpecialGroups() - { + public void testauthorizeMethodRespectSpecialGroups() { EPerson eperson1; EPerson eperson2; Group group1; Community dso; - try - { + try { context.turnOffAuthorisationSystem(); // create an eperson and a group @@ -124,21 +114,15 @@ public class AuthorizeServiceTest extends AbstractUnitTest context.setCurrentUser(eperson1); context.setSpecialGroup(group1.getID()); context.commit(); - } - catch (SQLException | AuthorizeException ex) - { + } catch (SQLException | AuthorizeException ex) { throw new RuntimeException(ex); - } - finally - { + } finally { context.restoreAuthSystemState(); } try { Assert.assertTrue(authorizeService.authorizeActionBoolean(context, eperson1, dso, Constants.ADD, true)); - } - catch (SQLException ex) - { + } catch (SQLException ex) { throw new RuntimeException(ex); } } diff --git a/dspace-api/src/test/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImplTest.java b/dspace-api/src/test/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImplTest.java index 10b824239a..2e33d96d73 100644 --- a/dspace-api/src/test/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImplTest.java +++ b/dspace-api/src/test/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImplTest.java @@ -7,12 +7,16 @@ */ package org.dspace.checker.dao.impl; +import static org.junit.Assert.assertEquals; + import java.io.ByteArrayInputStream; import java.io.InputStream; import java.sql.SQLException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import javax.persistence.Query; + import org.dspace.AbstractUnitTest; import org.dspace.checker.ChecksumResultCode; import org.dspace.content.Bitstream; @@ -20,46 +24,36 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.core.CoreHelpers; import org.dspace.core.HibernateDBConnection; -import org.hibernate.Query; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; - /** - * * @author mwood */ public class ChecksumHistoryDAOImplTest - extends AbstractUnitTest -{ - public ChecksumHistoryDAOImplTest() - { + extends AbstractUnitTest { + public ChecksumHistoryDAOImplTest() { } @BeforeClass public static void setUpClass() - throws SQLException, ClassNotFoundException - { + throws SQLException, ClassNotFoundException { } @AfterClass - public static void tearDownClass() - { + public static void tearDownClass() { } @Before - public void setUp() - { + public void setUp() { } @After public void tearDown() - throws SQLException - { + throws SQLException { } /** @@ -67,8 +61,7 @@ public class ChecksumHistoryDAOImplTest */ @Test public void testDeleteByDateAndCode() - throws Exception - { + throws Exception { System.out.println("deleteByDateAndCode"); GregorianCalendar cal = new GregorianCalendar(); @@ -78,9 +71,9 @@ public class ChecksumHistoryDAOImplTest // Create two older rows HibernateDBConnection dbc = (HibernateDBConnection) CoreHelpers.getDBConnection(context); Query qry = dbc.getSession().createSQLQuery( - "INSERT INTO checksum_history" - + "(check_id, process_end_date, result, bitstream_id)" - + " VALUES (:id, :date, :result, :bitstream)"); + "INSERT INTO checksum_history" + + "(check_id, process_end_date, result, bitstream_id)" + + " VALUES (:id, :date, :result, :bitstream)"); int checkId = 0; // Row with matching result code @@ -94,9 +87,9 @@ public class ChecksumHistoryDAOImplTest cal.add(Calendar.DATE, -1); Date matchDate = cal.getTime(); checkId++; - qry.setInteger("id", checkId); - qry.setDate("date", matchDate); - qry.setString("result", ChecksumResultCode.CHECKSUM_MATCH.name()); + qry.setParameter("id", checkId); + qry.setParameter("date", matchDate); + qry.setParameter("result", ChecksumResultCode.CHECKSUM_MATCH.name()); qry.setParameter("bitstream", bs.getID()); // FIXME identifier not being set??? qry.executeUpdate(); @@ -104,9 +97,9 @@ public class ChecksumHistoryDAOImplTest cal.add(Calendar.DATE, -1); Date noMatchDate = cal.getTime(); checkId++; - qry.setInteger("id", checkId); - qry.setDate("date", noMatchDate); - qry.setString("result", ChecksumResultCode.CHECKSUM_NO_MATCH.name()); + qry.setParameter("id", checkId); + qry.setParameter("date", noMatchDate); + qry.setParameter("result", ChecksumResultCode.CHECKSUM_NO_MATCH.name()); qry.setParameter("bitstream", bs.getID()); // FIXME identifier not being set??? qry.executeUpdate(); @@ -114,9 +107,9 @@ public class ChecksumHistoryDAOImplTest cal.add(Calendar.DATE, +3); Date futureDate = cal.getTime(); checkId++; - qry.setInteger("id", checkId); - qry.setDate("date", new java.sql.Date(futureDate.getTime())); - qry.setString("result", ChecksumResultCode.CHECKSUM_MATCH.name()); + qry.setParameter("id", checkId); + qry.setParameter("date", new java.sql.Date(futureDate.getTime())); + qry.setParameter("result", ChecksumResultCode.CHECKSUM_MATCH.name()); qry.setParameter("bitstream", bs.getID()); // FIXME identifier not being set??? qry.executeUpdate(); @@ -124,26 +117,26 @@ public class ChecksumHistoryDAOImplTest ChecksumHistoryDAOImpl instance = new ChecksumHistoryDAOImpl(); int expResult = 1; int result = instance.deleteByDateAndCode(context, retentionDate, - resultCode); + resultCode); assertEquals(expResult, result); // See if matching old row is gone. qry = dbc.getSession().createQuery( - "SELECT COUNT(*) FROM ChecksumHistory WHERE process_end_date = :date"); + "SELECT COUNT(*) FROM ChecksumHistory WHERE process_end_date = :date"); long count; - qry.setDate("date", matchDate); - count = (Long) qry.uniqueResult(); + qry.setParameter("date", matchDate); + count = (Long) qry.getSingleResult(); assertEquals("Should find no row at matchDate", count, 0); // See if nonmatching old row is still present. - qry.setDate("date", noMatchDate); - count = (Long) qry.uniqueResult(); + qry.setParameter("date", noMatchDate); + count = (Long) qry.getSingleResult(); assertEquals("Should find one row at noMatchDate", count, 1); // See if new row is still present. - qry.setDate("date", futureDate); - count = (Long) qry.uniqueResult(); + qry.setParameter("date", futureDate); + count = (Long) qry.getSingleResult(); assertEquals("Should find one row at futureDate", count, 1); } diff --git a/dspace-api/src/test/java/org/dspace/content/AbstractDSpaceObjectTest.java b/dspace-api/src/test/java/org/dspace/content/AbstractDSpaceObjectTest.java index eb096ac51a..8f0be66ac7 100644 --- a/dspace-api/src/test/java/org/dspace/content/AbstractDSpaceObjectTest.java +++ b/dspace-api/src/test/java/org/dspace/content/AbstractDSpaceObjectTest.java @@ -7,21 +7,36 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + import java.sql.SQLException; + import org.dspace.AbstractUnitTest; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.ResourcePolicyService; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.dspace.eperson.factory.EPersonServiceFactory; -import org.dspace.eperson.service.EPersonService; -import org.dspace.eperson.service.GroupService; -import org.junit.*; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; +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.DSpaceObjectService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Constants; 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; +import org.junit.After; +import org.junit.Test; /** @@ -31,8 +46,7 @@ import org.dspace.eperson.Group; * * @author pvillega */ -public abstract class AbstractDSpaceObjectTest extends AbstractUnitTest -{ +public abstract class AbstractDSpaceObjectTest extends AbstractUnitTest { /** * Protected instance of the class dspaceObject, will be initialized by @@ -50,7 +64,8 @@ public abstract class AbstractDSpaceObjectTest extends AbstractUnitTest protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService(); - protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); + protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance() + .getResourcePolicyService(); /** @@ -71,11 +86,9 @@ public abstract class AbstractDSpaceObjectTest extends AbstractUnitTest * Test of clearDetails method, of class DSpaceObject. */ @Test - public void testClearDetails() - { + public void testClearDetails() { String[] testData = new String[] {"details 1", "details 2", "details 3"}; - for(String s: testData) - { + for (String s : testData) { dspaceObject.addDetails(s); } @@ -90,12 +103,10 @@ public abstract class AbstractDSpaceObjectTest extends AbstractUnitTest * Test of addDetails method, of class DSpaceObject. */ @Test - public void testAddDetails() - { + public void testAddDetails() { dspaceObject.clearDetails(); String[] testData = new String[] {"details 1", "details 2", "details 3"}; - for(String s: testData) - { + for (String s : testData) { dspaceObject.addDetails(s); } assertThat("testAddDetails 0", dspaceObject.getDetails(), is(equalTo("details 1, details 2, details 3"))); @@ -106,122 +117,117 @@ public abstract class AbstractDSpaceObjectTest extends AbstractUnitTest * Test of getDetails method, of class DSpaceObject. */ @Test - public void testGetDetails() - { + public void testGetDetails() { dspaceObject.clearDetails(); assertThat("testGetDetails 0", dspaceObject.getDetails(), nullValue()); String[] testData = new String[] {"details 1", "details 2", "details 3"}; - for(String s: testData) - { + for (String s : testData) { dspaceObject.addDetails(s); } assertThat("testGetDetails 1", dspaceObject.getDetails(), is(equalTo("details 1, details 2, details 3"))); } - + /** * Test of find method, of class DSpaceObject. */ @Test - public void testFind() throws SQLException - { - DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService(dspaceObject.getType()); - if(this.dspaceObject instanceof Bitstream) - { + public void testFind() throws SQLException { + DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance() + .getDSpaceObjectService(dspaceObject.getType()); + if (this.dspaceObject instanceof Bitstream) { assertThat("BITSTREAM type", dSpaceObjectService.find(context, - dspaceObject.getID()), notNullValue()); - } - else if(this.dspaceObject instanceof Bundle) - { + dspaceObject.getID()), notNullValue()); + } else if (this.dspaceObject instanceof Bundle) { assertThat("BUNDLE type", dSpaceObjectService.find(context, - dspaceObject.getID()), notNullValue()); - } - else if(this.dspaceObject instanceof Item) - { + dspaceObject.getID()), notNullValue()); + } else if (this.dspaceObject instanceof Item) { assertThat("ITEM type", dSpaceObjectService.find(context, - dspaceObject.getID()), notNullValue()); - } - else if(this.dspaceObject instanceof Collection) - { + dspaceObject.getID()), notNullValue()); + } else if (this.dspaceObject instanceof Collection) { assertThat("COLLECTION type", dSpaceObjectService.find(context, - dspaceObject.getID()), notNullValue()); - } - else if(this.dspaceObject instanceof Community) - { + dspaceObject.getID()), notNullValue()); + } else if (this.dspaceObject instanceof Community) { assertThat("COMMUNITY type", dSpaceObjectService.find(context, - dspaceObject.getID()), notNullValue()); - } - else if(this.dspaceObject instanceof Group) - { + dspaceObject.getID()), notNullValue()); + } else if (this.dspaceObject instanceof Group) { assertThat("GROUP type", dSpaceObjectService.find(context, - dspaceObject.getID()), notNullValue()); - } - else if(this.dspaceObject instanceof EPerson) - { + dspaceObject.getID()), notNullValue()); + } else if (this.dspaceObject instanceof EPerson) { assertThat("EPERSON type", dSpaceObjectService.find(context, - dspaceObject.getID()), notNullValue()); - } - else if(this.dspaceObject instanceof Site) - { + dspaceObject.getID()), notNullValue()); + } else if (this.dspaceObject instanceof Site) { assertThat("SITE type", dSpaceObjectService.find(context, - dspaceObject.getID()), notNullValue()); - } - else - { + dspaceObject.getID()), notNullValue()); + } else { assertThat("Unknown type", dSpaceObjectService, - nullValue()); + nullValue()); } } - + /** * Test of getAdminObject method, of class DSpaceObject. */ @Test - public void testGetAdminObject() throws SQLException - { - DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService(dspaceObject.getType()); - assertThat("READ action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.READ), is(equalTo(dspaceObject))); + public void testGetAdminObject() throws SQLException { + DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance() + .getDSpaceObjectService(dspaceObject.getType()); + assertThat("READ action", dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.READ), + is(equalTo(dspaceObject))); - assertThat("WRITE action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.WRITE), is(equalTo(dspaceObject))); + assertThat("WRITE action", dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.WRITE), + is(equalTo(dspaceObject))); - assertThat("DELETE action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.DELETE), is(equalTo(dspaceObject))); + assertThat("DELETE action", dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.DELETE), + is(equalTo(dspaceObject))); - assertThat("ADD action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.ADD), is(equalTo(dspaceObject))); + assertThat("ADD action", dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.ADD), + is(equalTo(dspaceObject))); - assertThat("REMOVE action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.REMOVE), is(equalTo(dspaceObject))); + assertThat("REMOVE action", dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.REMOVE), + is(equalTo(dspaceObject))); - assertThat("WORKFLOW_STEP_1 action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.WORKFLOW_STEP_1), is(equalTo(dspaceObject))); + assertThat("WORKFLOW_STEP_1 action", + dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.WORKFLOW_STEP_1), + is(equalTo(dspaceObject))); - assertThat("WORKFLOW_STEP_2 action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.WORKFLOW_STEP_2), is(equalTo(dspaceObject))); + assertThat("WORKFLOW_STEP_2 action", + dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.WORKFLOW_STEP_2), + is(equalTo(dspaceObject))); - assertThat("WORKFLOW_STEP_3 action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.WORKFLOW_STEP_3), is(equalTo(dspaceObject))); + assertThat("WORKFLOW_STEP_3 action", + dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.WORKFLOW_STEP_3), + is(equalTo(dspaceObject))); - assertThat("WORKFLOW_ABORT action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.WORKFLOW_ABORT), is(equalTo(dspaceObject))); + assertThat("WORKFLOW_ABORT action", + dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.WORKFLOW_ABORT), + is(equalTo(dspaceObject))); - assertThat("DEFAULT_BITSTREAM_READ action", dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.DEFAULT_BITSTREAM_READ), is(equalTo(dspaceObject))); + assertThat("DEFAULT_BITSTREAM_READ action", + dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.DEFAULT_BITSTREAM_READ), + is(equalTo(dspaceObject))); - assertThat("DEFAULT_ITEM_READ action", dSpaceObjectService.getAdminObject(context, dspaceObject,Constants.DEFAULT_ITEM_READ), is(equalTo(dspaceObject))); + assertThat("DEFAULT_ITEM_READ action", + dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.DEFAULT_ITEM_READ), + is(equalTo(dspaceObject))); } /** * Test of getAdminObject method, of class DSpaceObject. */ - @Test(expected=IllegalArgumentException.class) - public void testGetAdminObjectwithException() throws SQLException - { - - if(this.dspaceObject instanceof Bundle - || this.dspaceObject instanceof Community - || this.dspaceObject instanceof Collection - || this.dspaceObject instanceof Item) - { + @Test(expected = IllegalArgumentException.class) + public void testGetAdminObjectwithException() throws SQLException { + + if (this.dspaceObject instanceof Bundle + || this.dspaceObject instanceof Community + || this.dspaceObject instanceof Collection + || this.dspaceObject instanceof Item) { //the previous classes overwrite the method, we add this to pass //this test throw new IllegalArgumentException(); - } - else - { - DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService(dspaceObject.getType()); + } else { + DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService( + dspaceObject.getType()); dSpaceObjectService.getAdminObject(context, dspaceObject, Constants.ADMIN); fail("Exception should have been thrown"); } @@ -231,9 +237,9 @@ public abstract class AbstractDSpaceObjectTest extends AbstractUnitTest * Test of getParentObject method, of class DSpaceObject. */ @Test - public void testGetParentObject() throws SQLException - { - DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService(dspaceObject.getType()); + public void testGetParentObject() throws SQLException { + DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance() + .getDSpaceObjectService(dspaceObject.getType()); assertThat("testGetParentObject 0", dSpaceObjectService.getParentObject(context, dspaceObject), nullValue()); } diff --git a/dspace-api/src/test/java/org/dspace/content/BitstreamFormatTest.java b/dspace-api/src/test/java/org/dspace/content/BitstreamFormatTest.java index 4fbf9d0ef9..07b83c3755 100644 --- a/dspace-api/src/test/java/org/dspace/content/BitstreamFormatTest.java +++ b/dspace-api/src/test/java/org/dspace/content/BitstreamFormatTest.java @@ -7,47 +7,59 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.sql.SQLException; import java.util.Arrays; +import java.util.Collections; import java.util.List; import mockit.NonStrictExpectations; -import org.apache.commons.collections.ListUtils; import org.apache.log4j.Logger; +import org.dspace.AbstractUnitTest; +import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeServiceImpl; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; import org.dspace.core.Context; -import org.junit.*; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; -import org.dspace.AbstractUnitTest; -import org.dspace.authorize.AuthorizeException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * This class tests BitstreamFormat. Due to it being tighly coupled with the * database, most of the methods use mock objects, which only proved a very * basic test level (ensure the method doesn't throw an exception). The real * testing of the class will be done in the Integration Tests. + * * @author pvillega */ -public class BitstreamFormatTest extends AbstractUnitTest -{ - /** log4j category */ +public class BitstreamFormatTest extends AbstractUnitTest { + /** + * log4j category + */ private final static Logger log = Logger.getLogger(BitstreamFormatTest.class); /** * Object to use in the tests */ private BitstreamFormat bf; - + /** * Object to use in the tests */ private BitstreamFormat bunknown; - protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); - + protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); + /** * This method will be run before every test as per @Before. It will @@ -58,16 +70,12 @@ public class BitstreamFormatTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { - bf = bitstreamFormatService.find(context, 5); + try { + bf = bitstreamFormatService.find(context, 5); bunknown = bitstreamFormatService.findUnknown(context); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -82,8 +90,7 @@ public class BitstreamFormatTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { bf = null; bunknown = null; super.destroy(); @@ -93,13 +100,12 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of find method, of class BitstreamFormat. */ @Test - public void testFind() throws SQLException - { - BitstreamFormat found = bitstreamFormatService.find(context, 1); + public void testFind() throws SQLException { + BitstreamFormat found = bitstreamFormatService.find(context, 1); assertThat("testFind 0", found, notNullValue()); assertThat("testFind 1", found.getShortDescription(), equalTo("Unknown")); - found = bitstreamFormatService.find(context, 2); + found = bitstreamFormatService.find(context, 2); assertThat("testFind 2", found, notNullValue()); assertThat("testFind 3", found.getShortDescription(), equalTo("License")); assertTrue("testFind 4", found.isInternal()); @@ -109,14 +115,13 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of findByMIMEType method, of class BitstreamFormat. */ @Test - public void testFindByMIMEType() throws SQLException - { - BitstreamFormat found = bitstreamFormatService.findByMIMEType(context, "text/plain"); + public void testFindByMIMEType() throws SQLException { + BitstreamFormat found = bitstreamFormatService.findByMIMEType(context, "text/plain"); assertThat("testFindByMIMEType 0", found, notNullValue()); assertThat("testFindByMIMEType 1", found.getMIMEType(), equalTo("text/plain")); assertFalse("testFindByMIMEType 2", found.isInternal()); - found = bitstreamFormatService.findByMIMEType(context, "text/xml"); + found = bitstreamFormatService.findByMIMEType(context, "text/xml"); assertThat("testFindByMIMEType 3", found, notNullValue()); assertThat("testFindByMIMEType 4", found.getMIMEType(), equalTo("text/xml")); assertFalse("testFindByMIMEType 5", found.isInternal()); @@ -126,14 +131,13 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of findByShortDescription method, of class BitstreamFormat. */ @Test - public void testFindByShortDescription() throws SQLException - { - BitstreamFormat found = bitstreamFormatService.findByShortDescription(context, "Adobe PDF"); + public void testFindByShortDescription() throws SQLException { + BitstreamFormat found = bitstreamFormatService.findByShortDescription(context, "Adobe PDF"); assertThat("testFindByShortDescription 0", found, notNullValue()); assertThat("testFindByShortDescription 1", found.getShortDescription(), equalTo("Adobe PDF")); assertFalse("testFindByShortDescription 2", found.isInternal()); - found = bitstreamFormatService.findByShortDescription(context, "XML"); + found = bitstreamFormatService.findByShortDescription(context, "XML"); assertThat("testFindByShortDescription 3", found, notNullValue()); assertThat("testFindByShortDescription 4", found.getShortDescription(), equalTo("XML")); assertFalse("testFindByShortDescription 5", found.isInternal()); @@ -144,9 +148,8 @@ public class BitstreamFormatTest extends AbstractUnitTest */ @Test public void testFindUnknown() - throws SQLException - { - BitstreamFormat found = bitstreamFormatService.findUnknown(context); + throws SQLException { + BitstreamFormat found = bitstreamFormatService.findUnknown(context); assertThat("testFindUnknown 0", found, notNullValue()); assertThat("testFindUnknown 1", found.getShortDescription(), equalTo("Unknown")); assertFalse("testFindUnknown 2", found.isInternal()); @@ -157,10 +160,9 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of findAll method, of class BitstreamFormat. */ @Test - public void testFindAll() throws SQLException - { - - List found = bitstreamFormatService.findAll(context); + public void testFindAll() throws SQLException { + + List found = bitstreamFormatService.findAll(context); assertThat("testFindAll 0", found, notNullValue()); //check pos 0 is Unknown @@ -169,30 +171,26 @@ public class BitstreamFormatTest extends AbstractUnitTest assertThat("testFindAll 3", found.get(0).getSupportLevel(), equalTo(0)); boolean added = false; - for(BitstreamFormat bsf: found) - { - if(bsf.equals(bf)) - { + for (BitstreamFormat bsf : found) { + if (bsf.equals(bf)) { added = true; } } - assertTrue("testFindAll 4",added); + assertTrue("testFindAll 4", added); } /** * Test of findNonInternal method, of class BitstreamFormat. */ @Test - public void testFindNonInternal() throws SQLException - { + public void testFindNonInternal() throws SQLException { - List found = bitstreamFormatService.findNonInternal(context); + List found = bitstreamFormatService.findNonInternal(context); assertThat("testFindNonInternal 0", found, notNullValue()); int i = 0; - for(BitstreamFormat b: found) - { + for (BitstreamFormat b : found) { i++; - assertFalse("testFindNonInternal "+i+" ("+b.getShortDescription()+")", b.isInternal()); + assertFalse("testFindNonInternal " + i + " (" + b.getShortDescription() + ")", b.isInternal()); } } @@ -200,15 +198,14 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of create method, of class BitstreamFormat. */ @Test - public void testCreateAdmin() throws SQLException,AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateAdmin() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full Admin perms - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; - - BitstreamFormat found = bitstreamFormatService.create(context); + + BitstreamFormat found = bitstreamFormatService.create(context); assertThat("testCreate 0", found, notNullValue()); assertThat("testCreate 1", found.getDescription(), nullValue()); assertThat("testCreate 2", found.getMIMEType(), nullValue()); @@ -220,16 +217,15 @@ public class BitstreamFormatTest extends AbstractUnitTest /** * Test of create method, of class BitstreamFormat. */ - @Test(expected=AuthorizeException.class) - public void testCreateNotAdmin() throws SQLException,AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateNotAdmin() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full Admin perms - authorizeService.isAdmin((Context) any); result = false; + authorizeService.isAdmin((Context) any); + result = false; }}; - BitstreamFormat found = bitstreamFormatService.create(context); + BitstreamFormat found = bitstreamFormatService.create(context); fail("Exception should have been thrown"); } @@ -237,8 +233,7 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of getID method, of class BitstreamFormat. */ @Test - public void testGetID() - { + public void testGetID() { assertTrue("testGetID 0", bf.getID() == 5); assertTrue("testGetID 1", bunknown.getID() == 1); } @@ -247,63 +242,59 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of getShortDescription method, of class BitstreamFormat. */ @Test - public void testGetShortDescription() - { + public void testGetShortDescription() { assertThat("getShortDescription 0", bf.getShortDescription(), - notNullValue()); + notNullValue()); assertThat("getShortDescription 1", bf.getShortDescription(), - not(equalTo(""))); + not(equalTo(""))); assertThat("getShortDescription 2", bf.getShortDescription(), - equalTo("XML")); + equalTo("XML")); } /** * Test of setShortDescription method, of class BitstreamFormat. */ @Test - public void testSetShortDescription() throws SQLException - { + public void testSetShortDescription() throws SQLException { String desc = "short"; bf.setShortDescription(context, desc); assertThat("testSetShortDescription 0", bf.getShortDescription(), - notNullValue()); + notNullValue()); assertThat("testSetShortDescription 1", bf.getShortDescription(), - not(equalTo(""))); + not(equalTo(""))); assertThat("testSetShortDescription 2", bf.getShortDescription(), - equalTo(desc)); + equalTo(desc)); } /** * Test of getDescription method, of class BitstreamFormat. */ @Test - public void testGetDescription() - { + public void testGetDescription() { assertThat("getDescription 0", bf.getDescription(), - notNullValue()); + notNullValue()); assertThat("getDescription 1", bf.getDescription(), - not(equalTo(""))); + not(equalTo(""))); assertThat("getDescription 2", bf.getDescription(), - equalTo("Extensible Markup Language")); + equalTo("Extensible Markup Language")); } /** * Test of setDescription method, of class BitstreamFormat. */ @Test - public void testSetDescription() - { + public void testSetDescription() { String desc = "long description stored here"; String oldDescription = bf.getDescription(); bf.setDescription(desc); assertThat("testSetDescription 0", bf.getDescription(), - notNullValue()); + notNullValue()); assertThat("testSetDescription 1", bf.getDescription(), - not(equalTo(""))); + not(equalTo(""))); assertThat("testSetDescription 2", bf.getDescription(), - equalTo(desc)); + equalTo(desc)); bf.setDescription(oldDescription); } @@ -311,33 +302,31 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of getMIMEType method, of class BitstreamFormat. */ @Test - public void testGetMIMEType() - { + public void testGetMIMEType() { assertThat("testGetMIMEType 0", bf.getMIMEType(), - notNullValue()); + notNullValue()); assertThat("testGetMIMEType 1", bf.getMIMEType(), - not(equalTo(""))); + not(equalTo(""))); assertThat("testGetMIMEType 2", bf.getMIMEType(), - equalTo("text/xml")); + equalTo("text/xml")); } /** * Test of setMIMEType method, of class BitstreamFormat. */ @Test - public void testSetMIMEType() - { + public void testSetMIMEType() { String mime = "text/plain"; String originalMime = bf.getMIMEType(); bf.setMIMEType(mime); try { assertThat("testSetMIMEType 0", bf.getMIMEType(), - notNullValue()); + notNullValue()); assertThat("testSetMIMEType 1", bf.getMIMEType(), - not(equalTo(""))); + not(equalTo(""))); assertThat("testSetMIMEType 2", bf.getMIMEType(), - equalTo(mime)); + equalTo(mime)); } finally { bf.setMIMEType(originalMime); } @@ -347,32 +336,29 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of getSupportLevel method, of class BitstreamFormat. */ @Test - public void testGetSupportLevel() throws SQLException - { + public void testGetSupportLevel() throws SQLException { assertTrue("testGetSupportLevel 0", bf.getSupportLevel() >= 0); assertTrue("testGetSupportLevel 1", bf.getSupportLevel() <= 2); - + assertTrue("testGetSupportLevel 2", bunknown.getSupportLevel() >= 0); assertTrue("testGetSupportLevel 3", bunknown.getSupportLevel() <= 2); - List found = bitstreamFormatService.findAll(context); + List found = bitstreamFormatService.findAll(context); int i = 0; - for(BitstreamFormat b: found) - { + for (BitstreamFormat b : found) { i++; - assertTrue("testGetSupportLevel "+i+" ("+b.getMIMEType()+")", b.getSupportLevel() >= 0); + assertTrue("testGetSupportLevel " + i + " (" + b.getMIMEType() + ")", b.getSupportLevel() >= 0); i++; - assertTrue("testGetSupportLevel "+i+" ("+b.getMIMEType()+")", b.getSupportLevel() <= 2); + assertTrue("testGetSupportLevel " + i + " (" + b.getMIMEType() + ")", b.getSupportLevel() <= 2); } } /** * Test of setSupportLevel method, of class BitstreamFormat. */ - @Test(expected=IllegalArgumentException.class) - public void testSetSupportLevelInvalidValue() - { + @Test(expected = IllegalArgumentException.class) + public void testSetSupportLevelInvalidValue() { bf.setSupportLevel(5); fail("Exception should be thrown"); } @@ -380,9 +366,8 @@ public class BitstreamFormatTest extends AbstractUnitTest /** * Test of setSupportLevel method, of class BitstreamFormat. */ - @Test(expected=IllegalArgumentException.class) - public void testSetSupportLevelNegativeValue() - { + @Test(expected = IllegalArgumentException.class) + public void testSetSupportLevelNegativeValue() { bf.setSupportLevel(-1); fail("Exception should be thrown"); } @@ -391,8 +376,7 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of setSupportLevel method, of class BitstreamFormat. */ @Test - public void testSetSupportLevelValidValues() - { + public void testSetSupportLevelValidValues() { bf.setSupportLevel(BitstreamFormat.UNKNOWN); assertThat("testSetSupportLevelValidValues 0", bf.getSupportLevel(), equalTo(BitstreamFormat.UNKNOWN)); bf.setSupportLevel(BitstreamFormat.KNOWN); @@ -406,8 +390,7 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of getSupportLevelID method, of class BitstreamFormat. */ @Test - public void testGetSupportLevelIDValid() - { + public void testGetSupportLevelIDValid() { int id1 = bitstreamFormatService.getSupportLevelID("UNKNOWN"); assertThat("testGetSupportLevelIDValid 0", id1, equalTo(BitstreamFormat.UNKNOWN)); int id2 = bitstreamFormatService.getSupportLevelID("KNOWN"); @@ -420,8 +403,7 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of getSupportLevelID method, of class BitstreamFormat. */ @Test - public void testGetSupportLevelIDInvalid() - { + public void testGetSupportLevelIDInvalid() { int id1 = bitstreamFormatService.getSupportLevelID("IAmNotAValidSupportLevel"); assertThat("testGetSupportLevelIDInvalid 0", id1, equalTo(-1)); } @@ -431,8 +413,7 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of isInternal method, of class BitstreamFormat. */ @Test - public void testIsInternal() throws SQLException - { + public void testIsInternal() throws SQLException { assertThat("testIsInternal 0", bf.isInternal(), equalTo(false)); BitstreamFormat found = bitstreamFormatService.findByShortDescription(context, "License"); @@ -448,8 +429,7 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of setInternal method, of class BitstreamFormat. */ @Test - public void testSetInternal() - { + public void testSetInternal() { assertFalse("testSetInternal 0", bf.isInternal()); bf.setInternal(true); @@ -460,13 +440,12 @@ public class BitstreamFormatTest extends AbstractUnitTest /** * Test of update method, of class BitstreamFormat. */ - @Test(expected=AuthorizeException.class) - public void testUpdateNotAdmin() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testUpdateNotAdmin() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full Admin perms - authorizeService.isAdmin((Context) any); result = false; + authorizeService.isAdmin((Context) any); + result = false; }}; bitstreamFormatService.update(context, bf); @@ -477,12 +456,11 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of update method, of class BitstreamFormat. */ @Test - public void testUpdateAdmin() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testUpdateAdmin() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full Admin perms - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; String desc = "Test description"; @@ -490,7 +468,7 @@ public class BitstreamFormatTest extends AbstractUnitTest bf.setDescription(desc); bitstreamFormatService.update(context, bf); - BitstreamFormat b = bitstreamFormatService.find(context, 5); + BitstreamFormat b = bitstreamFormatService.find(context, 5); assertThat("testUpdateAdmin 0", b.getDescription(), equalTo(desc)); bf.setDescription(oldDescription); } @@ -498,13 +476,12 @@ public class BitstreamFormatTest extends AbstractUnitTest /** * Test of delete method, of class BitstreamFormat. */ - @Test(expected=AuthorizeException.class) - public void testDeleteNotAdmin() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testDeleteNotAdmin() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full Admin perms - authorizeService.isAdmin((Context) any); result = false; + authorizeService.isAdmin((Context) any); + result = false; }}; bitstreamFormatService.delete(context, bf); @@ -515,31 +492,29 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of delete method, of class BitstreamFormat. */ @Test - public void testDeleteAdmin() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDeleteAdmin() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full Admin perms - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; BitstreamFormat bitstreamFormat = bitstreamFormatService.create(context); int toDeleteIdentifier = bitstreamFormat.getID(); bitstreamFormatService.delete(context, bitstreamFormat); - BitstreamFormat b = bitstreamFormatService.find(context, toDeleteIdentifier); + BitstreamFormat b = bitstreamFormatService.find(context, toDeleteIdentifier); assertThat("testDeleteAdmin 0", b, nullValue()); } /** * Test of delete method, of class BitstreamFormat. */ - @Test(expected=IllegalArgumentException.class) - public void testDeleteUnknown() throws SQLException, AuthorizeException - { - new NonStrictExpectations(AuthorizeServiceImpl.class) - {{ + @Test(expected = IllegalArgumentException.class) + public void testDeleteUnknown() throws SQLException, AuthorizeException { + new NonStrictExpectations(AuthorizeServiceImpl.class) {{ // Allow full Admin perms - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; bitstreamFormatService.delete(context, bunknown); @@ -550,8 +525,7 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of getExtensions method, of class BitstreamFormat. */ @Test - public void testGetExtensions() - { + public void testGetExtensions() { assertThat("testGetExtensions 0", bf.getExtensions(), notNullValue()); assertTrue("testGetExtensions 1", bf.getExtensions().size() == 1); assertThat("testGetExtensions 2", bf.getExtensions().get(0), equalTo("xml")); @@ -561,8 +535,7 @@ public class BitstreamFormatTest extends AbstractUnitTest * Test of setExtensions method, of class BitstreamFormat. */ @Test - public void setExtensions() - { + public void setExtensions() { List backupExtensions = bf.getExtensions(); assertThat("setExtensions 0", bf.getExtensions().get(0), equalTo("xml")); String[] values = {"1", "2", "3"}; @@ -573,7 +546,7 @@ public class BitstreamFormatTest extends AbstractUnitTest assertThat("setExtensions 4", bf.getExtensions().get(1), equalTo("2")); assertThat("setExtensions 5", bf.getExtensions().get(2), equalTo("3")); - bf.setExtensions(ListUtils.EMPTY_LIST); + bf.setExtensions(Collections.EMPTY_LIST); assertThat("setExtensions 6", bf.getExtensions(), notNullValue()); assertTrue("setExtensions 7", bf.getExtensions().size() == 0); bf.setExtensions(backupExtensions); diff --git a/dspace-api/src/test/java/org/dspace/content/BitstreamTest.java b/dspace-api/src/test/java/org/dspace/content/BitstreamTest.java index eea2ee66c4..fd46c3ec17 100644 --- a/dspace-api/src/test/java/org/dspace/content/BitstreamTest.java +++ b/dspace-api/src/test/java/org/dspace/content/BitstreamTest.java @@ -7,6 +7,15 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -14,28 +23,31 @@ import java.sql.SQLException; import java.util.List; import java.util.UUID; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.BitstreamFormatService; -import org.dspace.core.Context; -import org.junit.*; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; -import mockit.*; +import mockit.NonStrictExpectations; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.BitstreamFormatService; import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Unit Tests for class Bitstream + * * @author pvillega */ -public class BitstreamTest extends AbstractDSpaceObjectTest -{ - /** log4j category */ +public class BitstreamTest extends AbstractDSpaceObjectTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(BitstreamTest.class); - protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); /** * BitStream instance for the tests @@ -51,23 +63,18 @@ public class BitstreamTest extends AbstractDSpaceObjectTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { //we have to create a new bitstream in the database File f = new File(testProps.get("test.bitstream").toString()); this.bs = bitstreamService.create(context, new FileInputStream(f)); - this.dspaceObject = bs; + this.dspaceObject = bs; //we need to commit the changes so we don't block the table for testing - } - catch (IOException ex) { + } catch (IOException ex) { log.error("IO Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -82,8 +89,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest */ @After @Override - public void destroy() - { + public void destroy() { bs = null; super.destroy(); } @@ -92,10 +98,9 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of find method, of class Bitstream. */ @Test - public void testBSFind() throws SQLException - { + public void testBSFind() throws SQLException { UUID id = this.bs.getID(); - Bitstream found = bitstreamService.find(context, id); + Bitstream found = bitstreamService.find(context, id); assertThat("testBSFind 0", found, notNullValue()); //the item created by default has no name nor type set assertThat("testBSFind 1", found.getFormat(context).getMIMEType(), equalTo("application/octet-stream")); @@ -107,31 +112,27 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of findAll method, of class Bitstream. */ @Test - public void testFindAll() throws SQLException - { - List found = bitstreamService.findAll(context); + public void testFindAll() throws SQLException { + List found = bitstreamService.findAll(context); assertThat("testFindAll 0", found, notNullValue()); //we have many bs, one created per test run, so at least we have 1 if //this test is run first assertTrue("testFindAll 1", found.size() >= 1); boolean added = false; - for(Bitstream b: found) - { - if(b.equals(bs)) - { + for (Bitstream b : found) { + if (b.equals(bs)) { added = true; } } - assertTrue("testFindAll 2",added); + assertTrue("testFindAll 2", added); } /** * Test of create method, of class Bitstream. */ @Test - public void testCreate() throws IOException, SQLException - { + public void testCreate() throws IOException, SQLException { File f = new File(testProps.get("test.bitstream").toString()); Bitstream created = bitstreamService.create(context, new FileInputStream(f)); @@ -144,16 +145,15 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of register method, of class Bitstream. */ @Test - public void testRegister() throws IOException, SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRegister() throws IOException, SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; int assetstore = 0; File f = new File(testProps.get("test.bitstream").toString()); - Bitstream registered = bitstreamService.register(context,assetstore, f.getName()); + Bitstream registered = bitstreamService.register(context, assetstore, f.getName()); //the item created by default has no name nor type set assertThat("testRegister 0", registered.getFormat(context).getMIMEType(), equalTo("application/octet-stream")); assertThat("testRegister 1", registered.getName(), nullValue()); @@ -164,21 +164,21 @@ public class BitstreamTest extends AbstractDSpaceObjectTest */ @Override @Test - public void testGetID() - { + public void testGetID() { assertTrue("testGetID 0", bs.getID() != null); } @Test - public void testLegacyID() { assertTrue("testGetLegacyID 0", bs.getLegacyId() == null);} + public void testLegacyID() { + assertTrue("testGetLegacyID 0", bs.getLegacyId() == null); + } /** * Test of getHandle method, of class Bitstream. */ @Override @Test - public void testGetHandle() - { + public void testGetHandle() { //no handle for bitstreams assertThat("testGetHandle 0", bs.getHandle(), nullValue()); } @@ -187,8 +187,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of getSequenceID method, of class Bitstream. */ @Test - public void testGetSequenceID() - { + public void testGetSequenceID() { //sequence id is -1 when not set assertThat("testGetSequenceID 0", bs.getSequenceID(), equalTo(-1)); } @@ -197,8 +196,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of setSequenceID method, of class Bitstream. */ @Test - public void testSetSequenceID() - { + public void testSetSequenceID() { int val = 2; bs.setSequenceID(val); assertThat("testSetSequenceID 0", bs.getSequenceID(), equalTo(val)); @@ -209,8 +207,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest */ @Override @Test - public void testGetName() - { + public void testGetName() { //name is null when not set assertThat("testGetName 0", bs.getName(), nullValue()); } @@ -219,8 +216,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of setName method, of class Bitstream. */ @Test - public void testSetName() throws SQLException - { + public void testSetName() throws SQLException { String name = "new name"; bs.setName(context, name); assertThat("testGetName 0", bs.getName(), notNullValue()); @@ -232,8 +228,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of getSource method, of class Bitstream. */ @Test - public void testGetSource() - { + public void testGetSource() { //source is null if not set assertThat("testGetSource 0", bs.getSource(), nullValue()); } @@ -242,8 +237,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of setSource method, of class Bitstream. */ @Test - public void testSetSource() throws SQLException - { + public void testSetSource() throws SQLException { String source = "new source"; bs.setSource(context, source); assertThat("testSetSource 0", bs.getSource(), notNullValue()); @@ -255,8 +249,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of getDescription method, of class Bitstream. */ @Test - public void testGetDescription() - { + public void testGetDescription() { //default description is null if not set assertThat("testGetDescription 0", bs.getDescription(), nullValue()); } @@ -265,8 +258,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of setDescription method, of class Bitstream. */ @Test - public void testSetDescription() throws SQLException - { + public void testSetDescription() throws SQLException { String description = "new description"; bs.setDescription(context, description); assertThat("testSetDescription 0", bs.getDescription(), notNullValue()); @@ -278,8 +270,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of getChecksum method, of class Bitstream. */ @Test - public void testGetChecksum() - { + public void testGetChecksum() { String checksum = "75a060bf6eb63fd0aad88b7d757728d3"; assertThat("testGetChecksum 0", bs.getChecksum(), notNullValue()); assertThat("testGetChecksum 1", bs.getChecksum(), not(equalTo(""))); @@ -290,52 +281,48 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of getChecksumAlgorithm method, of class Bitstream. */ @Test - public void testGetChecksumAlgorithm() - { + public void testGetChecksumAlgorithm() { String alg = "MD5"; assertThat("testGetChecksumAlgorithm 0", bs.getChecksumAlgorithm(), - notNullValue()); + notNullValue()); assertThat("testGetChecksumAlgorithm 1", bs.getChecksumAlgorithm(), - not(equalTo(""))); + not(equalTo(""))); assertThat("testGetChecksumAlgorithm 2", bs.getChecksumAlgorithm(), - equalTo(alg)); + equalTo(alg)); } /** - * Test of getSize method, of class Bitstream. + * Test of getSizeBytes method, of class Bitstream. */ @Test - public void testGetSize() - { + public void testGetSize() { long size = 238413; // yuck, hardcoded! - assertThat("testGetSize 0", bs.getSize(), equalTo(size)); + assertThat("testGetSize 0", bs.getSizeBytes(), equalTo(size)); } /** * Test of setUserFormatDescription method, of class Bitstream. */ @Test - public void testSetUserFormatDescription() throws SQLException - { + public void testSetUserFormatDescription() throws SQLException { String userdescription = "user format description"; bs.setUserFormatDescription(context, userdescription); assertThat("testSetUserFormatDescription 0", bs.getUserFormatDescription() - , notNullValue()); + , notNullValue()); assertThat("testSetUserFormatDescription 1", bs.getUserFormatDescription() - , not(equalTo(""))); + , not(equalTo(""))); assertThat("testSetUserFormatDescription 2", bs.getUserFormatDescription() - , equalTo(userdescription)); + , equalTo(userdescription)); } /** * Test of getUserFormatDescription method, of class Bitstream. */ @Test - public void testGetUserFormatDescription() - { + public void testGetUserFormatDescription() { //null by default if not set assertThat("testGetUserFormatDescription 0", bs.getUserFormatDescription() - , nullValue()); + , nullValue()); } /** @@ -346,19 +333,18 @@ public class BitstreamTest extends AbstractDSpaceObjectTest //format is unknown by default String format = "Unknown"; assertThat("testGetFormatDescription 0", bs.getFormatDescription(context), - notNullValue()); + notNullValue()); assertThat("testGetFormatDescription 1", bs.getFormatDescription(context), - not(equalTo(""))); + not(equalTo(""))); assertThat("testGetFormatDescription 2", bs.getFormatDescription(context), - equalTo(format)); + equalTo(format)); } /** * Test of getFormat method, of class Bitstream. */ @Test - public void testGetFormat() throws SQLException - { + public void testGetFormat() throws SQLException { assertThat("testGetFormat 0", bs.getFormat(context), notNullValue()); assertThat("testGetFormat 1", bs.getFormat(context), equalTo(bitstreamFormatService.findUnknown(context))); } @@ -367,8 +353,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of setFormat method, of class Bitstream. */ @Test - public void testSetFormat() throws SQLException - { + public void testSetFormat() throws SQLException { int id = 3; BitstreamFormat format = bitstreamFormatService.find(context, id); bs.setFormat(format); @@ -379,14 +364,13 @@ public class BitstreamTest extends AbstractDSpaceObjectTest /** * Test of update method, of class Bitstream. */ - @Test(expected=AuthorizeException.class) - public void testUpdateNotAdmin() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testUpdateNotAdmin() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Bitstream WRITE perms - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = new AuthorizeException(); + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = new AuthorizeException(); }}; //TODO: we need to verify the update, how? @@ -397,16 +381,15 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of update method, of class Bitstream. */ @Test - public void testUpdateAdmin() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testUpdateAdmin() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bitstream WRITE perms - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = null; }}; - + //TODO: we need to verify the update, how? bitstreamService.update(context, bs); } @@ -415,15 +398,15 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of delete method, of class Bitstream. */ @Test - public void testDeleteAndExpunge() throws IOException, SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDeleteAndExpunge() throws IOException, SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bitstream WRITE perms - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.DELETE); result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.DELETE); + result = null; }}; // Create a new bitstream, which we can delete. As ordering of these @@ -447,13 +430,12 @@ public class BitstreamTest extends AbstractDSpaceObjectTest */ @Test public void testRetrieveCanRead() throws IOException, SQLException, - AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bitstream READ perms - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.READ); result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.READ); + result = null; }}; assertThat("testRetrieveCanRead 0", bitstreamService.retrieve(context, bs), notNullValue()); @@ -462,15 +444,14 @@ public class BitstreamTest extends AbstractDSpaceObjectTest /** * Test of retrieve method, of class Bitstream. */ - @Test(expected=AuthorizeException.class) + @Test(expected = AuthorizeException.class) public void testRetrieveNoRead() throws IOException, SQLException, - AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Bitstream READ perms authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.READ); result = new AuthorizeException(); + Constants.READ); + result = new AuthorizeException(); }}; assertThat("testRetrieveNoRead 0", bitstreamService.retrieve(context, bs), notNullValue()); @@ -480,8 +461,7 @@ public class BitstreamTest extends AbstractDSpaceObjectTest * Test of getBundles method, of class Bitstream. */ @Test - public void testGetBundles() throws SQLException - { + public void testGetBundles() throws SQLException { assertThat("testGetBundles 0", bs.getBundles(), notNullValue()); //by default no bundles assertTrue("testGetBundles 1", bs.getBundles().size() == 0); @@ -492,20 +472,18 @@ public class BitstreamTest extends AbstractDSpaceObjectTest */ @Override @Test - public void testGetType() - { - assertThat("testGetType 0", bs.getType(), equalTo(Constants.BITSTREAM)); + public void testGetType() { + assertThat("testGetType 0", bs.getType(), equalTo(Constants.BITSTREAM)); } /** * Test of isRegisteredBitstream method, of class Bitstream. */ @Test - public void testIsRegisteredBitstream() - { + public void testIsRegisteredBitstream() { //false by default assertThat("testIsRegisteredBitstream 0", bitstreamService.isRegisteredBitstream(bs), - equalTo(false)); + equalTo(false)); } /** @@ -522,11 +500,10 @@ public class BitstreamTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetParentObject() throws SQLException - { + public void testGetParentObject() throws SQLException { //by default this bitstream is not linked to any object assertThat("testGetParentObject 0", bitstreamService.getParentObject(context, bs), - nullValue()); + nullValue()); } - + } diff --git a/dspace-api/src/test/java/org/dspace/content/BundleTest.java b/dspace-api/src/test/java/org/dspace/content/BundleTest.java index aebff76661..09ca44ada1 100644 --- a/dspace-api/src/test/java/org/dspace/content/BundleTest.java +++ b/dspace-api/src/test/java/org/dspace/content/BundleTest.java @@ -7,38 +7,46 @@ */ package org.dspace.content; -import java.util.Iterator; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import org.apache.commons.collections.CollectionUtils; -import org.dspace.core.Constants; -import org.dspace.core.Context; -import mockit.NonStrictExpectations; -import java.io.FileInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import org.apache.log4j.Logger; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.UUID; +import mockit.NonStrictExpectations; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; - +import org.dspace.core.Constants; +import org.dspace.core.Context; import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; -import static org.hamcrest.CoreMatchers.*; /** * Units tests for class Bundle + * * @author pvillega */ -public class BundleTest extends AbstractDSpaceObjectTest -{ - /** log4j category */ +public class BundleTest extends AbstractDSpaceObjectTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(BundleTest.class); /** @@ -59,11 +67,9 @@ public class BundleTest extends AbstractDSpaceObjectTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { context.turnOffAuthorisationSystem(); this.owningCommunity = communityService.create(null, context); this.collection = collectionService.create(context, owningCommunity); @@ -74,9 +80,7 @@ public class BundleTest extends AbstractDSpaceObjectTest //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); - } - catch (SQLException | AuthorizeException ex) - { + } catch (SQLException | AuthorizeException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -91,8 +95,7 @@ public class BundleTest extends AbstractDSpaceObjectTest */ @After @Override - public void destroy() - { + public void destroy() { // try { // context.turnOffAuthorisationSystem(); // b = bundleService.find(context, b.getID()); @@ -116,13 +119,11 @@ public class BundleTest extends AbstractDSpaceObjectTest } @Test - public void testDeleteParents() throws Exception - { + public void testDeleteParents() throws Exception { try { context.turnOffAuthorisationSystem(); b = bundleService.find(context, b.getID()); - if(b != null) - { + if (b != null) { itemService.removeBundle(context, item, b); } item = itemService.find(context, item.getID()); @@ -143,10 +144,9 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of find method, of class Bundle. */ @Test - public void testBundleFind() throws SQLException - { + public void testBundleFind() throws SQLException { UUID id = b.getID(); - Bundle found = bundleService.find(context, id); + Bundle found = bundleService.find(context, id); assertThat("testBundleFind 0", found, notNullValue()); assertThat("testBundleFind 1", found.getID(), equalTo(id)); } @@ -155,16 +155,15 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of create method, of class Bundle. */ @Test - public void testCreate() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - { + public void testCreate() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) { { // Allow Bundle ADD perms authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); + Constants.ADD); result = null; - }}; + } + }; Bundle created = bundleService.create(context, item, "testCreateBundle"); //the item created by default has no name nor type set assertThat("testCreate 0", created, notNullValue()); @@ -178,21 +177,21 @@ public class BundleTest extends AbstractDSpaceObjectTest */ @Override @Test - public void testGetID() - { + public void testGetID() { assertTrue("testGetID 0", b.getID() != null); } @Test - public void testLegacyID() { assertTrue("testGetLegacyID 0", b.getLegacyId() == null);} + public void testLegacyID() { + assertTrue("testGetLegacyID 0", b.getLegacyId() == null); + } /** * Test of getName method, of class Bundle. */ @Override @Test - public void testGetName() - { + public void testGetName() { //created bundle has no name assertThat("testGetName 0", b.getName(), equalTo("TESTBUNDLE")); } @@ -201,8 +200,7 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of setName method, of class Bundle. */ @Test - public void testSetName() throws SQLException - { + public void testSetName() throws SQLException { String name = "new name"; b.setName(context, name); assertThat("testSetName 0", b.getName(), notNullValue()); @@ -214,8 +212,7 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of getPrimaryBitstreamID method, of class Bundle. */ @Test - public void testGetPrimaryBitstreamID() - { + public void testGetPrimaryBitstreamID() { //is -1 when not set assertThat("testGetPrimaryBitstreamID 0", b.getPrimaryBitstream(), equalTo(null)); } @@ -224,18 +221,17 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of setPrimaryBitstreamID method, of class Bundle. */ @Test - public void testSetPrimaryBitstreamID() throws SQLException, AuthorizeException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - { + public void testSetPrimaryBitstreamID() throws SQLException, AuthorizeException, IOException { + new NonStrictExpectations(authorizeService.getClass()) { { // Allow Bundle ADD perms authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); + Constants.ADD); authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); + Constants.WRITE); result = null; - }}; + } + }; File f = new File(testProps.get("test.bitstream").toString()); Bitstream bs = bitstreamService.create(context, new FileInputStream(f)); bundleService.addBitstream(context, b, bs); @@ -247,18 +243,17 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of unsetPrimaryBitstreamID method, of class Bundle. */ @Test - public void testUnsetPrimaryBitstreamID() throws IOException, SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - { + public void testUnsetPrimaryBitstreamID() throws IOException, SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) { { // Allow Bundle ADD perms authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); + Constants.ADD); authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); + Constants.WRITE); result = null; - }}; + } + }; //set a value different than default File f = new File(testProps.get("test.bitstream").toString()); Bitstream bs = bitstreamService.create(context, new FileInputStream(f)); @@ -275,8 +270,7 @@ public class BundleTest extends AbstractDSpaceObjectTest */ @Override @Test - public void testGetHandle() - { + public void testGetHandle() { //no handle for bundles assertThat("testGetHandle 0", b.getHandle(), nullValue()); } @@ -285,15 +279,15 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of getBitstreamByName method, of class Bundle. */ @Test - public void testGetBitstreamByName() throws FileNotFoundException, SQLException, IOException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testGetBitstreamByName() throws FileNotFoundException, SQLException, IOException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bundle ADD perms - authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = null; - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; + authorizeService.authorizeAction((Context) any, (Bundle) any, + Constants.ADD); + result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = null; }}; @@ -316,15 +310,15 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of getBitstreams method, of class Bundle. */ @Test - public void testGetBitstreams() throws FileNotFoundException, SQLException, IOException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testGetBitstreams() throws FileNotFoundException, SQLException, IOException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bundle ADD perms - authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = null; - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; + authorizeService.authorizeAction((Context) any, (Bundle) any, + Constants.ADD); + result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = null; }}; @@ -347,8 +341,7 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of getItems method, of class Bundle. */ @Test - public void testGetItems() throws SQLException - { + public void testGetItems() throws SQLException { //by default this bundle belong to no item assertThat("testGetItems 0", b.getItems(), notNullValue()); assertThat("testGetItems 1", b.getItems().size(), equalTo(1)); @@ -357,14 +350,14 @@ public class BundleTest extends AbstractDSpaceObjectTest /** * Test of createBitstream method, of class Bundle. */ - @Test(expected=AuthorizeException.class) - public void testCreateBitstreamNoAuth() throws FileNotFoundException, AuthorizeException, SQLException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateBitstreamNoAuth() + throws FileNotFoundException, AuthorizeException, SQLException, IOException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Bundle ADD perms - authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = new AuthorizeException(); + authorizeService.authorizeAction((Context) any, (Bundle) any, + Constants.ADD); + result = new AuthorizeException(); }}; @@ -377,15 +370,15 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of createBitstream method, of class Bundle. */ @Test - public void testCreateBitstreamAuth() throws FileNotFoundException, AuthorizeException, SQLException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateBitstreamAuth() throws FileNotFoundException, AuthorizeException, SQLException, IOException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bundle ADD perms - authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = null; - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; + authorizeService.authorizeAction((Context) any, (Bundle) any, + Constants.ADD); + result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = null; }}; @@ -401,14 +394,13 @@ public class BundleTest extends AbstractDSpaceObjectTest /** * Test of registerBitstream method, of class Bundle. */ - @Test(expected=AuthorizeException.class) - public void testRegisterBitstreamNoAuth() throws AuthorizeException, IOException, SQLException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testRegisterBitstreamNoAuth() throws AuthorizeException, IOException, SQLException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Bundle ADD perms - authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = new AuthorizeException(); + authorizeService.authorizeAction((Context) any, (Bundle) any, + Constants.ADD); + result = new AuthorizeException(); }}; @@ -422,16 +414,16 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of registerBitstream method, of class Bundle. */ @Test - public void testRegisterBitstreamAuth() throws AuthorizeException, IOException, SQLException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRegisterBitstreamAuth() throws AuthorizeException, IOException, SQLException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bundle ADD perms - authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = null; + authorizeService.authorizeAction((Context) any, (Bundle) any, + Constants.ADD); + result = null; - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = null; }}; int assetstore = 0; //default assetstore @@ -447,14 +439,13 @@ public class BundleTest extends AbstractDSpaceObjectTest /** * Test of addBitstream method, of class Bundle. */ - @Test(expected=AuthorizeException.class) - public void testAddBitstreamNoAuth() throws SQLException, AuthorizeException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testAddBitstreamNoAuth() throws SQLException, AuthorizeException, IOException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Bundle ADD perms - authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = new AuthorizeException(); + authorizeService.authorizeAction((Context) any, (Bundle) any, + Constants.ADD); + result = new AuthorizeException(); }}; @@ -470,15 +461,15 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of addBitstream method, of class Bundle. */ @Test - public void testAddBitstreamAuth() throws SQLException, AuthorizeException, FileNotFoundException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testAddBitstreamAuth() throws SQLException, AuthorizeException, FileNotFoundException, IOException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bundle ADD perms - authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = null; - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; + authorizeService.authorizeAction((Context) any, (Bundle) any, + Constants.ADD); + result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = null; }}; @@ -488,20 +479,20 @@ public class BundleTest extends AbstractDSpaceObjectTest bundleService.addBitstream(context, b, bs); assertThat("testAddBitstreamAuth 0", bundleService.getBitstreamByName(b, bs.getName()), notNullValue()); assertThat("testAddBitstreamAuth 1", bundleService.getBitstreamByName(b, bs.getName()), equalTo(bs)); - assertThat("testAddBitstreamAuth 2", bundleService.getBitstreamByName(b, bs.getName()).getName(), equalTo(bs.getName())); + assertThat("testAddBitstreamAuth 2", bundleService.getBitstreamByName(b, bs.getName()).getName(), + equalTo(bs.getName())); } /** * Test of removeBitstream method, of class Bundle. */ - @Test(expected=AuthorizeException.class) - public void testRemoveBitstreamNoAuth() throws SQLException, AuthorizeException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveBitstreamNoAuth() throws SQLException, AuthorizeException, IOException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Bundle REMOVE perms authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.REMOVE); result = new AuthorizeException(); + Constants.REMOVE); + result = new AuthorizeException(); }}; @@ -516,20 +507,22 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of removeBitstream method, of class Bundle. */ @Test - public void testRemoveBitstreamAuth() throws SQLException, AuthorizeException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRemoveBitstreamAuth() throws SQLException, AuthorizeException, IOException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bundle ADD perms (to create a new Bitstream and add it) authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow Bundle REMOVE perms (to test remove) authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.REMOVE); result = null; - authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; - authorizeService.authorizeAction(context, (Bitstream) any, - Constants.DELETE); result = null; + Constants.REMOVE); + result = null; + authorizeService.authorizeAction((Context) any, (Bitstream) any, + Constants.WRITE); + result = null; + authorizeService.authorizeAction(context, (Bitstream) any, + Constants.DELETE); + result = null; }}; @@ -546,8 +539,7 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of update method, of class Bundle. */ @Test - public void testUpdate() throws SQLException, AuthorizeException - { + public void testUpdate() throws SQLException, AuthorizeException { //TODO: we only check for sql errors //TODO: note that update can't throw authorize exception!! bundleService.update(context, b); @@ -557,18 +549,19 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of delete method, of class Bundle. */ @Test - public void testDelete() throws SQLException, AuthorizeException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDelete() throws SQLException, AuthorizeException, IOException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bundle ADD perms (to create a new Bitstream and add it) authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow Bundle REMOVE perms (to test remove) authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.REMOVE); result = null; + Constants.REMOVE); + result = null; authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.DELETE); result = null; + Constants.DELETE); + result = null; }}; UUID id = b.getID(); @@ -581,8 +574,7 @@ public class BundleTest extends AbstractDSpaceObjectTest */ @Override @Test - public void testGetType() - { + public void testGetType() { assertThat("testGetType 0", b.getType(), equalTo(Constants.BUNDLE)); } @@ -590,17 +582,15 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of inheritCollectionDefaultPolicies method, of class Bundle. */ @Test - public void testInheritCollectionDefaultPolicies() throws AuthorizeException, SQLException - { + public void testInheritCollectionDefaultPolicies() throws AuthorizeException, SQLException { //TODO: we would need a method to get policies from collection, probably better! - List defaultCollectionPolicies = authorizeService.getPoliciesActionFilter(context, collection, - Constants.DEFAULT_BITSTREAM_READ); + List defaultCollectionPolicies = + authorizeService.getPoliciesActionFilter(context, collection, Constants.DEFAULT_BITSTREAM_READ); Iterator it = defaultCollectionPolicies.iterator(); bundleService.inheritCollectionDefaultPolicies(context, b, collection); - while (it.hasNext()) - { + while (it.hasNext()) { ResourcePolicy rp = (ResourcePolicy) it.next(); rp.setAction(Constants.READ); } @@ -609,12 +599,11 @@ public class BundleTest extends AbstractDSpaceObjectTest assertTrue("testInheritCollectionDefaultPolicies 0", defaultCollectionPolicies.size() == bspolicies.size()); boolean equals = false; - for(int i=0; i < defaultCollectionPolicies.size(); i++) - { + for (int i = 0; i < defaultCollectionPolicies.size(); i++) { ResourcePolicy collectionPolicy = defaultCollectionPolicies.get(i); ResourcePolicy bundlePolicy = bspolicies.get(i); - if(collectionPolicy.getAction() == bundlePolicy.getAction() && collectionPolicy.getGroup().equals(bundlePolicy.getGroup())) - { + if (collectionPolicy.getAction() == bundlePolicy.getAction() && collectionPolicy.getGroup().equals( + bundlePolicy.getGroup())) { equals = true; } } @@ -622,12 +611,11 @@ public class BundleTest extends AbstractDSpaceObjectTest bspolicies = bundleService.getBitstreamPolicies(context, b); boolean exists = true; - for(int i=0; bspolicies.size() > 0 && i < defaultCollectionPolicies.size(); i++) - { + for (int i = 0; bspolicies.size() > 0 && i < defaultCollectionPolicies.size(); i++) { ResourcePolicy collectionPolicy = defaultCollectionPolicies.get(i); ResourcePolicy bitstreamPolicy = bspolicies.get(i); - if(collectionPolicy.getAction() == bitstreamPolicy.getAction() && collectionPolicy.getGroup().equals(bitstreamPolicy.getGroup())) - { + if (collectionPolicy.getAction() == bitstreamPolicy.getAction() && collectionPolicy.getGroup().equals( + bitstreamPolicy.getGroup())) { exists = true; } } @@ -639,8 +627,7 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of replaceAllBitstreamPolicies method, of class Bundle. */ @Test - public void testReplaceAllBitstreamPolicies() throws SQLException, AuthorizeException - { + public void testReplaceAllBitstreamPolicies() throws SQLException, AuthorizeException { List newpolicies = new ArrayList(); newpolicies.add(resourcePolicyService.create(context)); newpolicies.add(resourcePolicyService.create(context)); @@ -651,10 +638,8 @@ public class BundleTest extends AbstractDSpaceObjectTest assertTrue("testReplaceAllBitstreamPolicies 0", newpolicies.size() == bspolicies.size()); boolean equals = true; - for(int i=0; i < newpolicies.size() && equals; i++) - { - if(!newpolicies.contains(bspolicies.get(i))) - { + for (int i = 0; i < newpolicies.size() && equals; i++) { + if (!newpolicies.contains(bspolicies.get(i))) { equals = false; } } @@ -662,10 +647,8 @@ public class BundleTest extends AbstractDSpaceObjectTest bspolicies = bundleService.getBitstreamPolicies(context, b); boolean exists = true; - for(int i=0; bspolicies.size() > 0 && i < newpolicies.size() && exists; i++) - { - if(!bspolicies.contains(newpolicies.get(i))) - { + for (int i = 0; bspolicies.size() > 0 && i < newpolicies.size() && exists; i++) { + if (!bspolicies.contains(newpolicies.get(i))) { exists = false; } } @@ -676,8 +659,7 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of getBundlePolicies method, of class Bundle. */ @Test - public void testGetBundlePolicies() throws SQLException - { + public void testGetBundlePolicies() throws SQLException { //empty by default List bspolicies = bundleService.getBundlePolicies(context, b); assertTrue("testGetBundlePolicies 0", CollectionUtils.isNotEmpty(bspolicies)); @@ -687,23 +669,22 @@ public class BundleTest extends AbstractDSpaceObjectTest * Test of getBundlePolicies method, of class Bundle. */ @Test - public void testGetBitstreamPolicies() throws SQLException - { + public void testGetBitstreamPolicies() throws SQLException { //empty by default List bspolicies = bundleService.getBitstreamPolicies(context, b); assertTrue("testGetBitstreamPolicies 0", bspolicies.isEmpty()); } @Test - public void testSetOrder() throws SQLException, AuthorizeException, FileNotFoundException, IOException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testSetOrder() throws SQLException, AuthorizeException, FileNotFoundException, IOException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Bundle ADD perms authorizeService.authorizeAction((Context) any, (Bundle) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Bitstream) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; // Create three Bitstreams to test ordering with. Give them different names @@ -730,7 +711,7 @@ public class BundleTest extends AbstractDSpaceObjectTest UUID bsID3 = bs3.getID(); // Now define a new order and call setOrder() - UUID[] newBitstreamOrder = new UUID[] { bsID3, bsID1, bsID2 }; + UUID[] newBitstreamOrder = new UUID[] {bsID3, bsID1, bsID2}; bundleService.setOrder(context, b, newBitstreamOrder); // Assert Bitstreams are in the new order @@ -741,7 +722,7 @@ public class BundleTest extends AbstractDSpaceObjectTest assertThat("testSetOrder: Bitstream 2 is now third", bitstreams[2].getName(), equalTo(bs2.getName())); // Now give only a partial list of bitstreams - newBitstreamOrder = new UUID[] { bsID1, bsID2 }; + newBitstreamOrder = new UUID[] {bsID1, bsID2}; bundleService.setOrder(context, b, newBitstreamOrder); // Assert Bitstream order is unchanged @@ -749,7 +730,7 @@ public class BundleTest extends AbstractDSpaceObjectTest assertThat("testSetOrder: Partial data doesn't change order", bitstreamsAfterPartialData, equalTo(bitstreams)); // Now give bad data in the list of bitstreams - newBitstreamOrder = new UUID[] { bsID1, null, bsID2 }; + newBitstreamOrder = new UUID[] {bsID1, null, bsID2}; bundleService.setOrder(context, b, newBitstreamOrder); // Assert Bitstream order is unchanged @@ -762,11 +743,12 @@ public class BundleTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetAdminObject() throws SQLException - { + public void testGetAdminObject() throws SQLException { //default bundle has no admin object - assertThat("testGetAdminObject 0", bundleService.getAdminObject(context, b, Constants.REMOVE), instanceOf(Item.class)); - assertThat("testGetAdminObject 1", bundleService.getAdminObject(context, b, Constants.ADD), instanceOf(Item.class)); + assertThat("testGetAdminObject 0", bundleService.getAdminObject(context, b, Constants.REMOVE), + instanceOf(Item.class)); + assertThat("testGetAdminObject 1", bundleService.getAdminObject(context, b, Constants.ADD), + instanceOf(Item.class)); } /** @@ -774,8 +756,7 @@ public class BundleTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetParentObject() throws SQLException - { + public void testGetParentObject() throws SQLException { //default bundle has no parent assertThat("testGetParentObject 0", bundleService.getParentObject(context, b), notNullValue()); assertThat("testGetParentObject 0", bundleService.getParentObject(context, b), instanceOf(Item.class)); diff --git a/dspace-api/src/test/java/org/dspace/content/CollectionTest.java b/dspace-api/src/test/java/org/dspace/content/CollectionTest.java index 28e9d1a27f..1e05353dcf 100644 --- a/dspace-api/src/test/java/org/dspace/content/CollectionTest.java +++ b/dspace-api/src/test/java/org/dspace/content/CollectionTest.java @@ -7,6 +7,23 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + import mockit.NonStrictExpectations; import org.apache.log4j.Logger; import org.dspace.app.util.AuthorizeUtil; @@ -21,25 +38,16 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - /** * Unit Tests for class Collection + * * @author pvillega */ -public class CollectionTest extends AbstractDSpaceObjectTest -{ +public class CollectionTest extends AbstractDSpaceObjectTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(CollectionTest.class); private LicenseService licenseService = CoreServiceFactory.getInstance().getLicenseService(); @@ -60,11 +68,9 @@ public class CollectionTest extends AbstractDSpaceObjectTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { //we have to create a new community in the database context.turnOffAuthorisationSystem(); this.owningCommunity = communityService.create(null, context); @@ -72,14 +78,10 @@ public class CollectionTest extends AbstractDSpaceObjectTest this.dspaceObject = collection; //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -94,16 +96,14 @@ public class CollectionTest extends AbstractDSpaceObjectTest */ @After @Override - public void destroy() - { + public void destroy() { try { - if(collection != null){ + if (collection != null) { context.turnOffAuthorisationSystem(); collectionService.update(context, collection); communityService.update(context, owningCommunity); collection = collectionService.find(context, collection.getID()); - if(collection != null) - { + if (collection != null) { collectionService.delete(context, collection); communityService.delete(context, communityService.find(context, owningCommunity.getID())); } @@ -127,10 +127,9 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of find method, of class Collection. */ @Test - public void testCollectionFind() throws Exception - { + public void testCollectionFind() throws Exception { UUID id = collection.getID(); - Collection found = collectionService.find(context, id); + Collection found = collectionService.find(context, id); assertThat("testCollectionFind 0", found, notNullValue()); assertThat("testCollectionFind 1", found.getID(), equalTo(id)); //the community created by default has no name @@ -141,12 +140,11 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of create method, of class Collection. */ @Test - public void testCreate() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreate() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; Collection created = collectionService.create(context, owningCommunity); @@ -154,16 +152,15 @@ public class CollectionTest extends AbstractDSpaceObjectTest assertThat("testCreate 1", created.getName(), equalTo("")); } - /** + /** * Test of create method (with specified valid handle), of class Collection */ @Test - public void testCreateWithValidHandle() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateWithValidHandle() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; // test creating collection with a specified handle which is NOT already in use @@ -176,16 +173,15 @@ public class CollectionTest extends AbstractDSpaceObjectTest } - /** + /** * Test of create method (with specified invalid handle), of class Collection. */ - @Test(expected=IllegalStateException.class) - public void testCreateWithInvalidHandle() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = IllegalStateException.class) + public void testCreateWithInvalidHandle() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; //get handle of our default created collection @@ -202,29 +198,25 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of findAll method, of class Collection. */ @Test - public void testFindAll() throws Exception - { + public void testFindAll() throws Exception { List all = collectionService.findAll(context); assertThat("testFindAll 0", all, notNullValue()); assertTrue("testFindAll 1", all.size() >= 1); boolean added = false; - for(Collection cl: all) - { - if(cl.equals(collection)) - { + for (Collection cl : all) { + if (cl.equals(collection)) { added = true; } } - assertTrue("testFindAll 2",added); + assertTrue("testFindAll 2", added); } /** * Test of getItems method, of class Collection. */ @Test - public void testGetItems() throws Exception - { + public void testGetItems() throws Exception { Iterator items = itemService.findByCollection(context, collection); assertThat("testGetItems 0", items, notNullValue()); //by default is empty @@ -235,8 +227,7 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of getAllItems method, of class Collection. */ @Test - public void testGetAllItems() throws Exception - { + public void testGetAllItems() throws Exception { Iterator items = itemService.findByCollection(context, collection); assertThat("testGetAllItems 0", items, notNullValue()); //by default is empty @@ -248,21 +239,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetID() - { + public void testGetID() { assertTrue("testGetID 0", collection.getID() != null); } @Test - public void testLegacyID() { assertTrue("testGetLegacyID 0", collection.getLegacyId() == null);} + public void testLegacyID() { + assertTrue("testGetLegacyID 0", collection.getLegacyId() == null); + } /** * Test of getHandle method, of class Collection. */ @Test @Override - public void testGetHandle() - { + public void testGetHandle() { //default instance has a random handle assertTrue("testGetHandle 0", collection.getHandle().contains("123456789/")); } @@ -271,16 +262,16 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of getMetadata method, of class Collection. */ @Test - public void testGetMetadata() - { + public void testGetMetadata() { //by default all empty values will return "" - assertThat("testGetMetadata 0",collectionService.getMetadata(collection, "name"), equalTo("")); - assertThat("testGetMetadata 1",collectionService.getMetadata(collection, "short_description"), equalTo("")); - assertThat("testGetMetadata 2",collectionService.getMetadata(collection, "introductory_text"), equalTo("")); - assertThat("testGetMetadata 4",collectionService.getMetadata(collection, "copyright_text"), equalTo("")); - assertThat("testGetMetadata 6",collectionService.getMetadata(collection, "provenance_description"), equalTo("")); - assertThat("testGetMetadata 7",collectionService.getMetadata(collection, "side_bar_text"), equalTo("")); - assertThat("testGetMetadata 8",collectionService.getMetadata(collection, "license"), equalTo("")); + assertThat("testGetMetadata 0", collectionService.getMetadata(collection, "name"), equalTo("")); + assertThat("testGetMetadata 1", collectionService.getMetadata(collection, "short_description"), equalTo("")); + assertThat("testGetMetadata 2", collectionService.getMetadata(collection, "introductory_text"), equalTo("")); + assertThat("testGetMetadata 4", collectionService.getMetadata(collection, "copyright_text"), equalTo("")); + assertThat("testGetMetadata 6", collectionService.getMetadata(collection, "provenance_description"), + equalTo("")); + assertThat("testGetMetadata 7", collectionService.getMetadata(collection, "side_bar_text"), equalTo("")); + assertThat("testGetMetadata 8", collectionService.getMetadata(collection, "license"), equalTo("")); } /** @@ -305,13 +296,14 @@ public class CollectionTest extends AbstractDSpaceObjectTest collectionService.setMetadata(context, collection, "provenance_description", provDesc); collectionService.setMetadata(context, collection, "license", license); - assertThat("testSetMetadata 0",collectionService.getMetadata(collection, "name"), equalTo(name)); - assertThat("testSetMetadata 1",collectionService.getMetadata(collection, "short_description"), equalTo(sdesc)); - assertThat("testSetMetadata 2",collectionService.getMetadata(collection, "introductory_text"), equalTo(itext)); - assertThat("testSetMetadata 4",collectionService.getMetadata(collection, "copyright_text"), equalTo(copy)); - assertThat("testSetMetadata 5",collectionService.getMetadata(collection, "side_bar_text"), equalTo(sidebar)); - assertThat("testGetMetadata 7",collectionService.getMetadata(collection, "provenance_description"), equalTo(provDesc)); - assertThat("testGetMetadata 8",collectionService.getMetadata(collection, "license"), equalTo(license)); + assertThat("testSetMetadata 0", collectionService.getMetadata(collection, "name"), equalTo(name)); + assertThat("testSetMetadata 1", collectionService.getMetadata(collection, "short_description"), equalTo(sdesc)); + assertThat("testSetMetadata 2", collectionService.getMetadata(collection, "introductory_text"), equalTo(itext)); + assertThat("testSetMetadata 4", collectionService.getMetadata(collection, "copyright_text"), equalTo(copy)); + assertThat("testSetMetadata 5", collectionService.getMetadata(collection, "side_bar_text"), equalTo(sidebar)); + assertThat("testGetMetadata 7", collectionService.getMetadata(collection, "provenance_description"), + equalTo(provDesc)); + assertThat("testGetMetadata 8", collectionService.getMetadata(collection, "license"), equalTo(license)); } /** @@ -319,152 +311,155 @@ public class CollectionTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetName() - { + public void testGetName() { //by default is empty - assertThat("testGetName 0",collection.getName(), equalTo("")); + assertThat("testGetName 0", collection.getName(), equalTo("")); } /** * Test of getLogo method, of class Collection. */ @Test - public void testGetLogo() - { + public void testGetLogo() { //by default is empty - assertThat("testGetLogo 0",collection.getLogo(), nullValue()); + assertThat("testGetLogo 0", collection.getLogo(), nullValue()); } /** * Test of setLogo method, of class Collection. */ @Test - public void testSetLogoAuth() throws Exception - { + public void testSetLogoAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; File f = new File(testProps.get("test.bitstream").toString()); Bitstream logo = collectionService.setLogo(context, collection, new FileInputStream(f)); - assertThat("testSetLogoAuth 0",collection.getLogo(), equalTo(logo)); + assertThat("testSetLogoAuth 0", collection.getLogo(), equalTo(logo)); collection.setLogo(null); - assertThat("testSetLogoAuth 1",collection.getLogo(), nullValue()); + assertThat("testSetLogoAuth 1", collection.getLogo(), nullValue()); } /** * Test of setLogo method, of class Collection. */ @Test - public void testSetLogoAuth2() throws Exception - { + public void testSetLogoAuth2() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; File f = new File(testProps.get("test.bitstream").toString()); Bitstream logo = collectionService.setLogo(context, collection, new FileInputStream(f)); - assertThat("testSetLogoAuth2 0",collection.getLogo(), equalTo(logo)); + assertThat("testSetLogoAuth2 0", collection.getLogo(), equalTo(logo)); collection.setLogo(null); - assertThat("testSetLogoAuth2 1",collection.getLogo(), nullValue()); + assertThat("testSetLogoAuth2 1", collection.getLogo(), nullValue()); } /** * Test of setLogo method, of class Collection. */ @Test - public void testSetLogoAuth3() throws Exception - { + public void testSetLogoAuth3() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; File f = new File(testProps.get("test.bitstream").toString()); Bitstream logo = collectionService.setLogo(context, collection, new FileInputStream(f)); - assertThat("testSetLogoAuth3 0",collection.getLogo(), equalTo(logo)); + assertThat("testSetLogoAuth3 0", collection.getLogo(), equalTo(logo)); collection.setLogo(null); - assertThat("testSetLogoAuth3 1",collection.getLogo(), nullValue()); + assertThat("testSetLogoAuth3 1", collection.getLogo(), nullValue()); } /** * Test of setLogo method, of class Collection. */ @Test - public void testSetLogoAuth4() throws Exception - { + public void testSetLogoAuth4() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; File f = new File(testProps.get("test.bitstream").toString()); Bitstream logo = collectionService.setLogo(context, collection, new FileInputStream(f)); - assertThat("testSetLogoAuth4 0",collection.getLogo(), equalTo(logo)); + assertThat("testSetLogoAuth4 0", collection.getLogo(), equalTo(logo)); collection.setLogo(null); - assertThat("testSetLogoAuth4 1",collection.getLogo(), nullValue()); + assertThat("testSetLogoAuth4 1", collection.getLogo(), nullValue()); } /** * Test of setLogo method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testSetLogoNoAuth() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testSetLogoNoAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = new AuthorizeException(); + Constants.WRITE, true); + result = new AuthorizeException(); }}; File f = new File(testProps.get("test.bitstream").toString()); @@ -476,13 +471,11 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of createWorkflowGroup method, of class Collection. */ @Test - public void testCreateWorkflowGroupAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testCreateWorkflowGroupAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage WorkflowsGroup perms AuthorizeUtil.authorizeManageWorkflowsGroup((Context) any, (Collection) any); - result = null; + result = null; }}; int step = 1; @@ -493,14 +486,12 @@ public class CollectionTest extends AbstractDSpaceObjectTest /** * Test of createWorkflowGroup method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testCreateWorkflowGroupNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateWorkflowGroupNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Disallow manage WorkflowsGroup perms AuthorizeUtil.authorizeManageWorkflowsGroup((Context) any, (Collection) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; int step = 1; @@ -512,17 +503,16 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of setWorkflowGroup method, of class Collection. */ @Test - public void testSetWorkflowGroup() throws SQLException, AuthorizeException - { + public void testSetWorkflowGroup() throws SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); //must be an Admin to create a Group int step = 1; Group g = groupService.create(context); context.restoreAuthSystemState(); collection.setWorkflowGroup(context, step, g); - assertThat("testSetWorkflowGroup 0",collectionService.getWorkflowGroup(collection, step), notNullValue()); - assertThat("testSetWorkflowGroup 1",collectionService.getWorkflowGroup(collection, step), equalTo(g)); + assertThat("testSetWorkflowGroup 0", collectionService.getWorkflowGroup(collection, step), notNullValue()); + assertThat("testSetWorkflowGroup 1", collectionService.getWorkflowGroup(collection, step), equalTo(g)); } - + /** * Test of setWorkflowGroup method, of class Collection. * The setWorkflowGroup ajust the policies for the basic Workflow. This test @@ -530,8 +520,7 @@ public class CollectionTest extends AbstractDSpaceObjectTest * thrown during these adjustments. */ @Test - public void testChangeWorkflowGroup() throws SQLException, AuthorizeException - { + public void testChangeWorkflowGroup() throws SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); //must be an Admin to create a Group int step = 1; Group g1 = groupService.create(context); @@ -539,49 +528,44 @@ public class CollectionTest extends AbstractDSpaceObjectTest context.restoreAuthSystemState(); collection.setWorkflowGroup(context, step, g1); collection.setWorkflowGroup(context, step, g2); - assertThat("testSetWorkflowGroup 0",collectionService.getWorkflowGroup(collection, step), notNullValue()); - assertThat("testSetWorkflowGroup 1",collectionService.getWorkflowGroup(collection, step), equalTo(g2)); + assertThat("testSetWorkflowGroup 0", collectionService.getWorkflowGroup(collection, step), notNullValue()); + assertThat("testSetWorkflowGroup 1", collectionService.getWorkflowGroup(collection, step), equalTo(g2)); } /** * Test of getWorkflowGroup method, of class Collection. */ @Test - public void testGetWorkflowGroup() - { + public void testGetWorkflowGroup() { //null by default int step = 1; - assertThat("testGetWorkflowGroup 0",collectionService.getWorkflowGroup(collection, step), nullValue()); + assertThat("testGetWorkflowGroup 0", collectionService.getWorkflowGroup(collection, step), nullValue()); } /** * Test of createSubmitters method, of class Collection. */ @Test - public void testCreateSubmittersAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testCreateSubmittersAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage SubmittersGroup perms AuthorizeUtil.authorizeManageSubmittersGroup((Context) any, (Collection) any); - result = null; + result = null; }}; Group result = collectionService.createSubmitters(context, collection); - assertThat("testCreateSubmittersAuth 0",result, notNullValue()); + assertThat("testCreateSubmittersAuth 0", result, notNullValue()); } /** * Test of createSubmitters method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testCreateSubmittersNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateSubmittersNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Disallow manage SubmittersGroup perms AuthorizeUtil.authorizeManageSubmittersGroup((Context) any, (Collection) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; Group result = collectionService.createSubmitters(context, collection); @@ -592,13 +576,11 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of removeSubmitters method, of class Collection. */ @Test - public void testRemoveSubmittersAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testRemoveSubmittersAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage SubmittersGroup perms AuthorizeUtil.authorizeManageSubmittersGroup((Context) any, (Collection) any); - result = null; + result = null; }}; collectionService.removeSubmitters(context, collection); @@ -608,14 +590,12 @@ public class CollectionTest extends AbstractDSpaceObjectTest /** * Test of removeSubmitters method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testRemoveSubmittersNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveSubmittersNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Disallow manage SubmittersGroup perms AuthorizeUtil.authorizeManageSubmittersGroup((Context) any, (Collection) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; collectionService.removeSubmitters(context, collection); @@ -626,8 +606,7 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of getSubmitters method, of class Collection. */ @Test - public void testGetSubmitters() - { + public void testGetSubmitters() { assertThat("testGetSubmitters 0", collection.getSubmitters(), nullValue()); } @@ -635,13 +614,11 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of createAdministrators method, of class Collection. */ @Test - public void testCreateAdministratorsAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testCreateAdministratorsAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage AdminGroup perms AuthorizeUtil.authorizeManageAdminGroup((Context) any, (Collection) any); - result = null; + result = null; }}; Group result = collectionService.createAdministrators(context, collection); @@ -651,14 +628,12 @@ public class CollectionTest extends AbstractDSpaceObjectTest /** * Test of createAdministrators method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testCreateAdministratorsNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateAdministratorsNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Disallow manage AdminGroup perms AuthorizeUtil.authorizeManageAdminGroup((Context) any, (Collection) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; Group result = collectionService.createAdministrators(context, collection); @@ -669,22 +644,20 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of removeAdministrators method, of class Collection. */ @Test - public void testRemoveAdministratorsAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testRemoveAdministratorsAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage AdminGroup perms (needed to possibly create group first) AuthorizeUtil.authorizeManageAdminGroup((Context) any, (Collection) any); - result = null; + result = null; // Allow remove AdminGroup perms AuthorizeUtil.authorizeRemoveAdminGroup((Context) any, (Collection) any); - result = null; + result = null; }}; // Ensure admin group is created first Group result = collectionService.createAdministrators(context, collection); - assertThat("testRemoveAdministratorsAuth 0",collection.getAdministrators(), notNullValue()); - assertThat("testRemoveAdministratorsAuth 1",collection.getAdministrators(), equalTo(result)); + assertThat("testRemoveAdministratorsAuth 0", collection.getAdministrators(), notNullValue()); + assertThat("testRemoveAdministratorsAuth 1", collection.getAdministrators(), equalTo(result)); collectionService.removeAdministrators(context, collection); assertThat("testRemoveAdministratorsAuth 2", collection.getAdministrators(), nullValue()); } @@ -692,23 +665,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest /** * Test of removeAdministrators method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testRemoveAdministratorsNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveAdministratorsNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage AdminGroup perms (needed to possibly create group first) AuthorizeUtil.authorizeManageAdminGroup((Context) any, (Collection) any); - result = null; + result = null; // Disallow remove AdminGroup perms AuthorizeUtil.authorizeRemoveAdminGroup((Context) any, (Collection) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; // Ensure admin group is created first Group result = collectionService.createAdministrators(context, collection); - assertThat("testRemoveAdministratorsAuth 0",collection.getAdministrators(), notNullValue()); - assertThat("testRemoveAdministratorsAuth 1",collection.getAdministrators(), equalTo(result)); + assertThat("testRemoveAdministratorsAuth 0", collection.getAdministrators(), notNullValue()); + assertThat("testRemoveAdministratorsAuth 1", collection.getAdministrators(), equalTo(result)); collectionService.removeAdministrators(context, collection); fail("Exception expected"); } @@ -717,8 +688,7 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of getAdministrators method, of class Collection. */ @Test - public void testGetAdministrators() - { + public void testGetAdministrators() { assertThat("testGetAdministrators 0", collection.getAdministrators(), nullValue()); } @@ -726,18 +696,17 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of getLicense method, of class Collection. */ @Test - public void testGetLicense() - { + public void testGetLicense() { assertThat("testGetLicense 0", collectionService.getLicense(collection), notNullValue()); - assertThat("testGetLicense 1", collectionService.getLicense(collection), equalTo(licenseService.getDefaultSubmissionLicense())); + assertThat("testGetLicense 1", collectionService.getLicense(collection), + equalTo(licenseService.getDefaultSubmissionLicense())); } /** * Test of getLicenseCollection method, of class Collection. */ @Test - public void testGetLicenseCollection() - { + public void testGetLicenseCollection() { assertThat("testGetLicenseCollection 0", collection.getLicenseCollection(), notNullValue()); assertThat("testGetLicenseCollection 1", collection.getLicenseCollection(), equalTo("")); } @@ -746,8 +715,7 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of hasCustomLicense method, of class Collection. */ @Test - public void testHasCustomLicense() - { + public void testHasCustomLicense() { assertFalse("testHasCustomLicense 0", collectionService.hasCustomLicense(collection)); } @@ -768,8 +736,7 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of getTemplateItem method, of class Collection. */ @Test - public void testGetTemplateItem() throws Exception - { + public void testGetTemplateItem() throws Exception { assertThat("testGetTemplateItem 0", collection.getTemplateItem(), nullValue()); } @@ -777,30 +744,26 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of createTemplateItem method, of class Collection. */ @Test - public void testCreateTemplateItemAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testCreateTemplateItemAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage TemplateItem perms AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = null; + result = null; }}; itemService.createTemplateItem(context, collection); - assertThat("testCreateTemplateItemAuth 0",collection.getTemplateItem(), notNullValue()); + assertThat("testCreateTemplateItemAuth 0", collection.getTemplateItem(), notNullValue()); } /** * Test of createTemplateItem method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testCreateTemplateItemNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateTemplateItemNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Disallow manage TemplateItem perms AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; itemService.createTemplateItem(context, collection); @@ -811,30 +774,26 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of removeTemplateItem method, of class Collection. */ @Test - public void testRemoveTemplateItemAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testRemoveTemplateItemAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage TemplateItem perms AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = null; + result = null; }}; collectionService.removeTemplateItem(context, collection); - assertThat("testRemoveTemplateItemAuth 0",collection.getTemplateItem(), nullValue()); + assertThat("testRemoveTemplateItemAuth 0", collection.getTemplateItem(), nullValue()); } /** * Test of removeTemplateItem method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testRemoveTemplateItemNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveTemplateItemNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Disallow manage TemplateItem perms AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; collectionService.removeTemplateItem(context, collection); @@ -845,15 +804,15 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of addItem method, of class Collection. */ @Test - public void testAddItemAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testAddItemAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Collection ADD permissions authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, false); @@ -861,27 +820,24 @@ public class CollectionTest extends AbstractDSpaceObjectTest collectionService.addItem(context, collection, item); boolean added = false; Iterator ii = itemService.findByCollection(context, collection); - while(ii.hasNext()) - { - if(ii.next().equals(item)) - { + while (ii.hasNext()) { + if (ii.next().equals(item)) { added = true; } } - assertTrue("testAddItemAuth 0",added); + assertTrue("testAddItemAuth 0", added); } /** * Test of addItem method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testAddItemNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testAddItemNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Collection ADD permissions authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); }}; WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, false); @@ -894,19 +850,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of removeItem method, of class Collection. */ @Test - public void testRemoveItemAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRemoveItemAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Collection ADD/REMOVE permissions authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.REMOVE); result = null; + Constants.REMOVE); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.DELETE); result = null; + Constants.DELETE); + result = null; }}; WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, false); @@ -916,30 +874,28 @@ public class CollectionTest extends AbstractDSpaceObjectTest collectionService.removeItem(context, collection, item); boolean isthere = false; Iterator ii = itemService.findByCollection(context, collection); - while(ii.hasNext()) - { - if(ii.next().equals(item)) - { + while (ii.hasNext()) { + if (ii.next().equals(item)) { isthere = true; } } - assertFalse("testRemoveItemAuth 0",isthere); + assertFalse("testRemoveItemAuth 0", isthere); } /** * Test of removeItem method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testRemoveItemNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveItemNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Collection ADD permissions authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Disallow Collection REMOVE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.REMOVE); result = new AuthorizeException(); + Constants.REMOVE); + result = new AuthorizeException(); }}; WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, false); @@ -954,20 +910,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of update method, of class Collection. */ @Test - public void testUpdateAuth() throws Exception - { + public void testUpdateAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TODO: how to check update? @@ -978,20 +935,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of update method, of class Collection. */ @Test - public void testUpdateAuth2() throws Exception - { + public void testUpdateAuth2() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TODO: how to check update? @@ -1002,20 +960,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of update method, of class Collection. */ @Test - public void testUpdateAuth3() throws Exception - { + public void testUpdateAuth3() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TODO: how to check update? @@ -1026,20 +985,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of update method, of class Collection. */ @Test - public void testUpdateAuth4() throws Exception - { + public void testUpdateAuth4() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TODO: how to check update? @@ -1049,21 +1009,22 @@ public class CollectionTest extends AbstractDSpaceObjectTest /** * Test of update method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testUpdateNoAuth() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testUpdateNoAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = new AuthorizeException(); + Constants.WRITE, true); + result = new AuthorizeException(); }}; collectionService.update(context, collection); @@ -1074,20 +1035,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth() throws Exception - { + public void testCanEditBooleanAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth 0", collectionService.canEditBoolean(context, collection)); @@ -1097,20 +1059,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth2() throws Exception - { + public void testCanEditBooleanAuth2() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth2 0", collectionService.canEditBoolean(context, collection)); @@ -1120,20 +1083,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth3() throws Exception - { + public void testCanEditBooleanAuth3() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth3 0", collectionService.canEditBoolean(context, collection)); @@ -1143,20 +1107,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth4() throws Exception - { + public void testCanEditBooleanAuth4() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth4 0", collectionService.canEditBoolean(context, collection)); @@ -1166,20 +1131,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanNoAuth() throws Exception - { + public void testCanEditBooleanNoAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = new AuthorizeException(); + Constants.WRITE, true); + result = new AuthorizeException(); }}; assertFalse("testCanEditBooleanNoAuth 0", collectionService.canEditBoolean(context, collection)); @@ -1189,20 +1155,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth_boolean() throws Exception - { + public void testCanEditBooleanAuth_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth_boolean 0", collectionService.canEditBoolean(context, collection, true)); @@ -1212,20 +1179,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth2_boolean() throws Exception - { + public void testCanEditBooleanAuth2_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth2_boolean 0", collectionService.canEditBoolean(context, collection, true)); @@ -1235,20 +1203,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth3_boolean() throws Exception - { + public void testCanEditBooleanAuth3_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth3_boolean 0", collectionService.canEditBoolean(context, collection, true)); @@ -1258,20 +1227,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth4_boolean() throws Exception - { + public void testCanEditBooleanAuth4_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth4_boolean 0", collectionService.canEditBoolean(context, collection, true)); @@ -1281,20 +1251,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth5_boolean() throws Exception - { + public void testCanEditBooleanAuth5_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = true; + Constants.ADD, false); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = true; + Constants.WRITE, false); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; assertTrue("testCanEditBooleanAuth5_boolean 0", collectionService.canEditBoolean(context, collection, false)); @@ -1304,20 +1275,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth6_boolean() throws Exception - { + public void testCanEditBooleanAuth6_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = false; + Constants.ADD, false); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = true; + Constants.WRITE, false); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; assertTrue("testCanEditBooleanAuth6_boolean 0", collectionService.canEditBoolean(context, collection, false)); @@ -1327,20 +1299,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth7_boolean() throws Exception - { + public void testCanEditBooleanAuth7_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = true; + Constants.ADD, false); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = false; + Constants.WRITE, false); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; assertTrue("testCanEditBooleanAuth7_boolean 0", collectionService.canEditBoolean(context, collection, false)); @@ -1350,20 +1323,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanAuth8_boolean() throws Exception - { + public void testCanEditBooleanAuth8_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = false; + Constants.ADD, false); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = false; + Constants.WRITE, false); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; assertTrue("testCanEditBooleanAuth8_boolean 0", collectionService.canEditBoolean(context, collection, false)); @@ -1373,66 +1347,69 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanNoAuth_boolean() throws Exception - { + public void testCanEditBooleanNoAuth_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = new AuthorizeException(); + Constants.WRITE, true); + result = new AuthorizeException(); }}; - assertFalse("testCanEditBooleanNoAuth_boolean 0",collectionService.canEditBoolean(context, collection, true)); + assertFalse("testCanEditBooleanNoAuth_boolean 0", collectionService.canEditBoolean(context, collection, true)); } /** * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditBooleanNoAuth2_boolean() throws Exception - { + public void testCanEditBooleanNoAuth2_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = false; + Constants.ADD, false); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = false; + Constants.WRITE, false); + result = false; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = new AuthorizeException(); + Constants.WRITE, false); + result = new AuthorizeException(); }}; - assertFalse("testCanEditBooleanNoAuth_boolean 0",collectionService.canEditBoolean(context, collection, false)); + assertFalse("testCanEditBooleanNoAuth_boolean 0", collectionService.canEditBoolean(context, collection, false)); } /** * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth_0args() throws Exception - { + public void testCanEditAuth_0args() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TODO: how to check?? @@ -1443,20 +1420,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth2_0args() throws Exception - { + public void testCanEditAuth2_0args() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TODO: how to check?? @@ -1467,20 +1445,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth3_0args() throws Exception - { + public void testCanEditAuth3_0args() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TODO: how to check?? @@ -1491,20 +1470,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth4_0args() throws Exception - { + public void testCanEditAuth4_0args() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TODO: how to check?? @@ -1514,21 +1494,22 @@ public class CollectionTest extends AbstractDSpaceObjectTest /** * Test of canEditBoolean method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testCanEditNoAuth_0args() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testCanEditNoAuth_0args() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = new AuthorizeException(); + Constants.WRITE, true); + result = new AuthorizeException(); }}; collectionService.canEdit(context, collection); @@ -1539,20 +1520,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth_boolean() throws Exception - { + public void testCanEditAuth_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TOO: how to check? @@ -1563,20 +1545,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth2_boolean() throws Exception - { + public void testCanEditAuth2_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TOO: how to check? @@ -1587,20 +1570,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth3_boolean() throws Exception - { + public void testCanEditAuth3_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TOO: how to check? @@ -1611,20 +1595,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth4_boolean() throws Exception - { + public void testCanEditAuth4_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; //TOO: how to check? @@ -1635,20 +1620,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth5_boolean() throws Exception - { + public void testCanEditAuth5_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = true; + Constants.ADD, false); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = true; + Constants.WRITE, false); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; //TOO: how to check? @@ -1659,20 +1645,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth6_boolean() throws Exception - { + public void testCanEditAuth6_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = false; + Constants.ADD, false); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = true; + Constants.WRITE, false); + result = true; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; //TOO: how to check? @@ -1683,20 +1670,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth7_boolean() throws Exception - { + public void testCanEditAuth7_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = true; + Constants.ADD, false); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = false; + Constants.WRITE, false); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; //TOO: how to check? @@ -1707,20 +1695,21 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Collection. */ @Test - public void testCanEditAuth8_boolean() throws Exception - { + public void testCanEditAuth8_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = false; + Constants.ADD, false); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = false; + Constants.WRITE, false); + result = false; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; //TOO: how to check? @@ -1730,21 +1719,22 @@ public class CollectionTest extends AbstractDSpaceObjectTest /** * Test of canEditBoolean method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testCanEditNoAuth_boolean() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testCanEditNoAuth_boolean() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = false; + Constants.ADD, true); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = false; + Constants.WRITE, true); + result = false; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = new AuthorizeException(); + Constants.WRITE, true); + result = new AuthorizeException(); }}; //TOO: how to check? @@ -1755,21 +1745,22 @@ public class CollectionTest extends AbstractDSpaceObjectTest /** * Test of canEditBoolean method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testCanEditNoAuth2_boolean() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testCanEditNoAuth2_boolean() throws Exception { // Test permissions with inheritance turned *OFF* - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = false; + Constants.ADD, false); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, false); result = false; + Constants.WRITE, false); + result = false; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = new AuthorizeException(); + Constants.WRITE, false); + result = new AuthorizeException(); }}; //TOO: how to check? @@ -1781,58 +1772,55 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of delete method, of class Collection. */ @Test - public void testDeleteAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class, authorizeService.getClass()) - {{ + public void testDeleteAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class, authorizeService.getClass()) {{ // Allow manage TemplateItem perms AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = null; + result = null; // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, anyBoolean); result = null; + Constants.WRITE, anyBoolean); + result = null; }}; UUID id = collection.getID(); collectionService.delete(context, collection); collection = collectionService.find(context, id); - assertThat("testDelete 0", collection,nullValue()); + assertThat("testDelete 0", collection, nullValue()); } /** * Test of delete method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testDeleteNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class, authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testDeleteNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class, authorizeService.getClass()) {{ // Disallow manage TemplateItem perms AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = new AuthorizeException(); + result = new AuthorizeException(); // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, anyBoolean); result = null; + Constants.WRITE, anyBoolean); + result = null; }}; collectionService.delete(context, collection); fail("Exception expected"); } - /** + /** * Test of delete method, of class Collection. */ - @Test(expected=AuthorizeException.class) - public void testDeleteNoAuth2() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class, authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testDeleteNoAuth2() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class, authorizeService.getClass()) {{ // Allow manage TemplateItem perms AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = null; + result = null; // Disallow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, anyBoolean); result = new AuthorizeException(); + Constants.WRITE, anyBoolean); + result = new AuthorizeException(); }}; collectionService.delete(context, collection); @@ -1843,24 +1831,26 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of getCommunities method, of class Collection. */ @Test - public void testGetCommunities() throws Exception - { + public void testGetCommunities() throws Exception { context.turnOffAuthorisationSystem(); Community community = communityService.create(null, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "community 3"); + communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "community 3"); this.collection.addCommunity(community); community = communityService.create(null, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "community 1"); + communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "community 1"); this.collection.addCommunity(community); community = communityService.create(null, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "community 2"); + communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "community 2"); this.collection.addCommunity(community); context.restoreAuthSystemState(); - assertTrue("testGetCommunities 0",collection.getCommunities().size() == 4); + assertTrue("testGetCommunities 0", collection.getCommunities().size() == 4); //Communities should be sorted by name - assertTrue("testGetCommunities 1",collection.getCommunities().get(1).getName().equals("community 1")); - assertTrue("testGetCommunities 1",collection.getCommunities().get(2).getName().equals("community 2")); - assertTrue("testGetCommunities 1",collection.getCommunities().get(3).getName().equals("community 3")); + assertTrue("testGetCommunities 1", collection.getCommunities().get(1).getName().equals("community 1")); + assertTrue("testGetCommunities 1", collection.getCommunities().get(2).getName().equals("community 2")); + assertTrue("testGetCommunities 1", collection.getCommunities().get(3).getName().equals("community 3")); } /** @@ -1868,15 +1858,14 @@ public class CollectionTest extends AbstractDSpaceObjectTest */ @Test @SuppressWarnings("ObjectEqualsNull") - public void testEquals() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testEquals() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; - assertFalse("testEquals 0",collection.equals(null)); - assertFalse("testEquals 1",collection.equals(collectionService.create(context, owningCommunity))); + assertFalse("testEquals 0", collection.equals(null)); + assertFalse("testEquals 1", collection.equals(collectionService.create(context, owningCommunity))); assertTrue("testEquals 2", collection.equals(collection)); } @@ -1885,8 +1874,7 @@ public class CollectionTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetType() - { + public void testGetType() { assertThat("testGetType 0", collection.getType(), equalTo(Constants.COLLECTION)); } @@ -1894,35 +1882,34 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of findAuthorized method, of class Collection. */ @Test - public void testFindAuthorized() throws Exception - { + public void testFindAuthorized() throws Exception { context.turnOffAuthorisationSystem(); Community com = communityService.create(null, context); context.restoreAuthSystemState(); List found = collectionService.findAuthorized(context, com, Constants.WRITE); - assertThat("testFindAuthorized 0",found,notNullValue()); - assertTrue("testFindAuthorized 1",found.size() == 0); + assertThat("testFindAuthorized 0", found, notNullValue()); + assertTrue("testFindAuthorized 1", found.size() == 0); found = collectionService.findAuthorized(context, null, Constants.WRITE); - assertThat("testFindAuthorized 2",found,notNullValue()); - assertTrue("testFindAuthorized 3",found.size() == 0); + assertThat("testFindAuthorized 2", found, notNullValue()); + assertTrue("testFindAuthorized 3", found.size() == 0); found = collectionService.findAuthorized(context, com, Constants.ADD); - assertThat("testFindAuthorized 3",found,notNullValue()); - assertTrue("testFindAuthorized 4",found.size() == 0); + assertThat("testFindAuthorized 3", found, notNullValue()); + assertTrue("testFindAuthorized 4", found.size() == 0); found = collectionService.findAuthorized(context, null, Constants.ADD); - assertThat("testFindAuthorized 5",found,notNullValue()); - assertTrue("testFindAuthorized 6",found.size() == 0); + assertThat("testFindAuthorized 5", found, notNullValue()); + assertTrue("testFindAuthorized 6", found.size() == 0); found = collectionService.findAuthorized(context, com, Constants.READ); - assertThat("testFindAuthorized 7",found,notNullValue()); - assertTrue("testFindAuthorized 8",found.size() == 0); + assertThat("testFindAuthorized 7", found, notNullValue()); + assertTrue("testFindAuthorized 8", found.size() == 0); found = collectionService.findAuthorized(context, null, Constants.READ); - assertThat("testFindAuthorized 9",found,notNullValue()); - assertTrue("testFindAuthorized 10",found.size() >= 1); + assertThat("testFindAuthorized 9", found, notNullValue()); + assertTrue("testFindAuthorized 10", found.size() >= 1); } /** @@ -1930,8 +1917,7 @@ public class CollectionTest extends AbstractDSpaceObjectTest * We create some collections and some users with varying auth, and ensure we can access them all properly. */ @Test - public void testFindAuthorizedOptimized() throws Exception - { + public void testFindAuthorizedOptimized() throws Exception { context.turnOffAuthorisationSystem(); Community com = communityService.create(null, context); Collection collectionA = collectionService.create(context, com); @@ -1995,11 +1981,10 @@ public class CollectionTest extends AbstractDSpaceObjectTest * Test of countItems method, of class Collection. */ @Test - public void testCountItems() throws Exception - { + public void testCountItems() throws Exception { //0 by default assertTrue("testCountItems 0", itemService.countItems(context, collection) == 0); - + //NOTE: a more thorough test of item counting is in ITCommunityCollection integration test } @@ -2008,13 +1993,18 @@ public class CollectionTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetAdminObject() throws SQLException - { + public void testGetAdminObject() throws SQLException { //default community has no admin object - assertThat("testGetAdminObject 0", (Collection)collectionService.getAdminObject(context, collection, Constants.REMOVE), equalTo(collection)); - assertThat("testGetAdminObject 1", (Collection)collectionService.getAdminObject(context, collection, Constants.ADD), equalTo(collection)); - assertThat("testGetAdminObject 2", collectionService.getAdminObject(context, collection, Constants.DELETE), instanceOf(Community.class)); - assertThat("testGetAdminObject 3", collectionService.getAdminObject(context, collection, Constants.ADMIN), instanceOf(Collection.class)); + assertThat("testGetAdminObject 0", + (Collection) collectionService.getAdminObject(context, collection, Constants.REMOVE), + equalTo(collection)); + assertThat("testGetAdminObject 1", + (Collection) collectionService.getAdminObject(context, collection, Constants.ADD), + equalTo(collection)); + assertThat("testGetAdminObject 2", collectionService.getAdminObject(context, collection, Constants.DELETE), + instanceOf(Community.class)); + assertThat("testGetAdminObject 3", collectionService.getAdminObject(context, collection, Constants.ADMIN), + instanceOf(Collection.class)); } /** @@ -2022,10 +2012,10 @@ public class CollectionTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetParentObject() throws SQLException - { + public void testGetParentObject() throws SQLException { assertThat("testGetParentObject 1", collectionService.getParentObject(context, collection), notNullValue()); - assertThat("testGetParentObject 2", (Community)collectionService.getParentObject(context, collection), equalTo(owningCommunity)); + assertThat("testGetParentObject 2", (Community) collectionService.getParentObject(context, collection), + equalTo(owningCommunity)); } } diff --git a/dspace-api/src/test/java/org/dspace/content/CommunityTest.java b/dspace-api/src/test/java/org/dspace/content/CommunityTest.java index 0a52ae63b5..65bf7f6f73 100644 --- a/dspace-api/src/test/java/org/dspace/content/CommunityTest.java +++ b/dspace-api/src/test/java/org/dspace/content/CommunityTest.java @@ -8,6 +8,22 @@ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileInputStream; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + import mockit.NonStrictExpectations; import org.apache.log4j.Logger; import org.dspace.app.util.AuthorizeUtil; @@ -19,23 +35,16 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.File; -import java.io.FileInputStream; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - /** * Unit Tests for class Community + * * @author pvillega */ -public class CommunityTest extends AbstractDSpaceObjectTest -{ +public class CommunityTest extends AbstractDSpaceObjectTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(CommunityTest.class); /** @@ -52,11 +61,9 @@ public class CommunityTest extends AbstractDSpaceObjectTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { // we have to create a new community in the database // and only Admins can create a top-level community context.turnOffAuthorisationSystem(); @@ -64,14 +71,10 @@ public class CommunityTest extends AbstractDSpaceObjectTest this.dspaceObject = c; //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -86,8 +89,7 @@ public class CommunityTest extends AbstractDSpaceObjectTest */ @After @Override - public void destroy() - { + public void destroy() { c = null; super.destroy(); } @@ -96,10 +98,9 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of find method, of class Community. */ @Test - public void testCommunityFind() throws Exception - { + public void testCommunityFind() throws Exception { UUID id = c.getID(); - Community found = communityService.find(context, id); + Community found = communityService.find(context, id); assertThat("testCommunityFind 0", found, notNullValue()); assertThat("testCommunityFind 1", found.getID(), equalTo(id)); //the community created by default has no name @@ -110,19 +111,20 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of create method, of class Community. */ @Test - public void testCreateAuth() throws Exception - { + public void testCreateAuth() throws Exception { //Default to Community-Admin Rights (but not full Admin rights) - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms (needed for addSubCommunity functionality) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow current Community ADD perms (needed to just create community) authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; // Disallow full Admin perms - authorizeService.isAdmin((Context) any); result = false; + authorizeService.isAdmin((Context) any); + result = false; }}; // test that a Community Admin can create a Community with parent (Sub-Community) @@ -135,20 +137,20 @@ public class CommunityTest extends AbstractDSpaceObjectTest } - /** + /** * Test of create method, of class Community. */ @Test - public void testCreateAuth2() throws Exception - { + public void testCreateAuth2() throws Exception { //Default to Admin Rights, but NOT Community Admin Rights - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Allow full Admin perms - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; //Test that a full Admin can create a Community without a parent (Top-Level Community) @@ -169,17 +171,17 @@ public class CommunityTest extends AbstractDSpaceObjectTest /** * Test of create method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testCreateNoAuth() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testCreateNoAuth() throws Exception { //Default to NO Admin Rights, and NO Community Admin Rights - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Disallow full Admin perms - authorizeService.isAdmin((Context) any); result = false; + authorizeService.isAdmin((Context) any); + result = false; }}; // test creating community with no parent (as a non-admin & non-Community Admin) @@ -188,20 +190,20 @@ public class CommunityTest extends AbstractDSpaceObjectTest fail("Exception expected"); } - /** + /** * Test of create method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testCreateNoAuth2() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testCreateNoAuth2() throws Exception { //Default to Community-Admin Rights (but not full Admin rights) - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; // Disallow full Admin perms - authorizeService.isAdmin((Context) any); result = false; + authorizeService.isAdmin((Context) any); + result = false; }}; // test creating community with no parent (as a non-admin, but with Community Admin rights) @@ -209,21 +211,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest Community created = communityService.create(null, context); fail("Exception expected"); } - + /** * Test of create method (with specified valid handle), of class Community. */ @Test - public void testCreateWithValidHandle() throws Exception - { + public void testCreateWithValidHandle() throws Exception { //Default to Admin Rights, but NOT Community Admin Rights - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Allow full Admin perms - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; // test creating community with a specified handle which is NOT already in use @@ -234,22 +236,22 @@ public class CommunityTest extends AbstractDSpaceObjectTest assertThat("testCreateWithValidHandle 0", created, notNullValue()); assertThat("testCreateWithValidHandle 1", created.getHandle(), equalTo("987654321/100c")); } - - - /** + + + /** * Test of create method (with specified invalid handle), of class Community. */ - @Test(expected=IllegalStateException.class) - public void testCreateWithInvalidHandle() throws Exception - { + @Test(expected = IllegalStateException.class) + public void testCreateWithInvalidHandle() throws Exception { //Default to Admin Rights, but NOT Community Admin Rights - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Allow full Admin perms - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; //get handle of our default created community @@ -265,46 +267,39 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of findAll method, of class Community. */ @Test - public void testFindAll() throws Exception - { + public void testFindAll() throws Exception { List all = communityService.findAll(context); assertThat("testFindAll 0", all, notNullValue()); assertTrue("testFindAll 1", all.size() >= 1); boolean added = false; - for(Community cm: all) - { - if(cm.equals(c)) - { + for (Community cm : all) { + if (cm.equals(c)) { added = true; } } - assertTrue("testFindAll 2",added); + assertTrue("testFindAll 2", added); } /** * Test of findAllTop method, of class Community. */ @Test - public void testFindAllTop() throws Exception - { + public void testFindAllTop() throws Exception { List all = communityService.findAllTop(context); assertThat("testFindAllTop 0", all, notNullValue()); assertTrue("testFindAllTop 1", all.size() >= 1); - for(Community cm: all) - { + for (Community cm : all) { assertThat("testFindAllTop for", communityService.getAllParents(context, cm).size(), equalTo(0)); } boolean added = false; - for(Community cm: all) - { - if(cm.equals(c)) - { + for (Community cm : all) { + if (cm.equals(c)) { added = true; } } - assertTrue("testFindAllTop 2",added); + assertTrue("testFindAllTop 2", added); } /** @@ -312,21 +307,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetID() - { + public void testGetID() { assertTrue("testGetID 0", c.getID() != null); } @Test - public void testLegacyID() { assertTrue("testGetLegacyID 0", c.getLegacyId() == null);} - + public void testLegacyID() { + assertTrue("testGetLegacyID 0", c.getLegacyId() == null); + } + /** * Test of getHandle method, of class Community. */ @Test @Override - public void testGetHandle() - { + public void testGetHandle() { //default instance has a random handle assertTrue("testGetHandle 0", c.getHandle().contains("123456789/")); } @@ -335,22 +330,20 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of getMetadata method, of class Community. */ @Test - public void testGetMetadata() - { + public void testGetMetadata() { //by default all empty values will return "" - assertThat("testGetMetadata 0",communityService.getMetadata(c, "name"), equalTo("")); - assertThat("testGetMetadata 1",communityService.getMetadata(c, "short_description"), equalTo("")); - assertThat("testGetMetadata 2",communityService.getMetadata(c, "introductory_text"), equalTo("")); - assertThat("testGetMetadata 4",communityService.getMetadata(c, "copyright_text"), equalTo("")); - assertThat("testGetMetadata 5",communityService.getMetadata(c, "side_bar_text"), equalTo("")); + assertThat("testGetMetadata 0", communityService.getMetadata(c, "name"), equalTo("")); + assertThat("testGetMetadata 1", communityService.getMetadata(c, "short_description"), equalTo("")); + assertThat("testGetMetadata 2", communityService.getMetadata(c, "introductory_text"), equalTo("")); + assertThat("testGetMetadata 4", communityService.getMetadata(c, "copyright_text"), equalTo("")); + assertThat("testGetMetadata 5", communityService.getMetadata(c, "side_bar_text"), equalTo("")); } /** * Test of setMetadata method, of class Community. */ @Test - public void testSetMetadata() throws SQLException - { + public void testSetMetadata() throws SQLException { String name = "name"; String sdesc = "short description"; String itext = "introductory text"; @@ -363,11 +356,11 @@ public class CommunityTest extends AbstractDSpaceObjectTest communityService.setMetadata(context, c, "copyright_text", copy); communityService.setMetadata(context, c, "side_bar_text", sidebar); - assertThat("testSetMetadata 0",communityService.getMetadata(c, "name"), equalTo(name)); - assertThat("testSetMetadata 1",communityService.getMetadata(c, "short_description"), equalTo(sdesc)); - assertThat("testSetMetadata 2",communityService.getMetadata(c, "introductory_text"), equalTo(itext)); - assertThat("testSetMetadata 4",communityService.getMetadata(c, "copyright_text"), equalTo(copy)); - assertThat("testSetMetadata 5",communityService.getMetadata(c, "side_bar_text"), equalTo(sidebar)); + assertThat("testSetMetadata 0", communityService.getMetadata(c, "name"), equalTo(name)); + assertThat("testSetMetadata 1", communityService.getMetadata(c, "short_description"), equalTo(sdesc)); + assertThat("testSetMetadata 2", communityService.getMetadata(c, "introductory_text"), equalTo(itext)); + assertThat("testSetMetadata 4", communityService.getMetadata(c, "copyright_text"), equalTo(copy)); + assertThat("testSetMetadata 5", communityService.getMetadata(c, "side_bar_text"), equalTo(sidebar)); } /** @@ -375,152 +368,155 @@ public class CommunityTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetName() - { + public void testGetName() { //by default is empty - assertThat("testGetName 0",c.getName(), equalTo("")); + assertThat("testGetName 0", c.getName(), equalTo("")); } /** * Test of getLogo method, of class Community. */ @Test - public void testGetLogo() - { - //by default is empty - assertThat("testGetLogo 0",c.getLogo(), nullValue()); + public void testGetLogo() { + //by default is empty + assertThat("testGetLogo 0", c.getLogo(), nullValue()); } /** * Test of setLogo method, of class Community. */ @Test - public void testSetLogoAuth() throws Exception - { + public void testSetLogoAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = true; + Constants.WRITE); + result = true; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; File f = new File(testProps.get("test.bitstream").toString()); Bitstream logo = communityService.setLogo(context, c, new FileInputStream(f)); - assertThat("testSetLogoAuth 0",c.getLogo(), equalTo(logo)); + assertThat("testSetLogoAuth 0", c.getLogo(), equalTo(logo)); c.setLogo(null); - assertThat("testSetLogoAuth 1",c.getLogo(), nullValue()); + assertThat("testSetLogoAuth 1", c.getLogo(), nullValue()); } /** * Test of setLogo method, of class Community. */ @Test - public void testSetLogoAuth2() throws Exception - { + public void testSetLogoAuth2() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = true; + Constants.WRITE); + result = true; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; File f = new File(testProps.get("test.bitstream").toString()); Bitstream logo = communityService.setLogo(context, c, new FileInputStream(f)); - assertThat("testSetLogoAuth2 0",c.getLogo(), equalTo(logo)); + assertThat("testSetLogoAuth2 0", c.getLogo(), equalTo(logo)); c.setLogo(null); - assertThat("testSetLogoAuth2 1",c.getLogo(), nullValue()); + assertThat("testSetLogoAuth2 1", c.getLogo(), nullValue()); } /** * Test of setLogo method, of class Community. */ @Test - public void testSetLogoAuth3() throws Exception - { + public void testSetLogoAuth3() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; File f = new File(testProps.get("test.bitstream").toString()); Bitstream logo = communityService.setLogo(context, c, new FileInputStream(f)); - assertThat("testSetLogoAuth3 0",c.getLogo(), equalTo(logo)); + assertThat("testSetLogoAuth3 0", c.getLogo(), equalTo(logo)); c.setLogo(null); - assertThat("testSetLogoAuth3 1",c.getLogo(), nullValue()); + assertThat("testSetLogoAuth3 1", c.getLogo(), nullValue()); } /** * Test of setLogo method, of class Community. */ @Test - public void testSetLogoAuth4() throws Exception - { + public void testSetLogoAuth4() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; File f = new File(testProps.get("test.bitstream").toString()); Bitstream logo = communityService.setLogo(context, c, new FileInputStream(f)); - assertThat("testSetLogoAuth4 0",c.getLogo(), equalTo(logo)); + assertThat("testSetLogoAuth4 0", c.getLogo(), equalTo(logo)); c.setLogo(null); - assertThat("testSetLogoAuth4 1",c.getLogo(), nullValue()); + assertThat("testSetLogoAuth4 1", c.getLogo(), nullValue()); } /** * Test of setLogo method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testSetLogoNoAuth() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testSetLogoNoAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Disallow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = new AuthorizeException(); + Constants.WRITE); + result = new AuthorizeException(); }}; File f = new File(testProps.get("test.bitstream").toString()); @@ -531,17 +527,17 @@ public class CommunityTest extends AbstractDSpaceObjectTest /** * Test of update method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testUpdateNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testUpdateNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); // Disallow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = new AuthorizeException(); + Constants.WRITE); + result = new AuthorizeException(); }}; //TODO: we need to verify the update, how? @@ -553,16 +549,16 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of update method, of class Community. */ @Test - public void testUpdateAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testUpdateAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; //TODO: we need to verify the update, how? @@ -573,32 +569,28 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of createAdministrators method, of class Community. */ @Test - public void testCreateAdministratorsAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testCreateAdministratorsAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage AdminGroup perms AuthorizeUtil.authorizeManageAdminGroup((Context) any, (Community) any); - result = null; + result = null; }}; Group result = communityService.createAdministrators(context, c); - assertThat("testCreateAdministratorsAuth 0",c.getAdministrators(), notNullValue()); - assertThat("testCreateAdministratorsAuth 1",c.getAdministrators(), equalTo(result)); + assertThat("testCreateAdministratorsAuth 0", c.getAdministrators(), notNullValue()); + assertThat("testCreateAdministratorsAuth 1", c.getAdministrators(), equalTo(result)); } /** * Test of createAdministrators method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testCreateAdministratorsNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateAdministratorsNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Disallow manage AdminGroup perms AuthorizeUtil.authorizeManageAdminGroup((Context) any, (Community) any); - result = new AuthorizeException(); - + result = new AuthorizeException(); + }}; Group result = communityService.createAdministrators(context, c); @@ -610,46 +602,42 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of removeAdministrators method, of class Community. */ @Test - public void testRemoveAdministratorsAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testRemoveAdministratorsAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage AdminGroup perms (needed to possibly create group first) AuthorizeUtil.authorizeManageAdminGroup((Context) any, (Community) any); - result = null; + result = null; // Allow remove AdminGroup perms AuthorizeUtil.authorizeRemoveAdminGroup((Context) any, (Community) any); - result = null; + result = null; }}; // Ensure admin group is created first Group result = communityService.createAdministrators(context, c); - assertThat("testRemoveAdministratorsAuth 0",c.getAdministrators(), notNullValue()); - assertThat("testRemoveAdministratorsAuth 1",c.getAdministrators(), equalTo(result)); + assertThat("testRemoveAdministratorsAuth 0", c.getAdministrators(), notNullValue()); + assertThat("testRemoveAdministratorsAuth 1", c.getAdministrators(), equalTo(result)); communityService.removeAdministrators(context, c); - assertThat("testRemoveAdministratorsAuth 2",c.getAdministrators(), nullValue()); + assertThat("testRemoveAdministratorsAuth 2", c.getAdministrators(), nullValue()); } /** * Test of removeAdministrators method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testRemoveAdministratorsNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveAdministratorsNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow manage AdminGroup perms (needed to possibly create group first) AuthorizeUtil.authorizeManageAdminGroup((Context) any, (Community) any); - result = null; + result = null; // Disallow remove AdminGroup perms AuthorizeUtil.authorizeRemoveAdminGroup((Context) any, (Community) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; // Ensure admin group is created first Group result = communityService.createAdministrators(context, c); - assertThat("testRemoveAdministratorsAuth 0",c.getAdministrators(), notNullValue()); - assertThat("testRemoveAdministratorsAuth 1",c.getAdministrators(), equalTo(result)); + assertThat("testRemoveAdministratorsAuth 0", c.getAdministrators(), notNullValue()); + assertThat("testRemoveAdministratorsAuth 1", c.getAdministrators(), equalTo(result)); communityService.removeAdministrators(context, c); fail("Should have thrown exception"); } @@ -658,98 +646,103 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of getAdministrators method, of class Community. */ @Test - public void testGetAdministrators() - { + public void testGetAdministrators() { //null by default - assertThat("testGetAdministrators 0",c.getAdministrators(), nullValue()); + assertThat("testGetAdministrators 0", c.getAdministrators(), nullValue()); } /** * Test of getCollections method, of class Community. */ @Test - public void testGetCollections() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testGetCollections() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; //empty by default - assertThat("testGetCollections 0",c.getCollections(), notNullValue()); + assertThat("testGetCollections 0", c.getCollections(), notNullValue()); assertTrue("testGetCollections 1", c.getCollections().size() == 0); context.turnOffAuthorisationSystem(); Collection collection = collectionService.create(context, c); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "collection B"); + collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "collection B"); collection = collectionService.create(context, c); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "collection C"); + collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "collection C"); collection = collectionService.create(context, c); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "collection A"); + collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "collection A"); //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); //sorted - assertTrue("testGetCollections 2",c.getCollections().get(0).getName().equals("collection A")); - assertTrue("testGetCollections 3",c.getCollections().get(1).getName().equals("collection B")); - assertTrue("testGetCollections 4",c.getCollections().get(2).getName().equals("collection C")); + assertTrue("testGetCollections 2", c.getCollections().get(0).getName().equals("collection A")); + assertTrue("testGetCollections 3", c.getCollections().get(1).getName().equals("collection B")); + assertTrue("testGetCollections 4", c.getCollections().get(2).getName().equals("collection C")); } /** * Test of getSubcommunities method, of class Community. */ @Test - public void testGetSubcommunities() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testGetSubcommunities() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow *parent* Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; }}; //empty by default - assertThat("testGetSubcommunities 0",c.getSubcommunities(), notNullValue()); + assertThat("testGetSubcommunities 0", c.getSubcommunities(), notNullValue()); assertTrue("testGetSubcommunities 1", c.getSubcommunities().size() == 0); context.turnOffAuthorisationSystem(); Community community = communityService.create(c, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "subcommunity B"); + communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "subcommunity B"); community = communityService.create(c, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "subcommunity A"); + communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "subcommunity A"); community = communityService.create(c, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "subcommunity C"); + communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "subcommunity C"); //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); //get Subcommunities sorted - assertTrue("testGetCollections 2",c.getSubcommunities().get(0).getName().equals("subcommunity A")); - assertTrue("testGetCollections 3",c.getSubcommunities().get(1).getName().equals("subcommunity B")); - assertTrue("testGetCollections 4",c.getSubcommunities().get(2).getName().equals("subcommunity C")); + assertTrue("testGetCollections 2", c.getSubcommunities().get(0).getName().equals("subcommunity A")); + assertTrue("testGetCollections 3", c.getSubcommunities().get(1).getName().equals("subcommunity B")); + assertTrue("testGetCollections 4", c.getSubcommunities().get(2).getName().equals("subcommunity C")); } /** * Test of getParentCommunity method, of class Community. */ @Test - public void testGetParentCommunity() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testGetParentCommunity() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow *parent* Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; }}; //null by default @@ -757,7 +750,7 @@ public class CommunityTest extends AbstractDSpaceObjectTest //community with parent Community son = communityService.create(c, context); - assertThat("testGetParentCommunity 1",son.getParentCommunities().size(), not(0)); + assertThat("testGetParentCommunity 1", son.getParentCommunities().size(), not(0)); assertThat("testGetParentCommunity 2", son.getParentCommunities().get(0), equalTo(c)); } @@ -765,25 +758,25 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of getAllParents method, of class Community. */ @Test - public void testGetAllParents() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testGetAllParents() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow *parent* Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; }}; //empty by default - assertThat("testGetAllParents 0",communityService.getAllParents(context, c), notNullValue()); + assertThat("testGetAllParents 0", communityService.getAllParents(context, c), notNullValue()); assertTrue("testGetAllParents 1", communityService.getAllParents(context, c).size() == 0); //community with parent Community son = communityService.create(c, context); - assertThat("testGetAllParents 2",communityService.getAllParents(context, son), notNullValue()); + assertThat("testGetAllParents 2", communityService.getAllParents(context, son), notNullValue()); assertTrue("testGetAllParents 3", communityService.getAllParents(context, son).size() == 1); assertThat("testGetAllParents 4", communityService.getAllParents(context, son).get(0), equalTo(c)); } @@ -792,29 +785,30 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of getAllCollections method, of class Community. */ @Test - public void testGetAllCollections() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testGetAllCollections() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow *parent* Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; }}; //empty by default - assertThat("testGetAllCollections 0",communityService.getAllCollections(context, c), notNullValue()); + assertThat("testGetAllCollections 0", communityService.getAllCollections(context, c), notNullValue()); assertTrue("testGetAllCollections 1", communityService.getAllCollections(context, c).size() == 0); //community has a collection and a subcommunity, subcommunity has a collection Collection collOfC = collectionService.create(context, c); Community sub = communityService.create(c, context); Collection collOfSub = collectionService.create(context, sub); - assertThat("testGetAllCollections 2",communityService.getAllCollections(context, c), notNullValue()); + assertThat("testGetAllCollections 2", communityService.getAllCollections(context, c), notNullValue()); assertTrue("testGetAllCollections 3", communityService.getAllCollections(context, c).size() == 2); - assertThat("testGetAllCollections 4", communityService.getAllCollections(context, c).get(0), equalTo(collOfSub)); + assertThat("testGetAllCollections 4", communityService.getAllCollections(context, c).get(0), + equalTo(collOfSub)); assertThat("testGetAllCollections 5", communityService.getAllCollections(context, c).get(1), equalTo(collOfC)); } @@ -822,14 +816,13 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of createCollection method, of class Community. */ @Test - public void testCreateCollectionAuth() throws Exception - { + public void testCreateCollectionAuth() throws Exception { // Need current Community ADD permissions in order to create a Collection - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; Collection result = collectionService.create(context, c); @@ -841,14 +834,13 @@ public class CommunityTest extends AbstractDSpaceObjectTest /** * Test of createCollection method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testCreateCollectionNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateCollectionNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); }}; Collection result = collectionService.create(context, c); @@ -859,13 +851,12 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of addCollection method, of class Community. */ @Test - public void testAddCollectionAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testAddCollectionAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; Collection col = collectionService.create(context, c); @@ -877,14 +868,13 @@ public class CommunityTest extends AbstractDSpaceObjectTest /** * Test of addCollection method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testAddCollectionNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testAddCollectionNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); }}; Collection col = collectionService.create(context, c); @@ -896,20 +886,20 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of createSubcommunity method, of class Community. */ @Test - public void testCreateSubcommunityAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateSubcommunityAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow *parent* Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; }}; Community result = communityService.createSubcommunity(context, c); - assertThat("testCreateSubcommunityAuth 0",c.getSubcommunities(), notNullValue()); + assertThat("testCreateSubcommunityAuth 0", c.getSubcommunities(), notNullValue()); assertTrue("testCreateSubcommunityAuth 1", c.getSubcommunities().size() == 1); assertThat("testCreateSubcommunityAuth 2", c.getSubcommunities().get(0), equalTo(result)); } @@ -917,17 +907,17 @@ public class CommunityTest extends AbstractDSpaceObjectTest /** * Test of createSubcommunity method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testCreateSubcommunityNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateSubcommunityNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); // Allow *parent* Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; }}; Community result = communityService.createSubcommunity(context, c); @@ -938,25 +928,25 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of addSubcommunity method, of class Community. */ @Test - public void testAddSubcommunityAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testAddSubcommunityAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow *parent* Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; }}; // Turn off authorization temporarily to create a new top-level community context.turnOffAuthorisationSystem(); - Community result = communityService.create(null,context); + Community result = communityService.create(null, context); context.restoreAuthSystemState(); communityService.addSubcommunity(context, c, result); - assertThat("testAddSubcommunityAuth 0",c.getSubcommunities(), notNullValue()); + assertThat("testAddSubcommunityAuth 0", c.getSubcommunities(), notNullValue()); assertTrue("testAddSubcommunityAuth 1", c.getSubcommunities().size() == 1); assertThat("testAddSubcommunityAuth 2", c.getSubcommunities().get(0), equalTo(result)); } @@ -964,17 +954,17 @@ public class CommunityTest extends AbstractDSpaceObjectTest /** * Test of addSubcommunity method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testAddSubcommunityNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testAddSubcommunityNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); // Allow *parent* Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; }}; Community result = communityService.create(null, context); @@ -986,29 +976,30 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of removeCollection method, of class Community. */ @Test - public void testRemoveCollectionAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass(), AuthorizeUtil.class) - {{ + public void testRemoveCollectionAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass(), AuthorizeUtil.class) {{ // Allow current Community ADD perms (to add Collection) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow current Community REMOVE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.REMOVE); result = null; + Constants.REMOVE); + result = null; // Allow Collection ManageTemplateItem perms (needed to delete Collection) AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = null; + result = null; // Allow Collection WRITE perms (needed to delete Collection) authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; Collection col = collectionService.create(context, c); assertThat("testRemoveCollectionAuth 0", c.getCollections(), notNullValue()); assertTrue("testRemoveCollectionAuth 1", c.getCollections().size() == 1); assertThat("testRemoveCollectionAuth 2", c.getCollections().get(0), equalTo(col)); - + c.removeCollection(col); assertThat("testRemoveCollectionAuth 3", c.getCollections(), notNullValue()); assertTrue("testRemoveCollectionAuth 4", c.getCollections().size() == 0); @@ -1017,17 +1008,17 @@ public class CommunityTest extends AbstractDSpaceObjectTest /** * Test of removeCollection method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testRemoveCollectionNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveCollectionNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Disallow current Community REMOVE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.REMOVE); result = new AuthorizeException(); + Constants.REMOVE); + result = new AuthorizeException(); }}; Collection col = collectionService.create(context, c); @@ -1043,24 +1034,25 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of removeSubcommunity method, of class Community. */ @Test - public void testRemoveSubcommunityAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRemoveSubcommunityAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Community ADD perms (in order to add a new subcommunity to parent) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD, true); result = null; + Constants.ADD, true); + result = null; // Allow Community REMOVE perms (needed to unmap/remove subcommunity) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.REMOVE, true); result = null; + Constants.REMOVE, true); + result = null; // Allow Community DELETE perms (needed to actually delete subcommunity) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.DELETE, true); result = null; + Constants.DELETE, true); + result = null; }}; // Turn off authorization temporarily to create a new top-level community context.turnOffAuthorisationSystem(); - Community com = communityService.create(null,context); + Community com = communityService.create(null, context); context.restoreAuthSystemState(); communityService.addSubcommunity(context, c, com); @@ -1077,100 +1069,106 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of delete method, of class Community. */ @Test - public void testDeleteAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDeleteAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms (to create content to be deleted) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow current Community WRITE perms (to create content to be deleted) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; // Allow current Community DELETE perms (needed to delete community) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.DELETE); result = null; + Constants.DELETE); + result = null; // Disallow *parent* Community REMOVE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.REMOVE); result = false; + Constants.REMOVE); + result = false; }}; // Turn off authorization temporarily to create a new top-level community context.turnOffAuthorisationSystem(); - Community todelete = communityService.create(null,context); + Community todelete = communityService.create(null, context); context.restoreAuthSystemState(); // Now, test deletion UUID id = todelete.getID(); communityService.delete(context, todelete); Community found = communityService.find(context, id); - assertThat("testDeleteAuth 0",found, nullValue()); + assertThat("testDeleteAuth 0", found, nullValue()); } /** * Test of delete method, of class Community. */ @Test - public void testDeleteAuth2() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDeleteAuth2() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow current Community ADD perms (to create content to be deleted) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Allow current Community WRITE perms (to create content to be deleted) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; // Allow current Community DELETE perms (needed to delete community) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.DELETE); result = null; + Constants.DELETE); + result = null; // Allow *parent* Community REMOVE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.REMOVE, true); result = true; + Constants.REMOVE, true); + result = true; }}; // Turn off authorization temporarily to create a new top-level community context.turnOffAuthorisationSystem(); - Community todelete = communityService.create(null,context); + Community todelete = communityService.create(null, context); context.restoreAuthSystemState(); // Now, test deletion UUID id = todelete.getID(); communityService.delete(context, todelete); Community found = communityService.find(context, id); - assertThat("testDeleteAuth2 0",found, nullValue()); + assertThat("testDeleteAuth2 0", found, nullValue()); } /** * Test of delete method, of class Community, using a hierarchy of Communities and Collections. */ @Test - public void testDeleteHierachyAuth() throws Exception - { + public void testDeleteHierachyAuth() throws Exception { System.out.println("testDeleteHierarchyAuth"); - new NonStrictExpectations(authorizeService.getClass(), AuthorizeUtil.class) - {{ + new NonStrictExpectations(authorizeService.getClass(), AuthorizeUtil.class) {{ // Allow current Community DELETE perms (needed to delete a community) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.DELETE, true); result = null; + Constants.DELETE, true); + result = null; // Allow current Community REMOVE perms (needed to remove a sub-community from a community) authorizeService.authorizeAction((Context) any, (Community) any, - Constants.REMOVE, true); result = null; + Constants.REMOVE, true); + result = null; // Allow Collection ManageTemplateItem perms (needed to delete a collection) AuthorizeUtil.authorizeManageTemplateItem((Context) any, (Collection) any); - result = null; + result = null; // Allow current Collection DELETE perms (needed to delete a Collection) authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.DELETE, true); result = null; + Constants.DELETE, true); + result = null; // Allow current Item WRITE perms (needed to remove identifiers from an Item prior to deletion) authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; // Create a dummy Community hierarchy to test delete with // Turn off authorization temporarily to create some test objects. context.turnOffAuthorisationSystem(); - Community parent = communityService.create(null,context); + Community parent = communityService.create(null, context); // Create a hierachy of sub-Communities and Collections and Items. Community child = communityService.createSubcommunity(context, parent); @@ -1199,33 +1197,33 @@ public class CommunityTest extends AbstractDSpaceObjectTest // Test that everything created here is deleted. assertThat("top-level Community not deleted", - communityService.find(context, parentId), nullValue()); + communityService.find(context, parentId), nullValue()); assertThat("child Community not deleted", - communityService.find(context, childId), nullValue()); + communityService.find(context, childId), nullValue()); assertThat("grandchild Community not deleted", - communityService.find(context, grandchildId), nullValue()); + communityService.find(context, grandchildId), nullValue()); assertThat("Collection of child Community not deleted", - collectionService.find(context, childColId), nullValue()); + collectionService.find(context, childColId), nullValue()); assertThat("Collection of grandchild Community not deleted", - collectionService.find(context, grandchildColId), nullValue()); + collectionService.find(context, grandchildColId), nullValue()); assertThat("Item not deleted", - itemService.find(context, itemId), nullValue()); + itemService.find(context, itemId), nullValue()); } /** * Test of delete method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testDeleteNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testDeleteNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow current Community DELETE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.DELETE); result = new AuthorizeException(); + Constants.DELETE); + result = new AuthorizeException(); // Disallow *parent* Community REMOVE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.REMOVE); result = false; + Constants.REMOVE); + result = false; }}; communityService.delete(context, c); @@ -1237,16 +1235,15 @@ public class CommunityTest extends AbstractDSpaceObjectTest */ @Test @SuppressWarnings("ObjectEqualsNull") - public void testEquals() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testEquals() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full Admin perms (just to create top-level community) - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; - assertFalse("testEquals 0",c.equals(null)); - assertFalse("testEquals 1",c.equals(communityService.create(null, context))); + assertFalse("testEquals 0", c.equals(null)); + assertFalse("testEquals 1", c.equals(communityService.create(null, context))); assertTrue("testEquals 2", c.equals(c)); } @@ -1255,8 +1252,7 @@ public class CommunityTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetType() - { + public void testGetType() { assertThat("testGetType 0", c.getType(), equalTo(Constants.COMMUNITY)); } @@ -1264,20 +1260,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Community. */ @Test - public void testCanEditBooleanAuth() throws Exception - { + public void testCanEditBooleanAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = true; + Constants.WRITE); + result = true; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; assertTrue("testCanEditBooleanAuth 0", communityService.canEditBoolean(context, c)); @@ -1287,20 +1284,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Community. */ @Test - public void testCanEditBooleanAuth2() throws Exception - { + public void testCanEditBooleanAuth2() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = true; + Constants.WRITE); + result = true; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; assertTrue("testCanEditBooleanAuth2 0", communityService.canEditBoolean(context, c)); @@ -1310,20 +1308,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Community. */ @Test - public void testCanEditBooleanAuth3() throws Exception - { + public void testCanEditBooleanAuth3() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; assertTrue("testCanEditBooleanAuth3 0", communityService.canEditBoolean(context, c)); @@ -1333,20 +1332,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Community. */ @Test - public void testCanEditBooleanAuth4() throws Exception - { + public void testCanEditBooleanAuth4() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; assertTrue("testCanEditBooleanAuth4 0", communityService.canEditBoolean(context, c)); @@ -1356,43 +1356,45 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of canEditBoolean method, of class Community. */ @Test - public void testCanEditBooleanNoAuth() throws Exception - { + public void testCanEditBooleanNoAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Disallow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = new AuthorizeException(); + Constants.WRITE); + result = new AuthorizeException(); }}; assertFalse("testCanEditBooleanNoAuth 0", communityService.canEditBoolean(context, c)); - } + } /** * Test of canEdit method, of class Community. */ @Test - public void testCanEditAuth() throws Exception - { + public void testCanEditAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = true; + Constants.WRITE); + result = true; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; communityService.canEdit(context, c); @@ -1402,20 +1404,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Community. */ @Test - public void testCanEditAuth1() throws Exception - { + public void testCanEditAuth1() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Allow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = true; + Constants.WRITE); + result = true; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; communityService.canEdit(context, c); @@ -1425,20 +1428,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Community. */ @Test - public void testCanEditAuth2() throws Exception - { + public void testCanEditAuth2() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = true; + Constants.ADD); + result = true; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; communityService.canEdit(context, c); @@ -1448,20 +1452,21 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Community. */ @Test - public void testCanEditAuth3() throws Exception - { + public void testCanEditAuth3() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; communityService.canEdit(context, c); @@ -1470,21 +1475,22 @@ public class CommunityTest extends AbstractDSpaceObjectTest /** * Test of canEdit method, of class Community. */ - @Test(expected=AuthorizeException.class) - public void testCanEditNoAuth() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testCanEditNoAuth() throws Exception { // Test inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow parent Community ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + Constants.ADD); + result = false; // Disallow parent Community WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Disallow current Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE); result = new AuthorizeException(); + Constants.WRITE); + result = new AuthorizeException(); }}; communityService.canEdit(context, c); @@ -1495,11 +1501,10 @@ public class CommunityTest extends AbstractDSpaceObjectTest * Test of countItems method, of class Community. */ @Test - public void testCountItems() throws Exception - { + public void testCountItems() throws Exception { //0 by default assertTrue("testCountItems 0", itemService.countItems(context, c) == 0); - + //NOTE: a more thorough test of item counting is in ITCommunityCollection integration test } @@ -1508,13 +1513,15 @@ public class CommunityTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetAdminObject() throws SQLException - { + public void testGetAdminObject() throws SQLException { //default community has no admin object - assertThat("testGetAdminObject 0", (Community)communityService.getAdminObject(context, c, Constants.REMOVE), equalTo(c)); - assertThat("testGetAdminObject 1", (Community)communityService.getAdminObject(context, c, Constants.ADD), equalTo(c)); + assertThat("testGetAdminObject 0", (Community) communityService.getAdminObject(context, c, Constants.REMOVE), + equalTo(c)); + assertThat("testGetAdminObject 1", (Community) communityService.getAdminObject(context, c, Constants.ADD), + equalTo(c)); assertThat("testGetAdminObject 2", communityService.getAdminObject(context, c, Constants.DELETE), nullValue()); - assertThat("testGetAdminObject 3", (Community)communityService.getAdminObject(context, c, Constants.ADMIN), equalTo(c)); + assertThat("testGetAdminObject 3", (Community) communityService.getAdminObject(context, c, Constants.ADMIN), + equalTo(c)); } /** @@ -1522,10 +1529,8 @@ public class CommunityTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetParentObject() throws SQLException - { - try - { + public void testGetParentObject() throws SQLException { + try { //default has no parent assertThat("testGetParentObject 0", communityService.getParentObject(context, c), nullValue()); @@ -1533,10 +1538,8 @@ public class CommunityTest extends AbstractDSpaceObjectTest Community son = communityService.createSubcommunity(context, c); context.restoreAuthSystemState(); assertThat("testGetParentObject 1", communityService.getParentObject(context, son), notNullValue()); - assertThat("testGetParentObject 2", (Community)communityService.getParentObject(context, son), equalTo(c)); - } - catch(AuthorizeException ex) - { + assertThat("testGetParentObject 2", (Community) communityService.getParentObject(context, son), equalTo(c)); + } catch (AuthorizeException ex) { fail("Authorize exception catched"); } } diff --git a/dspace-api/src/test/java/org/dspace/content/DCDateTest.java b/dspace-api/src/test/java/org/dspace/content/DCDateTest.java index ee4fad713c..ced07c72b2 100644 --- a/dspace-api/src/test/java/org/dspace/content/DCDateTest.java +++ b/dspace-api/src/test/java/org/dspace/content/DCDateTest.java @@ -7,23 +7,30 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + import org.apache.commons.lang.time.DateUtils; import org.apache.log4j.Logger; - -import java.util.*; import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; /** - * * @author pvillega */ -public class DCDateTest -{ - /** log4j category */ +public class DCDateTest { + /** + * log4j category + */ private static Logger log = Logger.getLogger(DCDateTest.class); /** @@ -56,7 +63,7 @@ public class DCDateTest * but no execution order is guaranteed */ @After - public void destroy() { + public void destroy() { dc = null; c = null; } @@ -65,9 +72,8 @@ public class DCDateTest * Test of DCDate constructor, of class DCDate. */ @Test - public void testDCDateDate() - { - dc = new DCDate((String)null); + public void testDCDateDate() { + dc = new DCDate((String) null); assertThat("testDCDateDate 1", dc.getYear(), equalTo(-1)); assertThat("testDCDateDate 2", dc.getMonth(), equalTo(-1)); assertThat("testDCDateDate 3", dc.getDay(), equalTo(-1)); @@ -83,7 +89,7 @@ public class DCDateTest assertThat("testDCDateDate 12", dc.getSecondUTC(), equalTo(-1)); // NB. Months begin at 0 in GregorianCalendar so 0 is January. - c = new GregorianCalendar(2010,0,1); + c = new GregorianCalendar(2010, 0, 1); dc = new DCDate(c.getTime()); assertThat("testDCDateDate 1 ", dc.getYear(), equalTo(2010)); @@ -100,7 +106,7 @@ public class DCDateTest assertThat("testDCDateDate 11 ", dc.getMinuteUTC(), equalTo(0)); assertThat("testDCDateDate 12 ", dc.getSecondUTC(), equalTo(0)); - c = new GregorianCalendar(2009,11,31,18,30); + c = new GregorianCalendar(2009, 11, 31, 18, 30); dc = new DCDate(c.getTime()); assertThat("testDCDateDate 13 ", dc.getYear(), equalTo(2009)); @@ -122,9 +128,8 @@ public class DCDateTest * Test of DCDate constructor, of class DCDate. */ @Test - public void testDCDateIntBits() - { - dc = new DCDate(2010,1,1,-1,-1,-1); + public void testDCDateIntBits() { + dc = new DCDate(2010, 1, 1, -1, -1, -1); assertThat("testDCDateIntBits 1", dc.getYear(), equalTo(2010)); assertThat("testDCDateIntBits 2", dc.getMonth(), equalTo(1)); @@ -140,7 +145,7 @@ public class DCDateTest assertThat("testDCDateIntBits 11", dc.getMinuteUTC(), equalTo(-1)); assertThat("testDCDateIntBits 12", dc.getSecondUTC(), equalTo(-1)); - dc = new DCDate(2009,12,31,18,30,5); + dc = new DCDate(2009, 12, 31, 18, 30, 5); assertThat("testDCDateIntBits 13", dc.getYear(), equalTo(2009)); assertThat("testDCDateIntBits 14", dc.getMonth(), equalTo(12)); @@ -155,16 +160,15 @@ public class DCDateTest assertThat("testDCDateIntBits 22", dc.getHourUTC(), equalTo(2)); assertThat("testDCDateIntBits 23", dc.getMinuteUTC(), equalTo(30)); assertThat("testDCDateIntBits 24", dc.getSecondUTC(), equalTo(5)); - + } /** * Test of DCDate constructor, of class DCDate. */ @Test - public void testDCDateString() - { - dc = new DCDate((String)null); + public void testDCDateString() { + dc = new DCDate((String) null); assertThat("testDCDateString 1", dc.getYear(), equalTo(-1)); assertThat("testDCDateString 2", dc.getMonth(), equalTo(-1)); assertThat("testDCDateString 3", dc.getDay(), equalTo(-1)); @@ -286,14 +290,12 @@ public class DCDateTest } - /** * Test of toString method, of class DCDate. */ @Test - public void testToString() - { - dc = new DCDate((String)null); + public void testToString() { + dc = new DCDate((String) null); assertThat("testToString 0", dc.toString(), equalTo("null")); dc = new DCDate(""); @@ -313,162 +315,155 @@ public class DCDateTest dc = new DCDate("2010-04-14T00:01"); assertThat("testToString 6", dc.toString(), - equalTo("2010-04-14T00:01:00Z")); + equalTo("2010-04-14T00:01:00Z")); dc = new DCDate("2010-04-14T00:00:01Z"); assertThat("testToString 7", dc.toString(), - equalTo("2010-04-14T00:00:01Z")); + equalTo("2010-04-14T00:00:01Z")); } /** * Test of toDate method, of class DCDate. */ @Test - public void testToDate() - { - dc = new DCDate((Date)null); + public void testToDate() { + dc = new DCDate((Date) null); assertThat("testToDate 0", dc.toDate(), nullValue()); - c = new GregorianCalendar(2010,0,0); + c = new GregorianCalendar(2010, 0, 0); dc = new DCDate(c.getTime()); assertThat("testToDate 1", dc.toDate(), equalTo(c.getTime())); - c = new GregorianCalendar(2010,4,0); + c = new GregorianCalendar(2010, 4, 0); dc = new DCDate(c.getTime()); assertThat("testToDate 2", dc.toDate(), equalTo(c.getTime())); - c = new GregorianCalendar(2010,4,14); + c = new GregorianCalendar(2010, 4, 14); dc = new DCDate(c.getTime()); assertThat("testToDate 3", dc.toDate(), equalTo(c.getTime())); - c = new GregorianCalendar(2010,4,14,0,0,1); + c = new GregorianCalendar(2010, 4, 14, 0, 0, 1); dc = new DCDate(c.getTime()); assertThat("testToDate 4", dc.toDate(), equalTo(c.getTime())); } - - /** * Test of displayDate method, of class DCDate. */ @Test - public void testDisplayDate() - { + public void testDisplayDate() { dc = new DCDate("2010"); assertThat("testDisplayDate 1 ", dc.displayDate(true, true, - new Locale("en_GB")), - equalTo("2010")); + new Locale("en_GB")), + equalTo("2010")); dc = new DCDate("2010-04"); assertThat("testDisplayDate 2 ", dc.displayDate(true, true, - new Locale("en_GB")), - equalTo("Apr-2010")); + new Locale("en_GB")), + equalTo("Apr-2010")); dc = new DCDate("2010-04-14"); assertThat("testDisplayDate 3 ", dc.displayDate(true, true, - new Locale("en_GB")), - equalTo("14-Apr-2010")); + new Locale("en_GB")), + equalTo("14-Apr-2010")); dc = new DCDate("2010-04-14T00:00:01Z"); assertThat("testDisplayDate 4 ", dc.displayDate(true, true, - new Locale("en_GB")), - equalTo("13-Apr-2010 16:00:01")); + new Locale("en_GB")), + equalTo("13-Apr-2010 16:00:01")); dc = new DCDate("2010-04-14T00:00:01Z"); assertThat("testDisplayDate 5 ", dc.displayDate(false, true, - new Locale("en_GB")), - equalTo("13-Apr-2010")); + new Locale("en_GB")), + equalTo("13-Apr-2010")); dc = new DCDate("2010-04-14T00:00:01Z"); assertThat("testDisplayDate 6 ", dc.displayDate(true, false, - new Locale("es")), - equalTo("14-abr-2010 00:00:01")); + new Locale("es")), + equalTo("14-abr-2010 00:00:01")); dc = new DCDate("2010-04-14T00:00:01Z"); assertThat("testDisplayDate 7 ", dc.displayDate(false, false, - new Locale("en_GB")), - equalTo("14-Apr-2010")); + new Locale("en_GB")), + equalTo("14-Apr-2010")); } /** * Test of getCurrent method, of class DCDate. */ @Test - public void testGetCurrent() - { - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(System.currentTimeMillis()); - calendar.setTimeZone(TimeZone.getTimeZone("UTC")); - assertTrue("testGetCurrent 0", DateUtils.isSameDay(DCDate.getCurrent().toDate(), calendar.getTime())); + public void testGetCurrent() { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + calendar.setTimeZone(TimeZone.getTimeZone("UTC")); + assertTrue("testGetCurrent 0", DateUtils.isSameDay(DCDate.getCurrent().toDate(), calendar.getTime())); } - /** * Test of getMonthName method, of class DCDate. */ @Test - public void testGetMonthName() - { + public void testGetMonthName() { assertThat("testGetMonthName 0", DCDate.getMonthName(-1, new Locale("en")), - equalTo("Unspecified")); + equalTo("Unspecified")); assertThat("testGetMonthName 1", DCDate.getMonthName(0, new Locale("en")), - equalTo("Unspecified")); + equalTo("Unspecified")); assertThat("testGetMonthName 2", DCDate.getMonthName(13, new Locale("en")), - equalTo("Unspecified")); + equalTo("Unspecified")); assertThat("testGetMonthName 3", DCDate.getMonthName(14, new Locale("en")), - equalTo("Unspecified")); + equalTo("Unspecified")); assertThat("testGetMonthName 4", DCDate.getMonthName(1, new Locale("en")), - equalTo("January")); + equalTo("January")); assertThat("testGetMonthName 5", DCDate.getMonthName(2, new Locale("en")), - equalTo("February")); + equalTo("February")); assertThat("testGetMonthName 6", DCDate.getMonthName(3, new Locale("en")), - equalTo("March")); + equalTo("March")); assertThat("testGetMonthName 7", DCDate.getMonthName(4, new Locale("en")), - equalTo("April")); + equalTo("April")); assertThat("testGetMonthName 8", DCDate.getMonthName(5, new Locale("en")), - equalTo("May")); + equalTo("May")); assertThat("testGetMonthName 9", DCDate.getMonthName(6, new Locale("en")), - equalTo("June")); + equalTo("June")); assertThat("testGetMonthName 10", DCDate.getMonthName(7, new Locale("en")), - equalTo("July")); + equalTo("July")); assertThat("testGetMonthName 11", DCDate.getMonthName(8, new Locale("en")), - equalTo("August")); + equalTo("August")); assertThat("testGetMonthName 12", DCDate.getMonthName(9, new Locale("en")), - equalTo("September")); + equalTo("September")); assertThat("testGetMonthName 13", DCDate.getMonthName(10, new Locale("en")), - equalTo("October")); + equalTo("October")); assertThat("testGetMonthName 14", DCDate.getMonthName(11, new Locale("en")), - equalTo("November")); + equalTo("November")); assertThat("testGetMonthName 15", DCDate.getMonthName(12, new Locale("en")), - equalTo("December")); + equalTo("December")); assertThat("testGetMonthName 16", DCDate.getMonthName(1, new Locale("es")), - equalTo("enero")); + equalTo("enero")); assertThat("testGetMonthName 17", DCDate.getMonthName(2, new Locale("es")), - equalTo("febrero")); + equalTo("febrero")); assertThat("testGetMonthName 18", DCDate.getMonthName(3, new Locale("es")), - equalTo("marzo")); + equalTo("marzo")); assertThat("testGetMonthName 19", DCDate.getMonthName(4, new Locale("es")), - equalTo("abril")); + equalTo("abril")); assertThat("testGetMonthName 20", DCDate.getMonthName(5, new Locale("es")), - equalTo("mayo")); + equalTo("mayo")); assertThat("testGetMonthName 21", DCDate.getMonthName(6, new Locale("es")), - equalTo("junio")); + equalTo("junio")); assertThat("testGetMonthName 22", DCDate.getMonthName(7, new Locale("es")), - equalTo("julio")); + equalTo("julio")); assertThat("testGetMonthName 23", DCDate.getMonthName(8, new Locale("es")), - equalTo("agosto")); + equalTo("agosto")); assertThat("testGetMonthName 24", DCDate.getMonthName(9, new Locale("es")), - equalTo("septiembre")); + equalTo("septiembre")); assertThat("testGetMonthName 25", DCDate.getMonthName(10, new Locale("es")), - equalTo("octubre")); + equalTo("octubre")); assertThat("testGetMonthName 26", DCDate.getMonthName(11, new Locale("es")), - equalTo("noviembre")); + equalTo("noviembre")); assertThat("testGetMonthName 27", DCDate.getMonthName(12, new Locale("es")), - equalTo("diciembre")); + equalTo("diciembre")); } @@ -479,27 +474,27 @@ public class DCDateTest * @author Andrew Taylor */ /** - public void testDCDateStringConcurrency() throws InterruptedException { - ExecutorService exec = Executors.newFixedThreadPool(8); - List> callables = new ArrayList>(10000); - for (int i = 0; i < 10000; i++) { - callables.add(new Callable() { - public Void call() throws Exception { - DCDate date = new DCDate("2010-08-01T23:01:34Z"); - date.toDate(); - return null; - } - }); - } - List> invoked = exec.invokeAll(callables, 10, TimeUnit.SECONDS); - for (Future future : invoked) { - try { - future.get(); - } catch (ExecutionException e) { - log.error(e.toString(),e); - fail("Exception encountered (see stderr)"); - } - } - } - */ + public void testDCDateStringConcurrency() throws InterruptedException { + ExecutorService exec = Executors.newFixedThreadPool(8); + List> callables = new ArrayList>(10000); + for (int i = 0; i < 10000; i++) { + callables.add(new Callable() { + public Void call() throws Exception { + DCDate date = new DCDate("2010-08-01T23:01:34Z"); + date.toDate(); + return null; + } + }); + } + List> invoked = exec.invokeAll(callables, 10, TimeUnit.SECONDS); + for (Future future : invoked) { + try { + future.get(); + } catch (ExecutionException e) { + log.error(e.toString(),e); + fail("Exception encountered (see stderr)"); + } + } + } + */ } diff --git a/dspace-api/src/test/java/org/dspace/content/DCLanguageTest.java b/dspace-api/src/test/java/org/dspace/content/DCLanguageTest.java index 99046a63fc..cdc6cce75a 100644 --- a/dspace-api/src/test/java/org/dspace/content/DCLanguageTest.java +++ b/dspace-api/src/test/java/org/dspace/content/DCLanguageTest.java @@ -7,20 +7,22 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + import java.util.Locale; + import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; /** * Tests DCLanguageTest class + * * @author pvillega */ -public class DCLanguageTest -{ +public class DCLanguageTest { /** * Object to use in the tests @@ -36,8 +38,7 @@ public class DCLanguageTest * but no execution order is guaranteed */ @Before - public void init() - { + public void init() { dc = new DCLanguage(""); } @@ -49,8 +50,7 @@ public class DCLanguageTest * but no execution order is guaranteed */ @After - public void destroy() - { + public void destroy() { dc = null; } @@ -58,8 +58,7 @@ public class DCLanguageTest * Test of DCLanguage constructor, of class DCLanguage. */ @Test - public void testDCLanguage() - { + public void testDCLanguage() { dc = new DCLanguage(null); assertThat("testDCLanguage 0", dc.toString(), equalTo("")); @@ -86,8 +85,7 @@ public class DCLanguageTest * Test of toString method, of class DCLanguage. */ @Test - public void testToString() - { + public void testToString() { dc = new DCLanguage(null); assertThat("testToString 0", dc.toString(), equalTo("")); @@ -114,8 +112,7 @@ public class DCLanguageTest * Test of setLanguage method, of class DCLanguage. */ @Test - public void testSetLanguage() - { + public void testSetLanguage() { dc = new DCLanguage(null); assertThat("testSetLanguage 0", dc.toString(), equalTo("")); @@ -142,8 +139,7 @@ public class DCLanguageTest * Test of getDisplayName method, of class DCLanguage. */ @Test - public void testGetDisplayName() - { + public void testGetDisplayName() { dc = new DCLanguage(null); assertThat("testGetDisplayName 0", dc.getDisplayName(), equalTo("N/A")); @@ -152,14 +148,14 @@ public class DCLanguageTest dc = new DCLanguage("other"); assertThat("testGetDisplayName 2", dc.getDisplayName(), - equalTo("(Other)")); + equalTo("(Other)")); dc = new DCLanguage("en"); assertThat("testGetDisplayName 3", dc.getDisplayName(), - equalTo(new Locale("en","").getDisplayName())); + equalTo(new Locale("en", "").getDisplayName())); dc = new DCLanguage("en_GB"); assertThat("testGetDisplayName 4", dc.getDisplayName(), - equalTo(new Locale("en","GB").getDisplayName())); + equalTo(new Locale("en", "GB").getDisplayName())); } } diff --git a/dspace-api/src/test/java/org/dspace/content/DCPersonNameTest.java b/dspace-api/src/test/java/org/dspace/content/DCPersonNameTest.java index 570dc99d12..e61a84687e 100644 --- a/dspace-api/src/test/java/org/dspace/content/DCPersonNameTest.java +++ b/dspace-api/src/test/java/org/dspace/content/DCPersonNameTest.java @@ -7,20 +7,19 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + import org.junit.After; import org.junit.Before; import org.junit.Test; - -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; - /** * Tests DCPersonName class + * * @author pvillega */ -public class DCPersonNameTest -{ +public class DCPersonNameTest { /** * Object to use in the tests @@ -36,8 +35,7 @@ public class DCPersonNameTest * but no execution order is guaranteed */ @Before - public void init() - { + public void init() { dc = new DCPersonName(""); } @@ -49,8 +47,7 @@ public class DCPersonNameTest * but no execution order is guaranteed */ @After - public void destroy() - { + public void destroy() { dc = null; } @@ -58,8 +55,7 @@ public class DCPersonNameTest * Test of DCPersonName constructor, of class DCPersonName. */ @Test - public void testDCPersonName() - { + public void testDCPersonName() { dc = new DCPersonName(); assertThat("testDCPersonName 0", dc.getFirstNames(), equalTo("")); assertThat("testDCPersonName 1", dc.getLastName(), equalTo("")); @@ -69,8 +65,7 @@ public class DCPersonNameTest * Test of DCPersonName constructor, of class DCPersonName. */ @Test - public void testDCPersonNameValue() - { + public void testDCPersonNameValue() { dc = new DCPersonName(null); assertThat("testDCPersonNameValue 0", dc.getFirstNames(), equalTo("")); assertThat("testDCPersonNameValue 1", dc.getLastName(), equalTo("")); @@ -81,12 +76,12 @@ public class DCPersonNameTest dc = new DCPersonName("name,firstname"); assertThat("testDCPersonNameValue 4", dc.getFirstNames(), - equalTo("firstname")); + equalTo("firstname")); assertThat("testDCPersonNameValue 5", dc.getLastName(), equalTo("name")); dc = new DCPersonName("name , firstname"); assertThat("testDCPersonNameValue 6", dc.getFirstNames(), - equalTo("firstname")); + equalTo("firstname")); assertThat("testDCPersonNameValue 7", dc.getLastName(), equalTo("name")); } @@ -94,8 +89,7 @@ public class DCPersonNameTest * Test of DCPersonName constructor, of class DCPersonName. */ @Test - public void testDCPersonNameValues() - { + public void testDCPersonNameValues() { dc = new DCPersonName(null, null); assertThat("testDCPersonNameValues 0", dc.getFirstNames(), equalTo("")); assertThat("testDCPersonNameValues 1", dc.getLastName(), equalTo("")); @@ -106,12 +100,12 @@ public class DCPersonNameTest dc = new DCPersonName(null, "firstname"); assertThat("testDCPersonNameValues 4", dc.getFirstNames(), - equalTo("firstname")); + equalTo("firstname")); assertThat("testDCPersonNameValues 5", dc.getLastName(), equalTo("")); - dc = new DCPersonName("name","firstname"); + dc = new DCPersonName("name", "firstname"); assertThat("testDCPersonNameValues 6", dc.getFirstNames(), - equalTo("firstname")); + equalTo("firstname")); assertThat("testDCPersonNameValues 7", dc.getLastName(), equalTo("name")); } @@ -119,8 +113,7 @@ public class DCPersonNameTest * Test of toString method, of class DCPersonName. */ @Test - public void testToString() - { + public void testToString() { dc = new DCPersonName(null, null); assertThat("testToString 0", dc.toString(), equalTo("")); @@ -130,7 +123,7 @@ public class DCPersonNameTest dc = new DCPersonName(null, "firstname"); assertThat("testToString 2", dc.toString(), equalTo("")); - dc = new DCPersonName("name","firstname"); + dc = new DCPersonName("name", "firstname"); assertThat("testToString 3", dc.toString(), equalTo("name, firstname")); } @@ -138,9 +131,8 @@ public class DCPersonNameTest * Test of getFirstNames method, of class DCPersonName. */ @Test - public void testGetFirstNames() - { - dc = new DCPersonName(null, null); + public void testGetFirstNames() { + dc = new DCPersonName(null, null); assertThat("testGetFirstNames 0", dc.getFirstNames(), equalTo("")); dc = new DCPersonName("name", null); @@ -148,19 +140,18 @@ public class DCPersonNameTest dc = new DCPersonName(null, "firstname"); assertThat("testGetFirstNames 2", dc.getFirstNames(), - equalTo("firstname")); + equalTo("firstname")); - dc = new DCPersonName("name","firstname"); + dc = new DCPersonName("name", "firstname"); assertThat("testGetFirstNames 3", dc.getFirstNames(), - equalTo("firstname")); + equalTo("firstname")); } /** * Test of getLastName method, of class DCPersonName. */ @Test - public void testGetLastName() - { + public void testGetLastName() { dc = new DCPersonName(null, null); assertThat("testGetLastName 0", dc.getLastName(), equalTo("")); @@ -170,7 +161,7 @@ public class DCPersonNameTest dc = new DCPersonName(null, "firstname"); assertThat("testGetLastName 2", dc.getLastName(), equalTo("")); - dc = new DCPersonName("name","firstname"); + dc = new DCPersonName("name", "firstname"); assertThat("testGetLastName 3", dc.getLastName(), equalTo("name")); } diff --git a/dspace-api/src/test/java/org/dspace/content/DCSeriesNumberTest.java b/dspace-api/src/test/java/org/dspace/content/DCSeriesNumberTest.java index d417082744..82b127aedf 100644 --- a/dspace-api/src/test/java/org/dspace/content/DCSeriesNumberTest.java +++ b/dspace-api/src/test/java/org/dspace/content/DCSeriesNumberTest.java @@ -7,19 +7,20 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; - /** * Tests DCSeriesNumber class + * * @author pvillega */ -public class DCSeriesNumberTest -{ +public class DCSeriesNumberTest { /** * Object to use in the tests @@ -35,8 +36,7 @@ public class DCSeriesNumberTest * but no execution order is guaranteed */ @Before - public void init() - { + public void init() { dc = new DCSeriesNumber(); } @@ -48,8 +48,7 @@ public class DCSeriesNumberTest * but no execution order is guaranteed */ @After - public void destroy() - { + public void destroy() { dc = null; } @@ -57,8 +56,7 @@ public class DCSeriesNumberTest * Test of DCSeriesNumber constructor, of class DCSeriesNumber. */ @Test - public void testDCSeriesNumber() - { + public void testDCSeriesNumber() { dc = new DCSeriesNumber(); assertThat("testDCSeriesNumber 0", dc.getNumber(), equalTo("")); assertThat("testDCSeriesNumber 1", dc.getSeries(), equalTo("")); @@ -68,67 +66,64 @@ public class DCSeriesNumberTest * Test of DCSeriesNumber constructor, of class DCSeriesNumber. */ @Test - public void testDCSeriesNumberValue() - { + public void testDCSeriesNumberValue() { dc = new DCSeriesNumber(null); assertThat("testDCSeriesNumberValue 0", dc.getNumber(), equalTo("")); assertThat("testDCSeriesNumberValue 1", dc.getSeries(), equalTo("")); dc = new DCSeriesNumber("series"); assertThat("testDCSeriesNumberValue 2", dc.getNumber(), - equalTo("")); + equalTo("")); assertThat("testDCSeriesNumberValue 3", dc.getSeries(), - equalTo("series")); + equalTo("series")); dc = new DCSeriesNumber("series;number"); assertThat("testDCSeriesNumberValue 4", dc.getNumber(), - equalTo("number")); + equalTo("number")); assertThat("testDCSeriesNumberValue 5", dc.getSeries(), - equalTo("series")); + equalTo("series")); dc = new DCSeriesNumber("series;number;number2"); assertThat("testDCSeriesNumberValue 6", dc.getNumber(), - equalTo("number;number2")); + equalTo("number;number2")); assertThat("testDCSeriesNumberValue 7", dc.getSeries(), - equalTo("series")); + equalTo("series")); } /** * Test of DCSeriesNumber constructor, of class DCSeriesNumber. */ @Test - public void testDCSeriesNumberValues() - { + public void testDCSeriesNumberValues() { dc = new DCSeriesNumber(null, null); assertThat("testDCSeriesNumberValues 0", dc.getNumber(), equalTo("")); assertThat("testDCSeriesNumberValues 1", dc.getSeries(), equalTo("")); dc = new DCSeriesNumber(null, "number"); assertThat("testDCSeriesNumberValues 2", dc.getNumber(), - equalTo("number")); + equalTo("number")); assertThat("testDCSeriesNumberValues 3", dc.getSeries(), - equalTo("")); + equalTo("")); dc = new DCSeriesNumber("series", null); assertThat("testDCSeriesNumberValues 4", dc.getNumber(), - equalTo("")); + equalTo("")); assertThat("testDCSeriesNumberValues 5", dc.getSeries(), - equalTo("series")); + equalTo("series")); dc = new DCSeriesNumber("series", "number"); assertThat("testDCSeriesNumberValues 6", dc.getNumber(), - equalTo("number")); + equalTo("number")); assertThat("testDCSeriesNumberValues 7", dc.getSeries(), - equalTo("series")); + equalTo("series")); } /** * Test of toString method, of class DCSeriesNumber. */ @Test - public void testToString() - { - dc = new DCSeriesNumber(null, null); + public void testToString() { + dc = new DCSeriesNumber(null, null); assertThat("testToString 0", dc.toString(), nullValue()); dc = new DCSeriesNumber(null, "number"); @@ -145,8 +140,7 @@ public class DCSeriesNumberTest * Test of getSeries method, of class DCSeriesNumber. */ @Test - public void testGetSeries() - { + public void testGetSeries() { dc = new DCSeriesNumber(null, null); assertThat("testGetSeries 0", dc.getSeries(), equalTo("")); @@ -158,8 +152,7 @@ public class DCSeriesNumberTest * Test of getNumber method, of class DCSeriesNumber. */ @Test - public void testGetNumber() - { + public void testGetNumber() { dc = new DCSeriesNumber(null, null); assertThat("testGetNumber 0", dc.getNumber(), equalTo("")); diff --git a/dspace-api/src/test/java/org/dspace/content/FormatIdentifierTest.java b/dspace-api/src/test/java/org/dspace/content/FormatIdentifierTest.java index 57058202f7..eb2b79c9dd 100644 --- a/dspace-api/src/test/java/org/dspace/content/FormatIdentifierTest.java +++ b/dspace-api/src/test/java/org/dspace/content/FormatIdentifierTest.java @@ -7,30 +7,37 @@ */ package org.dspace.content; -import java.io.FileInputStream; -import java.io.File; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.io.File; +import java.io.FileInputStream; -import org.dspace.AbstractUnitTest; import org.apache.log4j.Logger; +import org.dspace.AbstractUnitTest; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamService; -import org.junit.*; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Unit Tests for class FormatIdentifier + * * @author pvillega */ -public class FormatIdentifierTest extends AbstractUnitTest -{ +public class FormatIdentifierTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(FormatIdentifierTest.class); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); /** * This method will be run before every test as per @Before. It will @@ -41,8 +48,7 @@ public class FormatIdentifierTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); } @@ -55,8 +61,7 @@ public class FormatIdentifierTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { super.destroy(); } @@ -64,34 +69,33 @@ public class FormatIdentifierTest extends AbstractUnitTest * Test of guessFormat method, of class FormatIdentifier. */ @Test - public void testGuessFormat() throws Exception - { + public void testGuessFormat() throws Exception { File f = new File(testProps.get("test.bitstream").toString()); - Bitstream bs = null; + Bitstream bs = null; BitstreamFormat result = null; BitstreamFormat pdf = bitstreamFormatService.findByShortDescription(context, "Adobe PDF"); - + //test null filename //TODO: the check if filename is null is wrong, as it checks after using a toLowerCase //which can trigger the NPE bs = bitstreamService.create(context, new FileInputStream(f)); bs.setName(context, null); result = bitstreamFormatService.guessFormat(context, bs); - assertThat("testGuessFormat 0",result, nullValue()); + assertThat("testGuessFormat 0", result, nullValue()); //test unknown format bs = bitstreamService.create(context, new FileInputStream(f)); bs.setName(context, "file_without_extension."); result = bitstreamFormatService.guessFormat(context, bs); - assertThat("testGuessFormat 1",result, nullValue()); + assertThat("testGuessFormat 1", result, nullValue()); //test known format bs = bitstreamService.create(context, new FileInputStream(f)); bs.setName(context, testProps.get("test.bitstream").toString()); result = bitstreamFormatService.guessFormat(context, bs); - assertThat("testGuessFormat 2",result.getID(), equalTo(pdf.getID())); - assertThat("testGuessFormat 3",result.getMIMEType(), equalTo(pdf.getMIMEType())); - assertThat("testGuessFormat 4",result.getExtensions(), equalTo(pdf.getExtensions())); + assertThat("testGuessFormat 2", result.getID(), equalTo(pdf.getID())); + assertThat("testGuessFormat 3", result.getMIMEType(), equalTo(pdf.getMIMEType())); + assertThat("testGuessFormat 4", result.getExtensions(), equalTo(pdf.getExtensions())); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/ITCommunityCollection.java b/dspace-api/src/test/java/org/dspace/content/ITCommunityCollection.java index f2da8ed84a..2d7271896d 100644 --- a/dspace-api/src/test/java/org/dspace/content/ITCommunityCollection.java +++ b/dspace-api/src/test/java/org/dspace/content/ITCommunityCollection.java @@ -7,13 +7,29 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.UUID; + import org.apache.log4j.Logger; -import org.databene.contiperf.PerfTest; -import org.databene.contiperf.Required; import org.dspace.AbstractIntegrationTest; import org.dspace.authorize.AuthorizeException; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +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.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; @@ -23,31 +39,18 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.util.UUID; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - /** * This is an integration test to ensure collections and communities interact properly. * - * The code below is attached as an example. Performance checks by ContiPerf - * can be applied at method level or at class level. This shows the syntax - * for class-level checks. - * @PerfTest(invocations = 1000, threads = 20) - * @Required(max = 1200, average = 250) + * The code below is attached as an example. * * @author pvillega * @author tdonohue */ -public class ITCommunityCollection extends AbstractIntegrationTest -{ - /** log4j category */ +public class ITCommunityCollection extends AbstractIntegrationTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(ITCommunityCollection.class); protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); @@ -69,8 +72,7 @@ public class ITCommunityCollection extends AbstractIntegrationTest */ @Before @Override - public void init() - { + public void init() { super.init(); } @@ -91,17 +93,15 @@ public class ITCommunityCollection extends AbstractIntegrationTest * Tests the creation of a community collection tree */ @Test - @PerfTest(invocations = 25, threads = 1) - @Required(percentile95 = 1200, average = 700, throughput = 1) public void testCreateTree() throws SQLException, AuthorizeException, IOException { //we create the structure context.turnOffAuthorisationSystem(); Community parent = communityService.create(null, context); Community child1 = communityService.create(parent, context); - + Collection col1 = collectionService.create(context, child1); Collection col2 = collectionService.create(context, child1); - + context.restoreAuthSystemState(); //verify it works as expected @@ -113,22 +113,20 @@ public class ITCommunityCollection extends AbstractIntegrationTest context.turnOffAuthorisationSystem(); communityService.delete(context, parent); } - + /** * Tests the creation of items in a community/collection tree */ @Test - @PerfTest(invocations = 25, threads = 1) - @Required(percentile95 = 1200, average = 700, throughput = 1) public void testCreateItems() throws SQLException, AuthorizeException, IOException { //we create the structure context.turnOffAuthorisationSystem(); Community parent = communityService.create(null, context); Community child1 = communityService.create(parent, context); - + Collection col1 = collectionService.create(context, child1); Collection col2 = collectionService.create(context, child1); - + Item item1 = installItemService.installItem(context, workspaceItemService.create(context, col1, false)); Item item2 = installItemService.installItem(context, workspaceItemService.create(context, col2, false)); @@ -142,13 +140,11 @@ public class ITCommunityCollection extends AbstractIntegrationTest communityService.delete(context, parent); } - /** - * Tests that count items works as expected - * NOTE: Counts are currently expensive (take a while) - */ + /** + * Tests that count items works as expected + * NOTE: Counts are currently expensive (take a while) + */ @Test - @PerfTest(invocations = 10, threads = 1) - @Required(percentile95 = 2000, average= 1800) public void testCountItems() throws SQLException, AuthorizeException, IOException { int items_per_collection = 2; @@ -161,20 +157,19 @@ public class ITCommunityCollection extends AbstractIntegrationTest Collection col2 = collectionService.create(context, childCom); // Add same number of items to each collection - for(int count = 0; count < items_per_collection; count++) - { + for (int count = 0; count < items_per_collection; count++) { Item item1 = installItemService.installItem(context, workspaceItemService.create(context, col1, false)); Item item2 = installItemService.installItem(context, workspaceItemService.create(context, col2, false)); } - + // Finally, let's throw in a small wrench and add a mapped item // Add it to collection 1 Item item3 = installItemService.installItem(context, workspaceItemService.create(context, col1, false)); // Map it into collection 2 collectionService.addItem(context, col2, item3); - + // Our total number of items should be - int totalitems = items_per_collection*2 + 1; + int totalitems = items_per_collection * 2 + 1; // Our collection counts should be int collTotalItems = items_per_collection + 1; @@ -190,13 +185,12 @@ public class ITCommunityCollection extends AbstractIntegrationTest communityService.delete(context, parentCom); } - /** - * Tests that ensure Community Admin deletion permissions are being properly - * inherited to all objects in the Community hierarchy. - */ + /** + * Tests that ensure Community Admin deletion permissions are being properly + * inherited to all objects in the Community hierarchy. + */ @Test - public void testCommunityAdminDeletions() throws SQLException, AuthorizeException, IOException - { + public void testCommunityAdminDeletions() throws SQLException, AuthorizeException, IOException { //Turn off auth while we create the EPerson and structure context.turnOffAuthorisationSystem(); @@ -215,6 +209,7 @@ public class ITCommunityCollection extends AbstractIntegrationTest // Create a hierachy of sub-Communities and Collections and Items. Community child = communityService.createSubcommunity(context, parentCom); Community child2 = communityService.createSubcommunity(context, parentCom); + Community child3 = communityService.createSubcommunity(context, parentCom); Community grandchild = communityService.createSubcommunity(context, child); Collection childCol = collectionService.create(context, child); Collection grandchildCol = collectionService.create(context, grandchild); @@ -237,24 +232,31 @@ public class ITCommunityCollection extends AbstractIntegrationTest UUID bitstreamId = bitstream.getID(); bitstreamService.delete(context, bitstream); assertTrue("Community Admin unable to flag Bitstream as deleted", - bitstream.isDeleted()); + bitstream.isDeleted()); // NOTE: A Community Admin CANNOT "expunge" a Bitstream, as delete() removes all their permissions // Test deletion of single Item as a Community Admin UUID itemId = item2.getID(); itemService.delete(context, item2); assertThat("Community Admin unable to delete sub-Item", - itemService.find(context, itemId), nullValue()); + itemService.find(context, itemId), nullValue()); // Test deletion of single Collection as a Community Admin UUID collId = grandchildCol.getID(); collectionService.delete(context, grandchildCol); assertThat("Community Admin unable to delete sub-Collection", - collectionService.find(context, collId), nullValue()); + collectionService.find(context, collId), nullValue()); // Test deletion of single Sub-Community as a Community Admin UUID commId = child2.getID(); communityService.delete(context, child2); + assertThat("Community Admin unable to delete sub-Community", + communityService.find(context, commId), nullValue()); + + // Test deletion of single Sub-Community with own admin group + communityService.createAdministrators(context, child3); + commId = child3.getID(); + communityService.delete(context, child3); assertThat("Community Admin unable to delete sub-Community", communityService.find(context, commId), nullValue()); @@ -264,11 +266,11 @@ public class ITCommunityCollection extends AbstractIntegrationTest itemId = item.getID(); communityService.delete(context, child); assertThat("Community Admin unable to delete sub-Community in hierarchy", - communityService.find(context, commId), nullValue()); + communityService.find(context, commId), nullValue()); assertThat("Community Admin unable to delete sub-Collection in hierarchy", - collectionService.find(context, collId), nullValue()); + collectionService.find(context, collId), nullValue()); assertThat("Community Admin unable to delete sub-Item in hierarchy", - itemService.find(context, itemId), nullValue()); + itemService.find(context, itemId), nullValue()); } /** @@ -276,8 +278,7 @@ public class ITCommunityCollection extends AbstractIntegrationTest * inherited to all objects in the Collection hierarchy. */ @Test - public void testCollectionAdminDeletions() throws SQLException, AuthorizeException, IOException - { + public void testCollectionAdminDeletions() throws SQLException, AuthorizeException, IOException { //Turn off auth while we create the EPerson and structure context.turnOffAuthorisationSystem(); @@ -314,14 +315,14 @@ public class ITCommunityCollection extends AbstractIntegrationTest UUID bitstreamId = bitstream2.getID(); bitstreamService.delete(context, bitstream2); assertTrue("Collection Admin unable to flag Bitstream as deleted", - bitstream2.isDeleted()); + bitstream2.isDeleted()); // NOTE: A Collection Admin CANNOT "expunge" a Bitstream, as delete() removes all their permissions // Test deletion of single Bundle as a Collection Admin UUID bundleId = bundle2.getID(); bundleService.delete(context, bundle2); assertThat("Collection Admin unable to delete Bundle", - bundleService.find(context, bundleId), nullValue()); + bundleService.find(context, bundleId), nullValue()); // Test deletion of single Item as a Collection Admin UUID itemId = item.getID(); @@ -329,10 +330,10 @@ public class ITCommunityCollection extends AbstractIntegrationTest bitstreamId = bitstream.getID(); itemService.delete(context, item); assertThat("Collection Admin unable to delete sub-Item", - itemService.find(context, itemId), nullValue()); + itemService.find(context, itemId), nullValue()); assertThat("Collection Admin unable to delete sub-Bundle", - bundleService.find(context, bundleId), nullValue()); + bundleService.find(context, bundleId), nullValue()); assertTrue("Collection Admin unable to flag sub-Bitstream as deleted", - bitstream.isDeleted()); + bitstream.isDeleted()); } } diff --git a/dspace-api/src/test/java/org/dspace/content/ITMetadata.java b/dspace-api/src/test/java/org/dspace/content/ITMetadata.java index ec7498f838..e8bc5e5414 100644 --- a/dspace-api/src/test/java/org/dspace/content/ITMetadata.java +++ b/dspace-api/src/test/java/org/dspace/content/ITMetadata.java @@ -7,31 +7,39 @@ */ package org.dspace.content; -import org.apache.log4j.Logger; -import org.databene.contiperf.PerfTest; -import org.databene.contiperf.Required; -import org.dspace.AbstractIntegrationTest; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.sql.SQLException; import java.util.List; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.*; +import org.apache.log4j.Logger; +import org.dspace.AbstractIntegrationTest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.MetadataValueService; +import org.dspace.content.service.WorkspaceItemService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * This is an integration test to validate the metadata classes + * * @author pvillega */ -public class ITMetadata extends AbstractIntegrationTest -{ - /** log4j category */ +public class ITMetadata extends AbstractIntegrationTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(ITMetadata.class); @@ -39,7 +47,8 @@ public class ITMetadata extends AbstractIntegrationTest protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); - protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); protected MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService(); @@ -52,8 +61,7 @@ public class ITMetadata extends AbstractIntegrationTest */ @Before @Override - public void init() - { + public void init() { super.init(); } @@ -66,8 +74,7 @@ public class ITMetadata extends AbstractIntegrationTest */ @After @Override - public void destroy() - { + public void destroy() { super.destroy(); } @@ -75,10 +82,7 @@ public class ITMetadata extends AbstractIntegrationTest * Tests the creation of a new metadata schema with some values */ @Test - @PerfTest(invocations = 50, threads = 1) - @Required(percentile95 = 500, average= 200) - public void testCreateSchema() throws SQLException, AuthorizeException, NonUniqueMetadataException, IOException - { + public void testCreateSchema() throws SQLException, AuthorizeException, NonUniqueMetadataException, IOException { String schemaName = "integration"; //we create the structure @@ -110,12 +114,10 @@ public class ITMetadata extends AbstractIntegrationTest List fields = metadataFieldService.findAllInSchema(context, schema); assertTrue("testCreateSchema 3", fields.size() == 2); boolean exist = true; - for(MetadataField f : fields) - { - if(!f.equals(field1) && !f.equals(field2)) - { - exist = false; - } + for (MetadataField f : fields) { + if (!f.equals(field1) && !f.equals(field2)) { + exist = false; + } } assertTrue("testCreateSchema 4", exist); diff --git a/dspace-api/src/test/java/org/dspace/content/InProgressSubmissionTest.java b/dspace-api/src/test/java/org/dspace/content/InProgressSubmissionTest.java index ac87c3853c..28f56a790a 100644 --- a/dspace-api/src/test/java/org/dspace/content/InProgressSubmissionTest.java +++ b/dspace-api/src/test/java/org/dspace/content/InProgressSubmissionTest.java @@ -18,12 +18,14 @@ import org.junit.Test; * (no implementation) no tests are added. This class is created for * coberture purposes and in case we want to use this class as parent * of the unit tests related to this interface + * * @author pvillega */ -public class InProgressSubmissionTest extends AbstractUnitTest -{ +public class InProgressSubmissionTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(InProgressSubmissionTest.class); /** @@ -35,8 +37,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); } @@ -49,8 +50,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { super.destroy(); } @@ -58,17 +58,15 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of getID method, of class InProgressSubmission. */ @Test - public void testGetID() - { - + public void testGetID() { + } /** * Test of deleteWrapper method, of class InProgressSubmission. */ @Test - public void testDeleteWrapper() throws Exception - { + public void testDeleteWrapper() throws Exception { } @@ -76,8 +74,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of update method, of class InProgressSubmission. */ @Test - public void testUpdate() throws Exception - { + public void testUpdate() throws Exception { } @@ -85,8 +82,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of getItem method, of class InProgressSubmission. */ @Test - public void testGetItem() - { + public void testGetItem() { } @@ -94,8 +90,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of getCollection method, of class InProgressSubmission. */ @Test - public void testGetCollection() - { + public void testGetCollection() { } @@ -103,8 +98,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of getSubmitter method, of class InProgressSubmission. */ @Test - public void testGetSubmitter() throws Exception - { + public void testGetSubmitter() throws Exception { } @@ -112,8 +106,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of hasMultipleFiles method, of class InProgressSubmission. */ @Test - public void testHasMultipleFiles() - { + public void testHasMultipleFiles() { } @@ -121,8 +114,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of setMultipleFiles method, of class InProgressSubmission. */ @Test - public void testSetMultipleFiles() - { + public void testSetMultipleFiles() { } @@ -130,8 +122,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of hasMultipleTitles method, of class InProgressSubmission. */ @Test - public void testHasMultipleTitles() - { + public void testHasMultipleTitles() { } @@ -139,8 +130,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of setMultipleTitles method, of class InProgressSubmission. */ @Test - public void testSetMultipleTitles() - { + public void testSetMultipleTitles() { } @@ -148,8 +138,7 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of isPublishedBefore method, of class InProgressSubmission. */ @Test - public void testIsPublishedBefore() - { + public void testIsPublishedBefore() { } @@ -157,9 +146,8 @@ public class InProgressSubmissionTest extends AbstractUnitTest * Test of setPublishedBefore method, of class InProgressSubmission. */ @Test - public void testSetPublishedBefore() - { + public void testSetPublishedBefore() { } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/InstallItemTest.java b/dspace-api/src/test/java/org/dspace/content/InstallItemTest.java index 2ff28bc599..72a7f626b8 100644 --- a/dspace-api/src/test/java/org/dspace/content/InstallItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/InstallItemTest.java @@ -7,12 +7,30 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.List; +import java.util.TimeZone; + import mockit.NonStrictExpectations; import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.eperson.EPerson; @@ -22,24 +40,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.text.SimpleDateFormat; -import java.util.List; -import java.util.Calendar; -import java.util.TimeZone; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.*; - /** * Unit Tests for class InstallItem + * * @author pvillega */ -public class InstallItemTest extends AbstractUnitTest -{ +public class InstallItemTest extends AbstractUnitTest { protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); @@ -51,28 +57,28 @@ public class InstallItemTest extends AbstractUnitTest private Collection collection; private Community owningCommunity; - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(InstallItemTest.class); - /** Used to check/verify thrown exceptions in below tests **/ + /** + * Used to check/verify thrown exceptions in below tests + **/ @Rule public ExpectedException thrown = ExpectedException.none(); - @Before @Override - public void init() - { + public void init() { super.init(); try { context.turnOffAuthorisationSystem(); this.owningCommunity = communityService.create(null, context); this.collection = collectionService.create(context, owningCommunity); context.restoreAuthSystemState(); - } - catch (SQLException | AuthorizeException ex) - { + } catch (SQLException | AuthorizeException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -87,8 +93,7 @@ public class InstallItemTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { try { context.turnOffAuthorisationSystem(); communityService.delete(context, owningCommunity); @@ -106,8 +111,7 @@ public class InstallItemTest extends AbstractUnitTest * Test of installItem method, of class InstallItem. */ @Test - public void testInstallItem_Context_InProgressSubmission() throws Exception - { + public void testInstallItem_Context_InProgressSubmission() throws Exception { context.turnOffAuthorisationSystem(); WorkspaceItem is = workspaceItemService.create(context, collection, false); @@ -120,12 +124,11 @@ public class InstallItemTest extends AbstractUnitTest * Test of installItem method (with a valid handle), of class InstallItem. */ @Test - public void testInstallItem_validHandle() throws Exception - { + public void testInstallItem_validHandle() throws Exception { context.turnOffAuthorisationSystem(); String handle = "123456789/56789"; WorkspaceItem is = workspaceItemService.create(context, collection, false); - + //Test assigning a specified handle to an item // (this handle should not already be used by system, as it doesn't start with "1234567689" prefix) Item result = installItemService.installItem(context, is, handle); @@ -138,23 +141,24 @@ public class InstallItemTest extends AbstractUnitTest * Test of installItem method (with an invalid handle), of class InstallItem. */ @Test - public void testInstallItem_invalidHandle() throws Exception - { + public void testInstallItem_invalidHandle() throws Exception { //Default to Full-Admin rights - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Deny Community ADD perms - authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD); result = false; + authorizeService.authorizeActionBoolean((Context) any, (Community) any, + Constants.ADD); + result = false; // Allow full Admin perms - authorizeService.isAdmin((Context) any); result = true; - authorizeService.isAdmin((Context) any, (EPerson) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; + authorizeService.isAdmin((Context) any, (EPerson) any); + result = true; }}; String handle = "123456789/56789"; WorkspaceItem is = workspaceItemService.create(context, collection, false); WorkspaceItem is2 = workspaceItemService.create(context, collection, false); - + //Test assigning the same Handle to two different items installItemService.installItem(context, is, handle); @@ -169,8 +173,7 @@ public class InstallItemTest extends AbstractUnitTest * Test of restoreItem method, of class InstallItem. */ @Test - public void testRestoreItem() throws Exception - { + public void testRestoreItem() throws Exception { context.turnOffAuthorisationSystem(); String handle = "123456789/56789"; WorkspaceItem is = workspaceItemService.create(context, collection, false); @@ -184,7 +187,7 @@ public class InstallItemTest extends AbstractUnitTest //Build the beginning of a dummy provenance message //(restoreItem should NEVER insert a provenance message with today's date) String provDescriptionBegins = "Made available in DSpace on " + date; - + Item result = installItemService.restoreItem(context, is, handle); context.restoreAuthSystemState(); @@ -192,10 +195,10 @@ public class InstallItemTest extends AbstractUnitTest assertThat("testRestoreItem 0", result, equalTo(is.getItem())); //Make sure that restore did NOT insert a new provenance message with today's date - List provMsgValues = itemService.getMetadata(result, "dc", "description", "provenance", Item.ANY); + List provMsgValues = itemService + .getMetadata(result, "dc", "description", "provenance", Item.ANY); int i = 1; - for(MetadataValue val : provMsgValues) - { + for (MetadataValue val : provMsgValues) { assertFalse("testRestoreItem " + i, val.getValue().startsWith(provDescriptionBegins)); i++; } @@ -205,8 +208,7 @@ public class InstallItemTest extends AbstractUnitTest * Test of getBitstreamProvenanceMessage method, of class InstallItem. */ @Test - public void testGetBitstreamProvenanceMessage() throws Exception - { + public void testGetBitstreamProvenanceMessage() throws Exception { File f = new File(testProps.get("test.bitstream").toString()); context.turnOffAuthorisationSystem(); WorkspaceItem is = workspaceItemService.create(context, collection, false); @@ -223,23 +225,23 @@ public class InstallItemTest extends AbstractUnitTest // Create provenance description String testMessage = "No. of bitstreams: 2\n"; testMessage += "one: " - + one.getSize() + " bytes, checksum: " - + one.getChecksum() + " (" - + one.getChecksumAlgorithm() + ")\n"; + + one.getSizeBytes() + " bytes, checksum: " + + one.getChecksum() + " (" + + one.getChecksumAlgorithm() + ")\n"; testMessage += "two: " - + two.getSize() + " bytes, checksum: " - + two.getChecksum() + " (" - + two.getChecksumAlgorithm() + ")\n"; + + two.getSizeBytes() + " bytes, checksum: " + + two.getChecksum() + " (" + + two.getChecksumAlgorithm() + ")\n"; - assertThat("testGetBitstreamProvenanceMessage 0", installItemService.getBitstreamProvenanceMessage(context, item), equalTo(testMessage)); + assertThat("testGetBitstreamProvenanceMessage 0", + installItemService.getBitstreamProvenanceMessage(context, item), equalTo(testMessage)); } /** * Test passing in "today" as an issued date to InstallItem. */ @Test - public void testInstallItem_todayAsIssuedDate() throws Exception - { + public void testInstallItem_todayAsIssuedDate() throws Exception { //create a dummy WorkspaceItem context.turnOffAuthorisationSystem(); String handle = "123456789/56789"; @@ -253,7 +255,7 @@ public class InstallItemTest extends AbstractUnitTest Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.setTimeZone(TimeZone.getTimeZone("UTC")); - + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String date = sdf.format(calendar.getTime()); @@ -272,8 +274,7 @@ public class InstallItemTest extends AbstractUnitTest * Test null issue date (when none set) in InstallItem */ @Test - public void testInstallItem_nullIssuedDate() throws Exception - { + public void testInstallItem_nullIssuedDate() throws Exception { //create a dummy WorkspaceItem with no dc.date.issued context.turnOffAuthorisationSystem(); String handle = "123456789/56789"; @@ -291,8 +292,7 @@ public class InstallItemTest extends AbstractUnitTest * Test passing in "today" as an issued date to restoreItem. */ @Test - public void testRestoreItem_todayAsIssuedDate() throws Exception - { + public void testRestoreItem_todayAsIssuedDate() throws Exception { //create a dummy WorkspaceItem context.turnOffAuthorisationSystem(); String handle = "123456789/56789"; diff --git a/dspace-api/src/test/java/org/dspace/content/ItemComparatorTest.java b/dspace-api/src/test/java/org/dspace/content/ItemComparatorTest.java index e9e2f8fd78..71fdcb41e8 100644 --- a/dspace-api/src/test/java/org/dspace/content/ItemComparatorTest.java +++ b/dspace-api/src/test/java/org/dspace/content/ItemComparatorTest.java @@ -7,24 +7,39 @@ */ package org.dspace.content; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; import java.sql.SQLException; + import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.junit.*; -import static org.junit.Assert.* ; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.MetadataValueService; +import org.dspace.content.service.WorkspaceItemService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Unit Tests for class ItemComparator + * * @author pvillega */ -public class ItemComparatorTest extends AbstractUnitTest -{ +public class ItemComparatorTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(ItemComparatorTest.class); protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); @@ -32,7 +47,8 @@ public class ItemComparatorTest extends AbstractUnitTest private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService(); - protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); private MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService(); @@ -60,10 +76,8 @@ public class ItemComparatorTest extends AbstractUnitTest */ @Before @Override - public void init() - { - try - { + public void init() { + try { super.init(); context.turnOffAuthorisationSystem(); @@ -76,14 +90,10 @@ public class ItemComparatorTest extends AbstractUnitTest workspaceItem = workspaceItemService.create(context, collection, false); this.two = installItemService.installItem(context, workspaceItem); context.restoreAuthSystemState(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init:" + ex.getMessage()); } catch (NonUniqueMetadataException ex) { @@ -101,16 +111,15 @@ public class ItemComparatorTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { context.turnOffAuthorisationSystem(); - try{ - // Remove all values added to the test MetadataField (MetadataField cannot be deleted if it is still used) - metadataValueService.deleteByMetadataField(context, metadataField); - // Delete the (unused) metadataField - metadataFieldService.delete(context, metadataField); - communityService.delete(context, owningCommunity); - context.restoreAuthSystemState(); + try { + // Remove all values added to the test MetadataField (MetadataField cannot be deleted if it is still used) + metadataValueService.deleteByMetadataField(context, metadataField); + // Delete the (unused) metadataField + metadataFieldService.delete(context, metadataField); + communityService.delete(context, owningCommunity); + context.restoreAuthSystemState(); } catch (SQLException | AuthorizeException | IOException ex) { log.error("SQL Error in destroy", ex); fail("SQL Error in destroy: " + ex.getMessage()); @@ -129,42 +138,42 @@ public class ItemComparatorTest extends AbstractUnitTest //one of the tiems has no value ic = new ItemComparator("test", "one", Item.ANY, true); result = ic.compare(one, two); - assertTrue("testCompare 0",result == 0); + assertTrue("testCompare 0", result == 0); ic = new ItemComparator("test", "one", Item.ANY, true); itemService.addMetadata(context, one, "dc", "test", "one", Item.ANY, "1"); result = ic.compare(one, two); - assertTrue("testCompare 1",result >= 1); + assertTrue("testCompare 1", result >= 1); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); - + ic = new ItemComparator("test", "one", Item.ANY, true); - itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "1"); + itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "1"); result = ic.compare(one, two); - assertTrue("testCompare 2",result <= -1); + assertTrue("testCompare 2", result <= -1); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); - + //value in both items ic = new ItemComparator("test", "one", Item.ANY, true); itemService.addMetadata(context, one, "dc", "test", "one", Item.ANY, "1"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "2"); result = ic.compare(one, two); - assertTrue("testCompare 3",result <= -1); + assertTrue("testCompare 3", result <= -1); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); - + ic = new ItemComparator("test", "one", Item.ANY, true); itemService.addMetadata(context, one, "dc", "test", "one", Item.ANY, "1"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "1"); result = ic.compare(one, two); - assertTrue("testCompare 4",result == 0); + assertTrue("testCompare 4", result == 0); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); - + ic = new ItemComparator("test", "one", Item.ANY, true); itemService.addMetadata(context, one, "dc", "test", "one", Item.ANY, "2"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "1"); result = ic.compare(one, two); - assertTrue("testCompare 5",result >= 1); + assertTrue("testCompare 5", result >= 1); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); @@ -175,7 +184,7 @@ public class ItemComparatorTest extends AbstractUnitTest itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "2"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "3"); result = ic.compare(one, two); - assertTrue("testCompare 3",result <= -1); + assertTrue("testCompare 3", result <= -1); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); @@ -185,7 +194,7 @@ public class ItemComparatorTest extends AbstractUnitTest itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "-1"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "1"); result = ic.compare(one, two); - assertTrue("testCompare 4",result == 0); + assertTrue("testCompare 4", result == 0); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); @@ -195,7 +204,7 @@ public class ItemComparatorTest extends AbstractUnitTest itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "1"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "-1"); result = ic.compare(one, two); - assertTrue("testCompare 5",result >= 1); + assertTrue("testCompare 5", result >= 1); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); @@ -205,7 +214,7 @@ public class ItemComparatorTest extends AbstractUnitTest itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "2"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "3"); result = ic.compare(one, two); - assertTrue("testCompare 3",result <= -1); + assertTrue("testCompare 3", result <= -1); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); @@ -215,7 +224,7 @@ public class ItemComparatorTest extends AbstractUnitTest itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "1"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "5"); result = ic.compare(one, two); - assertTrue("testCompare 4",result == 0); + assertTrue("testCompare 4", result == 0); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); @@ -225,7 +234,7 @@ public class ItemComparatorTest extends AbstractUnitTest itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "1"); itemService.addMetadata(context, two, "dc", "test", "one", Item.ANY, "4"); result = ic.compare(one, two); - assertTrue("testCompare 5",result >= 1); + assertTrue("testCompare 5", result >= 1); itemService.clearMetadata(context, one, "dc", "test", "one", Item.ANY); itemService.clearMetadata(context, two, "dc", "test", "one", Item.ANY); } @@ -234,9 +243,8 @@ public class ItemComparatorTest extends AbstractUnitTest * Test of equals method, of class ItemComparator. */ @Test - @SuppressWarnings({"ObjectEqualsNull", "IncompatibleEquals"}) - public void testEquals() - { + @SuppressWarnings( {"ObjectEqualsNull", "IncompatibleEquals"}) + public void testEquals() { ItemComparator ic = new ItemComparator("test", "one", Item.ANY, true); ItemComparator target = null; @@ -259,4 +267,4 @@ public class ItemComparatorTest extends AbstractUnitTest assertTrue("testEquals 6", ic.equals(target)); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/ItemTest.java b/dspace-api/src/test/java/org/dspace/content/ItemTest.java index 48b63dc404..32e6e5deb5 100644 --- a/dspace-api/src/test/java/org/dspace/content/ItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/ItemTest.java @@ -7,6 +7,27 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + import mockit.NonStrictExpectations; import org.apache.commons.lang.time.DateUtils; import org.apache.log4j.Logger; @@ -25,24 +46,16 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.sql.SQLException; -import java.util.*; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - /** * Unit Tests for class Item + * * @author pvillega */ -public class ItemTest extends AbstractDSpaceObjectTest -{ +public class ItemTest extends AbstractDSpaceObjectTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(ItemTest.class); /** @@ -50,8 +63,10 @@ public class ItemTest extends AbstractDSpaceObjectTest */ private Item it; - private MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); - private BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + private MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); + private BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); private MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); private Collection collection; @@ -67,11 +82,9 @@ public class ItemTest extends AbstractDSpaceObjectTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { //we have to create a new community in the database context.turnOffAuthorisationSystem(); this.owningCommunity = communityService.create(null, context); @@ -84,14 +97,10 @@ public class ItemTest extends AbstractDSpaceObjectTest this.dspaceObject = it; //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -106,31 +115,34 @@ public class ItemTest extends AbstractDSpaceObjectTest */ @After @Override - public void destroy() - { + public void destroy() { context.turnOffAuthorisationSystem(); try { itemService.delete(context, it); - } catch(Exception e){ + } catch (Exception e) { + // ignore } - + try { collectionService.delete(context, collection); - } catch(Exception e){ + } catch (Exception e) { + // ignore } - + try { communityService.delete(context, owningCommunity); - } catch(Exception e){ + } catch (Exception e) { + // ignore } - + context.restoreAuthSystemState(); it = null; collection = null; owningCommunity = null; try { super.destroy(); - } catch(Exception e){ + } catch (Exception e) { + // ignore } } @@ -139,12 +151,11 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of find method, of class Item. */ @Test - public void testItemFind() throws Exception - { + public void testItemFind() throws Exception { // Get ID of item created in init() UUID id = it.getID(); // Make sure we can find it via its ID - Item found = itemService.find(context, id); + Item found = itemService.find(context, id); assertThat("testItemFind 0", found, notNullValue()); assertThat("testItemFind 1", found.getID(), equalTo(id)); assertThat("testItemFind 2", found.getName(), nullValue()); @@ -154,15 +165,15 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of create method, of class Item. */ @Test - public void testCreate() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreate() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms (needed to create an Item) authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; Item created = createItem(); assertThat("testCreate 0", created, notNullValue()); @@ -173,42 +184,36 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of findAll method, of class Item. */ @Test - public void testFindAll() throws Exception - { + public void testFindAll() throws Exception { Iterator all = itemService.findAll(context); assertThat("testFindAll 0", all, notNullValue()); boolean added = false; - while(all.hasNext()) - { + while (all.hasNext()) { Item tmp = all.next(); - if(tmp.equals(it)) - { + if (tmp.equals(it)) { added = true; } } - assertTrue("testFindAll 1",added); + assertTrue("testFindAll 1", added); } /** * Test of findBySubmitter method, of class Item. */ @Test - public void testFindBySubmitter() throws Exception - { + public void testFindBySubmitter() throws Exception { Iterator all = itemService.findBySubmitter(context, context.getCurrentUser()); assertThat("testFindBySubmitter 0", all, notNullValue()); boolean added = false; - while(all.hasNext()) - { + while (all.hasNext()) { Item tmp = all.next(); - if(tmp.equals(it)) - { + if (tmp.equals(it)) { added = true; } } - assertTrue("testFindBySubmitter 1",added); + assertTrue("testFindBySubmitter 1", added); context.turnOffAuthorisationSystem(); all = itemService.findBySubmitter(context, ePersonService.create(context)); @@ -218,13 +223,130 @@ public class ItemTest extends AbstractDSpaceObjectTest assertFalse("testFindBySubmitter 3", all.hasNext()); } + /** + * Test of findInArchiveOrWithdrawnDiscoverableModifiedSince method, of class Item. + */ + @Test + public void testFindInArchiveOrWithdrawnDiscoverableModifiedSince() throws Exception { + // Init item to be both withdrawn and discoverable + it.setWithdrawn(true); + it.setArchived(false); + it.setDiscoverable(true); + // Test 0: Using a future 'modified since' date, we should get non-null list, with no items + Iterator all = itemService.findInArchiveOrWithdrawnDiscoverableModifiedSince(context, + DateUtils.addDays(it.getLastModified(),1)); + assertThat("Returned list should not be null", all, notNullValue()); + boolean added = false; + while (all.hasNext()) { + Item tmp = all.next(); + if (tmp.equals(it)) { + added = true; + } + } + // Test 1: we should NOT find our item in this list + assertFalse("List should not contain item when passing a date newer than item last-modified date", added); + // Test 2: Using a past 'modified since' date, we should get a non-null list containing our item + all = itemService.findInArchiveOrWithdrawnDiscoverableModifiedSince(context, + DateUtils.addDays(it.getLastModified(),-1)); + assertThat("Returned list should not be null", all, notNullValue()); + added = false; + while (all.hasNext()) { + Item tmp = all.next(); + if (tmp.equals(it)) { + added = true; + } + } + // Test 3: we should find our item in this list + assertTrue("List should contain item when passing a date older than item last-modified date", added); + // Repeat Tests 2, 3 with withdrawn = false and archived = true as this should result in same behaviour + it.setWithdrawn(false); + it.setArchived(true); + // Test 4: Using a past 'modified since' date, we should get a non-null list containing our item + all = itemService.findInArchiveOrWithdrawnDiscoverableModifiedSince(context, + DateUtils.addDays(it.getLastModified(),-1)); + assertThat("Returned list should not be null", all, notNullValue()); + added = false; + while (all.hasNext()) { + Item tmp = all.next(); + if (tmp.equals(it)) { + added = true; + } + } + // Test 5: We should find our item in this list + assertTrue("List should contain item when passing a date older than item last-modified date", added); + // Test 6: Make sure non-discoverable items are not returned, regardless of archived/withdrawn state + it.setDiscoverable(false); + all = itemService.findInArchiveOrWithdrawnDiscoverableModifiedSince(context, + DateUtils.addDays(it.getLastModified(),-1)); + assertThat("Returned list should not be null", all, notNullValue()); + added = false; + while (all.hasNext()) { + Item tmp = all.next(); + if (tmp.equals(it)) { + added = true; + } + } + // Test 7: We should not find our item in this list + assertFalse("List should not contain non-discoverable items", added); + } + /** + * Test of findInArchiveOrWithdrawnNonDiscoverableModifiedSince method, of class Item. + */ + @Test + public void testFindInArchiveOrWithdrawnNonDiscoverableModifiedSince() throws Exception { + // Init item to be both withdrawn and discoverable + it.setWithdrawn(true); + it.setArchived(false); + it.setDiscoverable(false); + // Test 0: Using a future 'modified since' date, we should get non-null list, with no items + Iterator all = itemService.findInArchiveOrWithdrawnNonDiscoverableModifiedSince(context, + DateUtils.addDays(it.getLastModified(),1)); + assertThat("Returned list should not be null", all, notNullValue()); + boolean added = false; + while (all.hasNext()) { + Item tmp = all.next(); + if (tmp.equals(it)) { + added = true; + } + } + // Test 1: We should NOT find our item in this list + assertFalse("List should not contain item when passing a date newer than item last-modified date", added); + // Test 2: Using a past 'modified since' date, we should get a non-null list containing our item + all = itemService.findInArchiveOrWithdrawnNonDiscoverableModifiedSince(context, + DateUtils.addDays(it.getLastModified(),-1)); + assertThat("Returned list should not be null", all, notNullValue()); + added = false; + while (all.hasNext()) { + Item tmp = all.next(); + if (tmp.equals(it)) { + added = true; + } + } + // Test 3: We should find our item in this list + assertTrue("List should contain item when passing a date older than item last-modified date", added); + // Repeat Tests 2, 3 with discoverable = true + it.setDiscoverable(true); + // Test 4: Now we should still get a non-null list with NO items since item is discoverable + all = itemService.findInArchiveOrWithdrawnNonDiscoverableModifiedSince(context, + DateUtils.addDays(it.getLastModified(),-1)); + assertThat("Returned list should not be null", all, notNullValue()); + added = false; + while (all.hasNext()) { + Item tmp = all.next(); + if (tmp.equals(it)) { + added = true; + } + } + // Test 5: We should NOT find our item in this list + assertFalse("List should not contain discoverable items", added); + } + /** * Test of getID method, of class Item. */ @Override @Test - public void testGetID() - { + public void testGetID() { assertTrue("testGetID 0", it.getID() != null); } @@ -233,8 +355,7 @@ public class ItemTest extends AbstractDSpaceObjectTest */ @Override @Test - public void testGetHandle() - { + public void testGetHandle() { //default instance has a random handle assertThat("testGetHandle 0", it.getHandle(), notNullValue()); } @@ -258,8 +379,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of isWithdrawn method, of class Item. */ @Test - public void testIsWithdrawn() - { + public void testIsWithdrawn() { assertFalse("testIsWithdrawn 0", it.isWithdrawn()); } @@ -267,8 +387,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getLastModified method, of class Item. */ @Test - public void testGetLastModified() - { + public void testGetLastModified() { assertThat("testGetLastModified 0", it.getLastModified(), notNullValue()); assertTrue("testGetLastModified 1", DateUtils.isSameDay(it.getLastModified(), new Date())); } @@ -277,8 +396,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of setArchived method, of class Item. */ @Test - public void testSetArchived() - { + public void testSetArchived() { it.setArchived(true); assertTrue("testSetArchived 0", it.isArchived()); } @@ -287,8 +405,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of setOwningCollection method, of class Item. */ @Test - public void testSetOwningCollection() throws SQLException, AuthorizeException - { + public void testSetOwningCollection() throws SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); Collection c = createCollection(); context.restoreAuthSystemState(); @@ -302,8 +419,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getOwningCollection method, of class Item. */ @Test - public void testGetOwningCollection() throws Exception - { + public void testGetOwningCollection() throws Exception { assertThat("testGetOwningCollection 0", it.getOwningCollection(), notNullValue()); assertEquals("testGetOwningCollection 1", it.getOwningCollection(), collection); } @@ -312,37 +428,35 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getMetadata method, of class Item. */ @Test - public void testGetMetadata_4args() - { + public void testGetMetadata_4args() { String schema = "dc"; String element = "contributor"; String qualifier = "author"; String lang = Item.ANY; List dc = itemService.getMetadata(it, schema, element, qualifier, lang); - assertThat("testGetMetadata_4args 0",dc,notNullValue()); - assertTrue("testGetMetadata_4args 1",dc.size() == 0); + assertThat("testGetMetadata_4args 0", dc, notNullValue()); + assertTrue("testGetMetadata_4args 1", dc.size() == 0); } /** * Test of getMetadataByMetadataString method, of class Item. */ @Test - public void testGetMetadata_String() - { + public void testGetMetadata_String() { String mdString = "dc.contributor.author"; List dc = itemService.getMetadataByMetadataString(it, mdString); - assertThat("testGetMetadata_String 0",dc,notNullValue()); - assertTrue("testGetMetadata_String 1",dc.size() == 0); + assertThat("testGetMetadata_String 0", dc, notNullValue()); + assertTrue("testGetMetadata_String 1", dc.size() == 0); mdString = "dc.contributor.*"; dc = itemService.getMetadataByMetadataString(it, mdString); - assertThat("testGetMetadata_String 2",dc,notNullValue()); - assertTrue("testGetMetadata_String 3",dc.size() == 0); + assertThat("testGetMetadata_String 2", dc, notNullValue()); + assertTrue("testGetMetadata_String 3", dc.size() == 0); mdString = "dc.contributor"; dc = itemService.getMetadataByMetadataString(it, mdString); - assertThat("testGetMetadata_String 4",dc,notNullValue()); - assertTrue("testGetMetadata_String 5",dc.size() == 0); + assertThat("testGetMetadata_String 4", dc, notNullValue()); + assertTrue("testGetMetadata_String 5", dc.size() == 0); } /** @@ -359,8 +473,8 @@ public class ItemTest extends AbstractDSpaceObjectTest // Set the item to have two pieces of metadata for dc.type and dc2.type String dcType = "DC-TYPE"; String testType = "TEST-TYPE"; - itemService.addMetadata(context, it, "dc", "type", null, null, dcType); - itemService.addMetadata(context, it, "test", "type", null, null, testType); + itemService.addMetadata(context, it, "dc", "type", null, null, dcType, "accepted", 0); + itemService.addMetadata(context, it, "test", "type", null, null, testType, "accepted", 0); // Check that only one is returned when we ask for all dc.type values List values = itemService.getMetadata(it, "dc", "type", null, null); @@ -378,35 +492,38 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of addMetadata method, of class Item. */ @Test - public void testAddMetadata_5args_1() throws SQLException - { + public void testAddMetadata_5args_1() throws SQLException { String schema = "dc"; String element = "contributor"; String qualifier = "author"; String lang = Item.ANY; - String[] values = {"value0","value1"}; + String[] values = {"value0", "value1"}; itemService.addMetadata(context, it, schema, element, qualifier, lang, Arrays.asList(values)); List dc = itemService.getMetadata(it, schema, element, qualifier, lang); - assertThat("testAddMetadata_5args_1 0",dc,notNullValue()); - assertTrue("testAddMetadata_5args_1 1",dc.size() == 2); - assertThat("testAddMetadata_5args_1 2",dc.get(0).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_5args_1 3",dc.get(0).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_5args_1 4",dc.get(0).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_5args_1 5",dc.get(0).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_5args_1 6",dc.get(0).getValue(),equalTo(values[0])); - assertThat("testAddMetadata_5args_1 7",dc.get(1).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_5args_1 8",dc.get(1).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_5args_1 9",dc.get(1).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_5args_1 10",dc.get(1).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_5args_1 11",dc.get(1).getValue(),equalTo(values[1])); + assertThat("testAddMetadata_5args_1 0", dc, notNullValue()); + assertTrue("testAddMetadata_5args_1 1", dc.size() == 2); + assertThat("testAddMetadata_5args_1 2", dc.get(0).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_5args_1 3", dc.get(0).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_5args_1 4", dc.get(0).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_5args_1 5", dc.get(0).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_5args_1 6", dc.get(0).getValue(), equalTo(values[0])); + assertThat("testAddMetadata_5args_1 7", dc.get(1).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_5args_1 8", dc.get(1).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_5args_1 9", dc.get(1).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_5args_1 10", dc.get(1).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_5args_1 11", dc.get(1).getValue(), equalTo(values[1])); } /** * Test of addMetadata method, of class Item. */ @Test - public void testAddMetadata_7args_1_authority() throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, SQLException { + public void testAddMetadata_7args_1_authority() + throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, + IllegalArgumentException, InvocationTargetException, SQLException { //we have enabled an authority control in our test local.cfg to run this test //as MetadataAuthorityManager can't be mocked properly @@ -414,64 +531,67 @@ public class ItemTest extends AbstractDSpaceObjectTest String element = "language"; String qualifier = "iso"; String lang = Item.ANY; - List values = Arrays.asList("en_US","en"); - List authorities = Arrays.asList("accepted","uncertain"); - List confidences = Arrays.asList(0,0); + List values = Arrays.asList("en_US", "en"); + List authorities = Arrays.asList("accepted", "uncertain"); + List confidences = Arrays.asList(0, 0); itemService.addMetadata(context, it, schema, element, qualifier, lang, values, authorities, confidences); List dc = itemService.getMetadata(it, schema, element, qualifier, lang); - assertThat("testAddMetadata_7args_1 0",dc,notNullValue()); - assertTrue("testAddMetadata_7args_1 1",dc.size() == 2); - assertThat("testAddMetadata_7args_1 2",dc.get(0).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_7args_1 3",dc.get(0).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_7args_1 4",dc.get(0).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_7args_1 5",dc.get(0).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_7args_1 6",dc.get(0).getValue(),equalTo(values.get(0))); - assertThat("testAddMetadata_7args_1 7",dc.get(0).getAuthority(),equalTo(authorities.get(0))); - assertThat("testAddMetadata_7args_1 8",dc.get(0).getConfidence(),equalTo(confidences.get(0))); - assertThat("testAddMetadata_7args_1 9",dc.get(1).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_7args_1 10",dc.get(1).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_7args_1 11",dc.get(1).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_7args_1 12",dc.get(1).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_7args_1 13",dc.get(1).getValue(),equalTo(values.get(1))); - assertThat("testAddMetadata_7args_1 14",dc.get(1).getAuthority(),equalTo(authorities.get(1))); - assertThat("testAddMetadata_7args_1 15",dc.get(1).getConfidence(),equalTo(confidences.get(1))); + assertThat("testAddMetadata_7args_1 0", dc, notNullValue()); + assertTrue("testAddMetadata_7args_1 1", dc.size() == 2); + assertThat("testAddMetadata_7args_1 2", dc.get(0).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_7args_1 3", dc.get(0).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_7args_1 4", dc.get(0).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_7args_1 5", dc.get(0).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_7args_1 6", dc.get(0).getValue(), equalTo(values.get(0))); + assertThat("testAddMetadata_7args_1 7", dc.get(0).getAuthority(), equalTo(authorities.get(0))); + assertThat("testAddMetadata_7args_1 8", dc.get(0).getConfidence(), equalTo(confidences.get(0))); + assertThat("testAddMetadata_7args_1 9", dc.get(1).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_7args_1 10", dc.get(1).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_7args_1 11", dc.get(1).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_7args_1 12", dc.get(1).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_7args_1 13", dc.get(1).getValue(), equalTo(values.get(1))); + assertThat("testAddMetadata_7args_1 14", dc.get(1).getAuthority(), equalTo(authorities.get(1))); + assertThat("testAddMetadata_7args_1 15", dc.get(1).getConfidence(), equalTo(confidences.get(1))); } - /** + /** * Test of addMetadata method, of class Item. */ @Test - public void testAddMetadata_7args_1_noauthority() throws SQLException - { + public void testAddMetadata_7args_1_noauthority() throws SQLException { //by default has no authority String schema = "dc"; String element = "contributor"; String qualifier = "author"; String lang = Item.ANY; - List values = Arrays.asList("value0","value1"); - List authorities = Arrays.asList("auth0","auth2"); - List confidences = Arrays.asList(0,0); + List values = Arrays.asList("value0", "value1"); + List authorities = Arrays.asList("auth0", "auth2"); + List confidences = Arrays.asList(0, 0); itemService.addMetadata(context, it, schema, element, qualifier, lang, values, authorities, confidences); List dc = itemService.getMetadata(it, schema, element, qualifier, lang); - assertThat("testAddMetadata_7args_1 0",dc,notNullValue()); - assertTrue("testAddMetadata_7args_1 1",dc.size() == 2); - assertThat("testAddMetadata_7args_1 2",dc.get(0).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_7args_1 3",dc.get(0).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_7args_1 4",dc.get(0).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_7args_1 5",dc.get(0).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_7args_1 6",dc.get(0).getValue(),equalTo(values.get(0))); - assertThat("testAddMetadata_7args_1 7",dc.get(0).getAuthority(),nullValue()); - assertThat("testAddMetadata_7args_1 8",dc.get(0).getConfidence(),equalTo(-1)); - assertThat("testAddMetadata_7args_1 9",dc.get(1).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_7args_1 10",dc.get(1).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_7args_1 11",dc.get(1).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_7args_1 12",dc.get(1).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_7args_1 13",dc.get(1).getValue(),equalTo(values.get(1))); - assertThat("testAddMetadata_7args_1 14",dc.get(1).getAuthority(),nullValue()); - assertThat("testAddMetadata_7args_1 15",dc.get(1).getConfidence(),equalTo(-1)); + assertThat("testAddMetadata_7args_1 0", dc, notNullValue()); + assertTrue("testAddMetadata_7args_1 1", dc.size() == 2); + assertThat("testAddMetadata_7args_1 2", dc.get(0).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_7args_1 3", dc.get(0).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_7args_1 4", dc.get(0).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_7args_1 5", dc.get(0).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_7args_1 6", dc.get(0).getValue(), equalTo(values.get(0))); + assertThat("testAddMetadata_7args_1 7", dc.get(0).getAuthority(), nullValue()); + assertThat("testAddMetadata_7args_1 8", dc.get(0).getConfidence(), equalTo(-1)); + assertThat("testAddMetadata_7args_1 9", dc.get(1).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_7args_1 10", dc.get(1).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_7args_1 11", dc.get(1).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_7args_1 12", dc.get(1).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_7args_1 13", dc.get(1).getValue(), equalTo(values.get(1))); + assertThat("testAddMetadata_7args_1 14", dc.get(1).getAuthority(), nullValue()); + assertThat("testAddMetadata_7args_1 15", dc.get(1).getConfidence(), equalTo(-1)); } /** @@ -479,34 +599,35 @@ public class ItemTest extends AbstractDSpaceObjectTest */ @Test public void testAddMetadata_5args_2() throws SQLException { - String schema = "dc"; + String schema = "dc"; String element = "contributor"; String qualifier = "author"; String lang = Item.ANY; - List values = Arrays.asList("value0","value1"); + List values = Arrays.asList("value0", "value1"); itemService.addMetadata(context, it, schema, element, qualifier, lang, values); List dc = itemService.getMetadata(it, schema, element, qualifier, lang); - assertThat("testAddMetadata_5args_2 0",dc,notNullValue()); - assertTrue("testAddMetadata_5args_2 1",dc.size() == 2); - assertThat("testAddMetadata_5args_2 2",dc.get(0).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_5args_2 3",dc.get(0).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_5args_2 4",dc.get(0).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_5args_2 5",dc.get(0).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_5args_2 6",dc.get(0).getValue(),equalTo(values.get(0))); - assertThat("testAddMetadata_5args_2 7",dc.get(1).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_5args_2 8",dc.get(1).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_5args_2 9",dc.get(1).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_5args_2 10",dc.get(1).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_5args_2 11",dc.get(1).getValue(),equalTo(values.get(1))); + assertThat("testAddMetadata_5args_2 0", dc, notNullValue()); + assertTrue("testAddMetadata_5args_2 1", dc.size() == 2); + assertThat("testAddMetadata_5args_2 2", dc.get(0).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_5args_2 3", dc.get(0).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_5args_2 4", dc.get(0).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_5args_2 5", dc.get(0).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_5args_2 6", dc.get(0).getValue(), equalTo(values.get(0))); + assertThat("testAddMetadata_5args_2 7", dc.get(1).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_5args_2 8", dc.get(1).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_5args_2 9", dc.get(1).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_5args_2 10", dc.get(1).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_5args_2 11", dc.get(1).getValue(), equalTo(values.get(1))); } /** * Test of addMetadata method, of class Item. */ @Test - public void testAddMetadata_7args_2_authority() throws SQLException - { + public void testAddMetadata_7args_2_authority() throws SQLException { //we have enabled an authority control in our test local.cfg to run this test //as MetadataAuthorityManager can't be mocked properly @@ -520,14 +641,15 @@ public class ItemTest extends AbstractDSpaceObjectTest itemService.addMetadata(context, it, schema, element, qualifier, lang, values, authorities, confidences); List dc = itemService.getMetadata(it, schema, element, qualifier, lang); - assertThat("testAddMetadata_7args_2 0",dc,notNullValue()); - assertTrue("testAddMetadata_7args_2 1",dc.size() == 1); - assertThat("testAddMetadata_7args_2 2",dc.get(0).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_7args_2 3",dc.get(0).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_7args_2 4",dc.get(0).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_7args_2 5",dc.get(0).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_7args_2 6",dc.get(0).getValue(),equalTo(values)); - assertThat("testAddMetadata_7args_2 7",dc.get(0).getAuthority(),equalTo(authorities)); + assertThat("testAddMetadata_7args_2 0", dc, notNullValue()); + assertTrue("testAddMetadata_7args_2 1", dc.size() == 1); + assertThat("testAddMetadata_7args_2 2", dc.get(0).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_7args_2 3", dc.get(0).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_7args_2 4", dc.get(0).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_7args_2 5", dc.get(0).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_7args_2 6", dc.get(0).getValue(), equalTo(values)); + assertThat("testAddMetadata_7args_2 7", dc.get(0).getAuthority(), equalTo(authorities)); assertThat("testAddMetadata_7args_2 8", dc.get(0).getConfidence(), equalTo(confidences)); } @@ -548,15 +670,16 @@ public class ItemTest extends AbstractDSpaceObjectTest itemService.addMetadata(context, it, schema, element, qualifier, lang, values, authorities, confidences); List dc = itemService.getMetadata(it, schema, element, qualifier, lang); - assertThat("testAddMetadata_7args_2 0",dc,notNullValue()); - assertTrue("testAddMetadata_7args_2 1",dc.size() == 1); - assertThat("testAddMetadata_7args_2 2",dc.get(0).getMetadataField().getMetadataSchema().getName(),equalTo(schema)); - assertThat("testAddMetadata_7args_2 3",dc.get(0).getMetadataField().getElement(),equalTo(element)); - assertThat("testAddMetadata_7args_2 4",dc.get(0).getMetadataField().getQualifier(),equalTo(qualifier)); - assertThat("testAddMetadata_7args_2 5",dc.get(0).getLanguage(),equalTo(lang)); - assertThat("testAddMetadata_7args_2 6",dc.get(0).getValue(),equalTo(values)); - assertThat("testAddMetadata_7args_2 7",dc.get(0).getAuthority(),nullValue()); - assertThat("testAddMetadata_7args_2 8",dc.get(0).getConfidence(),equalTo(-1)); + assertThat("testAddMetadata_7args_2 0", dc, notNullValue()); + assertTrue("testAddMetadata_7args_2 1", dc.size() == 1); + assertThat("testAddMetadata_7args_2 2", dc.get(0).getMetadataField().getMetadataSchema().getName(), + equalTo(schema)); + assertThat("testAddMetadata_7args_2 3", dc.get(0).getMetadataField().getElement(), equalTo(element)); + assertThat("testAddMetadata_7args_2 4", dc.get(0).getMetadataField().getQualifier(), equalTo(qualifier)); + assertThat("testAddMetadata_7args_2 5", dc.get(0).getLanguage(), equalTo(lang)); + assertThat("testAddMetadata_7args_2 6", dc.get(0).getValue(), equalTo(values)); + assertThat("testAddMetadata_7args_2 7", dc.get(0).getAuthority(), nullValue()); + assertThat("testAddMetadata_7args_2 8", dc.get(0).getConfidence(), equalTo(-1)); } /** @@ -574,7 +697,7 @@ public class ItemTest extends AbstractDSpaceObjectTest itemService.clearMetadata(context, it, schema, element, qualifier, lang); List dc = itemService.getMetadata(it, schema, element, qualifier, lang); - assertThat("testClearMetadata 0",dc,notNullValue()); + assertThat("testClearMetadata 0", dc, notNullValue()); assertTrue("testClearMetadata 1", dc.size() == 0); } @@ -582,8 +705,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getSubmitter method, of class Item. */ @Test - public void testGetSubmitter() throws Exception - { + public void testGetSubmitter() throws Exception { assertThat("testGetSubmitter 0", it.getSubmitter(), notNullValue()); //null by default @@ -597,12 +719,11 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of setSubmitter method, of class Item. */ @Test - public void testSetSubmitter() throws SQLException, AuthorizeException - { + public void testSetSubmitter() throws SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); EPerson sub = ePersonService.create(context); context.restoreAuthSystemState(); - + it.setSubmitter(sub); assertThat("testSetSubmitter 0", it.getSubmitter(), notNullValue()); @@ -613,14 +734,15 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getCollections method, of class Item. */ @Test - public void testGetCollections() throws Exception - { + public void testGetCollections() throws Exception { context.turnOffAuthorisationSystem(); Collection collection = collectionService.create(context, owningCommunity); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "collection B"); + collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "collection B"); it.addCollection(collection); collection = collectionService.create(context, owningCommunity); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, "collection A"); + collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, + "collection A"); it.addCollection(collection); context.restoreAuthSystemState(); assertThat("testGetCollections 0", it.getCollections(), notNullValue()); @@ -633,8 +755,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getCommunities method, of class Item. */ @Test - public void testGetCommunities() throws Exception - { + public void testGetCommunities() throws Exception { assertThat("testGetCommunities 0", itemService.getCommunities(context, it), notNullValue()); assertTrue("testGetCommunities 1", itemService.getCommunities(context, it).size() == 1); } @@ -643,8 +764,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getBundles method, of class Item. */ @Test - public void testGetBundles_0args() throws Exception - { + public void testGetBundles_0args() throws Exception { assertThat("testGetBundles_0args 0", it.getBundles(), notNullValue()); assertTrue("testGetBundles_0args 1", it.getBundles().size() == 0); } @@ -653,8 +773,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getBundles method, of class Item. */ @Test - public void testGetBundles_String() throws Exception - { + public void testGetBundles_String() throws Exception { String name = "name"; assertThat("testGetBundles_String 0", itemService.getBundles(it, name), notNullValue()); assertTrue("testGetBundles_String 1", itemService.getBundles(it, name).size() == 0); @@ -664,20 +783,19 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of createBundle method, of class Item. */ @Test - public void testCreateBundleAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateBundleAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; String name = "bundle"; Bundle created = bundleService.create(context, it, name); - assertThat("testCreateBundleAuth 0",created, notNullValue()); - assertThat("testCreateBundleAuth 1",created.getName(), equalTo(name)); + assertThat("testCreateBundleAuth 0", created, notNullValue()); + assertThat("testCreateBundleAuth 1", created.getName(), equalTo(name)); assertThat("testCreateBundleAuth 2", itemService.getBundles(it, name), notNullValue()); assertTrue("testCreateBundleAuth 3", itemService.getBundles(it, name).size() == 1); } @@ -685,14 +803,13 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of createBundle method, of class Item. */ - @Test(expected=SQLException.class) - public void testCreateBundleNoName() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = SQLException.class) + public void testCreateBundleNoName() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; @@ -704,14 +821,13 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of createBundle method, of class Item. */ - @Test(expected=SQLException.class) - public void testCreateBundleNoName2() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = SQLException.class) + public void testCreateBundleNoName2() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; @@ -724,14 +840,13 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of createBundle method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testCreateBundleNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateBundleNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); }}; @@ -744,13 +859,12 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of addBundle method, of class Item. */ @Test - public void testAddBundleAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testAddBundleAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; }}; @@ -766,21 +880,20 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of addBundle method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testAddBundleNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testAddBundleNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); }}; String name = "bundle"; Bundle created = bundleService.create(context, it, name); created.setName(context, name); - + it.addBundle(created); fail("Exception expected"); } @@ -789,24 +902,25 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of removeBundle method, of class Item. */ @Test - public void testRemoveBundleAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRemoveBundleAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD and REMOVE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE); result = null; + Constants.REMOVE); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.DELETE); result = null; + Constants.DELETE); + result = null; }}; String name = "bundle"; Bundle created = bundleService.create(context, it, name); created.setName(context, name); itemService.addBundle(context, it, created); - + itemService.removeBundle(context, it, created); assertThat("testRemoveBundleAuth 0", itemService.getBundles(it, name), notNullValue()); assertTrue("testRemoveBundleAuth 1", itemService.getBundles(it, name).size() == 0); @@ -815,17 +929,17 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of removeBundle method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testRemoveBundleNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveBundleNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Disallow Item REMOVE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE); result = new AuthorizeException(); + Constants.REMOVE); + result = new AuthorizeException(); }}; String name = "bundle"; @@ -841,15 +955,15 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of createSingleBitstream method, of class Item. */ @Test - public void testCreateSingleBitstream_InputStream_StringAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateSingleBitstream_InputStream_StringAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; String name = "new bundle"; @@ -861,14 +975,13 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of createSingleBitstream method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testCreateSingleBitstream_InputStream_StringNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateSingleBitstream_InputStream_StringNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); }}; @@ -882,15 +995,15 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of createSingleBitstream method, of class Item. */ @Test - public void testCreateSingleBitstream_InputStreamAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateSingleBitstream_InputStreamAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; @@ -902,14 +1015,13 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of createSingleBitstream method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testCreateSingleBitstream_InputStreamNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateSingleBitstream_InputStreamNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = new AuthorizeException(); + Constants.ADD); + result = new AuthorizeException(); }}; @@ -922,8 +1034,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of getNonInternalBitstreams method, of class Item. */ @Test - public void testGetNonInternalBitstreams() throws Exception - { + public void testGetNonInternalBitstreams() throws Exception { assertThat("testGetNonInternalBitstreams 0", itemService.getNonInternalBitstreams(context, it), notNullValue()); assertTrue("testGetNonInternalBitstreams 1", itemService.getNonInternalBitstreams(context, it).size() == 0); } @@ -932,17 +1043,18 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of removeDSpaceLicense method, of class Item. */ @Test - public void testRemoveDSpaceLicenseAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRemoveDSpaceLicenseAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD and REMOVE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE); result = null; + Constants.REMOVE); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.DELETE); result = null; + Constants.DELETE); + result = null; }}; String name = "LICENSE"; @@ -958,17 +1070,17 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of removeDSpaceLicense method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testRemoveDSpaceLicenseNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testRemoveDSpaceLicenseNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; // Disallow Item REMOVE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE); result = new AuthorizeException(); + Constants.REMOVE); + result = new AuthorizeException(); }}; String name = "LICENSE"; @@ -983,19 +1095,21 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of removeLicenses method, of class Item. */ @Test - public void testRemoveLicensesAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRemoveLicensesAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD and REMOVE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE); result = null; + Constants.REMOVE); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; authorizeService.authorizeAction(context, (Bitstream) any, - Constants.DELETE); result = null; + Constants.DELETE); + result = null; }}; @@ -1010,7 +1124,6 @@ public class ItemTest extends AbstractDSpaceObjectTest bundleService.addBitstream(context, created, result); - itemService.removeLicenses(context, it); assertThat("testRemoveLicensesAuth 0", itemService.getBundles(it, name), notNullValue()); assertTrue("testRemoveLicensesAuth 1", itemService.getBundles(it, name).size() == 0); @@ -1019,16 +1132,16 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of removeLicenses method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testRemoveLicensesNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - { + @Test(expected = AuthorizeException.class) + public void testRemoveLicensesNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) { { authorizeService.authorizeAction((Context) any, (Item) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE); result = new AuthorizeException(); + Constants.REMOVE); + result = new AuthorizeException(); } }; @@ -1050,13 +1163,12 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of update method, of class Item. */ @Test - public void testUpdateAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testUpdateAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item WRITE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; @@ -1068,22 +1180,24 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of update method, of class Item. */ @Test - public void testUpdateAuth2() throws Exception - { + public void testUpdateAuth2() throws Exception { // Test permission inheritence - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = new AuthorizeException(); + Constants.WRITE); + result = new AuthorizeException(); // Allow parent Community WRITE and ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Disallow parent Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = new AuthorizeException(); + Constants.WRITE, true); + result = new AuthorizeException(); }}; @@ -1099,23 +1213,25 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of update method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testUpdateNoAuth() throws Exception - { + @Test(expected = AuthorizeException.class) + public void testUpdateNoAuth() throws Exception { // Test permission inheritence - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = new AuthorizeException(); + Constants.WRITE); + result = new AuthorizeException(); // Disallow parent Community WRITE or ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, anyBoolean); result = false; + Constants.WRITE, anyBoolean); + result = false; authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, anyBoolean); result = false; + Constants.ADD, anyBoolean); + result = false; // Disallow parent Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, anyBoolean); result = new AuthorizeException(); + Constants.WRITE, anyBoolean); + result = new AuthorizeException(); }}; context.turnOffAuthorisationSystem(); @@ -1131,19 +1247,17 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of withdraw method, of class Item. */ @Test - public void testWithdrawAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testWithdrawAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow Item withdraw permissions AuthorizeUtil.authorizeWithdrawItem((Context) any, (Item) any); - result = null; + result = null; }}; - new NonStrictExpectations(authorizeService.getClass()) - {{ - authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + new NonStrictExpectations(authorizeService.getClass()) {{ + authorizeService.authorizeAction((Context) any, (Item) any, + Constants.WRITE); + result = null; }}; @@ -1154,14 +1268,12 @@ public class ItemTest extends AbstractDSpaceObjectTest /** * Test of withdraw method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testWithdrawNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testWithdrawNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Disallow Item withdraw permissions AuthorizeUtil.authorizeWithdrawItem((Context) any, (Item) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; @@ -1173,47 +1285,43 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of reinstate method, of class Item. */ @Test - public void testReinstateAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + public void testReinstateAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ AuthorizeUtil.authorizeWithdrawItem((Context) any, (Item) any); - result = null; + result = null; AuthorizeUtil.authorizeReinstateItem((Context) any, (Item) any); - result = null; + result = null; }}; - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item withdraw and reinstate permissions authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; itemService.withdraw(context, it); itemService.reinstate(context, it); - assertFalse("testReinstate 0",it.isWithdrawn()); + assertFalse("testReinstate 0", it.isWithdrawn()); } /** * Test of reinstate method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testReinstateNoAuth() throws Exception - { - new NonStrictExpectations(AuthorizeUtil.class) - {{ + @Test(expected = AuthorizeException.class) + public void testReinstateNoAuth() throws Exception { + new NonStrictExpectations(AuthorizeUtil.class) {{ // Allow Item withdraw permissions AuthorizeUtil.authorizeWithdrawItem((Context) any, (Item) any); - result = null; + result = null; // Disallow Item reinstate permissions AuthorizeUtil.authorizeReinstateItem((Context) any, (Item) any); - result = new AuthorizeException(); + result = new AuthorizeException(); }}; - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; itemService.withdraw(context, it); @@ -1225,38 +1333,38 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of delete method, of class Item. */ @Test - public void testDeleteAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDeleteAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item REMOVE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE, true); result = null; + Constants.REMOVE, true); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.DELETE, true); result = null; + Constants.DELETE, true); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; }}; UUID id = it.getID(); - itemService.delete(context, it); + itemService.delete(context, it); Item found = itemService.find(context, id); - assertThat("testDeleteAuth 0",found,nullValue()); + assertThat("testDeleteAuth 0", found, nullValue()); } /** * Test of delete method, of class Item. */ - @Test(expected=AuthorizeException.class) - public void testDeleteNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testDeleteNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item REMOVE perms authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE); result = new AuthorizeException(); + Constants.REMOVE); + result = new AuthorizeException(); }}; - + itemService.delete(context, it); fail("Exception expected"); } @@ -1267,24 +1375,27 @@ public class ItemTest extends AbstractDSpaceObjectTest @Test @SuppressWarnings("ObjectEqualsNull") public void testEquals() throws SQLException, AuthorizeException, IOException, IllegalAccessException { - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item ADD perms (needed to create an Item) authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.ADD); result = null; + Constants.ADD); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.REMOVE); result = null; + Constants.REMOVE); + result = null; authorizeService.authorizeAction((Context) any, (Item) any, - Constants.DELETE); result = null; + Constants.DELETE); + result = null; }}; assertFalse("testEquals 0", it.equals(null)); Item item = createItem(); try { - assertFalse("testEquals 1",it.equals(item)); + assertFalse("testEquals 1", it.equals(item)); assertTrue("testEquals 2", it.equals(it)); } finally { itemService.delete(context, item); @@ -1295,14 +1406,13 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of isOwningCollection method, of class Item. */ @Test - public void testIsOwningCollection() throws SQLException, AuthorizeException - { + public void testIsOwningCollection() throws SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); Collection c = createCollection(); context.restoreAuthSystemState(); - + boolean result = itemService.isOwningCollection(it, c); - assertFalse("testIsOwningCollection 0",result); + assertFalse("testIsOwningCollection 0", result); } /** @@ -1310,8 +1420,7 @@ public class ItemTest extends AbstractDSpaceObjectTest */ @Override @Test - public void testGetType() - { + public void testGetType() { assertThat("testGetType 0", it.getType(), equalTo(Constants.ITEM)); } @@ -1319,22 +1428,21 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of replaceAllItemPolicies method, of class Item. */ @Test - public void testReplaceAllItemPolicies() throws Exception - { + public void testReplaceAllItemPolicies() throws Exception { List newpolicies = new ArrayList(); ResourcePolicy pol1 = resourcePolicyService.create(context); newpolicies.add(pol1); - new NonStrictExpectations(authorizeService.getClass()) - { + new NonStrictExpectations(authorizeService.getClass()) { { authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; } }; itemService.replaceAllItemPolicies(context, it, newpolicies); List retrieved = authorizeService.getPolicies(context, it); - assertThat("testReplaceAllItemPolicies 0",retrieved, notNullValue()); + assertThat("testReplaceAllItemPolicies 0", retrieved, notNullValue()); assertThat("testReplaceAllItemPolicies 1", retrieved.size(), equalTo(newpolicies.size())); } @@ -1342,8 +1450,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of replaceAllBitstreamPolicies method, of class Item. */ @Test - public void testReplaceAllBitstreamPolicies() throws Exception - { + public void testReplaceAllBitstreamPolicies() throws Exception { context.turnOffAuthorisationSystem(); //we add some bundles for the test String name = "LICENSE"; @@ -1366,29 +1473,26 @@ public class ItemTest extends AbstractDSpaceObjectTest List retrieved = new ArrayList(); List bundles = it.getBundles(); - for(Bundle b: bundles) - { + for (Bundle b : bundles) { retrieved.addAll(authorizeService.getPolicies(context, b)); retrieved.addAll(bundleService.getBitstreamPolicies(context, b)); } - assertFalse("testReplaceAllBitstreamPolicies 0",retrieved.isEmpty()); + assertFalse("testReplaceAllBitstreamPolicies 0", retrieved.isEmpty()); boolean equals = true; - for(int i=0; i < newpolicies.size() && equals; i++) - { - if(!newpolicies.contains(retrieved.get(i))) - { + for (int i = 0; i < newpolicies.size() && equals; i++) { + if (!newpolicies.contains(retrieved.get(i))) { equals = false; } } - assertTrue("testReplaceAllBitstreamPolicies 1", equals); } + assertTrue("testReplaceAllBitstreamPolicies 1", equals); + } /** * Test of removeGroupPolicies method, of class Item. */ @Test - public void testRemoveGroupPolicies() throws Exception - { + public void testRemoveGroupPolicies() throws Exception { context.turnOffAuthorisationSystem(); List newpolicies = new ArrayList(); Group g = groupService.create(context); @@ -1401,7 +1505,7 @@ public class ItemTest extends AbstractDSpaceObjectTest context.restoreAuthSystemState(); List retrieved = authorizeService.getPolicies(context, it); - assertThat("testRemoveGroupPolicies 0",retrieved, notNullValue()); + assertThat("testRemoveGroupPolicies 0", retrieved, notNullValue()); assertTrue("testRemoveGroupPolicies 1", retrieved.isEmpty()); } @@ -1409,17 +1513,15 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of inheritCollectionDefaultPolicies method, of class Item. */ @Test - public void testInheritCollectionDefaultPolicies() throws Exception - { + public void testInheritCollectionDefaultPolicies() throws Exception { context.turnOffAuthorisationSystem(); Collection c = createCollection(); - List defaultCollectionPolicies = authorizeService.getPoliciesActionFilter(context, c, - Constants.DEFAULT_BITSTREAM_READ); + List defaultCollectionPolicies = + authorizeService.getPoliciesActionFilter(context, c, Constants.DEFAULT_BITSTREAM_READ); List newPolicies = new ArrayList(); - for(ResourcePolicy collRp : defaultCollectionPolicies) - { + for (ResourcePolicy collRp : defaultCollectionPolicies) { ResourcePolicy rp = resourcePolicyService.clone(context, collRp); rp.setAction(Constants.READ); rp.setRpType(ResourcePolicy.TYPE_INHERITED); @@ -1439,11 +1541,11 @@ public class ItemTest extends AbstractDSpaceObjectTest context.restoreAuthSystemState(); - new NonStrictExpectations(authorizeService.getClass()) - { + new NonStrictExpectations(authorizeService.getClass()) { { authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; } }; @@ -1452,10 +1554,8 @@ public class ItemTest extends AbstractDSpaceObjectTest //test item policies List retrieved = authorizeService.getPolicies(context, it); boolean equals = true; - for(int i=0; i < retrieved.size() && equals; i++) - { - if(!newPolicies.contains(retrieved.get(i))) - { + for (int i = 0; i < retrieved.size() && equals; i++) { + if (!newPolicies.contains(retrieved.get(i))) { equals = false; } } @@ -1463,18 +1563,15 @@ public class ItemTest extends AbstractDSpaceObjectTest retrieved = new ArrayList(); List bundles = it.getBundles(); - for(Bundle b: bundles) - { + for (Bundle b : bundles) { retrieved.addAll(authorizeService.getPolicies(context, b)); retrieved.addAll(bundleService.getBitstreamPolicies(context, b)); } - assertFalse("testInheritCollectionDefaultPolicies 1",retrieved.isEmpty()); + assertFalse("testInheritCollectionDefaultPolicies 1", retrieved.isEmpty()); equals = true; - for(int i=0; i < newPolicies.size() && equals; i++) - { - if(!newPolicies.contains(retrieved.get(i))) - { + for (int i = 0; i < newPolicies.size() && equals; i++) { + if (!newPolicies.contains(retrieved.get(i))) { equals = false; } } @@ -1485,8 +1582,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of move method, of class Item. */ @Test - public void testMove() throws Exception - { + public void testMove() throws Exception { //we disable the permission testing as it's shared with other methods where it's already tested (can edit) context.turnOffAuthorisationSystem(); Collection from = createCollection(); @@ -1496,7 +1592,7 @@ public class ItemTest extends AbstractDSpaceObjectTest itemService.move(context, it, from, to); context.restoreAuthSystemState(); - assertThat("testMove 0",it.getOwningCollection(), notNullValue()); + assertThat("testMove 0", it.getOwningCollection(), notNullValue()); assertThat("testMove 1", it.getOwningCollection(), equalTo(to)); } @@ -1504,53 +1600,50 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of hasUploadedFiles method, of class Item. */ @Test - public void testHasUploadedFiles() throws Exception - { - assertFalse("testHasUploadedFiles 0",itemService.hasUploadedFiles(it)); + public void testHasUploadedFiles() throws Exception { + assertFalse("testHasUploadedFiles 0", itemService.hasUploadedFiles(it)); } /** * Test of getCollectionsNotLinked method, of class Item. */ @Test - public void testGetCollectionsNotLinked() throws Exception - { + public void testGetCollectionsNotLinked() throws Exception { List result = itemService.getCollectionsNotLinked(context, it); boolean isin = false; - for(Collection c: result) - { + for (Collection c : result) { Iterator iit = itemService.findByCollection(context, c); - while(iit.hasNext()) - { - if(iit.next().getID().equals(it.getID())) - { + while (iit.hasNext()) { + if (iit.next().getID().equals(it.getID())) { isin = true; } } } - assertFalse("testGetCollectionsNotLinked 0",isin); + assertFalse("testGetCollectionsNotLinked 0", isin); } /** * Test of canEdit method, of class Item. */ @Test - public void testCanEditBooleanAuth() throws Exception - { + public void testCanEditBooleanAuth() throws Exception { // Test Inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Item) any, - Constants.WRITE); result = true; + Constants.WRITE); + result = true; // Allow parent Community WRITE and ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Allow parent Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = null; + Constants.WRITE, true); + result = null; }}; assertTrue("testCanEditBooleanAuth 0", itemService.canEdit(context, it)); @@ -1560,22 +1653,24 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Item. */ @Test - public void testCanEditBooleanAuth2() throws Exception - { + public void testCanEditBooleanAuth2() throws Exception { // Test Inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Item) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow parent Community WRITE and ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, true); result = true; + Constants.ADD, true); + result = true; // Allow parent Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; assertTrue("testCanEditBooleanAuth2 0", itemService.canEdit(context, it)); @@ -1585,17 +1680,17 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Item. */ @Test - public void testCanEditBooleanAuth3() throws Exception - { + public void testCanEditBooleanAuth3() throws Exception { // Test Inheritance of permissions for owning collection - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Item) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow parent Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, false); result = null; + Constants.WRITE, false); + result = null; }}; // Create a new Collection and assign it as the owner @@ -1612,22 +1707,24 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Item. */ @Test - public void testCanEditBooleanAuth4() throws Exception - { + public void testCanEditBooleanAuth4() throws Exception { // Test Inheritance of permissions for Community Admins - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Item) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Allow parent Community WRITE and ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, true); result = true; + Constants.WRITE, true); + result = true; authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, false); result = true; + Constants.ADD, false); + result = true; // Disallow parent Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, true); result = new AuthorizeException(); + Constants.WRITE, true); + result = new AuthorizeException(); }}; // Ensure person with WRITE perms on the Collection can edit item @@ -1638,17 +1735,17 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Item. */ @Test - public void testCanEditBooleanAuth5() throws Exception - { + public void testCanEditBooleanAuth5() throws Exception { // Test Inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms - authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = new AuthorizeException(); + authorizeService.authorizeAction((Context) any, (Item) any, + Constants.WRITE); + result = new AuthorizeException(); // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE,anyBoolean); result = null; + Constants.WRITE, anyBoolean); + result = null; }}; collectionService.createTemplateItem(context, collection); @@ -1660,22 +1757,24 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Item. */ @Test - public void testCanEditBooleanNoAuth() throws Exception - { + public void testCanEditBooleanNoAuth() throws Exception { // Test Inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms authorizeService.authorizeActionBoolean((Context) any, (Item) any, - Constants.WRITE); result = false; + Constants.WRITE); + result = false; // Disallow parent Community WRITE and ADD perms authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.WRITE, anyBoolean); result = false; + Constants.WRITE, anyBoolean); + result = false; authorizeService.authorizeActionBoolean((Context) any, (Community) any, - Constants.ADD, anyBoolean); result = false; + Constants.ADD, anyBoolean); + result = false; // Disallow parent Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE, anyBoolean); result = new AuthorizeException(); + Constants.WRITE, anyBoolean); + result = new AuthorizeException(); }}; context.turnOffAuthorisationSystem(); @@ -1690,114 +1789,108 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of canEdit method, of class Item. */ @Test - public void testCanEditBooleanNoAuth2() throws Exception - { + public void testCanEditBooleanNoAuth2() throws Exception { context.turnOffAuthorisationSystem(); WorkspaceItem wi = workspaceItemService.create(context, collection, true); context.restoreAuthSystemState(); // Test Inheritance of permissions - new NonStrictExpectations(authorizeService.getClass()) - {{ + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms - authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE, anyBoolean); result = new AuthorizeException(); + authorizeService.authorizeAction((Context) any, (Item) any, + Constants.WRITE, anyBoolean); + result = new AuthorizeException(); }}; assertFalse("testCanEditBooleanNoAuth2 0", itemService.canEdit(context, wi.getItem())); } /** * Test of isInProgressSubmission method, of class Item. - * @throws AuthorizeException - * @throws SQLException - * @throws IOException - * + * + * @throws AuthorizeException + * @throws SQLException + * @throws IOException */ @Test - public void testIsInProgressSubmission() throws SQLException, AuthorizeException, IOException - { - context.turnOffAuthorisationSystem(); - Collection c = createCollection(); + public void testIsInProgressSubmission() throws SQLException, AuthorizeException, IOException { + context.turnOffAuthorisationSystem(); + Collection c = createCollection(); WorkspaceItem wi = workspaceItemService.create(context, c, true); - context.restoreAuthSystemState(); + context.restoreAuthSystemState(); assertTrue("testIsInProgressSubmission 0", itemService.isInProgressSubmission(context, wi.getItem())); } - + /** * Test of isInProgressSubmission method, of class Item. - * @throws AuthorizeException - * @throws SQLException - * @throws IOException - * + * + * @throws AuthorizeException + * @throws SQLException + * @throws IOException */ @Test - public void testIsInProgressSubmissionFalse() throws SQLException, AuthorizeException, IOException - { - context.turnOffAuthorisationSystem(); - Collection c = createCollection(); + public void testIsInProgressSubmissionFalse() throws SQLException, AuthorizeException, IOException { + context.turnOffAuthorisationSystem(); + Collection c = createCollection(); WorkspaceItem wi = workspaceItemService.create(context, c, true); Item item = installItemService.installItem(context, wi); - context.restoreAuthSystemState(); + context.restoreAuthSystemState(); assertFalse("testIsInProgressSubmissionFalse 0", itemService.isInProgressSubmission(context, item)); } /** * Test of isInProgressSubmission method, of class Item. - * @throws AuthorizeException - * @throws SQLException - * @throws IOException - * + * + * @throws AuthorizeException + * @throws SQLException + * @throws IOException */ @Test - public void testIsInProgressSubmissionFalse2() throws SQLException, AuthorizeException, IOException - { - context.turnOffAuthorisationSystem(); - Collection c = createCollection(); + public void testIsInProgressSubmissionFalse2() throws SQLException, AuthorizeException, IOException { + context.turnOffAuthorisationSystem(); + Collection c = createCollection(); collectionService.createTemplateItem(context, c); collectionService.update(context, c); Item item = c.getTemplateItem(); - context.restoreAuthSystemState(); + context.restoreAuthSystemState(); assertFalse("testIsInProgressSubmissionFalse2 0", itemService.isInProgressSubmission(context, item)); } - + /** * Test of getName method, of class Item. */ @Override @Test - public void testGetName() - { - assertThat("testGetName 0",it.getName(),nullValue()); + public void testGetName() { + assertThat("testGetName 0", it.getName(), nullValue()); } /** * Test of findByMetadataField method, of class Item. */ @Test - public void testFindByMetadataField() throws Exception - { + public void testFindByMetadataField() throws Exception { String schema = "dc"; String element = "contributor"; String qualifier = "author"; String value = "value"; Iterator result = itemService.findByMetadataField(context, schema, element, qualifier, value); - assertThat("testFindByMetadataField 0",result,notNullValue()); - assertFalse("testFindByMetadataField 1",result.hasNext()); + assertThat("testFindByMetadataField 0", result, notNullValue()); + assertFalse("testFindByMetadataField 1", result.hasNext()); - itemService.addMetadata(context, it, schema,element, qualifier, Item.ANY, value); - new NonStrictExpectations(authorizeService.getClass()) - { + itemService.addMetadata(context, it, schema, element, qualifier, Item.ANY, value); + new NonStrictExpectations(authorizeService.getClass()) { { authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; } }; itemService.update(context, it); result = itemService.findByMetadataField(context, schema, element, qualifier, value); - assertThat("testFindByMetadataField 3",result,notNullValue()); - assertTrue("testFindByMetadataField 4",result.hasNext()); - assertTrue("testFindByMetadataField 5",result.next().equals(it)); + assertThat("testFindByMetadataField 3", result, notNullValue()); + assertTrue("testFindByMetadataField 4", result.hasNext()); + assertTrue("testFindByMetadataField 5", result.next().equals(it)); } /** @@ -1805,13 +1898,15 @@ public class ItemTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetAdminObject() throws SQLException - { + public void testGetAdminObject() throws SQLException { //default community has no admin object - assertThat("testGetAdminObject 0", (Item) itemService.getAdminObject(context, it, Constants.REMOVE), equalTo(it)); + assertThat("testGetAdminObject 0", (Item) itemService.getAdminObject(context, it, Constants.REMOVE), + equalTo(it)); assertThat("testGetAdminObject 1", (Item) itemService.getAdminObject(context, it, Constants.ADD), equalTo(it)); - assertThat("testGetAdminObject 2", (Collection) itemService.getAdminObject(context, it, Constants.DELETE), equalTo(collection)); - assertThat("testGetAdminObject 3", (Item) itemService.getAdminObject(context, it, Constants.ADMIN), equalTo(it)); + assertThat("testGetAdminObject 2", (Collection) itemService.getAdminObject(context, it, Constants.DELETE), + equalTo(collection)); + assertThat("testGetAdminObject 3", (Item) itemService.getAdminObject(context, it, Constants.ADMIN), + equalTo(it)); } /** @@ -1819,10 +1914,8 @@ public class ItemTest extends AbstractDSpaceObjectTest */ @Test @Override - public void testGetParentObject() throws SQLException - { - try - { + public void testGetParentObject() throws SQLException { + try { //default has no parent assertThat("testGetParentObject 0", itemService.getParentObject(context, it), notNullValue()); @@ -1832,9 +1925,7 @@ public class ItemTest extends AbstractDSpaceObjectTest context.restoreAuthSystemState(); assertThat("testGetParentObject 1", itemService.getParentObject(context, it), notNullValue()); assertThat("testGetParentObject 2", (Collection) itemService.getParentObject(context, it), equalTo(parent)); - } - catch(AuthorizeException ex) - { + } catch (AuthorizeException ex) { fail("Authorize exception catched"); } } @@ -1843,8 +1934,7 @@ public class ItemTest extends AbstractDSpaceObjectTest * Test of findByAuthorityValue method, of class Item. */ @Test - public void testFindByAuthorityValue() throws Exception - { + public void testFindByAuthorityValue() throws Exception { String schema = "dc"; String element = "language"; String qualifier = "iso"; @@ -1858,19 +1948,19 @@ public class ItemTest extends AbstractDSpaceObjectTest itemService.addMetadata(context, it, schema, element, qualifier, Item.ANY, value, authority, confidence); //Ensure that the current user can update the item - new NonStrictExpectations(authorizeService.getClass()) - { + new NonStrictExpectations(authorizeService.getClass()) { { authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + Constants.WRITE); + result = null; } }; itemService.update(context, it); result = itemService.findByAuthorityValue(context, schema, element, qualifier, authority); - assertThat("testFindByAuthorityValue 3",result,notNullValue()); - assertTrue("testFindByAuthorityValue 4",result.hasNext()); - assertThat("testFindByAuthorityValue 5",result.next(),equalTo(it)); + assertThat("testFindByAuthorityValue 3", result, notNullValue()); + assertTrue("testFindByAuthorityValue 4", result.hasNext()); + assertThat("testFindByAuthorityValue 5", result.next(), equalTo(it)); } protected Collection createCollection() throws SQLException, AuthorizeException { diff --git a/dspace-api/src/test/java/org/dspace/content/LicenseUtilsTest.java b/dspace-api/src/test/java/org/dspace/content/LicenseUtilsTest.java index d135d326d3..c1dee50994 100644 --- a/dspace-api/src/test/java/org/dspace/content/LicenseUtilsTest.java +++ b/dspace-api/src/test/java/org/dspace/content/LicenseUtilsTest.java @@ -7,38 +7,48 @@ */ package org.dspace.content; -import org.apache.commons.io.IOUtils; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.StringWriter; import java.sql.SQLException; import java.util.HashMap; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.dspace.AbstractUnitTest; - import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; + +import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; +import org.dspace.AbstractUnitTest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.core.service.LicenseService; import org.dspace.eperson.EPerson; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; -import org.junit.*; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Unit Tests for class LicenseUtils + * * @author pvillega */ -public class LicenseUtilsTest extends AbstractUnitTest -{ +public class LicenseUtilsTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(LicenseUtilsTest.class); protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); @@ -60,18 +70,14 @@ public class LicenseUtilsTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { context.turnOffAuthorisationSystem(); this.owningCommunity = communityService.create(null, context); //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); - } - catch (SQLException | AuthorizeException ex) - { + } catch (SQLException | AuthorizeException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -87,8 +93,7 @@ public class LicenseUtilsTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { super.destroy(); } @@ -109,7 +114,8 @@ public class LicenseUtilsTest extends AbstractUnitTest String template = "Template license: %1$s %2$s %3$s %5$s %6$s"; String templateLong = "Template license: %1$s %2$s %3$s %5$s %6$s %8$s %9$s %10$s %11$s"; String templateResult = "Template license: first name last name testgetlicensetext_5args@email.com "; - String templateLongResult = "Template license: first name last name testgetlicensetext_5args@email.com arg1 arg2 arg3 arg4"; + String templateLongResult = "Template license: first name last name testgetlicensetext_5args@email.com arg1" + + " arg2 arg3 arg4"; String defaultLicense = licenseService.getDefaultSubmissionLicense(); context.turnOffAuthorisationSystem(); person = ePersonService.create(context); @@ -124,13 +130,17 @@ public class LicenseUtilsTest extends AbstractUnitTest collection = collectionService.create(context, owningCommunity); item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); additionalInfo = null; - assertThat("testGetLicenseText_5args 0", LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), equalTo(defaultLicense)); + assertThat("testGetLicenseText_5args 0", + LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), + equalTo(defaultLicense)); locale = Locale.GERMAN; collection = collectionService.create(context, owningCommunity); item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); additionalInfo = null; - assertThat("testGetLicenseText_5args 1", LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), equalTo(defaultLicense)); + assertThat("testGetLicenseText_5args 1", + LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), + equalTo(defaultLicense)); locale = Locale.ENGLISH; collection = collectionService.create(context, owningCommunity); @@ -139,7 +149,9 @@ public class LicenseUtilsTest extends AbstractUnitTest additionalInfo.put("arg1", "arg1"); additionalInfo.put("arg2", "arg2"); additionalInfo.put("arg3", "arg3"); - assertThat("testGetLicenseText_5args 2", LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), equalTo(defaultLicense)); + assertThat("testGetLicenseText_5args 2", + LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), + equalTo(defaultLicense)); //test collection template locale = Locale.ENGLISH; @@ -147,14 +159,18 @@ public class LicenseUtilsTest extends AbstractUnitTest collection.setLicense(context, template); item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); additionalInfo = null; - assertThat("testGetLicenseText_5args 3", LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), equalTo(templateResult)); + assertThat("testGetLicenseText_5args 3", + LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), + equalTo(templateResult)); locale = Locale.GERMAN; collection = collectionService.create(context, owningCommunity); collection.setLicense(context, template); item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); additionalInfo = null; - assertThat("testGetLicenseText_5args 4", LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), equalTo(templateResult)); + assertThat("testGetLicenseText_5args 4", + LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), + equalTo(templateResult)); locale = Locale.ENGLISH; collection = collectionService.create(context, owningCommunity); @@ -165,7 +181,9 @@ public class LicenseUtilsTest extends AbstractUnitTest additionalInfo.put("arg2", "arg2"); additionalInfo.put("arg3", "arg3"); additionalInfo.put("arg4", "arg4"); - assertThat("testGetLicenseText_5args 5", LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), equalTo(templateLongResult)); + assertThat("testGetLicenseText_5args 5", + LicenseUtils.getLicenseText(locale, collection, item, person, additionalInfo), + equalTo(templateLongResult)); context.restoreAuthSystemState(); } @@ -199,25 +217,29 @@ public class LicenseUtilsTest extends AbstractUnitTest locale = Locale.ENGLISH; collection = collectionService.create(context, owningCommunity); item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); - assertThat("testGetLicenseText_5args 0", LicenseUtils.getLicenseText(locale, collection, item, person), equalTo(defaultLicense)); + assertThat("testGetLicenseText_5args 0", LicenseUtils.getLicenseText(locale, collection, item, person), + equalTo(defaultLicense)); locale = Locale.GERMAN; collection = collectionService.create(context, owningCommunity); item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); - assertThat("testGetLicenseText_5args 1", LicenseUtils.getLicenseText(locale, collection, item, person), equalTo(defaultLicense)); + assertThat("testGetLicenseText_5args 1", LicenseUtils.getLicenseText(locale, collection, item, person), + equalTo(defaultLicense)); //test collection template locale = Locale.ENGLISH; collection = collectionService.create(context, owningCommunity); collection.setLicense(context, template); item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); - assertThat("testGetLicenseText_5args 3", LicenseUtils.getLicenseText(locale, collection, item, person), equalTo(templateResult)); + assertThat("testGetLicenseText_5args 3", LicenseUtils.getLicenseText(locale, collection, item, person), + equalTo(templateResult)); locale = Locale.GERMAN; collection = collectionService.create(context, owningCommunity); collection.setLicense(context, template); item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); - assertThat("testGetLicenseText_5args 4", LicenseUtils.getLicenseText(locale, collection, item, person), equalTo(templateResult)); + assertThat("testGetLicenseText_5args 4", LicenseUtils.getLicenseText(locale, collection, item, person), + equalTo(templateResult)); context.restoreAuthSystemState(); } @@ -226,21 +248,22 @@ public class LicenseUtilsTest extends AbstractUnitTest * Test of grantLicense method, of class LicenseUtils. */ @Test - public void testGrantLicense() throws Exception - { + public void testGrantLicense() throws Exception { context.turnOffAuthorisationSystem(); Collection collection = collectionService.create(context, owningCommunity); Item item = installItemService.installItem(context, workspaceItemService.create(context, collection, false)); String defaultLicense = licenseService.getDefaultSubmissionLicense(); - LicenseUtils.grantLicense(context, item, defaultLicense); + LicenseUtils.grantLicense(context, item, defaultLicense, null); StringWriter writer = new StringWriter(); - IOUtils.copy(bitstreamService.retrieve(context, itemService.getBundles(item, "LICENSE").get(0).getBitstreams().get(0)), writer); + IOUtils.copy( + bitstreamService.retrieve(context, itemService.getBundles(item, "LICENSE").get(0).getBitstreams().get(0)), + writer); String license = writer.toString(); - assertThat("testGrantLicense 0",license, equalTo(defaultLicense)); + assertThat("testGrantLicense 0", license, equalTo(defaultLicense)); context.restoreAuthSystemState(); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/MetadataFieldTest.java b/dspace-api/src/test/java/org/dspace/content/MetadataFieldTest.java index 687ba14ffa..b41e8acd97 100644 --- a/dspace-api/src/test/java/org/dspace/content/MetadataFieldTest.java +++ b/dspace-api/src/test/java/org/dspace/content/MetadataFieldTest.java @@ -7,6 +7,16 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.sql.SQLException; +import java.util.List; + import mockit.NonStrictExpectations; import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; @@ -18,27 +28,23 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.sql.SQLException; -import java.util.List; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - /** * Unit Tests for class MetadataFieldTest + * * @author pvillega */ -public class MetadataFieldTest extends AbstractUnitTest -{ +public class MetadataFieldTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(MetadataFieldTest.class); /** * MetadataField instance for the tests */ private MetadataField mf; - + private MetadataSchema dcSchema; /** @@ -56,7 +62,8 @@ public class MetadataFieldTest extends AbstractUnitTest */ private String scopeNote = "scope note"; - protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); /** @@ -68,25 +75,22 @@ public class MetadataFieldTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { this.dcSchema = metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA); this.mf = metadataFieldService.findByElement(context, - MetadataSchema.DC_SCHEMA, element, qualifier); - if(mf == null) - { + MetadataSchema.DC_SCHEMA, element, qualifier); + if (mf == null) { context.turnOffAuthorisationSystem(); - this.mf = metadataFieldService.create(context, metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA), element, qualifier, scopeNote); + this.mf = metadataFieldService + .create(context, metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA), element, qualifier, + scopeNote); context.restoreAuthSystemState(); } this.mf.setScopeNote(scopeNote); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } catch (NonUniqueMetadataException ex) { @@ -107,8 +111,7 @@ public class MetadataFieldTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { mf = null; super.destroy(); } @@ -117,106 +120,96 @@ public class MetadataFieldTest extends AbstractUnitTest * Test of getElement method, of class MetadataField. */ @Test - public void testGetElement() - { - assertThat("testGetElement 0",mf.getElement(), equalTo(element)); + public void testGetElement() { + assertThat("testGetElement 0", mf.getElement(), equalTo(element)); } /** * Test of setElement method, of class MetadataField. */ @Test - public void testSetElement() - { + public void testSetElement() { String elem = "newelem"; mf.setElement(elem); - assertThat("testSetElement 0",mf.getElement(), equalTo(elem)); + assertThat("testSetElement 0", mf.getElement(), equalTo(elem)); } /** * Test of getFieldID method, of class MetadataField. */ @Test - public void testGetFieldID() - { - assertTrue("testGetFieldID 0",mf.getID() >= 0); + public void testGetFieldID() { + assertTrue("testGetFieldID 0", mf.getID() >= 0); } /** * Test of getQualifier method, of class MetadataField. */ @Test - public void testGetQualifier() - { - assertThat("testGetQualifier 0",mf.getQualifier(), equalTo(qualifier)); + public void testGetQualifier() { + assertThat("testGetQualifier 0", mf.getQualifier(), equalTo(qualifier)); } /** * Test of setQualifier method, of class MetadataField. */ @Test - public void testSetQualifier() - { + public void testSetQualifier() { String qual = "qualif"; mf.setQualifier(qual); - assertThat("testSetQualifier 0",mf.getQualifier(), equalTo(qual)); + assertThat("testSetQualifier 0", mf.getQualifier(), equalTo(qual)); } /** * Test of getSchemaID method, of class MetadataField. */ @Test - public void testGetSchema() - { - assertThat("testGetSchemaID 0",mf.getMetadataSchema().getName(), equalTo(MetadataSchema.DC_SCHEMA)); + public void testGetSchema() { + assertThat("testGetSchemaID 0", mf.getMetadataSchema().getName(), equalTo(MetadataSchema.DC_SCHEMA)); } /** * Test of setSchemaID method, of class MetadataField. */ @Test - public void testSetSchema() throws NonUniqueMetadataException, SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testSetSchema() throws NonUniqueMetadataException, SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; MetadataSchema newSchema = metadataSchemaService.create(context, "testSetSchema", "testSetSchemaNS"); mf.setMetadataSchema(newSchema); - assertThat("testSetSchemaID 0",mf.getMetadataSchema(), equalTo(newSchema)); + assertThat("testSetSchemaID 0", mf.getMetadataSchema(), equalTo(newSchema)); } /** * Test of getScopeNote method, of class MetadataField. */ @Test - public void testGetScopeNote() - { - assertThat("testGetScopeNote 0",mf.getScopeNote(), equalTo(scopeNote)); + public void testGetScopeNote() { + assertThat("testGetScopeNote 0", mf.getScopeNote(), equalTo(scopeNote)); } /** * Test of setScopeNote method, of class MetadataField. */ @Test - public void testSetScopeNote() - { + public void testSetScopeNote() { String scn = "new scope note"; mf.setScopeNote(scn); - assertThat("testSetScopeNote 0",mf.getScopeNote(), equalTo(scn)); + assertThat("testSetScopeNote 0", mf.getScopeNote(), equalTo(scn)); } /** * Test of create method, of class MetadataField. */ @Test - public void testCreateAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String elem = "elem1"; @@ -224,19 +217,18 @@ public class MetadataFieldTest extends AbstractUnitTest MetadataField m = metadataFieldService.create(context, dcSchema, elem, qual, null); MetadataField found = metadataFieldService.findByElement(context, dcSchema, elem, qual); - assertThat("testCreateAuth 0",found.getID(), equalTo(m.getID())); + assertThat("testCreateAuth 0", found.getID(), equalTo(m.getID())); } /** * Test of create method, of class MetadataField. */ - @Test(expected=AuthorizeException.class) - public void testCreateNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full admin permissions - authorizeService.isAdmin(context); result = false; + authorizeService.isAdmin(context); + result = false; }}; String elem = "elem1"; @@ -248,13 +240,12 @@ public class MetadataFieldTest extends AbstractUnitTest /** * Test of create method, of class MetadataField. */ - @Test(expected=NonUniqueMetadataException.class) - public void testCreateRepeated() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = NonUniqueMetadataException.class) + public void testCreateRepeated() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String elem = element; @@ -267,68 +258,61 @@ public class MetadataFieldTest extends AbstractUnitTest * Test of findByElement method, of class MetadataField. */ @Test - public void testFindByElement() throws Exception - { + public void testFindByElement() throws Exception { MetadataField found = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, element, qualifier); - assertThat("testFindByElement 0",found, notNullValue()); - assertThat("testFindByElement 1",found.getID(), equalTo(mf.getID())); - assertThat("testFindByElement 2",found.getElement(), equalTo(mf.getElement())); - assertThat("testFindByElement 3",found.getQualifier(), equalTo(mf.getQualifier())); + assertThat("testFindByElement 0", found, notNullValue()); + assertThat("testFindByElement 1", found.getID(), equalTo(mf.getID())); + assertThat("testFindByElement 2", found.getElement(), equalTo(mf.getElement())); + assertThat("testFindByElement 3", found.getQualifier(), equalTo(mf.getQualifier())); } /** * Test of findAll method, of class MetadataField. */ @Test - public void testFindAll() throws Exception - { + public void testFindAll() throws Exception { List found = metadataFieldService.findAll(context); - assertThat("testFindAll 0",found, notNullValue()); - assertTrue("testFindAll 1",found.size() >= 1); + assertThat("testFindAll 0", found, notNullValue()); + assertTrue("testFindAll 1", found.size() >= 1); boolean added = false; - for(MetadataField mdf: found) - { - if(mdf.equals(mf)) - { + for (MetadataField mdf : found) { + if (mdf.equals(mf)) { added = true; } - } - assertTrue("testFindAll 2",added); + } + assertTrue("testFindAll 2", added); } /** * Test of findAllInSchema method, of class MetadataField. */ @Test - public void testFindAllInSchema() throws Exception - { - List found = metadataFieldService.findAllInSchema(context, metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA)); - assertThat("testFindAllInSchema 0",found, notNullValue()); - assertTrue("testFindAllInSchema 1",found.size() >= 1); - assertTrue("testFindAllInSchema 2",found.size() <= metadataFieldService.findAll(context).size()); + public void testFindAllInSchema() throws Exception { + List found = metadataFieldService + .findAllInSchema(context, metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA)); + assertThat("testFindAllInSchema 0", found, notNullValue()); + assertTrue("testFindAllInSchema 1", found.size() >= 1); + assertTrue("testFindAllInSchema 2", found.size() <= metadataFieldService.findAll(context).size()); boolean added = false; - for(MetadataField mdf: found) - { - if(mdf.equals(mf)) - { + for (MetadataField mdf : found) { + if (mdf.equals(mf)) { added = true; } - } - assertTrue("testFindAllInSchema 3",added); + } + assertTrue("testFindAllInSchema 3", added); } /** * Test of update method, of class MetadataField. */ @Test - public void testUpdateAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testUpdateAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String elem = "elem2"; @@ -337,19 +321,18 @@ public class MetadataFieldTest extends AbstractUnitTest metadataFieldService.update(context, m); MetadataField found = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, elem, qual); - assertThat("testUpdateAuth 0",found.getID(), equalTo(m.getID())); + assertThat("testUpdateAuth 0", found.getID(), equalTo(m.getID())); } /** * Test of update method, of class MetadataField. */ - @Test(expected=AuthorizeException.class) - public void testUpdateNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testUpdateNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full admin permissions - authorizeService.isAdmin(context); result = false; + authorizeService.isAdmin(context); + result = false; }}; String elem = "elem2"; @@ -362,13 +345,12 @@ public class MetadataFieldTest extends AbstractUnitTest /** * Test of update method, of class MetadataField. */ - @Test(expected=NonUniqueMetadataException.class) - public void testUpdateRepeated() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = NonUniqueMetadataException.class) + public void testUpdateRepeated() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String elem = element; @@ -385,12 +367,11 @@ public class MetadataFieldTest extends AbstractUnitTest * Test of delete method, of class MetadataField. */ @Test - public void testDeleteAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDeleteAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String elem = "elem3"; @@ -400,19 +381,18 @@ public class MetadataFieldTest extends AbstractUnitTest metadataFieldService.delete(context, m); MetadataField found = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, elem, qual); - assertThat("testDeleteAuth 0",found, nullValue()); + assertThat("testDeleteAuth 0", found, nullValue()); } /** * Test of delete method, of class MetadataField. */ - @Test(expected=AuthorizeException.class) - public void testDeleteNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testDeleteNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full admin permissions - authorizeService.isAdmin(context); result = false; + authorizeService.isAdmin(context); + result = false; }}; String elem = "elem3"; @@ -427,13 +407,12 @@ public class MetadataFieldTest extends AbstractUnitTest * Test of find method, of class MetadataField. */ @Test - public void testFind() throws Exception - { + public void testFind() throws Exception { int id = mf.getID(); - + MetadataField found = metadataFieldService.find(context, id); - assertThat("testFind 0",found, notNullValue()); - assertThat("testFind 1",found.getID(), equalTo(mf.getID())); + assertThat("testFind 0", found, notNullValue()); + assertThat("testFind 1", found.getID(), equalTo(mf.getID())); } } diff --git a/dspace-api/src/test/java/org/dspace/content/MetadataSchemaTest.java b/dspace-api/src/test/java/org/dspace/content/MetadataSchemaTest.java index e93d406183..35a82a9cec 100644 --- a/dspace-api/src/test/java/org/dspace/content/MetadataSchemaTest.java +++ b/dspace-api/src/test/java/org/dspace/content/MetadataSchemaTest.java @@ -7,6 +7,17 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.sql.SQLException; +import java.util.List; + import mockit.NonStrictExpectations; import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; @@ -16,20 +27,16 @@ import org.dspace.content.service.MetadataSchemaService; import org.junit.Before; import org.junit.Test; -import java.sql.SQLException; -import java.util.List; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - /** * Unit Tests for class MetadataSchema + * * @author pvillega */ -public class MetadataSchemaTest extends AbstractUnitTest -{ +public class MetadataSchemaTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(MetadataSchemaTest.class); /** @@ -37,7 +44,8 @@ public class MetadataSchemaTest extends AbstractUnitTest */ private MetadataSchema ms; - protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); /** * This method will be run before every test as per @Before. It will @@ -48,15 +56,11 @@ public class MetadataSchemaTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { this.ms = metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -66,24 +70,22 @@ public class MetadataSchemaTest extends AbstractUnitTest * Test of getNamespace method, of class MetadataSchema. */ @Test - public void testGetNamespace() - { - assertThat("testGetNamespace 0",ms.getNamespace(),notNullValue()); - assertThat("testGetNamespace 1",ms.getNamespace(),not(equalTo(""))); + public void testGetNamespace() { + assertThat("testGetNamespace 0", ms.getNamespace(), notNullValue()); + assertThat("testGetNamespace 1", ms.getNamespace(), not(equalTo(""))); } /** * Test of setNamespace method, of class MetadataSchema. */ @Test - public void testSetNamespace() - { + public void testSetNamespace() { String oldnamespace = ms.getNamespace(); String namespace = "new namespace"; ms.setNamespace(namespace); - assertThat("testSetNamespace 0",ms.getNamespace(),notNullValue()); - assertThat("testSetNamespace 1",ms.getNamespace(),not(equalTo(""))); - assertThat("testSetNamespace 2",ms.getNamespace(),equalTo(namespace)); + assertThat("testSetNamespace 0", ms.getNamespace(), notNullValue()); + assertThat("testSetNamespace 1", ms.getNamespace(), not(equalTo(""))); + assertThat("testSetNamespace 2", ms.getNamespace(), equalTo(namespace)); //we restore the old namespace to avoid issues in other tests ms.setNamespace(oldnamespace); @@ -93,24 +95,22 @@ public class MetadataSchemaTest extends AbstractUnitTest * Test of getName method, of class MetadataSchema. */ @Test - public void testGetName() - { - assertThat("testGetName 0",ms.getName(),notNullValue()); - assertThat("testGetName 1",ms.getName(),not(equalTo(""))); + public void testGetName() { + assertThat("testGetName 0", ms.getName(), notNullValue()); + assertThat("testGetName 1", ms.getName(), not(equalTo(""))); } /** * Test of setName method, of class MetadataSchema. */ @Test - public void testSetName() - { + public void testSetName() { String oldname = ms.getName(); String name = "new name"; ms.setName(name); - assertThat("testSetName 0",ms.getName(),notNullValue()); - assertThat("testSetName 1",ms.getName(),not(equalTo(""))); - assertThat("testSetName 2",ms.getName(),equalTo(name)); + assertThat("testSetName 0", ms.getName(), notNullValue()); + assertThat("testSetName 1", ms.getName(), not(equalTo(""))); + assertThat("testSetName 2", ms.getName(), equalTo(name)); //we restore the old name to avoid issues in other tests ms.setName(oldname); @@ -120,21 +120,20 @@ public class MetadataSchemaTest extends AbstractUnitTest * Test of getSchemaID method, of class MetadataSchema. */ @Test - public void testGetSchemaID() throws SQLException - { - assertThat("testGetSchemaID 0",ms.getID(), equalTo(metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA).getID())); + public void testGetSchemaID() throws SQLException { + assertThat("testGetSchemaID 0", ms.getID(), + equalTo(metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA).getID())); } /** * Test of create method, of class MetadataSchema. */ @Test - public void testCreateAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String namespace = "namespace"; @@ -142,19 +141,18 @@ public class MetadataSchemaTest extends AbstractUnitTest metadataSchemaService.create(context, name, namespace); MetadataSchema found = metadataSchemaService.findByNamespace(context, namespace); - assertThat("testCreateAuth 0",found, notNullValue()); + assertThat("testCreateAuth 0", found, notNullValue()); } /** * Test of create method, of class MetadataSchema. */ - @Test(expected=AuthorizeException.class) - public void testCreateNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full admin permissions - authorizeService.isAdmin(context); result = false; + authorizeService.isAdmin(context); + result = false; }}; String namespace = "namespace"; @@ -166,13 +164,12 @@ public class MetadataSchemaTest extends AbstractUnitTest /** * Test of create method, of class MetadataSchema. */ - @Test(expected=NonUniqueMetadataException.class) - public void testCreateRepeated() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = NonUniqueMetadataException.class) + public void testCreateRepeated() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String namespace = ms.getNamespace(); @@ -185,24 +182,22 @@ public class MetadataSchemaTest extends AbstractUnitTest * Test of findByNamespace method, of class MetadataSchema. */ @Test - public void testFindByNamespace() throws Exception - { - log.info(">>"+ms.getNamespace()+" "+ms.getName()); + public void testFindByNamespace() throws Exception { + log.info(">>" + ms.getNamespace() + " " + ms.getName()); MetadataSchema found = metadataSchemaService.findByNamespace(context, ms.getNamespace()); - assertThat("testFindByNamespace 0",found, notNullValue()); - assertThat("testFindByNamespace 1",found.getID(), equalTo(ms.getID())); + assertThat("testFindByNamespace 0", found, notNullValue()); + assertThat("testFindByNamespace 1", found.getID(), equalTo(ms.getID())); } /** * Test of update method, of class MetadataSchema. */ @Test - public void testUpdateAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testUpdateAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String namespace = "namespace2"; @@ -212,20 +207,18 @@ public class MetadataSchemaTest extends AbstractUnitTest metadataSchemaService.update(context, metadataSchema); MetadataSchema found = metadataSchemaService.findByNamespace(context, namespace); - assertThat("testUpdateAuth 0",found.getID(), equalTo(metadataSchema.getID())); + assertThat("testUpdateAuth 0", found.getID(), equalTo(metadataSchema.getID())); } /** * Test of update method, of class MetadataSchema. */ - @Test(expected=AuthorizeException.class) - public void testUpdateNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testUpdateNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full admin permissions authorizeService.isAdmin(context); - result = false; + result = false; }}; metadataSchemaService.update(context, ms); @@ -235,13 +228,12 @@ public class MetadataSchemaTest extends AbstractUnitTest /** * Test of update method, of class MetadataSchema. */ - @Test(expected=NonUniqueMetadataException.class) - public void testUpdateRepeated() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = NonUniqueMetadataException.class) + public void testUpdateRepeated() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String namespace = ms.getNamespace(); @@ -258,12 +250,11 @@ public class MetadataSchemaTest extends AbstractUnitTest * Test of delete method, of class MetadataSchema. */ @Test - public void testDeleteAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDeleteAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow full admin permissions - authorizeService.isAdmin(context); result = true; + authorizeService.isAdmin(context); + result = true; }}; String namespace = "namespace3"; @@ -273,19 +264,18 @@ public class MetadataSchemaTest extends AbstractUnitTest metadataSchemaService.delete(context, m); MetadataSchema found = metadataSchemaService.findByNamespace(context, namespace); - assertThat("testDeleteAuth 0",found, nullValue()); + assertThat("testDeleteAuth 0", found, nullValue()); } /** * Test of delete method, of class MetadataSchema. */ - @Test(expected=AuthorizeException.class) - public void testDeleteNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testDeleteNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow full admin permissions - authorizeService.isAdmin(context); result = false; + authorizeService.isAdmin(context); + result = false; }}; String namespace = "namespace3"; @@ -300,51 +290,46 @@ public class MetadataSchemaTest extends AbstractUnitTest * Test of findAll method, of class MetadataSchema. */ @Test - public void testFindAll() throws Exception - { + public void testFindAll() throws Exception { List found = metadataSchemaService.findAll(context); - assertThat("testFindAll 0",found, notNullValue()); - assertTrue("testFindAll 1",found.size() >= 1); + assertThat("testFindAll 0", found, notNullValue()); + assertTrue("testFindAll 1", found.size() >= 1); boolean added = false; - for(MetadataSchema msc: found) - { - if(msc.equals(ms)) - { + for (MetadataSchema msc : found) { + if (msc.equals(ms)) { added = true; } } - assertTrue("testFindAll 2",added); + assertTrue("testFindAll 2", added); } /** * Test of find method, of class MetadataSchema. */ @Test - public void testFind_Context_int() throws Exception - { + public void testFind_Context_int() throws Exception { MetadataSchema found = metadataSchemaService.find(context, ms.getID()); - assertThat("testFind_Context_int 0",found, notNullValue()); - assertThat("testFind_Context_int 1",found.getID(), equalTo(ms.getID())); - assertThat("testFind_Context_int 2",found.getName(), equalTo(ms.getName())); - assertThat("testFind_Context_int 3",found.getNamespace(), equalTo(ms.getNamespace())); + assertThat("testFind_Context_int 0", found, notNullValue()); + assertThat("testFind_Context_int 1", found.getID(), equalTo(ms.getID())); + assertThat("testFind_Context_int 2", found.getName(), equalTo(ms.getName())); + assertThat("testFind_Context_int 3", found.getNamespace(), equalTo(ms.getNamespace())); } /** * Test of find method, of class MetadataSchema. */ @Test - public void testFind_Context_String() throws Exception - { + public void testFind_Context_String() throws Exception { String shortName = ms.getName(); MetadataSchema found = metadataSchemaService.find(context, shortName); - assertThat("testFind_Context_String 0",found, notNullValue()); - assertThat("testFind_Context_String 1",found.getID(), equalTo(ms.getID())); - assertThat("testFind_Context_String 2",found.getName(), equalTo(ms.getName())); - assertThat("testFind_Context_String 3",found.getNamespace(), equalTo(ms.getNamespace())); + assertThat("testFind_Context_String 0", found, notNullValue()); + assertThat("testFind_Context_String 1", found.getID(), equalTo(ms.getID())); + assertThat("testFind_Context_String 2", found.getName(), equalTo(ms.getName())); + assertThat("testFind_Context_String 3", found.getNamespace(), equalTo(ms.getNamespace())); found = metadataSchemaService.find(context, null); - assertThat("testFind_Context_String 4",found, nullValue()); + assertThat("testFind_Context_String 4", found, nullValue()); } } diff --git a/dspace-api/src/test/java/org/dspace/content/MetadataValueTest.java b/dspace-api/src/test/java/org/dspace/content/MetadataValueTest.java index 6bade66746..bee228aa05 100644 --- a/dspace-api/src/test/java/org/dspace/content/MetadataValueTest.java +++ b/dspace-api/src/test/java/org/dspace/content/MetadataValueTest.java @@ -7,30 +7,41 @@ */ package org.dspace.content; -import org.apache.log4j.Logger; -import org.dspace.AbstractUnitTest; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.sql.SQLException; import java.util.List; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; +import org.apache.log4j.Logger; +import org.dspace.AbstractUnitTest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.content.service.MetadataValueService; +import org.dspace.content.service.WorkspaceItemService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Unit Tests for class MetadataValue + * * @author pvillega */ -public class MetadataValueTest extends AbstractUnitTest -{ +public class MetadataValueTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(MetadataValueTest.class); /** @@ -74,11 +85,9 @@ public class MetadataValueTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { context.turnOffAuthorisationSystem(); this.owningCommunity = communityService.create(null, context); this.collection = collectionService.create(context, owningCommunity); @@ -86,17 +95,13 @@ public class MetadataValueTest extends AbstractUnitTest this.it = installItemService.installItem(context, workspaceItem); this.mf = metadataFieldService.findByElement(context, - MetadataSchema.DC_SCHEMA, element, qualifier); - this.mv = metadataValueService.create(context, it , mf); + MetadataSchema.DC_SCHEMA, element, qualifier); + this.mv = metadataValueService.create(context, it, mf); context.restoreAuthSystemState(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorize Error in init", ex); fail("Authorize Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -111,15 +116,14 @@ public class MetadataValueTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { try { context.turnOffAuthorisationSystem(); communityService.delete(context, owningCommunity); } catch (SQLException | AuthorizeException | IOException ex) { log.error("Error in destroy", ex); fail("Error in destroy: " + ex.getMessage()); - }finally { + } finally { context.restoreAuthSystemState(); } @@ -132,8 +136,7 @@ public class MetadataValueTest extends AbstractUnitTest * Test of getFieldId method, of class MetadataValue. */ @Test - public void testGetFieldId() - { + public void testGetFieldId() { MetadataValue instance = new MetadataValue(); assertThat("testGetFieldId 0", instance.getID(), equalTo(0)); @@ -144,8 +147,7 @@ public class MetadataValueTest extends AbstractUnitTest * Test of getItemId method, of class MetadataValue. */ @Test - public void testGetDSpaceObject() - { + public void testGetDSpaceObject() { assertTrue("testGetItemId 0", mv.getDSpaceObject().equals(it)); } @@ -153,8 +155,7 @@ public class MetadataValueTest extends AbstractUnitTest * Test of getLanguage method, of class MetadataValue. */ @Test - public void testGetLanguage() - { + public void testGetLanguage() { assertThat("testGetLanguage 0", mv.getLanguage(), nullValue()); } @@ -162,8 +163,7 @@ public class MetadataValueTest extends AbstractUnitTest * Test of setLanguage method, of class MetadataValue. */ @Test - public void testSetLanguage() - { + public void testSetLanguage() { String language = "eng"; mv.setLanguage(language); assertThat("testSetLanguage 0", mv.getLanguage(), equalTo(language)); @@ -173,97 +173,87 @@ public class MetadataValueTest extends AbstractUnitTest * Test of getPlace method, of class MetadataValue. */ @Test - public void testGetPlace() - { - assertThat("testGetPlace 0",mv.getPlace(), equalTo(1)); + public void testGetPlace() { + assertThat("testGetPlace 0", mv.getPlace(), equalTo(1)); } /** * Test of setPlace method, of class MetadataValue. */ @Test - public void testSetPlace() - { + public void testSetPlace() { int place = 5; mv.setPlace(place); - assertThat("testSetPlace 0",mv.getPlace(), equalTo(place)); + assertThat("testSetPlace 0", mv.getPlace(), equalTo(place)); } /** * Test of getValueId method, of class MetadataValue. */ @Test - public void testGetValueId() - { - assertThat("testGetValueId 0",mv.getID(), notNullValue()); + public void testGetValueId() { + assertThat("testGetValueId 0", mv.getID(), notNullValue()); } /** * Test of getValue method, of class MetadataValue. */ @Test - public void testGetValue() - { - assertThat("testGetValue 0",mv.getValue(), nullValue()); + public void testGetValue() { + assertThat("testGetValue 0", mv.getValue(), nullValue()); } /** * Test of setValue method, of class MetadataValue. */ @Test - public void testSetValue() - { + public void testSetValue() { String value = "value"; mv.setValue(value); - assertThat("testSetValue 0",mv.getValue(), equalTo(value)); + assertThat("testSetValue 0", mv.getValue(), equalTo(value)); } /** * Test of getAuthority method, of class MetadataValue. */ @Test - public void testGetAuthority() - { - assertThat("testGetAuthority 0",mv.getAuthority(), nullValue()); + public void testGetAuthority() { + assertThat("testGetAuthority 0", mv.getAuthority(), nullValue()); } /** * Test of setAuthority method, of class MetadataValue. */ @Test - public void testSetAuthority() - { + public void testSetAuthority() { String value = "auth_val"; mv.setAuthority(value); - assertThat("testSetAuthority 0",mv.getAuthority(), equalTo(value)); + assertThat("testSetAuthority 0", mv.getAuthority(), equalTo(value)); } /** * Test of getConfidence method, of class MetadataValue. */ @Test - public void testGetConfidence() - { - assertThat("testGetConfidence 0",mv.getConfidence(), equalTo(-1)); + public void testGetConfidence() { + assertThat("testGetConfidence 0", mv.getConfidence(), equalTo(-1)); } /** * Test of setConfidence method, of class MetadataValue. */ @Test - public void testSetConfidence() - { + public void testSetConfidence() { int value = 5; mv.setConfidence(value); - assertThat("testSetConfidence 0",mv.getConfidence(), equalTo(value)); + assertThat("testSetConfidence 0", mv.getConfidence(), equalTo(value)); } /** * Test of create method, of class MetadataValue. */ @Test - public void testCreate() throws Exception - { + public void testCreate() throws Exception { metadataValueService.create(context, it, mf); } @@ -271,33 +261,30 @@ public class MetadataValueTest extends AbstractUnitTest * Test of find method, of class MetadataValue. */ @Test - public void testFind() throws Exception - { + public void testFind() throws Exception { metadataValueService.create(context, it, mf); int id = mv.getID(); MetadataValue found = metadataValueService.find(context, id); - assertThat("testFind 0",found, notNullValue()); - assertThat("testFind 1",found.getID(), equalTo(id)); + assertThat("testFind 0", found, notNullValue()); + assertThat("testFind 1", found.getID(), equalTo(id)); } /** * Test of findByField method, of class MetadataValue. */ @Test - public void testFindByField() throws Exception - { + public void testFindByField() throws Exception { metadataValueService.create(context, it, mf); List found = metadataValueService.findByField(context, mf); - assertThat("testFind 0",found, notNullValue()); - assertTrue("testFind 1",found.size() >= 1); + assertThat("testFind 0", found, notNullValue()); + assertTrue("testFind 1", found.size() >= 1); } /** * Test of update method, of class MetadataValue. */ @Test - public void testUpdate() throws Exception - { + public void testUpdate() throws Exception { metadataValueService.create(context, it, mf); metadataValueService.update(context, mv); } diff --git a/dspace-api/src/test/java/org/dspace/content/NonUniqueMetadataExceptionTest.java b/dspace-api/src/test/java/org/dspace/content/NonUniqueMetadataExceptionTest.java index c7b55fb43c..52a8e0fe17 100644 --- a/dspace-api/src/test/java/org/dspace/content/NonUniqueMetadataExceptionTest.java +++ b/dspace-api/src/test/java/org/dspace/content/NonUniqueMetadataExceptionTest.java @@ -7,29 +7,30 @@ */ package org.dspace.content; -import org.apache.log4j.Logger; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; -import org.junit.*; +import org.apache.log4j.Logger; +import org.junit.Test; /** * Unit Tests for class NonUniqueMetadataException. Being an exception * no tests have to be done, the class is created for coberture purposes + * * @author pvillega */ -public class NonUniqueMetadataExceptionTest -{ +public class NonUniqueMetadataExceptionTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(NonUniqueMetadataExceptionTest.class); /** * Dummy test to avoid initialization errors */ @Test - public void testDummy() - { + public void testDummy() { assertTrue(true); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/SiteTest.java b/dspace-api/src/test/java/org/dspace/content/SiteTest.java index 36e79c5d8f..f0d0e4243c 100644 --- a/dspace-api/src/test/java/org/dspace/content/SiteTest.java +++ b/dspace-api/src/test/java/org/dspace/content/SiteTest.java @@ -7,25 +7,34 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.sql.SQLException; + +import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.SiteService; import org.dspace.core.ConfigurationManager; -import java.sql.SQLException; import org.dspace.core.Constants; -import org.junit.*; -import static org.hamcrest.CoreMatchers.*; -import org.apache.log4j.Logger; -import static org.junit.Assert.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Unit Tests for class Site + * * @author pvillega */ -public class SiteTest extends AbstractUnitTest -{ +public class SiteTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(SiteTest.class); /** @@ -44,19 +53,15 @@ public class SiteTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { //we have to create a new community in the database context.turnOffAuthorisationSystem(); this.s = (Site) siteService.findSite(context); //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -71,8 +76,7 @@ public class SiteTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { s = null; super.destroy(); } @@ -81,8 +85,7 @@ public class SiteTest extends AbstractUnitTest * Test of getType method, of class Site. */ @Test - public void testGetType() - { + public void testGetType() { assertThat("testGetType 0", s.getType(), equalTo(Constants.SITE)); } @@ -90,8 +93,7 @@ public class SiteTest extends AbstractUnitTest * Test of getID method, of class Site. */ @Test - public void testGetID() - { + public void testGetID() { assertTrue("testGetID 0", s.getID() != null); } @@ -99,42 +101,38 @@ public class SiteTest extends AbstractUnitTest * Test of getHandle method, of class Site. */ @Test - public void testGetHandle() - { + public void testGetHandle() { assertThat("testGetHandle 0", s.getHandle(), equalTo(ConfigurationManager.getProperty("handle.prefix") - +"/0")); + + "/0")); } /** * Test of getSiteHandle method, of class Site. */ @Test - public void testGetSiteHandle() - { + public void testGetSiteHandle() { assertThat("testGetSiteHandle 0", s.getHandle(), equalTo(ConfigurationManager.getProperty("handle.prefix") - +"/0")); + + "/0")); } /** * Test of find method, of class Site. */ @Test - public void testSiteFind() throws Exception - { + public void testSiteFind() throws Exception { int id = 0; - Site found = (Site)siteService.findSite(context); - assertThat("testSiteFind 0",found, notNullValue()); - assertThat("testSiteFind 1",found, equalTo(s)); + Site found = (Site) siteService.findSite(context); + assertThat("testSiteFind 0", found, notNullValue()); + assertThat("testSiteFind 1", found, equalTo(s)); } /** * Test of getName method, of class Site. */ @Test - public void testGetName() - { - assertThat("testGetName 0",s.getName(), equalTo(ConfigurationManager.getProperty("dspace.name"))); - assertThat("testGetName 1",siteService.getName(s), equalTo(ConfigurationManager.getProperty("dspace.name"))); + public void testGetName() { + assertThat("testGetName 0", s.getName(), equalTo(ConfigurationManager.getProperty("dspace.name"))); + assertThat("testGetName 1", siteService.getName(s), equalTo(ConfigurationManager.getProperty("dspace.name"))); } @@ -142,9 +140,8 @@ public class SiteTest extends AbstractUnitTest * Test of getURL method, of class Site. */ @Test - public void testGetURL() - { - assertThat("testGetURL 0",s.getURL(), equalTo(ConfigurationManager.getProperty("dspace.url"))); + public void testGetURL() { + assertThat("testGetURL 0", s.getURL(), equalTo(ConfigurationManager.getProperty("dspace.url"))); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/SupervisedItemTest.java b/dspace-api/src/test/java/org/dspace/content/SupervisedItemTest.java index a7976b521a..f0c289442b 100644 --- a/dspace-api/src/test/java/org/dspace/content/SupervisedItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/SupervisedItemTest.java @@ -7,18 +7,25 @@ */ package org.dspace.content; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.CollectionService; -import org.dspace.content.service.CommunityService; -import org.dspace.content.service.SupervisedItemService; -import org.dspace.content.service.WorkspaceItemService; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; import java.sql.SQLException; import java.util.List; import java.util.UUID; -import org.dspace.authorize.AuthorizeException; +import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.SupervisedItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; @@ -26,26 +33,26 @@ import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.SupervisorService; -import org.junit.*; -import static org.hamcrest.CoreMatchers.*; -import org.apache.log4j.Logger; -import static org.junit.Assert.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** - * * @author pvillega */ -public class SupervisedItemTest extends AbstractUnitTest -{ +public class SupervisedItemTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(SupervisedItemTest.class); protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - protected SupervisedItemService supervisedItemService = ContentServiceFactory.getInstance().getSupervisedItemService(); + protected SupervisedItemService supervisedItemService = ContentServiceFactory.getInstance() + .getSupervisedItemService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); protected SupervisorService supervisorService = EPersonServiceFactory.getInstance().getSupervisorService(); @@ -63,11 +70,9 @@ public class SupervisedItemTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { //we have to create a new community in the database context.turnOffAuthorisationSystem(); Community owningCommunity = communityService.create(null, context); @@ -90,13 +95,10 @@ public class SupervisedItemTest extends AbstractUnitTest context.complete(); context = new Context(); context.setCurrentUser(currentUser); - } catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init"); } @@ -111,8 +113,7 @@ public class SupervisedItemTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { try { context.turnOffAuthorisationSystem(); communityService.delete(context, communityService.find(context, communityId)); @@ -128,29 +129,25 @@ public class SupervisedItemTest extends AbstractUnitTest * Test of getAll method, of class SupervisedItem. */ @Test - public void testGetAll() throws Exception - { + public void testGetAll() throws Exception { List found = supervisedItemService.getAll(context); assertThat("testGetAll 0", found, notNullValue()); assertTrue("testGetAll 1", found.size() >= 1); boolean added = false; - for(WorkspaceItem sia: found) - { - if(sia.getID() == workspaceItemId) - { + for (WorkspaceItem sia : found) { + if (sia.getID() == workspaceItemId) { added = true; } } - assertTrue("testGetAll 2",added); + assertTrue("testGetAll 2", added); } /** * Test of getSupervisorGroups method, of class SupervisedItem. */ @Test - public void testGetSupervisorGroups_Context_int() throws Exception - { + public void testGetSupervisorGroups_Context_int() throws Exception { List found = workspaceItemService.find(context, workspaceItemId).getSupervisorGroups(); assertThat("testGetSupervisorGroups_Context_int 0", found, notNullValue()); assertTrue("testGetSupervisorGroups_Context_int 1", found.size() == 1); @@ -161,49 +158,43 @@ public class SupervisedItemTest extends AbstractUnitTest * Test of getSupervisorGroups method, of class SupervisedItem. */ @Test - public void testGetSupervisorGroups_0args() throws Exception - { + public void testGetSupervisorGroups_0args() throws Exception { List found = workspaceItemService.find(context, workspaceItemId).getSupervisorGroups(); assertThat("testGetSupervisorGroups_0args 0", found, notNullValue()); assertTrue("testGetSupervisorGroups_0args 1", found.size() == 1); boolean added = false; - for(Group g: found) - { - if(g.getID().equals(groupId)) - { + for (Group g : found) { + if (g.getID().equals(groupId)) { added = true; } } - assertTrue("testGetSupervisorGroups_0args 2",added); + assertTrue("testGetSupervisorGroups_0args 2", added); } /** * Test of findbyEPerson method, of class SupervisedItem. */ @Test - public void testFindbyEPerson() throws Exception - { + public void testFindbyEPerson() throws Exception { context.turnOffAuthorisationSystem(); List found = supervisedItemService.findbyEPerson(context, ePersonService.create(context)); assertThat("testFindbyEPerson 0", found, notNullValue()); assertTrue("testFindbyEPerson 1", found.size() == 0); found = supervisedItemService.findbyEPerson(context, context.getCurrentUser()); - assertThat("testFindbyEPerson 2", found, notNullValue()); + assertThat("testFindbyEPerson 2", found, notNullValue()); assertTrue("testFindbyEPerson 3", found.size() >= 1); boolean added = false; - for(WorkspaceItem sia: found) - { - if(sia.getID() == workspaceItemId) - { + for (WorkspaceItem sia : found) { + if (sia.getID() == workspaceItemId) { added = true; } } - assertTrue("testFindbyEPerson 4",added); + assertTrue("testFindbyEPerson 4", added); context.restoreAuthSystemState(); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/ThumbnailTest.java b/dspace-api/src/test/java/org/dspace/content/ThumbnailTest.java index eabeec141e..a350d3d0b8 100644 --- a/dspace-api/src/test/java/org/dspace/content/ThumbnailTest.java +++ b/dspace-api/src/test/java/org/dspace/content/ThumbnailTest.java @@ -7,27 +7,33 @@ */ package org.dspace.content; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.sql.SQLException; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.BitstreamService; -import org.junit.*; -import static org.junit.Assert.* ; import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.BitstreamService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Unit Test for class Thumbnail. The class is a bean (just getters and setters) * so no specific tests are created. + * * @author pvillega */ -public class ThumbnailTest extends AbstractUnitTest -{ +public class ThumbnailTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(ThumbnailTest.class); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); @@ -56,23 +62,18 @@ public class ThumbnailTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { //we have to create a new bitstream in the database File f = new File(testProps.get("test.bitstream").toString()); thumb = bitstreamService.create(context, new FileInputStream(f)); orig = bitstreamService.create(context, new FileInputStream(f)); t = new Thumbnail(thumb, orig); - } - catch (IOException ex) { + } catch (IOException ex) { log.error("IO Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -87,8 +88,7 @@ public class ThumbnailTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { thumb = null; orig = null; t = null; @@ -99,8 +99,7 @@ public class ThumbnailTest extends AbstractUnitTest * Dummy test to avoid initialization errors */ @Test - public void testDummy() - { + public void testDummy() { assertTrue(true); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/VersioningTest.java b/dspace-api/src/test/java/org/dspace/content/VersioningTest.java index e6d067342c..00ad114097 100644 --- a/dspace-api/src/test/java/org/dspace/content/VersioningTest.java +++ b/dspace-api/src/test/java/org/dspace/content/VersioningTest.java @@ -7,11 +7,24 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.sql.SQLException; + import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.ConfigurationManager; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; @@ -24,13 +37,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.sql.SQLException; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - /** * Unit Tests for versioning @@ -54,9 +60,11 @@ public class VersioningTest extends AbstractUnitTest { protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); protected VersioningService versionService = VersionServiceFactory.getInstance().getVersionService(); - protected VersionHistoryService versionHistoryService = VersionServiceFactory.getInstance().getVersionHistoryService(); + protected VersionHistoryService versionHistoryService = VersionServiceFactory.getInstance() + .getVersionHistoryService(); - //A regex that can be used to see if a handle contains the format of handle created by the org.dspace.identifier.VersionedHandleIdentifierProvider* + //A regex that can be used to see if a handle contains the format of handle created by the org.dspace.identifier + // .VersionedHandleIdentifierProvider* protected String versionedHandleRegex = ConfigurationManager.getProperty("handle.prefix") + "\\/[0-9]*\\.[0-9]"; /** @@ -68,11 +76,9 @@ public class VersioningTest extends AbstractUnitTest { */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { context.turnOffAuthorisationSystem(); Community community = communityService.create(null, context); @@ -87,14 +93,10 @@ public class VersioningTest extends AbstractUnitTest { versionedItem = installItemService.installItem(context, wsi); context.restoreAuthSystemState(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -110,16 +112,14 @@ public class VersioningTest extends AbstractUnitTest { */ @After @Override - public void destroy() - { + public void destroy() { context.abort(); super.destroy(); } @Test - public void testVersionFind() throws SQLException - { + public void testVersionFind() throws SQLException { VersionHistory versionHistory = versionHistoryService.findByItem(context, originalItem); assertThat("testFindVersionHistory", versionHistory, notNullValue()); Version version = versionHistoryService.getVersion(context, versionHistory, versionedItem); @@ -130,8 +130,7 @@ public class VersioningTest extends AbstractUnitTest { * Test of installItem method, of class InstallItem. */ @Test - public void testVersionSummary() throws Exception - { + public void testVersionSummary() throws Exception { //Start by creating a new item ! VersionHistory versionHistory = versionHistoryService.findByItem(context, originalItem); Version version = versionHistoryService.getVersion(context, versionHistory, versionedItem); @@ -147,8 +146,8 @@ public class VersioningTest extends AbstractUnitTest { assertThat("Test_version_handle 1", versionedItem.getHandle(), notNullValue()); assertThat("Test_version_handle 2", originalItem.getHandle(), notNullValue()); assertTrue("Test_version_handle 3 ", originalItem.getHandles().size() == 1); - - /* The following assertments are specific to the VersionHandleIdentifier + + /* The following assertments are specific to the VersionHandleIdentifier * that use "canonical" handles that are moved from version to version. * It would be good to create Tests for each IdentifierProvider, which * would need to tell Spring which one to use for which test. @@ -158,8 +157,10 @@ public class VersioningTest extends AbstractUnitTest { * assertTrue("Test_version_handle 6 ", originalItem.getHandle().startsWith(originalHandle + ".")); * //The getHandle method should always return the original handle * assertTrue("Test_version_handle 7 ", versionedItem.getHandle().equals(originalHandle)); - * assertTrue("Test_version_handle 8 ", versionedItem.getHandles().get(1).getHandle().startsWith(originalHandle + ".")); - * assertTrue("Test_version_handle 9 ", versionedItem.getHandles().get(1).getHandle().matches(versionedHandleRegex)); + * assertTrue("Test_version_handle 8 ", versionedItem.getHandles().get(1).getHandle().startsWith + * (originalHandle + ".")); + * assertTrue("Test_version_handle 9 ", versionedItem.getHandles().get(1).getHandle().matches + * (versionedHandleRegex)); */ } diff --git a/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java b/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java index a2ac0803f3..02a2953498 100644 --- a/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java @@ -7,37 +7,47 @@ */ package org.dspace.content; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import mockit.NonStrictExpectations; +import org.apache.log4j.Logger; +import org.dspace.AbstractUnitTest; +import org.dspace.authorize.AuthorizeException; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Constants; -import mockit.NonStrictExpectations; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; - -import org.dspace.authorize.AuthorizeException; import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import org.dspace.AbstractUnitTest; -import org.apache.log4j.Logger; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; -import org.junit.*; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * Unit Tests for class WorkspaceItem + * * @author pvillega */ -public class WorkspaceItemTest extends AbstractUnitTest -{ +public class WorkspaceItemTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(WorkspaceItemTest.class); /** @@ -62,11 +72,9 @@ public class WorkspaceItemTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { //we have to create a new community in the database context.turnOffAuthorisationSystem(); this.owningCommunity = communityService.create(null, context); @@ -74,13 +82,10 @@ public class WorkspaceItemTest extends AbstractUnitTest this.wi = workspaceItemService.create(context, collection, true); //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); - } catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } @@ -95,24 +100,18 @@ public class WorkspaceItemTest extends AbstractUnitTest */ @After @Override - public void destroy() - { + public void destroy() { wi = null; try { context.turnOffAuthorisationSystem(); communityService.removeCollection(context, owningCommunity, collection); - } - catch (IOException ex) { + } catch (IOException ex) { log.error("IO Error in init", ex); fail("IO Error in init: " + ex.getMessage()); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } finally { @@ -126,27 +125,25 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of find method, of class WorkspaceItem. */ @Test - public void testFind() throws Exception - { + public void testFind() throws Exception { int id = wi.getID(); WorkspaceItem found = workspaceItemService.find(context, id); - assertThat("testFind 0",found,notNullValue()); - assertThat("testFind 1",found.getID(), equalTo(id)); - assertThat("testFind 2",found, equalTo(wi)); - assertThat("testFind 3",found.getCollection(),equalTo(wi.getCollection())); + assertThat("testFind 0", found, notNullValue()); + assertThat("testFind 1", found.getID(), equalTo(id)); + assertThat("testFind 2", found, equalTo(wi)); + assertThat("testFind 3", found.getCollection(), equalTo(wi.getCollection())); } /** * Test of create method, of class WorkspaceItem. */ @Test - public void testCreateAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testCreateAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Collection ADD perms - authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.ADD); result = null; + authorizeService.authorizeAction((Context) any, (Collection) any, + Constants.ADD); + result = null; }}; boolean template = false; @@ -154,28 +151,27 @@ public class WorkspaceItemTest extends AbstractUnitTest template = false; created = workspaceItemService.create(context, collection, template); - assertThat("testCreate 0",created,notNullValue()); - assertTrue("testCreate 1",created.getID() >= 0); - assertThat("testCreate 2",created.getCollection(),equalTo(collection)); + assertThat("testCreate 0", created, notNullValue()); + assertTrue("testCreate 1", created.getID() >= 0); + assertThat("testCreate 2", created.getCollection(), equalTo(collection)); template = true; created = workspaceItemService.create(context, collection, template); - assertThat("testCreate 3",created,notNullValue()); - assertTrue("testCreate 4",created.getID() >= 0); - assertThat("testCreate 5",created.getCollection(),equalTo(collection)); + assertThat("testCreate 3", created, notNullValue()); + assertTrue("testCreate 4", created.getID() >= 0); + assertThat("testCreate 5", created.getCollection(), equalTo(collection)); } /** * Test of create method, of class WorkspaceItem. */ - @Test(expected=AuthorizeException.class) - public void testCreateNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testCreateNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Collection ADD perms - authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.ADD); result = new AuthorizeException(); + authorizeService.authorizeAction((Context) any, (Collection) any, + Constants.ADD); + result = new AuthorizeException(); }}; boolean template = false; @@ -190,66 +186,58 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of findByEPerson method, of class WorkspaceItem. */ @Test - public void testFindByEPerson() throws Exception - { + public void testFindByEPerson() throws Exception { EPerson ep = context.getCurrentUser(); List found = workspaceItemService.findByEPerson(context, ep); - assertThat("testFindByEPerson 0",found,notNullValue()); - assertTrue("testFindByEPerson 1",found.size() >= 1); + assertThat("testFindByEPerson 0", found, notNullValue()); + assertTrue("testFindByEPerson 1", found.size() >= 1); boolean exists = false; - for(WorkspaceItem w: found) - { - if(w.equals(wi)) - { + for (WorkspaceItem w : found) { + if (w.equals(wi)) { exists = true; } } - assertTrue("testFindByEPerson 2",exists); + assertTrue("testFindByEPerson 2", exists); } /** * Test of findByCollection method, of class WorkspaceItem. */ @Test - public void testFindByCollection() throws Exception - { + public void testFindByCollection() throws Exception { Collection c = wi.getCollection(); List found = workspaceItemService.findByCollection(context, c); - assertThat("testFindByCollection 0",found,notNullValue()); - assertTrue("testFindByCollection 1",found.size() >= 1); - assertThat("testFindByCollection 2",found.get(0).getID(), equalTo(wi.getID())); - assertThat("testFindByCollection 3",found.get(0), equalTo(wi)); - assertThat("testFindByCollection 4",found.get(0).getCollection(),equalTo(wi.getCollection())); + assertThat("testFindByCollection 0", found, notNullValue()); + assertTrue("testFindByCollection 1", found.size() >= 1); + assertThat("testFindByCollection 2", found.get(0).getID(), equalTo(wi.getID())); + assertThat("testFindByCollection 3", found.get(0), equalTo(wi)); + assertThat("testFindByCollection 4", found.get(0).getCollection(), equalTo(wi.getCollection())); } /** * Test of findAll method, of class WorkspaceItem. */ @Test - public void testFindAll() throws Exception - { + public void testFindAll() throws Exception { List found = workspaceItemService.findAll(context); - assertTrue("testFindAll 0",found.size() >= 1); + assertTrue("testFindAll 0", found.size() >= 1); boolean added = false; - for(WorkspaceItem f: found) - { - assertThat("testFindAll 1",f,notNullValue()); - assertThat("testFindAll 2",f.getItem(),notNullValue()); - assertThat("testFindAll 3",f.getSubmitter(),notNullValue()); - if(f.equals(wi)) - { + for (WorkspaceItem f : found) { + assertThat("testFindAll 1", f, notNullValue()); + assertThat("testFindAll 2", f.getItem(), notNullValue()); + assertThat("testFindAll 3", f.getSubmitter(), notNullValue()); + if (f.equals(wi)) { added = true; } } - assertTrue("testFindAll 4",added); + assertTrue("testFindAll 4", added); } /** * Test of getID method, of class WorkspaceItem. */ @Test - public void testGetID() - { + public void testGetID() { assertTrue("testGetID 0", wi.getID() >= 0); } @@ -257,8 +245,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of getStageReached method, of class WorkspaceItem. */ @Test - public void testGetStageReached() - { + public void testGetStageReached() { assertTrue("testGetStageReached 0", wi.getStageReached() == -1); } @@ -266,8 +253,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of setStageReached method, of class WorkspaceItem. */ @Test - public void testSetStageReached() - { + public void testSetStageReached() { wi.setStageReached(4); assertTrue("testSetStageReached 0", wi.getStageReached() == 4); } @@ -276,8 +262,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of getPageReached method, of class WorkspaceItem. */ @Test - public void testGetPageReached() - { + public void testGetPageReached() { assertTrue("testGetPageReached 0", wi.getPageReached() == -1); } @@ -285,8 +270,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of setPageReached method, of class WorkspaceItem. */ @Test - public void testSetPageReached() - { + public void testSetPageReached() { wi.setPageReached(4); assertTrue("testSetPageReached 0", wi.getPageReached() == 4); } @@ -295,75 +279,69 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of update method, of class WorkspaceItem. */ @Test - public void testUpdateAuth() throws Exception - { - // no need to mockup the authorization as we are the same user that have - // created the wi + public void testUpdateAuth() throws Exception { + // no need to mockup the authorization as we are the same user that have + // created the wi boolean pBefore = wi.isPublishedBefore(); wi.setPublishedBefore(!pBefore); workspaceItemService.update(context, wi); context.commit(); // force to read the data from the database context.uncacheEntity(wi); - // read all our test attributes objects from the fresh session + // read all our test attributes objects from the fresh session // to avoid duplicate object in session issue wi = workspaceItemService.find(context, wi.getID()); collection = wi.getCollection(); owningCommunity = collection.getCommunities().get(0); assertTrue("testUpdate", pBefore != wi.isPublishedBefore()); } - + /** * Test of update method, of class WorkspaceItem with no WRITE auth. */ - @Test(expected=AuthorizeException.class) - public void testUpdateNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ - // Remove Item WRITE perms - authorizeService.authorizeActionBoolean((Context) any, (Item) any, - Constants.WRITE); result = false; - authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = new AuthorizeException(); + @Test(expected = AuthorizeException.class) + public void testUpdateNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ + // Remove Item WRITE perms + authorizeService.authorizeActionBoolean((Context) any, (Item) any, + Constants.WRITE); + result = false; + authorizeService.authorizeAction((Context) any, (Item) any, + Constants.WRITE); + result = new AuthorizeException(); }}; boolean pBefore = wi.isPublishedBefore(); wi.setPublishedBefore(!pBefore); workspaceItemService.update(context, wi); - fail("Exception expected"); + fail("Exception expected"); } /** * Test of deleteAll method, of class WorkspaceItem. */ @Test - public void testDeleteAllAuth() throws Exception - { + public void testDeleteAllAuth() throws Exception { int id = wi.getID(); //we are the user that created it (same context) so we can delete workspaceItemService.deleteAll(context, wi); WorkspaceItem found = workspaceItemService.find(context, id); - assertThat("testDeleteAllAuth 0",found,nullValue()); + assertThat("testDeleteAllAuth 0", found, nullValue()); } /** * Test of deleteAll method, of class WorkspaceItem. */ @Test - public void testDeleteAllNoAuth() throws Exception - { + public void testDeleteAllNoAuth() throws Exception { //we create a new user in context so we can't delete EPerson old = context.getCurrentUser(); context.turnOffAuthorisationSystem(); context.setCurrentUser(ePersonService.create(context)); context.restoreAuthSystemState(); - try - { + try { workspaceItemService.deleteAll(context, wi); fail("Exception expected"); - } - catch(AuthorizeException ex) - { + } catch (AuthorizeException ex) { context.setCurrentUser(old); } } @@ -372,35 +350,33 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of deleteWrapper method, of class WorkspaceItem. */ @Test - public void testDeleteWrapperAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testDeleteWrapperAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Item WRITE perms - authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = null; + authorizeService.authorizeAction((Context) any, (Item) any, + Constants.WRITE); + result = null; }}; UUID itemid = wi.getItem().getID(); int id = wi.getID(); workspaceItemService.deleteWrapper(context, wi); Item found = itemService.find(context, itemid); - assertThat("testDeleteWrapperAuth 0",found,notNullValue()); + assertThat("testDeleteWrapperAuth 0", found, notNullValue()); WorkspaceItem wfound = workspaceItemService.find(context, id); - assertThat("testDeleteWrapperAuth 1",wfound,nullValue()); + assertThat("testDeleteWrapperAuth 1", wfound, nullValue()); } /** * Test of deleteWrapper method, of class WorkspaceItem. */ - @Test(expected=AuthorizeException.class) - public void testDeleteWrapperNoAuth() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + @Test(expected = AuthorizeException.class) + public void testDeleteWrapperNoAuth() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Disallow Item WRITE perms - authorizeService.authorizeAction((Context) any, (Item) any, - Constants.WRITE); result = new AuthorizeException(); + authorizeService.authorizeAction((Context) any, (Item) any, + Constants.WRITE); + result = new AuthorizeException(); }}; workspaceItemService.deleteWrapper(context, wi); @@ -411,8 +387,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of getItem method, of class WorkspaceItem. */ @Test - public void testGetItem() - { + public void testGetItem() { assertThat("testGetItem 0", wi.getItem(), notNullValue()); } @@ -420,8 +395,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of getCollection method, of class WorkspaceItem. */ @Test - public void testGetCollection() - { + public void testGetCollection() { assertThat("testGetCollection 0", wi.getCollection(), notNullValue()); } @@ -429,8 +403,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of getSubmitter method, of class WorkspaceItem. */ @Test - public void testGetSubmitter() throws Exception - { + public void testGetSubmitter() throws Exception { assertThat("testGetSubmitter 0", wi.getSubmitter(), notNullValue()); assertThat("testGetSubmitter 1", wi.getSubmitter(), equalTo(context.getCurrentUser())); } @@ -439,8 +412,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of hasMultipleFiles method, of class WorkspaceItem. */ @Test - public void testHasMultipleFiles() - { + public void testHasMultipleFiles() { assertFalse("testHasMultipleFiles 0", wi.hasMultipleFiles()); } @@ -448,8 +420,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of setMultipleFiles method, of class WorkspaceItem. */ @Test - public void testSetMultipleFiles() - { + public void testSetMultipleFiles() { wi.setMultipleFiles(true); assertTrue("testSetMultipleFiles 0", wi.hasMultipleFiles()); } @@ -458,8 +429,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of hasMultipleTitles method, of class WorkspaceItem. */ @Test - public void testHasMultipleTitles() - { + public void testHasMultipleTitles() { assertFalse("testHasMultipleTitles 0", wi.hasMultipleTitles()); } @@ -467,8 +437,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of setMultipleTitles method, of class WorkspaceItem. */ @Test - public void testSetMultipleTitles() - { + public void testSetMultipleTitles() { wi.setMultipleTitles(true); assertTrue("testSetMultipleTitles 0", wi.hasMultipleTitles()); } @@ -477,8 +446,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of isPublishedBefore method, of class WorkspaceItem. */ @Test - public void testIsPublishedBefore() - { + public void testIsPublishedBefore() { assertFalse("testIsPublishedBefore 0", wi.isPublishedBefore()); } @@ -486,8 +454,7 @@ public class WorkspaceItemTest extends AbstractUnitTest * Test of setPublishedBefore method, of class WorkspaceItem. */ @Test - public void testSetPublishedBefore() - { + public void testSetPublishedBefore() { wi.setPublishedBefore(true); assertTrue("testSetPublishedBefore 0", wi.isPublishedBefore()); } diff --git a/dspace-api/src/test/java/org/dspace/content/authority/DSpaceControlledVocabularyTest.java b/dspace-api/src/test/java/org/dspace/content/authority/DSpaceControlledVocabularyTest.java index 9d6049f6cc..0d431a5a5b 100644 --- a/dspace-api/src/test/java/org/dspace/content/authority/DSpaceControlledVocabularyTest.java +++ b/dspace-api/src/test/java/org/dspace/content/authority/DSpaceControlledVocabularyTest.java @@ -7,46 +7,45 @@ */ package org.dspace.content.authority; -import java.io.IOException; - -import org.dspace.content.Collection; -import org.dspace.AbstractDSpaceTest; -import org.dspace.core.factory.CoreServiceFactory; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import org.junit.*; + +import java.io.IOException; + +import org.dspace.AbstractDSpaceTest; +import org.dspace.content.Collection; +import org.dspace.core.factory.CoreServiceFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; /** * Unit tests for DSpaceControlledVocabulary. * * @author mwood */ -public class DSpaceControlledVocabularyTest extends AbstractDSpaceTest -{ - public DSpaceControlledVocabularyTest() - { +public class DSpaceControlledVocabularyTest extends AbstractDSpaceTest { + public DSpaceControlledVocabularyTest() { } @BeforeClass public static void setUpClass() - throws Exception - { + throws Exception { } @AfterClass public static void tearDownClass() - throws Exception - { + throws Exception { } @Before - public void setUp() - { + public void setUp() { } @After - public void tearDown() - { + public void tearDown() { } /** @@ -69,8 +68,7 @@ public class DSpaceControlledVocabularyTest extends AbstractDSpaceTest * Test of getMatches method, of class DSpaceControlledVocabulary. */ @Test - public void testGetMatches() throws IOException, ClassNotFoundException - { + public void testGetMatches() throws IOException, ClassNotFoundException { System.out.println("getMatches"); final String PLUGIN_INTERFACE = "org.dspace.content.authority.ChoiceAuthority"; @@ -82,14 +80,14 @@ public class DSpaceControlledVocabularyTest extends AbstractDSpaceTest int start = 0; int limit = 0; String locale = null; - // This "farm" Controlled Vocab is included in TestEnvironment data + // This "farm" Controlled Vocab is included in TestEnvironment data // (under /src/test/data/dspaceFolder/) and it should be auto-loaded // by test configs in /src/test/data/dspaceFolder/config/local.cfg DSpaceControlledVocabulary instance = (DSpaceControlledVocabulary) - CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(Class.forName(PLUGIN_INTERFACE), "farm"); + CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(Class.forName(PLUGIN_INTERFACE), "farm"); assertNotNull(instance); Choices result = instance.getMatches(field, text, collection, start, - limit, locale); + limit, locale); assertEquals("the farm::north 40", result.values[0].value); } diff --git a/dspace-api/src/test/java/org/dspace/content/comparator/NameAscendingComparatorTest.java b/dspace-api/src/test/java/org/dspace/content/comparator/NameAscendingComparatorTest.java index 86953be1ba..d65360e8fb 100644 --- a/dspace-api/src/test/java/org/dspace/content/comparator/NameAscendingComparatorTest.java +++ b/dspace-api/src/test/java/org/dspace/content/comparator/NameAscendingComparatorTest.java @@ -7,15 +7,15 @@ */ package org.dspace.content.comparator; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + import org.dspace.content.DSpaceObject; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.when; - @RunWith(MockitoJUnitRunner.class) public class NameAscendingComparatorTest { @@ -94,4 +94,4 @@ public class NameAscendingComparatorTest { assertTrue(comparator.compare(dso1, dso2) < 0); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java b/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java index 66fdab1005..9ea23718b7 100644 --- a/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java +++ b/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java @@ -7,6 +7,12 @@ */ package org.dspace.content.packager; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -24,17 +30,27 @@ import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.ResourcePolicyService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.WorkspaceItem; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.dspace.core.*; +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.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Constants; +import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.core.service.PluginService; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; - import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; @@ -45,25 +61,27 @@ import org.dspace.handle.service.HandleService; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.workflow.WorkflowException; -import org.junit.*; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; import org.junit.rules.TemporaryFolder; /** * Basic integration testing for the AIP Backup and Restore feature * https://wiki.duraspace.org/display/DSDOC5x/AIP+Backup+and+Restore - * + * * @author Tim Donohue */ -public class ITDSpaceAIP extends AbstractUnitTest -{ - /** log4j category */ +public class ITDSpaceAIP extends AbstractUnitTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(ITDSpaceAIP.class); - + protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); @@ -74,31 +92,40 @@ public class ITDSpaceAIP extends AbstractUnitTest protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); protected PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); protected ConfigurationService configService = DSpaceServicesFactory.getInstance().getConfigurationService(); - protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); + protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance() + .getResourcePolicyService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); - /** InfoMap multiple value separator (see saveObjectInfo() and assertObject* methods) **/ + /** + * InfoMap multiple value separator (see saveObjectInfo() and assertObject* methods) + **/ private static final String valueseparator = "::"; - - /** Handles for Test objects initialized in setUpClass() and used in various tests below **/ + + /** + * Handles for Test objects initialized in setUpClass() and used in various tests below + **/ private static String topCommunityHandle = null; private static String testCollectionHandle = null; private static String testItemHandle = null; private static String testMappedItemHandle = null; private static String submitterEmail = "aip-test@dspace.org"; private Context context; - - /** Create a global temporary upload folder which will be cleaned up automatically by JUnit. - NOTE: As a ClassRule, this temp folder is shared by ALL tests below. **/ + + /** + * Create a global temporary upload folder which will be cleaned up automatically by JUnit. + * NOTE: As a ClassRule, this temp folder is shared by ALL tests below. + **/ @ClassRule public static final TemporaryFolder uploadTempFolder = new TemporaryFolder(); - /** Create another temporary folder for AIPs. As a Rule, this one is *recreated* for each - test, in order to ensure each test is standalone with respect to AIPs. **/ + /** + * Create another temporary folder for AIPs. As a Rule, this one is *recreated* for each + * test, in order to ensure each test is standalone with respect to AIPs. + **/ @Rule public final TemporaryFolder aipTempFolder = new TemporaryFolder(); - + /** * This method will be run during class initialization. It will initialize * shared resources required for all the tests. It is only run once. @@ -107,10 +134,8 @@ public class ITDSpaceAIP extends AbstractUnitTest * but no execution order is guaranteed */ @BeforeClass - public static void setUpClass() - { - try - { + public static void setUpClass() { + try { Context context = new Context(); // Create a dummy Community hierarchy to test with // Turn off authorization temporarily to create some test objects. @@ -124,7 +149,7 @@ public class ITDSpaceAIP extends AbstractUnitTest InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService(); log.info("setUpClass() - CREATE TEST HIERARCHY"); - // Create a hierachy of sub-Communities and Collections and Items, + // Create a hierachy of sub-Communities and Collections and Items, // which looks like this: // "Top Community" // - "Child Community" @@ -138,16 +163,19 @@ public class ITDSpaceAIP extends AbstractUnitTest // - "Mapped Item" (owning collection) // Community topCommunity = communityService.create(null, context); - communityService.addMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, null, "Top Community"); + communityService + .addMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, null, "Top Community"); communityService.update(context, topCommunity); topCommunityHandle = topCommunity.getHandle(); - + Community child = communityService.createSubcommunity(context, topCommunity); - communityService.addMetadata(context, child, MetadataSchema.DC_SCHEMA, "title", null, null, "Child Community"); + communityService + .addMetadata(context, child, MetadataSchema.DC_SCHEMA, "title", null, null, "Child Community"); communityService.update(context, child); - + Community grandchild = communityService.createSubcommunity(context, child); - communityService.addMetadata(context, grandchild, MetadataSchema.DC_SCHEMA, "title", null, null, "Grandchild Community"); + communityService.addMetadata(context, grandchild, MetadataSchema.DC_SCHEMA, "title", null, null, + "Grandchild Community"); communityService.update(context, grandchild); // Create our primary Test Collection @@ -158,7 +186,8 @@ public class ITDSpaceAIP extends AbstractUnitTest // Create an additional Test Collection Collection greatgrandchildCol = collectionService.create(context, grandchild); - collectionService.addMetadata(context, greatgrandchildCol, "dc", "title", null, null, "GreatGrandchild Collection"); + collectionService + .addMetadata(context, greatgrandchildCol, "dc", "title", null, null, "GreatGrandchild Collection"); collectionService.update(context, greatgrandchildCol); EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); @@ -205,40 +234,31 @@ public class ITDSpaceAIP extends AbstractUnitTest // Commit these changes to our DB context.restoreAuthSystemState(); context.complete(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in setUpClass()", ex); fail("Authorization Error in setUpClass(): " + ex.getMessage()); - } - catch (IOException ex) - { + } catch (IOException ex) { log.error("IO Error in setUpClass()", ex); fail("IO Error in setUpClass(): " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in setUpClass()", ex); fail("SQL Error in setUpClass(): " + ex.getMessage()); } } - + /** * This method will be run once at the very end */ @AfterClass - public static void tearDownClass() - { - try - { + public static void tearDownClass() { + try { Context context = new Context(); CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); Community topCommunity = (Community) handleService.resolveToObject(context, topCommunityHandle); // Delete top level test community and test hierarchy under it - if(topCommunity!=null) - { + if (topCommunity != null) { log.info("tearDownClass() - DESTROY TEST HIERARCHY"); context.turnOffAuthorisationSystem(); communityService.delete(context, topCommunity); @@ -249,8 +269,7 @@ public class ITDSpaceAIP extends AbstractUnitTest // Delete the Eperson created to submit test items EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); EPerson eperson = ePersonService.findByEmail(context, submitterEmail); - if(eperson!=null) - { + if (eperson != null) { log.info("tearDownClass() - DESTROY TEST EPERSON"); context.turnOffAuthorisationSystem(); ePersonService.delete(context, eperson); @@ -258,22 +277,20 @@ public class ITDSpaceAIP extends AbstractUnitTest context.commit(); } - if(context.isValid()) + if (context.isValid()) { context.abort(); - } - catch (Exception ex) - { + } + } catch (Exception ex) { log.error("Error in tearDownClass()", ex); } } - + /** * Create an initial set of AIPs for the test content generated in setUpClass() above. */ @Before @Override - public void init() - { + public void init() { // call init() from AbstractUnitTest to initialize testing framework super.init(); @@ -281,16 +298,15 @@ public class ITDSpaceAIP extends AbstractUnitTest // JUnit TemporaryFolder. This ensures Crosswalk classes like RoleCrosswalk // store their temp files in a place where JUnit can clean them up automatically. new NonStrictExpectations(configService.getClass()) {{ - configService.getProperty("upload.temp.dir"); result = uploadTempFolder.getRoot().getAbsolutePath(); + configService.getProperty("upload.temp.dir"); + result = uploadTempFolder.getRoot().getAbsolutePath(); }}; - - try - { + + try { context = new Context(); - context.setCurrentUser(EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, submitterEmail)); - } - catch (SQLException ex) - { + context.setCurrentUser( + EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, submitterEmail)); + } catch (SQLException ex) { log.error("SQL Error in init()", ex); fail("SQL Error in init(): " + ex.getMessage()); } @@ -307,13 +323,12 @@ public class ITDSpaceAIP extends AbstractUnitTest * Test restoration from AIP of entire Community Hierarchy */ @Test - public void testRestoreCommunityHierarchy() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRestoreCommunityHierarchy() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy you really need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testRestoreCommunityHierarchy() - BEGIN"); @@ -325,7 +340,7 @@ public class ITDSpaceAIP extends AbstractUnitTest DSpaceObject parent = communityService.getParentObject(context, topCommunity); // Save basic info about top community (and children) to an infoMap - HashMap infoMap = new HashMap(); + HashMap infoMap = new HashMap(); saveObjectInfo(topCommunity, infoMap); // Export community & child AIPs @@ -341,7 +356,7 @@ public class ITDSpaceAIP extends AbstractUnitTest // Restore this Community (recursively) from AIPs log.info("testRestoreCommunityHierarchy() - RESTORE Community Hierarchy"); - // Ensure "skipIfParentMissing" flag is set to true. + // Ensure "skipIfParentMissing" flag is set to true. // As noted in the documentation, this is often needed for larger, hierarchical // restores when you have Mapped Items (which we do in our test data) PackageParameters pkgParams = new PackageParameters(); @@ -350,26 +365,26 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert all objects in infoMap now exist again! assertObjectsExist(infoMap); - + // SPECIAL CASE: Test Item Mapping restoration was successful // In our community, we have one Item which should be in two Collections Item mappedItem = (Item) handleService.resolveToObject(context, testMappedItemHandle); - assertEquals("testRestoreCommunityHierarchy() - Mapped Item's Collection mappings restored", 2, mappedItem.getCollections().size()); - + assertEquals("testRestoreCommunityHierarchy() - Mapped Item's Collection mappings restored", 2, + mappedItem.getCollections().size()); + log.info("testRestoreCommunityHierarchy() - END"); } - + /** * Test restoration from AIP of an access restricted Community */ @Test - public void testRestoreRestrictedCommunity() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRestoreRestrictedCommunity() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy (Items/Bundles/Bitstreams) you need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testRestoreRestrictedCommunity() - BEGIN"); @@ -410,7 +425,8 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted collection no longer exists DSpaceObject obj = handleService.resolveToObject(context, communityHandle); - assertThat("testRestoreRestrictedCommunity() Community " + communityHandle + " doesn't exist", obj, nullValue()); + assertThat("testRestoreRestrictedCommunity() Community " + communityHandle + " doesn't exist", obj, + nullValue()); // Restore Collection from AIP (non-recursive) log.info("testRestoreRestrictedCommunity() - RESTORE Community"); @@ -418,32 +434,36 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted Collection is RESTORED DSpaceObject objRestored = handleService.resolveToObject(context, communityHandle); - assertThat("testRestoreRestrictedCommunity() Community " + communityHandle + " exists", objRestored, notNullValue()); + assertThat("testRestoreRestrictedCommunity() Community " + communityHandle + " exists", objRestored, + notNullValue()); // Assert the number of restored policies is equal List policiesRestored = authorizeService.getPolicies(context, objRestored); - assertEquals("testRestoreRestrictedCommunity() restored policy count equal", policies.size(), policiesRestored.size()); + assertEquals("testRestoreRestrictedCommunity() restored policy count equal", policies.size(), + policiesRestored.size()); // Assert the restored policy has same name, group and permission settings ResourcePolicy restoredPolicy = policiesRestored.get(0); - assertEquals("testRestoreRestrictedCommunity() restored policy group successfully", policy.getGroup().getName(), restoredPolicy.getGroup().getName()); - assertEquals("testRestoreRestrictedCommunity() restored policy action successfully", policy.getAction(), restoredPolicy.getAction()); - assertEquals("testRestoreRestrictedCommunity() restored policy name successfully", policy.getRpName(), restoredPolicy.getRpName()); + assertEquals("testRestoreRestrictedCommunity() restored policy group successfully", policy.getGroup().getName(), + restoredPolicy.getGroup().getName()); + assertEquals("testRestoreRestrictedCommunity() restored policy action successfully", policy.getAction(), + restoredPolicy.getAction()); + assertEquals("testRestoreRestrictedCommunity() restored policy name successfully", policy.getRpName(), + restoredPolicy.getRpName()); log.info("testRestoreRestrictedCommunity() - END"); } - + /** * Test replacement from AIP of entire Community Hierarchy */ @Test - public void testReplaceCommunityHierarchy() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testReplaceCommunityHierarchy() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy you really need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testReplaceCommunityHierarchy() - BEGIN"); @@ -453,39 +473,40 @@ public class ITDSpaceAIP extends AbstractUnitTest // Get the count of collections under our Community or any Sub-Communities int numberOfCollections = communityService.getAllCollections(context, topCommunity).size(); - + // Export community & child AIPs log.info("testReplaceCommunityHierarchy() - CREATE AIPs"); File aipFile = createAIP(topCommunity, null, true); - + // Get some basic info about Collection to be deleted - // In this scenario, we'll delete the test "Grandchild Collection" + // In this scenario, we'll delete the test "Grandchild Collection" // (which is initialized as being under the Top Community) String deletedCollectionHandle = testCollectionHandle; Collection collectionToDelete = (Collection) handleService.resolveToObject(context, deletedCollectionHandle); Community parent = (Community) collectionService.getParentObject(context, collectionToDelete); - + // How many items are in this Collection we are about to delete? int numberOfItems = itemService.countItems(context, collectionToDelete); // Get an Item that should be deleted when we delete this Collection // (NOTE: This item is initialized to be a member of the deleted Collection) String deletedItemHandle = testItemHandle; - + // Now, delete that one collection log.info("testReplaceCommunityHierarchy() - DELETE Collection"); communityService.removeCollection(context, parent, collectionToDelete); // Assert the deleted collection no longer exists DSpaceObject obj = handleService.resolveToObject(context, deletedCollectionHandle); - assertThat("testReplaceCommunityHierarchy() collection " + deletedCollectionHandle + " doesn't exist", obj, nullValue()); - + assertThat("testReplaceCommunityHierarchy() collection " + deletedCollectionHandle + " doesn't exist", obj, + nullValue()); + // Assert the child item no longer exists DSpaceObject obj2 = handleService.resolveToObject(context, deletedItemHandle); assertThat("testReplaceCommunityHierarchy() item " + deletedItemHandle + " doesn't exist", obj2, nullValue()); // Replace Community (and all child objects, recursively) from AIPs log.info("testReplaceCommunityHierarchy() - REPLACE Community Hierarchy"); - // Ensure "skipIfParentMissing" flag is set to true. + // Ensure "skipIfParentMissing" flag is set to true. // As noted in the documentation, this is often needed for larger, hierarchical // replacements when you have Mapped Items (which we do in our test data) PackageParameters pkgParams = new PackageParameters(); @@ -494,32 +515,35 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted collection is RESTORED DSpaceObject objRestored = handleService.resolveToObject(context, deletedCollectionHandle); - assertThat("testReplaceCommunityHierarchy() collection " + deletedCollectionHandle + " exists", objRestored, notNullValue()); - + assertThat("testReplaceCommunityHierarchy() collection " + deletedCollectionHandle + " exists", objRestored, + notNullValue()); + // Assert the deleted item is also RESTORED DSpaceObject obj2Restored = handleService.resolveToObject(context, deletedItemHandle); - assertThat("testReplaceCommunityHierarchy() item " + deletedItemHandle + " exists", obj2Restored, notNullValue()); + assertThat("testReplaceCommunityHierarchy() item " + deletedItemHandle + " exists", obj2Restored, + notNullValue()); // Assert the Collection count and Item count are same as before - assertEquals("testReplaceCommunityHierarchy() collection count", numberOfCollections, communityService.getAllCollections(context, topCommunity).size()); - assertEquals("testReplaceCommunityHierarchy() item count", numberOfItems, itemService.countItems(context, ((Collection) objRestored))); - + assertEquals("testReplaceCommunityHierarchy() collection count", numberOfCollections, + communityService.getAllCollections(context, topCommunity).size()); + assertEquals("testReplaceCommunityHierarchy() item count", numberOfItems, + itemService.countItems(context, ((Collection) objRestored))); + log.info("testReplaceCommunityHierarchy() - END"); } - + /** * Test replacement from AIP of JUST a Community object */ @Test - public void testReplaceCommunityOnly() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testReplaceCommunityOnly() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Community WRITE perms authorizeService.authorizeAction((Context) any, (Community) any, - Constants.WRITE,true); result = null; + Constants.WRITE, true); + result = null; }}; - + log.info("testReplaceCommunityOnly() - BEGIN"); // Locate the top level community (from our test data) @@ -527,11 +551,11 @@ public class ITDSpaceAIP extends AbstractUnitTest // Get its current name / title String oldName = topCommunity.getName(); - + // Export only community AIP log.info("testReplaceCommunityOnly() - CREATE Community AIP"); File aipFile = createAIP(topCommunity, null, false); - + // Change the Community name String newName = "This is NOT my Community name!"; communityService.clearMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); @@ -539,37 +563,36 @@ public class ITDSpaceAIP extends AbstractUnitTest // Ensure name is changed assertEquals("testReplaceCommunityOnly() new name", topCommunity.getName(), newName); - + // Now, replace our Community from AIP (non-recursive) replaceFromAIP(topCommunity, aipFile, null, false); // Check if name reverted to previous value assertEquals("testReplaceCommunityOnly() old name", topCommunity.getName(), oldName); } - + /** * Test restoration from AIP of entire Collection Hierarchy */ @Test - public void testRestoreCollectionHierarchy() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRestoreCollectionHierarchy() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy you really need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testRestoreCollectionHierarchy() - BEGIN"); // Locate the collection (from our test data) Collection testCollection = (Collection) handleService.resolveToObject(context, testCollectionHandle); - + // Get parent object, so that we can restore to same parent later Community parent = (Community) collectionService.getParentObject(context, testCollection); // Save basic info about collection (and children) to an infoMap - HashMap infoMap = new HashMap(); + HashMap infoMap = new HashMap(); saveObjectInfo(testCollection, infoMap); // Export collection & child AIPs @@ -589,21 +612,20 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert all objects in infoMap now exist again! assertObjectsExist(infoMap); - + log.info("testRestoreCollectionHierarchy() - END"); } - + /** * Test restoration from AIP of an access restricted Collection */ @Test - public void testRestoreRestrictedCollection() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRestoreRestrictedCollection() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy (Items/Bundles/Bitstreams) you need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testRestoreRestrictedCollection() - BEGIN"); @@ -644,7 +666,8 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted collection no longer exists DSpaceObject obj = handleService.resolveToObject(context, collectionHandle); - assertThat("testRestoreRestrictedCollection() Collection " + collectionHandle + " doesn't exist", obj, nullValue()); + assertThat("testRestoreRestrictedCollection() Collection " + collectionHandle + " doesn't exist", obj, + nullValue()); // Restore Collection from AIP (non-recursive) log.info("testRestoreRestrictedCollection() - RESTORE Collection"); @@ -652,53 +675,57 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted Collection is RESTORED DSpaceObject objRestored = handleService.resolveToObject(context, collectionHandle); - assertThat("testRestoreRestrictedCollection() Collection " + collectionHandle + " exists", objRestored, notNullValue()); + assertThat("testRestoreRestrictedCollection() Collection " + collectionHandle + " exists", objRestored, + notNullValue()); // Assert the number of restored policies is equal List policiesRestored = authorizeService.getPolicies(context, objRestored); - assertEquals("testRestoreRestrictedCollection() restored policy count equal", policies.size(), policiesRestored.size()); + assertEquals("testRestoreRestrictedCollection() restored policy count equal", policies.size(), + policiesRestored.size()); // Assert the restored policy has same name, group and permission settings ResourcePolicy restoredPolicy = policiesRestored.get(0); - assertEquals("testRestoreRestrictedCollection() restored policy group successfully", policy.getGroup().getName(), restoredPolicy.getGroup().getName()); - assertEquals("testRestoreRestrictedCollection() restored policy action successfully", policy.getAction(), restoredPolicy.getAction()); - assertEquals("testRestoreRestrictedCollection() restored policy name successfully", policy.getRpName(), restoredPolicy.getRpName()); + assertEquals("testRestoreRestrictedCollection() restored policy group successfully", + policy.getGroup().getName(), restoredPolicy.getGroup().getName()); + assertEquals("testRestoreRestrictedCollection() restored policy action successfully", policy.getAction(), + restoredPolicy.getAction()); + assertEquals("testRestoreRestrictedCollection() restored policy name successfully", policy.getRpName(), + restoredPolicy.getRpName()); log.info("testRestoreRestrictedCollection() - END"); } - + /** * Test replacement from AIP of entire Collection (with Items) */ @Test - public void testReplaceCollectionHierarchy() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testReplaceCollectionHierarchy() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy you really need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testReplaceCollectionHierarchy() - BEGIN"); // Locate the collection (from our test data) Collection testCollection = (Collection) handleService.resolveToObject(context, testCollectionHandle); - + // How many items are in this Collection? int numberOfItems = itemService.countItems(context, testCollection); - + // Export collection & child AIPs log.info("testReplaceCollectionHierarchy() - CREATE AIPs"); File aipFile = createAIP(testCollection, null, true); - + // Get some basic info about Item to be deleted - // In this scenario, we'll delete the test "Grandchild Collection Item #1" + // In this scenario, we'll delete the test "Grandchild Collection Item #1" // (which is initialized as being an Item within this Collection) String deletedItemHandle = testItemHandle; Item itemToDelete = (Item) handleService.resolveToObject(context, deletedItemHandle); Collection parent = (Collection) itemService.getParentObject(context, itemToDelete); - + // Now, delete that one item log.info("testReplaceCollectionHierarchy() - DELETE Item"); collectionService.removeItem(context, parent, itemToDelete); @@ -706,9 +733,10 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted item no longer exists DSpaceObject obj = handleService.resolveToObject(context, deletedItemHandle); assertThat("testReplaceCollectionHierarchy() item " + deletedItemHandle + " doesn't exist", obj, nullValue()); - + // Assert the item count is one less - assertEquals("testReplaceCollectionHierarchy() updated item count for collection " + testCollectionHandle, numberOfItems - 1, itemService.countItems(context, testCollection)); + assertEquals("testReplaceCollectionHierarchy() updated item count for collection " + testCollectionHandle, + numberOfItems - 1, itemService.countItems(context, testCollection)); // Replace Collection (and all child objects, recursively) from AIPs log.info("testReplaceCollectionHierarchy() - REPLACE Collection Hierarchy"); @@ -716,40 +744,41 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted item is RESTORED DSpaceObject objRestored = handleService.resolveToObject(context, deletedItemHandle); - assertThat("testReplaceCollectionHierarchy() item " + deletedItemHandle + " exists", objRestored, notNullValue()); - + assertThat("testReplaceCollectionHierarchy() item " + deletedItemHandle + " exists", objRestored, + notNullValue()); + // Assert the Item count is same as before - assertEquals("testReplaceCollectionHierarchy() restored item count for collection " + testCollectionHandle, numberOfItems, itemService.countItems(context, testCollection)); + assertEquals("testReplaceCollectionHierarchy() restored item count for collection " + testCollectionHandle, + numberOfItems, itemService.countItems(context, testCollection)); log.info("testReplaceCollectionHierarchy() - END"); } - - + + /** * Test replacement from AIP of JUST a Collection object */ @Test - public void testReplaceCollectionOnly() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testReplaceCollectionOnly() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Collection WRITE perms authorizeService.authorizeAction((Context) any, (Collection) any, - Constants.WRITE,true); result = null; + Constants.WRITE, true); + result = null; }}; - + log.info("testReplaceCollectionOnly() - BEGIN"); // Locate the collection (from our test data) Collection testCollection = (Collection) handleService.resolveToObject(context, testCollectionHandle); - + // Get its current name / title String oldName = testCollection.getName(); - + // Export only collection AIP log.info("testReplaceCollectionOnly() - CREATE Collection AIP"); File aipFile = createAIP(testCollection, null, false); - + // Change the Collection name String newName = "This is NOT my Collection name!"; collectionService.clearMetadata(context, testCollection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); @@ -757,61 +786,59 @@ public class ITDSpaceAIP extends AbstractUnitTest // Ensure name is changed assertEquals("testReplaceCollectionOnly() new name", testCollection.getName(), newName); - + // Now, replace our Collection from AIP (non-recursive) replaceFromAIP(testCollection, aipFile, null, false); // Check if name reverted to previous value assertEquals("testReplaceCollectionOnly() old name", testCollection.getName(), oldName); } - - + + /** * Test restoration from AIP of an Item */ @Test - public void testRestoreItem() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRestoreItem() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy (Items/Bundles/Bitstreams) you need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testRestoreItem() - BEGIN"); // Locate the item (from our test data) Item testItem = (Item) handleService.resolveToObject(context, testItemHandle); - + // Get information about the Item's Bitstreams // (There should be one bitstream initialized above) int bitstreamCount = 0; String bitstreamName = null; String bitstreamCheckSum = null; List bundles = itemService.getBundles(testItem, Constants.CONTENT_BUNDLE_NAME); - if(bundles.size()>0) - { + if (bundles.size() > 0) { List bitstreams = bundles.get(0).getBitstreams(); bitstreamCount = bitstreams.size(); - if(bitstreamCount>0) - { + if (bitstreamCount > 0) { bitstreamName = bitstreams.get(0).getName(); bitstreamCheckSum = bitstreams.get(0).getChecksum(); } } // We need a test bitstream to work with! - if(bitstreamCount<=0) + if (bitstreamCount <= 0) { fail("No test bitstream found for Item in testRestoreItem()!"); + } // Export item AIP log.info("testRestoreItem() - CREATE Item AIP"); File aipFile = createAIP(testItem, null, false); - + // Get parent, so we can restore under the same parent Collection parent = (Collection) itemService.getParentObject(context, testItem); - + // Now, delete that item log.info("testRestoreItem() - DELETE Item"); collectionService.removeItem(context, parent, testItem); @@ -819,7 +846,7 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted item no longer exists DSpaceObject obj = handleService.resolveToObject(context, testItemHandle); assertThat("testRestoreItem() item " + testItemHandle + " doesn't exist", obj, nullValue()); - + // Restore Item from AIP (non-recursive) log.info("testRestoreItem() - RESTORE Item"); restoreFromAIP(parent, aipFile, null, false); @@ -827,7 +854,7 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted item is RESTORED DSpaceObject objRestored = handleService.resolveToObject(context, testItemHandle); assertThat("testRestoreItem() item " + testItemHandle + " exists", objRestored, notNullValue()); - + // Assert Bitstream exists again & is associated with restored item List restoredBund = itemService.getBundles(((Item) objRestored), Constants.CONTENT_BUNDLE_NAME); Bitstream restoredBitstream = bundleService.getBitstreamByName(restoredBund.get(0), bitstreamName); @@ -836,18 +863,17 @@ public class ITDSpaceAIP extends AbstractUnitTest log.info("testRestoreItem() - END"); } - + /** * Test restoration from AIP of an access restricted Item */ @Test - public void testRestoreRestrictedItem() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRestoreRestrictedItem() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy (Items/Bundles/Bitstreams) you need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testRestoreRestrictedItem() - BEGIN"); @@ -901,13 +927,17 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the number of restored policies is equal List policiesRestored = authorizeService.getPolicies(context, objRestored); - assertEquals("testRestoreRestrictedItem() restored policy count equal", policies.size(), policiesRestored.size()); + assertEquals("testRestoreRestrictedItem() restored policy count equal", policies.size(), + policiesRestored.size()); // Assert the restored policy has same name, group and permission settings ResourcePolicy restoredPolicy = policiesRestored.get(0); - assertEquals("testRestoreRestrictedItem() restored policy group successfully", admin_policy.getGroup().getName(), restoredPolicy.getGroup().getName()); - assertEquals("testRestoreRestrictedItem() restored policy action successfully", admin_policy.getAction(), restoredPolicy.getAction()); - assertEquals("testRestoreRestrictedItem() restored policy name successfully", admin_policy.getRpName(), restoredPolicy.getRpName()); + assertEquals("testRestoreRestrictedItem() restored policy group successfully", + admin_policy.getGroup().getName(), restoredPolicy.getGroup().getName()); + assertEquals("testRestoreRestrictedItem() restored policy action successfully", admin_policy.getAction(), + restoredPolicy.getAction()); + assertEquals("testRestoreRestrictedItem() restored policy name successfully", admin_policy.getRpName(), + restoredPolicy.getRpName()); log.info("testRestoreRestrictedItem() - END"); } @@ -916,13 +946,12 @@ public class ITDSpaceAIP extends AbstractUnitTest * Test restoration from AIP of an Item that has no access policies associated with it. */ @Test - public void testRestoreItemNoPolicies() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRestoreItemNoPolicies() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy (Items/Bundles/Bitstreams) you need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; log.info("testRestoreItemNoPolicies() - BEGIN"); @@ -978,27 +1007,26 @@ public class ITDSpaceAIP extends AbstractUnitTest * Test replacement from AIP of an Item object */ @Test - public void testReplaceItem() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testReplaceItem() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy (Items/Bundles/Bitstreams) you need full admin rights - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; - + log.info("testReplaceItem() - BEGIN"); // Locate the item (from our test data) Item testItem = (Item) handleService.resolveToObject(context, testItemHandle); - + // Get its current name / title String oldName = testItem.getName(); - + // Export item AIP log.info("testReplaceItem() - CREATE Item AIP"); File aipFile = createAIP(testItem, null, false); - + // Change the Item name String newName = "This is NOT my Item name!"; itemService.clearMetadata(context, testItem, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); @@ -1006,28 +1034,29 @@ public class ITDSpaceAIP extends AbstractUnitTest // Ensure name is changed assertEquals("testReplaceItem() new name", testItem.getName(), newName); - + // Now, replace our Item from AIP (non-recursive) replaceFromAIP(testItem, aipFile, null, false); // Check if name reverted to previous value assertEquals("testReplaceItem() old name", testItem.getName(), oldName); } - + /** * Test restoration from AIP of an Item that is mapped to multiple Collections. * This tests restoring the mapped Item FROM its own AIP */ @Test - public void testRestoreMappedItem() throws Exception - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testRestoreMappedItem() throws Exception { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Full Admin permissions. Since we are working with an object // hierarchy (Items/Bundles/Bitstreams) you need full admin rights - authorizeService.isAdmin((Context) any); result = true; - authorizeService.authorizeAction(context, (Collection) any, Constants.REMOVE); result = null; - authorizeService.authorizeAction(context, (Collection) any, Constants.ADD); result = null; + authorizeService.isAdmin((Context) any); + result = true; + authorizeService.authorizeAction(context, (Collection) any, Constants.REMOVE); + result = null; + authorizeService.authorizeAction(context, (Collection) any, Constants.ADD); + result = null; }}; log.info("testRestoreMappedItem() - BEGIN"); @@ -1036,15 +1065,16 @@ public class ITDSpaceAIP extends AbstractUnitTest Item item = (Item) handleService.resolveToObject(context, testMappedItemHandle); // Get owning Collection Collection owner = item.getOwningCollection(); - + // Assert that it is in multiple collections List mappedCollections = item.getCollections(); - assertEquals("testRestoreMappedItem() item " + testMappedItemHandle + " is mapped to multiple collections", 2, mappedCollections.size()); - + assertEquals("testRestoreMappedItem() item " + testMappedItemHandle + " is mapped to multiple collections", 2, + mappedCollections.size()); + // Export mapped item AIP log.info("testRestoreMappedItem() - CREATE Mapped Item AIP"); File aipFile = createAIP(item, null, false); - + // Now, delete that item (must be removed from BOTH collections to delete it) log.info("testRestoreMappedItem() - DELETE Item"); itemService.delete(context, item); @@ -1052,7 +1082,7 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted item no longer exists DSpaceObject obj = handleService.resolveToObject(context, testMappedItemHandle); assertThat("testRestoreMappedItem() item " + testMappedItemHandle + " doesn't exist", obj, nullValue()); - + // Restore Item from AIP (non-recursive) into its original parent collection log.info("testRestoreMappedItem() - RESTORE Item"); restoreFromAIP(owner, aipFile, null, false); @@ -1061,240 +1091,237 @@ public class ITDSpaceAIP extends AbstractUnitTest // Assert the deleted item is RESTORED Item itemRestored = (Item) handleService.resolveToObject(context, testMappedItemHandle); assertThat("testRestoreMappedItem() item " + testMappedItemHandle + " exists", itemRestored, notNullValue()); - + // Test that this restored Item exists in multiple Collections List restoredMappings = itemRestored.getCollections(); assertEquals("testRestoreMappedItem() collection count", 2, restoredMappings.size()); - + log.info("testRestoreMappedItem() - END"); } - + /** * Create AIP(s) based on a given DSpaceObject. This is a simple utility method * to avoid having to rewrite this code into several tests. - * @param dso DSpaceObject to create AIP(s) for - * @param pkParams any special PackageParameters to pass (if any) + * + * @param dso DSpaceObject to create AIP(s) for + * @param pkParams any special PackageParameters to pass (if any) * @param recursive whether to recursively create AIPs or just a single AIP * @return exported root AIP file */ private File createAIP(DSpaceObject dso, PackageParameters pkgParams, boolean recursive) - throws PackageException, CrosswalkException, AuthorizeException, SQLException, IOException - { + throws PackageException, CrosswalkException, AuthorizeException, SQLException, IOException { // Get a reference to the configured "AIP" package disseminator PackageDisseminator dip = (PackageDisseminator) pluginService - .getNamedPlugin(PackageDisseminator.class, "AIP"); - if (dip == null) - { + .getNamedPlugin(PackageDisseminator.class, "AIP"); + if (dip == null) { fail("Could not find a disseminator for type 'AIP'"); return null; - } - else - { - // Export file (this is placed in JUnit's temporary folder, so that it can be cleaned up after tests complete) - File exportAIPFile = new File(aipTempFolder.getRoot().getAbsolutePath() + File.separator + PackageUtils.getPackageName(dso, "zip")); + } else { + // Export file (this is placed in JUnit's temporary folder, so that it can be cleaned up after tests + // complete) + File exportAIPFile = new File( + aipTempFolder.getRoot().getAbsolutePath() + File.separator + PackageUtils.getPackageName(dso, "zip")); // If unspecified, set default PackageParameters - if (pkgParams==null) + if (pkgParams == null) { pkgParams = new PackageParameters(); + } // Actually disseminate the object(s) to AIPs - if(recursive) + if (recursive) { dip.disseminateAll(context, dso, pkgParams, exportAIPFile); - else + } else { dip.disseminate(context, dso, pkgParams, exportAIPFile); + } return exportAIPFile; } } - + /** * Restore DSpaceObject(s) from AIP(s). This is a simple utility method * to avoid having to rewrite this code into several tests. - * @param parent The DSpaceObject which will be the parent object of the newly restored object(s) - * @param aipFile AIP file to start restoration from - * @param pkParams any special PackageParameters to pass (if any) + * + * @param parent The DSpaceObject which will be the parent object of the newly restored object(s) + * @param aipFile AIP file to start restoration from + * @param pkParams any special PackageParameters to pass (if any) * @param recursive whether to recursively restore AIPs or just a single AIP */ private void restoreFromAIP(DSpaceObject parent, File aipFile, PackageParameters pkgParams, boolean recursive) - throws PackageException, CrosswalkException, AuthorizeException, SQLException, IOException, WorkflowException { + throws PackageException, CrosswalkException, AuthorizeException, SQLException, IOException, WorkflowException { // Get a reference to the configured "AIP" package ingestor PackageIngester sip = (PackageIngester) pluginService - .getNamedPlugin(PackageIngester.class, "AIP"); - if(sip == null) - { + .getNamedPlugin(PackageIngester.class, "AIP"); + if (sip == null) { fail("Could not find a ingestor for type 'AIP'"); - } - else - { - if(!aipFile.exists()) - { + } else { + if (!aipFile.exists()) { fail("AIP Package File does NOT exist: " + aipFile.getAbsolutePath()); } // If unspecified, set default PackageParameters - if(pkgParams==null) + if (pkgParams == null) { pkgParams = new PackageParameters(); + } // Ensure restore mode is enabled pkgParams.setRestoreModeEnabled(true); // Actually ingest the object(s) from AIPs - if(recursive) + if (recursive) { sip.ingestAll(context, parent, aipFile, pkgParams, null); - else + } else { sip.ingest(context, parent, aipFile, pkgParams, null); + } } } - + /** * Replace DSpaceObject(s) from AIP(s). This is a simple utility method * to avoid having to rewrite this code into several tests. - * @param dso The DSpaceObject to be replaced from AIP - * @param aipFile AIP file to start replacement from - * @param pkParams any special PackageParameters to pass (if any) + * + * @param dso The DSpaceObject to be replaced from AIP + * @param aipFile AIP file to start replacement from + * @param pkParams any special PackageParameters to pass (if any) * @param recursive whether to recursively restore AIPs or just a single AIP */ private void replaceFromAIP(DSpaceObject dso, File aipFile, PackageParameters pkgParams, boolean recursive) - throws PackageException, CrosswalkException, AuthorizeException, SQLException, IOException, WorkflowException { + throws PackageException, CrosswalkException, AuthorizeException, SQLException, IOException, WorkflowException { // Get a reference to the configured "AIP" package ingestor PackageIngester sip = (PackageIngester) pluginService - .getNamedPlugin(PackageIngester.class, "AIP"); - if (sip == null) - { + .getNamedPlugin(PackageIngester.class, "AIP"); + if (sip == null) { fail("Could not find a ingestor for type 'AIP'"); - } - else - { - if(!aipFile.exists()) - { + } else { + if (!aipFile.exists()) { fail("AIP Package File does NOT exist: " + aipFile.getAbsolutePath()); } // If unspecified, set default PackageParameters - if (pkgParams==null) + if (pkgParams == null) { pkgParams = new PackageParameters(); + } // Ensure restore mode is enabled pkgParams.setRestoreModeEnabled(true); // Actually replace the object(s) from AIPs - if(recursive) + if (recursive) { sip.replaceAll(context, dso, aipFile, pkgParams); - else + } else { sip.replace(context, dso, aipFile, pkgParams); + } } } - + /** * Save Object hierarchy info to the given HashMap. This utility method can * be used in conjunction with "assertObjectsExist" and "assertObjectsNotExist" * methods below, in order to assert whether a restoration succeeded or not. *

    * In HashMap, Key is the object handle, and Value is "[type-text]::[title]". - * @param dso DSpaceObject + * + * @param dso DSpaceObject * @param infoMap HashMap * @throws SQLException if database error */ - private void saveObjectInfo(DSpaceObject dso, HashMap infoMap) - throws SQLException - { + private void saveObjectInfo(DSpaceObject dso, HashMap infoMap) + throws SQLException { // We need the HashMap to be non-null - if(infoMap==null) + if (infoMap == null) { return; - - if(dso instanceof Community) - { + } + + if (dso instanceof Community) { // Save this Community's info to the infoMap Community community = (Community) dso; - infoMap.put(community.getHandle(), communityService.getTypeText(community) + valueseparator + community.getName()); - + infoMap.put(community.getHandle(), + communityService.getTypeText(community) + valueseparator + community.getName()); + // Recursively call method for each SubCommunity List subCommunities = community.getSubcommunities(); - for(Community c : subCommunities) - { + for (Community c : subCommunities) { saveObjectInfo(c, infoMap); } - + // Recursively call method for each Collection List collections = community.getCollections(); - for(Collection c : collections) - { + for (Collection c : collections) { saveObjectInfo(c, infoMap); } - } - else if(dso instanceof Collection) - { + } else if (dso instanceof Collection) { // Save this Collection's info to the infoMap Collection collection = (Collection) dso; - infoMap.put(collection.getHandle(), collectionService.getTypeText(collection) + valueseparator + collection.getName()); - + infoMap.put(collection.getHandle(), + collectionService.getTypeText(collection) + valueseparator + collection.getName()); + // Recursively call method for each Item in Collection Iterator items = itemService.findByCollection(context, collection); - while(items.hasNext()) - { + while (items.hasNext()) { Item i = items.next(); saveObjectInfo(i, infoMap); } - } - else if(dso instanceof Item) - { + } else if (dso instanceof Item) { // Save this Item's info to the infoMap Item item = (Item) dso; infoMap.put(item.getHandle(), itemService.getTypeText(item) + valueseparator + item.getName()); } } - + /** - * Assert the objects listed in a HashMap all exist in DSpace and have + * Assert the objects listed in a HashMap all exist in DSpace and have * properties equal to HashMap value(s). *

    * In HashMap, Key is the object handle, and Value is "[type-text]::[title]". + * * @param infoMap HashMap of objects to check for * @throws SQLException if database error */ - private void assertObjectsExist(HashMap infoMap) - throws SQLException - { - if(infoMap==null || infoMap.isEmpty()) + private void assertObjectsExist(HashMap infoMap) + throws SQLException { + if (infoMap == null || infoMap.isEmpty()) { fail("Cannot assert against an empty infoMap"); - + } + // Loop through everything in infoMap, and ensure it all exists - for(String key : infoMap.keySet()) - { + for (String key : infoMap.keySet()) { // The Key is the Handle, so make sure this object exists DSpaceObject obj = handleService.resolveToObject(context, key); - assertThat("assertObjectsExist object " + key + " (info=" + infoMap.get(key) + ") exists", obj, notNullValue()); - + assertThat("assertObjectsExist object " + key + " (info=" + infoMap.get(key) + ") exists", obj, + notNullValue()); + // Get the typeText & name of this object from the values String info = infoMap.get(key); String[] values = info.split(valueseparator); String typeText = values[0]; String name = values[1]; - + // Also assert type and name are correct - assertEquals("assertObjectsExist object " + key + " type", ContentServiceFactory.getInstance().getDSpaceObjectService(obj).getTypeText(obj), typeText); + assertEquals("assertObjectsExist object " + key + " type", + ContentServiceFactory.getInstance().getDSpaceObjectService(obj).getTypeText(obj), typeText); assertEquals("assertObjectsExist object " + key + " name", obj.getName(), name); } - + } - + /** * Assert the objects listed in a HashMap do NOT exist in DSpace. + * * @param infoMap HashMap of objects to check for * @throws SQLException if database error */ - public void assertObjectsNotExist(HashMap infoMap) - throws SQLException - { - if(infoMap==null || infoMap.isEmpty()) + public void assertObjectsNotExist(HashMap infoMap) + throws SQLException { + if (infoMap == null || infoMap.isEmpty()) { fail("Cannot assert against an empty infoMap"); - + } + // Loop through everything in infoMap, and ensure it all exists - for(String key : infoMap.keySet()) - { + for (String key : infoMap.keySet()) { // The key is the Handle, so make sure this object does NOT exist DSpaceObject obj = handleService.resolveToObject(context, key); - assertThat("assertObjectsNotExist object " + key + " (info=" + infoMap.get(key) + ") doesn't exist", obj, nullValue()); + assertThat("assertObjectsNotExist object " + key + " (info=" + infoMap.get(key) + ") doesn't exist", obj, + nullValue()); } } } diff --git a/dspace-api/src/test/java/org/dspace/content/packager/PackageUtilsTest.java b/dspace-api/src/test/java/org/dspace/content/packager/PackageUtilsTest.java index 228ca81d6c..a0b21f8221 100644 --- a/dspace-api/src/test/java/org/dspace/content/packager/PackageUtilsTest.java +++ b/dspace-api/src/test/java/org/dspace/content/packager/PackageUtilsTest.java @@ -7,6 +7,14 @@ */ package org.dspace.content.packager; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.sql.SQLException; + import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; @@ -14,26 +22,28 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.MetadataSchema; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.GroupService; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; -import org.junit.*; - -import java.sql.SQLException; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.*; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; /** * @author Andrea Schweer schweer@waikato.ac.nz - * for the University of Waikato's Institutional Research Repositories + * for the University of Waikato's Institutional Research Repositories */ -public class PackageUtilsTest extends AbstractUnitTest -{ +public class PackageUtilsTest extends AbstractUnitTest { private static final Logger log = Logger.getLogger(PackageUtilsTest.class); protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); @@ -44,7 +54,9 @@ public class PackageUtilsTest extends AbstractUnitTest protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService(); protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - /** Handles for Test objects initialized in setUpClass() and used in various tests below **/ + /** + * Handles for Test objects initialized in setUpClass() and used in various tests below + **/ private static String topCommunityHandle = null; private static String testCollectionHandle = null; @@ -56,10 +68,8 @@ public class PackageUtilsTest extends AbstractUnitTest * but no execution order is guaranteed */ @BeforeClass - public static void setUpClass() - { - try - { + public static void setUpClass() { + try { Context context = new Context(); // Create a dummy Community hierarchy to test with // Turn off authorization temporarily to create some test objects. @@ -76,12 +86,14 @@ public class PackageUtilsTest extends AbstractUnitTest // - "Grandchild Collection" // Community topCommunity = communityService.create(null, context); - communityService.addMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, null, "Top Community"); + communityService + .addMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, null, "Top Community"); communityService.update(context, topCommunity); topCommunityHandle = topCommunity.getHandle(); Community child = communityService.createSubcommunity(context, topCommunity); - communityService.addMetadata(context, child, MetadataSchema.DC_SCHEMA, "title", null, null, "Child Community"); + communityService + .addMetadata(context, child, MetadataSchema.DC_SCHEMA, "title", null, null, "Child Community"); communityService.update(context, child); // Create our primary Test Collection @@ -93,14 +105,10 @@ public class PackageUtilsTest extends AbstractUnitTest // Commit these changes to our DB context.restoreAuthSystemState(); context.complete(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in setUpClass()", ex); fail("Authorization Error in setUpClass(): " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in setUpClass()", ex); fail("SQL Error in setUpClass(): " + ex.getMessage()); } @@ -110,18 +118,15 @@ public class PackageUtilsTest extends AbstractUnitTest * This method will be run once at the very end */ @AfterClass - public static void tearDownClass() - { - try - { + public static void tearDownClass() { + try { Context context = new Context(); CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); Community topCommunity = (Community) handleService.resolveToObject(context, topCommunityHandle); // Delete top level test community and test hierarchy under it - if(topCommunity!=null) - { + if (topCommunity != null) { log.info("tearDownClass() - DESTROY TEST HIERARCHY"); context.turnOffAuthorisationSystem(); communityService.delete(context, topCommunity); @@ -129,11 +134,10 @@ public class PackageUtilsTest extends AbstractUnitTest context.complete(); } - if(context.isValid()) + if (context.isValid()) { context.abort(); - } - catch (Exception ex) - { + } + } catch (Exception ex) { log.error("Error in tearDownClass()", ex); } } @@ -143,16 +147,14 @@ public class PackageUtilsTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { // call init() from AbstractUnitTest to initialize testing framework super.init(); context.turnOffAuthorisationSystem(); } @Test - public void testCrosswalkGroupNameWithoutUnderscore() throws Exception - { + public void testCrosswalkGroupNameWithoutUnderscore() throws Exception { Collection testCollection = (Collection) handleService.resolveToObject(context, testCollectionHandle); Group originalFirstStepWorkflowGroup = testCollection.getWorkflowStep1(); @@ -162,18 +164,19 @@ public class PackageUtilsTest extends AbstractUnitTest testCollection.setWorkflowGroup(context, 1, testGroup); String exportName = PackageUtils.translateGroupNameForExport(context, - testGroup.getName()); - assertEquals("Group name without underscore unchanged by translation for export", testGroup.getName(), exportName); + testGroup.getName()); + assertEquals("Group name without underscore unchanged by translation for export", testGroup.getName(), + exportName); String importName = PackageUtils.translateGroupNameForImport(context, exportName); - assertEquals("Exported Group name without underscore unchanged by translation for import", exportName, importName); + assertEquals("Exported Group name without underscore unchanged by translation for import", exportName, + importName); testCollection.setWorkflowGroup(context, 1, originalFirstStepWorkflowGroup); } @Test - public void testCrosswalkGroupNameUnderscoresNoDSO() throws Exception - { + public void testCrosswalkGroupNameUnderscoresNoDSO() throws Exception { Collection testCollection = (Collection) handleService.resolveToObject(context, testCollectionHandle); Group originalFirstStepWorkflowGroup = testCollection.getWorkflowStep1(); @@ -183,30 +186,32 @@ public class PackageUtilsTest extends AbstractUnitTest testCollection.setWorkflowGroup(context, 1, testGroup); String exportName = PackageUtils.translateGroupNameForExport(context, - testGroup.getName()); - assertEquals("Group name with underscores but no DSO unchanged by translation for export", testGroup.getName(), exportName); + testGroup.getName()); + assertEquals("Group name with underscores but no DSO unchanged by translation for export", testGroup.getName(), + exportName); String importName = PackageUtils.translateGroupNameForImport(context, exportName); - assertEquals("Exported Group name with underscores but no DSO unchanged by translation for import", exportName, importName); + assertEquals("Exported Group name with underscores but no DSO unchanged by translation for import", exportName, + importName); testCollection.setWorkflowGroup(context, 1, originalFirstStepWorkflowGroup); } @Test - public void testCrosswalkGroupNameUnderscoresAndDSO() throws Exception - { + public void testCrosswalkGroupNameUnderscoresAndDSO() throws Exception { Collection testCollection = (Collection) handleService.resolveToObject(context, testCollectionHandle); Group originalFirstStepWorkflowGroup = testCollection.getWorkflowStep1(); Group group = collectionService.createWorkflowGroup(context, testCollection, 1); String exportName = PackageUtils.translateGroupNameForExport(context, - group.getName()); + group.getName()); assertNotEquals("Exported group name should differ from original", group.getName(), exportName); assertThat("Exported group name should contain '_hdl:' substring", exportName, containsString("_hdl:")); String importName = PackageUtils.translateGroupNameForImport(context, exportName); - assertEquals("Exported Group name with dso unchanged by roundtrip translation for export/import", group.getName(), importName); + assertEquals("Exported Group name with dso unchanged by roundtrip translation for export/import", + group.getName(), importName); testCollection.setWorkflowGroup(context, 1, originalFirstStepWorkflowGroup); } diff --git a/dspace-api/src/test/java/org/dspace/core/ContextReadOnlyCacheTest.java b/dspace-api/src/test/java/org/dspace/core/ContextReadOnlyCacheTest.java index fe11b9e33c..b948c63212 100644 --- a/dspace-api/src/test/java/org/dspace/core/ContextReadOnlyCacheTest.java +++ b/dspace-api/src/test/java/org/dspace/core/ContextReadOnlyCacheTest.java @@ -7,6 +7,15 @@ */ package org.dspace.core; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.UUID; + import org.dspace.content.Item; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; @@ -17,13 +26,6 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; -import java.util.Arrays; -import java.util.HashSet; -import java.util.UUID; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.when; - /** * Class to test the read-only Context cache */ @@ -118,4 +120,4 @@ public class ContextReadOnlyCacheTest { return group; } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/core/ContextTest.java b/dspace-api/src/test/java/org/dspace/core/ContextTest.java index 00cade17df..78b759fa34 100644 --- a/dspace-api/src/test/java/org/dspace/core/ContextTest.java +++ b/dspace-api/src/test/java/org/dspace/core/ContextTest.java @@ -7,6 +7,13 @@ */ package org.dspace.core; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.sql.SQLException; import java.util.List; import java.util.Locale; @@ -22,16 +29,14 @@ import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; -import org.junit.*; -import static org.junit.Assert.* ; -import static org.hamcrest.CoreMatchers.*; +import org.junit.Test; /** * Perform some basic unit tests for Context Class + * * @author tdonohue */ -public class ContextTest extends AbstractUnitTest -{ +public class ContextTest extends AbstractUnitTest { protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); @@ -40,10 +45,9 @@ public class ContextTest extends AbstractUnitTest * Test of getDBConnection method, of class Context. */ @Test - public void testGetDBConnection() throws SQLException - { + public void testGetDBConnection() throws SQLException { DBConnection connection = context.getDBConnection(); - + assertThat("testGetDBConnection 0", connection, notNullValue()); assertThat("testGetDBConnection 1", connection.isSessionAlive(), equalTo(true)); } @@ -52,16 +56,15 @@ public class ContextTest extends AbstractUnitTest * Test of setCurrentUser method, of class Context. */ @Test - public void testSetCurrentUser() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testSetCurrentUser() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Admin permissions - needed to create a new EPerson - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; - + EPerson oldUser = context.getCurrentUser(); - + // Create a dummy EPerson to set as current user EPerson newUser = ePersonService.create(context); newUser.setFirstName(context, "Jane"); @@ -69,12 +72,12 @@ public class ContextTest extends AbstractUnitTest newUser.setEmail("jane@email.com"); newUser.setCanLogIn(true); newUser.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - + context.setCurrentUser(newUser); - + assertThat("testSetCurrentUser 0", context.getCurrentUser(), notNullValue()); assertThat("testSetCurrentUser 1", context.getCurrentUser(), equalTo(newUser)); - + // Restore the previous current user context.setCurrentUser(oldUser); } @@ -83,8 +86,7 @@ public class ContextTest extends AbstractUnitTest * Test of getCurrentUser method, of class Context. */ @Test - public void testGetCurrentUser() - { + public void testGetCurrentUser() { //NOTE: 'eperson' is initialized by AbstractUnitTest & set as the "currentUser" there assertThat("testGetCurrentUser 0", context.getCurrentUser(), notNullValue()); assertThat("testGetCurrentUser 1", context.getCurrentUser(), equalTo(eperson)); @@ -94,8 +96,7 @@ public class ContextTest extends AbstractUnitTest * Test of getCurrentLocale method, of class Context. */ @Test - public void testGetCurrentLocale() - { + public void testGetCurrentLocale() { //NOTE: CurrentLocale is not initialized in AbstractUnitTest. So it should be DEFAULTLOCALE assertThat("testGetCurrentLocale 0", context.getCurrentLocale(), notNullValue()); assertThat("testGetCurrentLocale 1", context.getCurrentLocale(), equalTo(I18nUtil.DEFAULTLOCALE)); @@ -106,17 +107,17 @@ public class ContextTest extends AbstractUnitTest */ @Test public void testSetCurrentLocale() { - + //Get previous value Locale oldLocale = context.getCurrentLocale(); - + //Set a new, non-English value Locale newLocale = Locale.FRENCH; context.setCurrentLocale(newLocale); - + assertThat("testSetCurrentLocale 0", context.getCurrentLocale(), notNullValue()); assertThat("testSetCurrentLocale 1", context.getCurrentLocale(), equalTo(newLocale)); - + // Restore previous value context.setCurrentLocale(oldLocale); } @@ -125,12 +126,11 @@ public class ContextTest extends AbstractUnitTest * Test of ignoreAuthorization method, of class Context. */ @Test - public void testIgnoreAuthorization() - { + public void testIgnoreAuthorization() { // Turn off authorization context.turnOffAuthorisationSystem(); assertThat("testIgnoreAuthorization 0", context.ignoreAuthorization(), equalTo(true)); - + // Turn it back on context.restoreAuthSystemState(); assertThat("testIgnoreAuthorization 1", context.ignoreAuthorization(), equalTo(false)); @@ -141,7 +141,7 @@ public class ContextTest extends AbstractUnitTest */ /*@Test public void testTurnOffAuthorisationSystem() { - // Already tested in testIgnoreAuthorization() + // Already tested in testIgnoreAuthorization() }*/ /** @@ -164,15 +164,14 @@ public class ContextTest extends AbstractUnitTest * Test of setExtraLogInfo method, of class Context. */ @Test - public void testSetExtraLogInfo() - { + public void testSetExtraLogInfo() { // Get the previous value String oldValue = context.getExtraLogInfo(); - + // Set a new value String newValue = "This is some extra log info"; context.setExtraLogInfo(newValue); - + assertThat("testSetExtraLogInfo 0", context.getExtraLogInfo(), notNullValue()); assertThat("testSetExtraLogInfo 1", context.getExtraLogInfo(), equalTo(newValue)); } @@ -181,11 +180,10 @@ public class ContextTest extends AbstractUnitTest * Test of getExtraLogInfo method, of class Context. */ @Test - public void testGetExtraLogInfo() - { + public void testGetExtraLogInfo() { // Extra log info has a default value of "", and AbstractUnitTest doesn't change it String defaultValue = ""; - + assertThat("testGetExtraLogInfo 0", context.getExtraLogInfo(), notNullValue()); assertThat("testGetExtraLogInfo 1", context.getExtraLogInfo(), equalTo(defaultValue)); } @@ -194,16 +192,15 @@ public class ContextTest extends AbstractUnitTest * Test of complete method, of class Context. */ @Test - public void testComplete() throws SQLException - { + public void testComplete() throws SQLException { // To test complete() we need a new Context object Context instance = new Context(); - + // By default, we should have a new DB connection, so let's make sure it is there assertThat("testComplete 0", instance.getDBConnection(), notNullValue()); assertThat("testComplete 1", instance.getDBConnection().isSessionAlive(), equalTo(true)); assertThat("testComplete 2", instance.isValid(), equalTo(true)); - + // Now, call complete(). This should set DB connection to null & invalidate context instance.complete(); assertThat("testComplete 3", instance.getDBConnection(), nullValue()); @@ -213,17 +210,16 @@ public class ContextTest extends AbstractUnitTest cleanupContext(instance); // TODO: May also want to test that complete() is calling commit()? } - + /** * Test of complete method, of class Context. */ @Test - public void testComplete2() throws SQLException - { + public void testComplete2() throws SQLException { // To test complete() we need a new Context object Context instance = new Context(); - - // Call complete twice. The second call should NOT throw an error + + // Call complete twice. The second call should NOT throw an error // and effectively does nothing instance.complete(); instance.complete(); @@ -236,17 +232,16 @@ public class ContextTest extends AbstractUnitTest * Test of abort method, of class Context. */ @Test - public void testAbort() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testAbort() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Admin permissions - needed to create a new EPerson - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; // To test abort() we need a new Context object Context instance = new Context(); - + // Create a new EPerson (DO NOT COMMIT IT) String createdEmail = "susie@email.com"; EPerson newUser = ePersonService.create(instance); @@ -255,12 +250,12 @@ public class ContextTest extends AbstractUnitTest newUser.setEmail(createdEmail); newUser.setCanLogIn(true); newUser.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - + // Abort our context instance.abort(); // Ensure the context is no longer valid assertThat("testAbort 0", instance.isValid(), equalTo(false)); - + // Open a new context, let's make sure that EPerson isn't there Context newInstance = new Context(); EPerson found = ePersonService.findByEmail(newInstance, createdEmail); @@ -270,17 +265,54 @@ public class ContextTest extends AbstractUnitTest cleanupContext(instance); cleanupContext(newInstance); } - + + /** + * Test of close method, of class Context. + */ + @Test + public void testClose() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ + // Allow Admin permissions - needed to create a new EPerson + authorizeService.isAdmin((Context) any); + result = true; + }}; + + String createdEmail = "susie@email.com"; + + // To test close() we need a new Context object in a try-with-resources block + try (Context instance = new Context()) { + + // Create a new EPerson (DO NOT COMMIT IT) + EPerson newUser = ePersonService.create(instance); + newUser.setFirstName(context, "Susan"); + newUser.setLastName(context, "Doe"); + newUser.setEmail(createdEmail); + newUser.setCanLogIn(true); + newUser.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + + } + + // Open a new context, let's make sure that EPerson isn't there + Context newInstance = new Context(); + EPerson found = ePersonService.findByEmail(newInstance, createdEmail); + assertThat("testClose 0", found, nullValue()); + + // Cleanup our contexts + cleanupContext(newInstance); + + //Calling close on a finished context should not result in errors + newInstance.close(); + } + /** * Test of abort method, of class Context. */ @Test - public void testAbort2() throws SQLException - { + public void testAbort2() throws SQLException { // To test abort() we need a new Context object Context instance = new Context(); - - // Call abort twice. The second call should NOT throw an error + + // Call abort twice. The second call should NOT throw an error // and effectively does nothing instance.abort(); instance.abort(); @@ -301,11 +333,10 @@ public class ContextTest extends AbstractUnitTest * Test of isReadOnly method, of class Context. */ @Test - public void testIsReadOnly() throws SQLException - { + public void testIsReadOnly() throws SQLException { // Our default context should NOT be read only assertThat("testIsReadOnly 0", context.isReadOnly(), equalTo(false)); - + // Create a new read-only context Context instance = new Context(Context.Mode.READ_ONLY); assertThat("testIsReadOnly 1", instance.isReadOnly(), equalTo(true)); @@ -321,8 +352,7 @@ public class ContextTest extends AbstractUnitTest * Test that commit cannot be called when the context is in read-only mode */ @Test - public void testIsReadOnlyCommit() throws SQLException - { + public void testIsReadOnlyCommit() throws SQLException { // Create a new read-only context Context instance = new Context(Context.Mode.READ_ONLY); assertThat("testIsReadOnly 1", instance.isReadOnly(), equalTo(true)); @@ -353,17 +383,16 @@ public class ContextTest extends AbstractUnitTest * Test of setSpecialGroup method, of class Context. */ @Test - public void testSetSpecialGroup() throws SQLException - { + public void testSetSpecialGroup() throws SQLException { // To test special groups we need a new Context object Context instance = new Context(); - + // Pass in random integers (need not be valid group IDs) UUID groupID1 = UUID.randomUUID(); UUID groupID2 = UUID.randomUUID(); instance.setSpecialGroup(groupID1); instance.setSpecialGroup(groupID2); - + assertThat("testSetSpecialGroup 0", instance.inSpecialGroup(groupID1), equalTo(true)); assertThat("testSetSpecialGroup 1", instance.inSpecialGroup(groupID2), equalTo(true)); assertThat("testSetSpecialGroup 2", instance.inSpecialGroup(UUID.randomUUID()), equalTo(false)); @@ -384,27 +413,26 @@ public class ContextTest extends AbstractUnitTest * Test of getSpecialGroups method, of class Context. */ @Test - public void testGetSpecialGroups() throws SQLException, AuthorizeException - { - new NonStrictExpectations(authorizeService.getClass()) - {{ + public void testGetSpecialGroups() throws SQLException, AuthorizeException { + new NonStrictExpectations(authorizeService.getClass()) {{ // Allow Admin permissions - needed to create a new Group - authorizeService.isAdmin((Context) any); result = true; + authorizeService.isAdmin((Context) any); + result = true; }}; - + // To test special groups we need a new Context object Context instance = new Context(); - + // Create a new group & add it as a special group Group group = groupService.create(instance); UUID groupID = group.getID(); instance.setSpecialGroup(groupID); - + // Also add Administrator group as a special group Group adminGroup = groupService.findByName(instance, Group.ADMIN); UUID adminGroupID = adminGroup.getID(); instance.setSpecialGroup(adminGroupID); - + // Now get our special groups List specialGroups = instance.getSpecialGroups(); assertThat("testGetSpecialGroup 0", specialGroups.size(), equalTo(2)); @@ -422,13 +450,35 @@ public class ContextTest extends AbstractUnitTest public void testFinalize() throws Throwable { // We need a new Context object Context instance = new Context(); - + instance.finalize(); - + // Finalize is like abort()...should invalidate our context assertThat("testSetSpecialGroup 0", instance.isValid(), equalTo(false)); // Cleanup our context cleanupContext(instance); } + + /** + * Test of updateDatabase method, of class Context. + */ + @Test + public void testUpdateDatabase() throws Throwable { + // We create a new Context object and force the databaseUpdated flag to false + Context instance = new Context() { + @Override + protected void init() { + super.init(); + databaseUpdated.set(false); + } + }; + + // Finalize is like abort()...should invalidate our context + assertThat("updateDatabase 0", Context.updateDatabase(), equalTo(true)); + + // Cleanup our context + cleanupContext(instance); + } + } diff --git a/dspace-api/src/test/java/org/dspace/core/CoreHelpers.java b/dspace-api/src/test/java/org/dspace/core/CoreHelpers.java index db2cce27b7..a47652844b 100644 --- a/dspace-api/src/test/java/org/dspace/core/CoreHelpers.java +++ b/dspace-api/src/test/java/org/dspace/core/CoreHelpers.java @@ -12,16 +12,20 @@ package org.dspace.core; * * @author mwood */ -public class CoreHelpers -{ +public class CoreHelpers { + + /** + * Default constructor + */ + private CoreHelpers() { } + /** * Expose a Context's DBConnection. * * @param ctx * @return */ - static public DBConnection getDBConnection(Context ctx) - { + static public DBConnection getDBConnection(Context ctx) { return ctx.getDBConnection(); } } diff --git a/dspace-api/src/test/java/org/dspace/core/I18nUtilTest.java b/dspace-api/src/test/java/org/dspace/core/I18nUtilTest.java index 98ea86fb8c..6f9241663e 100644 --- a/dspace-api/src/test/java/org/dspace/core/I18nUtilTest.java +++ b/dspace-api/src/test/java/org/dspace/core/I18nUtilTest.java @@ -8,7 +8,10 @@ package org.dspace.core; +import static org.junit.Assert.assertEquals; + import java.util.Locale; + import mockit.Expectations; import org.dspace.AbstractDSpaceTest; import org.dspace.services.ConfigurationService; @@ -19,38 +22,26 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; - /** - * * @author mwood */ -public class I18nUtilTest extends AbstractDSpaceTest -{ - - public I18nUtilTest() - { - } +public class I18nUtilTest extends AbstractDSpaceTest { @BeforeClass - public static void setUpClass() - { + public static void setUpClass() { } @AfterClass - public static void tearDownClass() - { + public static void tearDownClass() { } @SuppressWarnings("ResultOfObjectAllocationIgnored") @Before - public void setUp() - { + public void setUp() { } @After - public void tearDown() - { + public void tearDown() { } /** @@ -140,27 +131,25 @@ public class I18nUtilTest extends AbstractDSpaceTest * Test of getMessage method, of class I18nUtil. */ @Test - public void testGetMessage_String() - { + public void testGetMessage_String() { System.out.println("getMessage"); final ConfigurationService configService = DSpaceServicesFactory.getInstance().getConfigurationService(); - + // Override "default.locale" and ensure it is set to US English new Expectations(configService.getClass()) {{ - configService.getProperty("default.locale"); result = "en_US.UTF-8"; + configService.getProperty("default.locale"); + result = "en_US.UTF-8"; }}; // Assert our overridden default.locale is set in I18nUtil assertEquals("Default locale", new Locale("en", "US", "UTF-8"), I18nUtil.getDefaultLocale()); - - String key, expResult, result; // Test for a stock key - key = "jsp.general.home"; - expResult = "DSpace Home"; - result = I18nUtil.getMessage(key); + String key = "jsp.general.home"; + String expResult = "DSpace Home"; + String result = I18nUtil.getMessage(key); assertEquals("Returns the translation of the key if it is defined", - expResult, result); + expResult, result); // Test for a missing key key = expResult = "bogus key"; @@ -172,18 +161,16 @@ public class I18nUtilTest extends AbstractDSpaceTest * Test of getMessage method, of class I18nUtil. */ @Test - public void testGetMessage_String_Locale() - { + public void testGetMessage_String_Locale() { System.out.println("getMessage"); - String key, expResult, result; Locale locale = Locale.US; // Test for a stock key - key = "jsp.general.home"; - expResult = "DSpace Home"; - result = I18nUtil.getMessage(key, locale); + String key = "jsp.general.home"; + String expResult = "DSpace Home"; + String result = I18nUtil.getMessage(key, locale); assertEquals("Returns the translation of the key if it is defined", - expResult, result); + expResult, result); // Test for a missing key key = expResult = "bogus key"; diff --git a/dspace-api/src/test/java/org/dspace/core/PathsClassLoaderTest.java b/dspace-api/src/test/java/org/dspace/core/PathsClassLoaderTest.java index 2f662ab876..b09437e804 100644 --- a/dspace-api/src/test/java/org/dspace/core/PathsClassLoaderTest.java +++ b/dspace-api/src/test/java/org/dspace/core/PathsClassLoaderTest.java @@ -8,15 +8,17 @@ package org.dspace.core; import static com.sun.org.apache.bcel.internal.Constants.ACC_PUBLIC; -import com.sun.org.apache.bcel.internal.generic.ClassGen; +import static org.junit.Assert.assertTrue; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; + +import com.sun.org.apache.bcel.internal.generic.ClassGen; import org.junit.After; import org.junit.AfterClass; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -26,32 +28,37 @@ import org.junit.Test; * * @author mhwood */ -public class PathsClassLoaderTest -{ +public class PathsClassLoaderTest { private static final String FILENAME_PREFIX = "foo"; private static final String CLASS_FILENAME_SUFFIX = ".class"; private static final String JAR_FILENAME_SUFFIX = ".jar"; private static final ClassLoader parentCL = PathsClassLoaderTest.class.getClassLoader(); - /** The test bare class file. */ + /** + * The test bare class file. + */ private static File classFile; - /** The test class file in a JAR. */ + /** + * The test class file in a JAR. + */ private static File jarFile; - /** Name of the test class in the file. */ + /** + * Name of the test class in the file. + */ private static String className; - /** Name of the test class in the JAR. */ + /** + * Name of the test class in the JAR. + */ private static String jarClassName; - public PathsClassLoaderTest() - { + public PathsClassLoaderTest() { } @BeforeClass - public static void setUpClass() - { + public static void setUpClass() { // Create a name for a temporary class file. try { @@ -64,11 +71,11 @@ public class PathsClassLoaderTest String classFileName = classFile.getName(); className = classFileName.substring(0, - classFileName.length() - CLASS_FILENAME_SUFFIX.length()); + classFileName.length() - CLASS_FILENAME_SUFFIX.length()); // Create an empty class. ClassGen cg = new ClassGen(className, "java.lang.Object", - "", ACC_PUBLIC, null); + "", ACC_PUBLIC, null); cg.addEmptyConstructor(ACC_PUBLIC); // Create a class file from the empty class. @@ -86,10 +93,10 @@ public class PathsClassLoaderTest jarFile.deleteOnExit(); String jarFileName = jarFile.getName(); jarClassName = jarFileName.substring(0, - jarFileName.length() - JAR_FILENAME_SUFFIX.length()); + jarFileName.length() - JAR_FILENAME_SUFFIX.length()); cg = new ClassGen(jarClassName, "java.lang.Object", - "", ACC_PUBLIC, null); + "", ACC_PUBLIC, null); cg.addEmptyConstructor(ACC_PUBLIC); jar = new JarOutputStream(new FileOutputStream(jarFile)); @@ -104,32 +111,29 @@ public class PathsClassLoaderTest } @AfterClass - public static void tearDownClass() - { + public static void tearDownClass() { } @Before - public void setUp() - { + public void setUp() { } @After - public void tearDown() - { + public void tearDown() { } /** * Test of findClass method, of class PathsClassLoader. + * * @throws Exception if error */ @Test public void testFindClass() - throws Exception - { + throws Exception { System.out.println("findClass"); - String[] classpath = { classFile.getParent(), - jarFile.getCanonicalPath() }; + String[] classpath = {classFile.getParent(), + jarFile.getCanonicalPath()}; PathsClassLoader instance = new PathsClassLoader(parentCL, classpath); Class result = instance.findClass(className); assertTrue("Should return a Class from file", result instanceof Class); diff --git a/dspace-api/src/test/java/org/dspace/core/PluginServiceTest.java b/dspace-api/src/test/java/org/dspace/core/PluginServiceTest.java index 193e08bc1b..abd8b23304 100644 --- a/dspace-api/src/test/java/org/dspace/core/PluginServiceTest.java +++ b/dspace-api/src/test/java/org/dspace/core/PluginServiceTest.java @@ -7,14 +7,15 @@ */ package org.dspace.core; -import org.dspace.AbstractDSpaceTest; -import org.dspace.core.factory.CoreServiceFactory; -import org.dspace.core.service.PluginService; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; + +import org.dspace.AbstractDSpaceTest; +import org.dspace.core.factory.CoreServiceFactory; +import org.dspace.core.service.PluginService; import org.junit.Test; /** @@ -25,8 +26,7 @@ import org.junit.Test; * * @author Tim Donohue */ -public class PluginServiceTest extends AbstractDSpaceTest -{ +public class PluginServiceTest extends AbstractDSpaceTest { // Get our enabled pluginService private PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); @@ -34,8 +34,7 @@ public class PluginServiceTest extends AbstractDSpaceTest * Test of getAllPluginNames() method */ @Test - public void testGetAllPluginNames() - { + public void testGetAllPluginNames() { // Get all plugins defined from List interface (see test local.cfg) String[] names = pluginService.getAllPluginNames(java.util.List.class); @@ -47,8 +46,7 @@ public class PluginServiceTest extends AbstractDSpaceTest * Test of getNamedPlugin() method */ @Test - public void testGetNamedPlugin() - { + public void testGetNamedPlugin() { // Get the plugin named "MyArrayList" Object plugin = pluginService.getNamedPlugin(java.util.List.class, "MyArrayList"); @@ -61,7 +59,7 @@ public class PluginServiceTest extends AbstractDSpaceTest assertNull("Plugin 2 doesn't exist", plugin); // Test for one plugin that is "selfnamed" - // The DCInputAuthority plugin enabled in test local.cfg reads all in input-forms.xml + // The DCInputAuthority plugin enabled in test local.cfg reads all in submission-forms.xml // and defines a self named plugin for each. So, we SHOULD have a "common_types" plugin. plugin = pluginService.getNamedPlugin(org.dspace.content.authority.ChoiceAuthority.class, "common_types"); assertNotNull("Plugin 3 exists", plugin); @@ -74,8 +72,7 @@ public class PluginServiceTest extends AbstractDSpaceTest * Test of hasNamedPlugin() method */ @Test - public void testHasNamedPlugin() - { + public void testHasNamedPlugin() { // Assert there is a plugin named "MyLinkedList" assertTrue(pluginService.hasNamedPlugin(java.util.List.class, "MyLinkedList")); @@ -90,8 +87,7 @@ public class PluginServiceTest extends AbstractDSpaceTest * Test of getSinglePlugin() method */ @Test - public void testGetSinglePlugin() - { + public void testGetSinglePlugin() { // There should be a SINGLE Map plugin (unnamed) Object plugin = pluginService.getSinglePlugin(java.util.Map.class); assertNotNull("Plugin exists", plugin); @@ -103,8 +99,7 @@ public class PluginServiceTest extends AbstractDSpaceTest * Test of getSinglePlugin() method */ @Test - public void testGetPluginSequence() - { + public void testGetPluginSequence() { // There should be a sequence of Collection plugins Object[] plugins = pluginService.getPluginSequence(java.util.Collection.class); @@ -117,6 +112,6 @@ public class PluginServiceTest extends AbstractDSpaceTest assertTrue("Plugin 2 is Stack", plugins[2] instanceof java.util.Stack); assertTrue("Plugin 3 is TreeSet", plugins[3] instanceof java.util.TreeSet); } - + } diff --git a/dspace-api/src/test/java/org/dspace/discovery/FullTextContentStreamsTest.java b/dspace-api/src/test/java/org/dspace/discovery/FullTextContentStreamsTest.java index 601460c1f5..de0781d31d 100644 --- a/dspace-api/src/test/java/org/dspace/discovery/FullTextContentStreamsTest.java +++ b/dspace-api/src/test/java/org/dspace/discovery/FullTextContentStreamsTest.java @@ -7,6 +7,17 @@ */ package org.dspace.discovery; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + import org.apache.commons.io.Charsets; import org.apache.commons.io.IOUtils; import org.dspace.content.Bitstream; @@ -20,14 +31,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.when; - @RunWith(MockitoJUnitRunner.class) public class FullTextContentStreamsTest { @@ -69,13 +72,16 @@ public class FullTextContentStreamsTest { when(textBitstream2.getName()).thenReturn("Full Text 2"); when(textBitstream3.getName()).thenReturn("Full Text 3"); - when(textBitstream1.getSize()).thenReturn(1L); - when(textBitstream2.getSize()).thenReturn(2L); - when(textBitstream3.getSize()).thenReturn(3L); + when(textBitstream1.getSizeBytes()).thenReturn(1L); + when(textBitstream2.getSizeBytes()).thenReturn(2L); + when(textBitstream3.getSizeBytes()).thenReturn(3L); - when(bitstreamService.retrieve(null, textBitstream1)).thenReturn(new ByteArrayInputStream("This is text 1".getBytes(Charsets.UTF_8))); - when(bitstreamService.retrieve(null, textBitstream2)).thenReturn(new ByteArrayInputStream("This is text 2".getBytes(Charsets.UTF_8))); - when(bitstreamService.retrieve(null, textBitstream3)).thenReturn(new ByteArrayInputStream("This is text 3".getBytes(Charsets.UTF_8))); + when(bitstreamService.retrieve(null, textBitstream1)) + .thenReturn(new ByteArrayInputStream("This is text 1".getBytes(Charsets.UTF_8))); + when(bitstreamService.retrieve(null, textBitstream2)) + .thenReturn(new ByteArrayInputStream("This is text 2".getBytes(Charsets.UTF_8))); + when(bitstreamService.retrieve(null, textBitstream3)) + .thenReturn(new ByteArrayInputStream("This is text 3".getBytes(Charsets.UTF_8))); streams.bitstreamService = bitstreamService; } @@ -144,7 +150,7 @@ public class FullTextContentStreamsTest { InputStream inputStream = streams.getStream(); assertNotNull(inputStream); assertEquals("The data in the input stream should match the text of the bitstream", "\nThis is text 1", - IOUtils.toString(inputStream, Charsets.UTF_8)); + IOUtils.toString(inputStream, Charsets.UTF_8)); } @Test @@ -157,13 +163,13 @@ public class FullTextContentStreamsTest { assertEquals("Source info should give you the handle", HANDLE, streams.getSourceInfo()); assertEquals("Content type should be plain text", CONTENT_TYPE, streams.getContentType()); assertEquals("The name should match the concatenation of the names of the bitstreams", - "Full Text 1;Full Text 2;Full Text 3", streams.getName()); + "Full Text 1;Full Text 2;Full Text 3", streams.getName()); assertEquals("The size of the streams should be the sum of the bitstream sizes", (Long) 6L, streams.getSize()); assertFalse("Content stream should not be empty", streams.isEmpty()); InputStream inputStream = streams.getStream(); assertNotNull(inputStream); assertEquals("The data in the input stream should match 'This is text 1'", "\nThis is text 1" + - "\nThis is text 2\nThis is text 3", IOUtils.toString(inputStream, Charsets.UTF_8)); + "\nThis is text 2\nThis is text 3", IOUtils.toString(inputStream, Charsets.UTF_8)); } @Test @@ -177,22 +183,22 @@ public class FullTextContentStreamsTest { assertEquals("Source info should give you the handle", HANDLE, streams.getSourceInfo()); assertEquals("Content type should be plain text", CONTENT_TYPE, streams.getContentType()); assertEquals("The name should match the concatenation of the names of the bitstreams", - "Full Text 1;Full Text 2;Full Text 3", streams.getName()); + "Full Text 1;Full Text 2;Full Text 3", streams.getName()); assertEquals("The size of the streams should be the sum of the bitstream sizes", (Long) 6L, streams.getSize()); assertFalse("Content stream should not be empty", streams.isEmpty()); InputStream inputStream = streams.getStream(); assertNotNull(inputStream); String content = IOUtils.toString(inputStream, Charsets.UTF_8); assertTrue("The data should contain data of the first bitstream that is not corrupt", - content.contains("This is text 1")); + content.contains("This is text 1")); assertFalse("The data should NOT contain data of the second bitstream that is corrupt", - content.contains("This is text 2")); + content.contains("This is text 2")); assertTrue("The data should contain data of the third bistream that is not corrupt", - content.contains("This is text 3")); + content.contains("This is text 3")); assertTrue("The data should contain data on the exception that occurred", - content.contains("java.io.IOException")); + content.contains("java.io.IOException")); assertTrue("The data should contain data on the exception that occurred", - content.contains("NOTFOUND")); + content.contains("NOTFOUND")); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/discovery/MockIndexEventConsumer.java b/dspace-api/src/test/java/org/dspace/discovery/MockIndexEventConsumer.java index 8fe44ab274..d6830a1c80 100644 --- a/dspace-api/src/test/java/org/dspace/discovery/MockIndexEventConsumer.java +++ b/dspace-api/src/test/java/org/dspace/discovery/MockIndexEventConsumer.java @@ -19,13 +19,12 @@ import org.dspace.event.Event; * @author tdonohue */ public class MockIndexEventConsumer - extends MockUp -{ + extends MockUp { @Mock public void consume(Context ctx, Event event) throws Exception { //do nothing - Solr is not running during unit testing, so we cannot index test content in Solr } - + @Mock public void end(Context ctx) throws Exception { //do nothing - Solr is not running during unit testing, so we cannot index test content in Solr diff --git a/dspace-api/src/test/java/org/dspace/discovery/MockSolrServiceImpl.java b/dspace-api/src/test/java/org/dspace/discovery/MockSolrServiceImpl.java new file mode 100644 index 0000000000..ecbc0ed44b --- /dev/null +++ b/dspace-api/src/test/java/org/dspace/discovery/MockSolrServiceImpl.java @@ -0,0 +1,25 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.discovery; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Service; + +/** + * Mock SOLR service for the Search Core + */ +@Service +public class MockSolrServiceImpl extends SolrServiceImpl implements InitializingBean { + + @Override + public void afterPropertiesSet() throws Exception { + //We don't use SOLR in the tests of this module + solr = null; + } + +} diff --git a/dspace-api/src/test/java/org/dspace/eperson/EPersonTest.java b/dspace-api/src/test/java/org/dspace/eperson/EPersonTest.java index f3fc4471f4..5e5e9c0fcc 100644 --- a/dspace-api/src/test/java/org/dspace/eperson/EPersonTest.java +++ b/dspace-api/src/test/java/org/dspace/eperson/EPersonTest.java @@ -8,7 +8,11 @@ package org.dspace.eperson; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import java.sql.SQLException; + import org.apache.commons.codec.DecoderException; import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; @@ -16,21 +20,18 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.core.Constants; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; -import org.junit.*; -import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; /** - * * @author mwood */ -public class EPersonTest extends AbstractUnitTest -{ +public class EPersonTest extends AbstractUnitTest { protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); private static final Logger log = Logger.getLogger(EPersonTest.class); - public EPersonTest() - { + public EPersonTest() { } /** @@ -42,8 +43,7 @@ public class EPersonTest extends AbstractUnitTest */ @Before @Override - public void init() - { + public void init() { super.init(); context.turnOffAuthorisationSystem(); @@ -68,8 +68,7 @@ public class EPersonTest extends AbstractUnitTest context.turnOffAuthorisationSystem(); try { EPerson testPerson = ePersonService.findByEmail(context, "kevin@dspace.org"); - if(testPerson != null) - { + if (testPerson != null) { ePersonService.delete(context, testPerson); } } catch (Exception ex) { @@ -688,8 +687,7 @@ public class EPersonTest extends AbstractUnitTest */ @Test public void testCheckPassword() - throws SQLException, DecoderException - { + throws SQLException, DecoderException { EPerson eperson = ePersonService.findByEmail(context, "kevin@dspace.org"); ePersonService.checkPassword(context, eperson, "test"); } @@ -715,8 +713,7 @@ public class EPersonTest extends AbstractUnitTest */ @Test public void testGetType() - throws SQLException - { + throws SQLException { System.out.println("getType"); int expResult = Constants.EPERSON; int result = eperson.getType(); diff --git a/dspace-api/src/test/java/org/dspace/eperson/GroupServiceImplIT.java b/dspace-api/src/test/java/org/dspace/eperson/GroupServiceImplIT.java index 9a05bdc653..6d61483e29 100644 --- a/dspace-api/src/test/java/org/dspace/eperson/GroupServiceImplIT.java +++ b/dspace-api/src/test/java/org/dspace/eperson/GroupServiceImplIT.java @@ -7,6 +7,8 @@ */ package org.dspace.eperson; +import java.sql.SQLException; + import org.dspace.AbstractUnitTest; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.GroupService; @@ -14,18 +16,14 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.sql.SQLException; - /** * Test integration of GroupServiceImpl. * * @author mwood */ public class GroupServiceImplIT - extends AbstractUnitTest -{ - public GroupServiceImplIT() - { + extends AbstractUnitTest { + public GroupServiceImplIT() { super(); } @@ -45,15 +43,13 @@ public class GroupServiceImplIT @Before @Override - public void init() - { + public void init() { super.init(); } @After @Override - public void destroy() - { + public void destroy() { super.destroy(); } @@ -100,8 +96,7 @@ public class GroupServiceImplIT */ @Test(expected = SQLException.class) public void testSetName_permanent() - throws Exception - { + throws Exception { System.out.println("setName on a 'permanent' Group"); String name = "NOTANONYMOUS"; GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); @@ -408,8 +403,7 @@ public class GroupServiceImplIT */ @Test(expected = SQLException.class) public void testDelete_permanent() - throws Exception - { + throws Exception { System.out.println("delete on a 'permanent' Group"); GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); Group group = groupService.findByName(context, Group.ANONYMOUS); diff --git a/dspace-api/src/test/java/org/dspace/eperson/GroupTest.java b/dspace-api/src/test/java/org/dspace/eperson/GroupTest.java index 827b444043..2dbd4c1428 100644 --- a/dspace-api/src/test/java/org/dspace/eperson/GroupTest.java +++ b/dspace-api/src/test/java/org/dspace/eperson/GroupTest.java @@ -7,6 +7,20 @@ */ package org.dspace.eperson; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; @@ -17,13 +31,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.IOException; -import java.sql.SQLException; -import java.util.*; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.*; - /** * Unit tests for the Group class * @@ -43,7 +50,6 @@ public class GroupTest extends AbstractUnitTest { protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - /** * This method will be run before every test as per @Before. It will * initialize resources required for the tests. @@ -53,8 +59,7 @@ public class GroupTest extends AbstractUnitTest { */ @Before @Override - public void init() - { + public void init() { super.init(); try { //Only admins can perform group operations, so add as default user @@ -66,14 +71,13 @@ public class GroupTest extends AbstractUnitTest { level2Group = createGroup("level2Group"); groupService.addMember(context, level1Group, level2Group); - groupService.update(context, topGroup); - groupService.update(context, level1Group); - groupService.update(context, level2Group); + groupService.update(context, topGroup); + groupService.update(context, level1Group); + groupService.update(context, level2Group); context.restoreAuthSystemState(); - }catch(SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } catch (AuthorizeException ex) { @@ -84,23 +88,19 @@ public class GroupTest extends AbstractUnitTest { @After @Override - public void destroy() - { + public void destroy() { try { context.turnOffAuthorisationSystem(); - if(level2Group != null) - { - groupService.delete(context,level2Group); + if (level2Group != null) { + groupService.delete(context, level2Group); level2Group = null; } - if(level1Group != null) - { + if (level1Group != null) { groupService.delete(context, level1Group); level1Group = null; } - if(topGroup != null) - { - groupService.delete(context,topGroup); + if (topGroup != null) { + groupService.delete(context, topGroup); topGroup = null; } context.restoreAuthSystemState(); @@ -125,8 +125,7 @@ public class GroupTest extends AbstractUnitTest { group = groupService.create(context); assertThat("testCreateGroup", group, notNullValue()); } finally { - if(group != null) - { + if (group != null) { groupService.delete(context, group); } context.restoreAuthSystemState(); @@ -190,7 +189,8 @@ public class GroupTest extends AbstractUnitTest { // listNames.add(group.getID().toString()); // setNames.add(group.getID().toString()); // } -// assertTrue("findAllIdSort 2 ", ArrayUtils.isEquals(setNames.toArray(new String[setNames.size()]), listNames.toArray(new String[listNames.size()]))); +// assertTrue("findAllIdSort 2 ", ArrayUtils.isEquals(setNames.toArray(new String[setNames.size()]), listNames +// .toArray(new String[listNames.size()]))); // } @@ -206,7 +206,8 @@ public class GroupTest extends AbstractUnitTest { List names = new ArrayList<>(); List sortedNames = new ArrayList<>(); for (Group group : groups) { - // Ignore any unnamed groups. This is only necessary when running unit tests via a persistent database (e.g. Postgres) as unnamed groups may be created by other tests. + // Ignore any unnamed groups. This is only necessary when running unit tests via a persistent database (e + // .g. Postgres) as unnamed groups may be created by other tests. if (group.getName() == null) { continue; } @@ -239,8 +240,7 @@ public class GroupTest extends AbstractUnitTest { } @Test - public void searchByID() throws SQLException - { + public void searchByID() throws SQLException { List searchResult = groupService.search(context, String.valueOf(topGroup.getID()), 0, 10); assertEquals("searchID 1", searchResult.size(), 1); assertEquals("searchID 2", searchResult.iterator().next(), topGroup); @@ -254,7 +254,7 @@ public class GroupTest extends AbstractUnitTest { @Test public void addMemberEPerson() throws SQLException, AuthorizeException, EPersonDeletionException, IOException { - EPerson ePerson = null; + EPerson ePerson = null; try { ePerson = createEPersonAndAddToGroup("addMemberEPerson@dspace.org", topGroup); groupService.update(context, topGroup); @@ -262,8 +262,7 @@ public class GroupTest extends AbstractUnitTest { assertEquals("addMemberEPerson 1", topGroup.getMembers().size(), 1); assertTrue("addMemberEPerson 2", topGroup.getMembers().contains(ePerson)); } finally { - if(ePerson != null) - { + if (ePerson != null) { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson); context.restoreAuthSystemState(); @@ -286,8 +285,9 @@ public class GroupTest extends AbstractUnitTest { @Test - public void deleteGroupEPersonMembers() throws SQLException, AuthorizeException, EPersonDeletionException, IOException { - EPerson ePerson = null; + public void deleteGroupEPersonMembers() + throws SQLException, AuthorizeException, EPersonDeletionException, IOException { + EPerson ePerson = null; context.turnOffAuthorisationSystem(); try { Group toDeleteGroup = createGroup("toDelete"); @@ -297,8 +297,7 @@ public class GroupTest extends AbstractUnitTest { groupService.delete(context, toDeleteGroup); assertEquals("deleteGroupEPersonMembers", ePerson.getGroups().size(), 0); } finally { - if(ePerson != null) - { + if (ePerson != null) { ePersonService.delete(context, ePerson); } context.restoreAuthSystemState(); @@ -306,7 +305,8 @@ public class GroupTest extends AbstractUnitTest { } @Test - public void deleteGroupGroupMembers() throws SQLException, AuthorizeException, EPersonDeletionException, IOException { + public void deleteGroupGroupMembers() + throws SQLException, AuthorizeException, EPersonDeletionException, IOException { //Delete parent first Group parentGroup = createGroup("toDeleteParent"); Group childGroup = createGroup("toDeleteChild"); @@ -327,8 +327,7 @@ public class GroupTest extends AbstractUnitTest { } @Test - public void isMemberGroup() throws SQLException - { + public void isMemberGroup() throws SQLException { assertTrue("isMemberGroup 1", groupService.isMember(topGroup, level1Group)); assertTrue("isMemberGroup 2", groupService.isMember(level1Group, level2Group)); assertFalse("isMemberGroup 3", groupService.isMember(level1Group, topGroup)); @@ -356,8 +355,7 @@ public class GroupTest extends AbstractUnitTest { assertTrue(groupService.isDirectMember(level1Group, ePerson)); assertFalse(groupService.isDirectMember(topGroup, ePerson)); } finally { - if(ePerson != null) - { + if (ePerson != null) { ePersonService.delete(context, ePerson); } context.restoreAuthSystemState(); @@ -375,8 +373,7 @@ public class GroupTest extends AbstractUnitTest { assertTrue(groupService.isMember(context, ePerson, level1Group)); assertTrue(groupService.isMember(context, ePerson, level2Group)); } finally { - if(ePerson != null) - { + if (ePerson != null) { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson); } @@ -384,7 +381,8 @@ public class GroupTest extends AbstractUnitTest { } @Test - public void isMemberContextGroupId() throws SQLException, AuthorizeException, EPersonDeletionException, IOException { + public void isMemberContextGroupId() + throws SQLException, AuthorizeException, EPersonDeletionException, IOException { EPerson ePerson = null; try { ePerson = createEPersonAndAddToGroup("isMemberContextGroupId@dspace.org", level2Group); @@ -393,8 +391,7 @@ public class GroupTest extends AbstractUnitTest { assertTrue(groupService.isMember(context, ePerson, level1Group.getName())); assertTrue(groupService.isMember(context, ePerson, level2Group.getName())); } finally { - if(ePerson != null) - { + if (ePerson != null) { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson); } @@ -402,7 +399,8 @@ public class GroupTest extends AbstractUnitTest { } @Test - public void isMemberContextSpecialGroup() throws SQLException, AuthorizeException, EPersonDeletionException, IOException { + public void isMemberContextSpecialGroup() + throws SQLException, AuthorizeException, EPersonDeletionException, IOException { EPerson ePerson = null; Group specialGroup = null; try { @@ -421,13 +419,11 @@ public class GroupTest extends AbstractUnitTest { assertTrue(groupService.isMember(context, specialGroup)); } finally { - if(ePerson != null) - { + if (ePerson != null) { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson); } - if(specialGroup != null) - { + if (specialGroup != null) { context.turnOffAuthorisationSystem(); groupService.delete(context, specialGroup); } @@ -435,7 +431,8 @@ public class GroupTest extends AbstractUnitTest { } @Test - public void isMemberContextSpecialGroupOtherUser() throws SQLException, AuthorizeException, EPersonDeletionException, IOException { + public void isMemberContextSpecialGroupOtherUser() + throws SQLException, AuthorizeException, EPersonDeletionException, IOException { EPerson ePerson1 = null; EPerson ePerson2 = null; Group specialGroup = null; @@ -461,18 +458,15 @@ public class GroupTest extends AbstractUnitTest { assertTrue(groupService.isMember(context, ePerson1, specialGroup)); } finally { - if(ePerson1 != null) - { + if (ePerson1 != null) { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson1); } - if(ePerson2 != null) - { + if (ePerson2 != null) { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson2); } - if(specialGroup != null) - { + if (specialGroup != null) { context.turnOffAuthorisationSystem(); groupService.delete(context, specialGroup); } @@ -480,7 +474,8 @@ public class GroupTest extends AbstractUnitTest { } @Test - public void isMemberContextSpecialGroupDbMembership() throws SQLException, AuthorizeException, EPersonDeletionException, IOException { + public void isMemberContextSpecialGroupDbMembership() + throws SQLException, AuthorizeException, EPersonDeletionException, IOException { EPerson ePerson = null; Group specialGroup = null; try { @@ -499,13 +494,11 @@ public class GroupTest extends AbstractUnitTest { assertTrue(groupService.isMember(context, specialGroup)); } finally { - if(ePerson != null) - { + if (ePerson != null) { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson); } - if(specialGroup != null) - { + if (specialGroup != null) { context.turnOffAuthorisationSystem(); groupService.delete(context, specialGroup); } @@ -514,8 +507,7 @@ public class GroupTest extends AbstractUnitTest { @Test public void isPermanent() - throws SQLException - { + throws SQLException { Group anonymousGroup = groupService.findByName(context, Group.ANONYMOUS); assertTrue("Anonymous group should be 'permanent'", anonymousGroup.isPermanent()); assertFalse("topGroup should *not* be 'permanent'", topGroup.isPermanent()); @@ -523,15 +515,14 @@ public class GroupTest extends AbstractUnitTest { @Test public void setPermanent() - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { Group permaGroup = new Group(); permaGroup.setPermanent(true); assertTrue("setPermanent(true) should be reflected in the group's state", - permaGroup.isPermanent()); + permaGroup.isPermanent()); permaGroup.setPermanent(false); assertFalse("setPermanent(false) should be reflected in the group's state", - permaGroup.isPermanent()); + permaGroup.isPermanent()); } @Test @@ -560,8 +551,7 @@ public class GroupTest extends AbstractUnitTest { assertTrue(groupService.isMember(context, level1Group)); assertTrue(groupService.isMember(context, level2Group)); } finally { - if(ePerson != null) - { + if (ePerson != null) { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson); } @@ -584,7 +574,8 @@ public class GroupTest extends AbstractUnitTest { public void allMemberGroups() throws SQLException, AuthorizeException, EPersonDeletionException, IOException { EPerson ePerson = createEPersonAndAddToGroup("allMemberGroups@dspace.org", level1Group); try { - assertTrue(groupService.allMemberGroups(context, ePerson).containsAll(Arrays.asList(topGroup, level1Group))); + assertTrue( + groupService.allMemberGroups(context, ePerson).containsAll(Arrays.asList(topGroup, level1Group))); } finally { context.turnOffAuthorisationSystem(); ePersonService.delete(context, ePerson); @@ -631,7 +622,6 @@ public class GroupTest extends AbstractUnitTest { } - protected Group createGroup(String name) throws SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); Group group = groupService.create(context); diff --git a/dspace-api/src/test/java/org/dspace/eperson/PasswordHashTest.java b/dspace-api/src/test/java/org/dspace/eperson/PasswordHashTest.java index b6a5d9c4c8..60721044ef 100644 --- a/dspace-api/src/test/java/org/dspace/eperson/PasswordHashTest.java +++ b/dspace-api/src/test/java/org/dspace/eperson/PasswordHashTest.java @@ -7,31 +7,35 @@ */ package org.dspace.eperson; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; + import org.apache.commons.codec.DecoderException; import org.dspace.AbstractDSpaceTest; -import org.junit.*; -import static org.junit.Assert.*; +import org.dspace.core.Constants; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** - * * @author mwood */ -public class PasswordHashTest extends AbstractDSpaceTest -{ - public PasswordHashTest() - { +public class PasswordHashTest extends AbstractDSpaceTest { + public PasswordHashTest() { } @Before - public void setUp() - { + public void setUp() { } - + @After - public void tearDown() - { + public void tearDown() { } /** @@ -39,13 +43,13 @@ public class PasswordHashTest extends AbstractDSpaceTest */ @Test public void testConstructors() - throws DecoderException - { - PasswordHash h1, h3; + throws DecoderException { + PasswordHash h1; + PasswordHash h3; // Test null inputs, as from NULL database columns (old EPerson using // unsalted hash, for example). - h3 = new PasswordHash(null, (byte[])null, (byte[])null); + h3 = new PasswordHash(null, (byte[]) null, (byte[]) null); assertNull("Null algorithm", h3.getAlgorithm()); assertNull("Null salt", h3.getSalt()); assertNull("Null hash", h3.getHash()); @@ -53,7 +57,7 @@ public class PasswordHashTest extends AbstractDSpaceTest assertFalse("Match non-null string?", h3.matches("not null")); // Test 3-argument constructor with null string arguments - h3 = new PasswordHash(null, (String)null, (String)null); + h3 = new PasswordHash(null, (String) null, (String) null); assertNull("Null algorithm", h3.getAlgorithm()); assertNull("Null salt", h3.getSalt()); assertNull("Null hash", h3.getHash()); @@ -77,14 +81,13 @@ public class PasswordHashTest extends AbstractDSpaceTest */ @Test public void testMatches() - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException, UnsupportedEncodingException { System.out.println("matches"); final String secret = "Clark Kent is Superman"; // Test old 1-trip MD5 hash MessageDigest digest = MessageDigest.getInstance("MD5"); - PasswordHash hash = new PasswordHash(null, null, digest.digest(secret.getBytes())); + PasswordHash hash = new PasswordHash(null, null, digest.digest(secret.getBytes(Constants.DEFAULT_ENCODING))); boolean result = hash.matches(secret); assertTrue("Old unsalted 1-trip MD5 hash", result); diff --git a/dspace-api/src/test/java/org/dspace/handle/dao/impl/HandleDAOImplTest.java b/dspace-api/src/test/java/org/dspace/handle/dao/impl/HandleDAOImplTest.java index e1bd5e460f..8285e2552d 100644 --- a/dspace-api/src/test/java/org/dspace/handle/dao/impl/HandleDAOImplTest.java +++ b/dspace-api/src/test/java/org/dspace/handle/dao/impl/HandleDAOImplTest.java @@ -7,6 +7,12 @@ */ package org.dspace.handle.dao.impl; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.sql.SQLException; + import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; @@ -15,7 +21,12 @@ import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; +import org.dspace.content.service.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; @@ -27,18 +38,14 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.IOException; -import java.sql.SQLException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - /** * Test class for the Handle DAO */ public class HandleDAOImplTest extends AbstractUnitTest { - /** log4j category */ + /** + * log4j category + */ private static final Logger log = Logger.getLogger(HandleDAOImplTest.class); /** @@ -71,11 +78,9 @@ public class HandleDAOImplTest extends AbstractUnitTest { @Before @Override - public void init() - { + public void init() { super.init(); - try - { + try { //we have to create a new community in the database context.turnOffAuthorisationSystem(); this.owningCommunity = communityService.create(null, context); @@ -100,14 +105,10 @@ public class HandleDAOImplTest extends AbstractUnitTest { //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } catch (IOException ex) { @@ -118,12 +119,12 @@ public class HandleDAOImplTest extends AbstractUnitTest { @After @Override - public void destroy() - { + public void destroy() { try { context.turnOffAuthorisationSystem(); - //Context might have been committed in the test method, so best to reload to entity so we're sure that it is attached. + //Context might have been committed in the test method, so best to reload to entity so we're sure that it + // is attached. owningCommunity = context.reloadEntity(owningCommunity); ContentServiceFactory.getInstance().getCommunityService().delete(context, owningCommunity); owningCommunity = null; @@ -159,4 +160,4 @@ public class HandleDAOImplTest extends AbstractUnitTest { context.restoreAuthSystemState(); } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/identifier/DOIIdentifierProviderTest.java b/dspace-api/src/test/java/org/dspace/identifier/DOIIdentifierProviderTest.java index 0837db32c0..51b0556401 100644 --- a/dspace-api/src/test/java/org/dspace/identifier/DOIIdentifierProviderTest.java +++ b/dspace-api/src/test/java/org/dspace/identifier/DOIIdentifierProviderTest.java @@ -7,16 +7,30 @@ */ package org.dspace.identifier; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeNotNull; + import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; + +import org.apache.commons.lang.ObjectUtils; import org.apache.log4j.Logger; import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.WorkspaceItem; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; @@ -29,22 +43,23 @@ import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.workflow.WorkflowException; import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.factory.WorkflowServiceFactory; -import org.junit.*; -import static org.junit.Assert.*; -import static org.junit.Assume.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** -* Tests for {@link DataCiteIdentifierProvider}. -* -* @author Mark H. Wood -* @author Pascal-Nicolas Becker -*/ + * Tests for {@link DataCiteIdentifierProvider}. + * + * @author Mark H. Wood + * @author Pascal-Nicolas Becker + */ public class DOIIdentifierProviderTest - extends AbstractUnitTest -{ - /** log4j category */ + extends AbstractUnitTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(DOIIdentifierProviderTest.class); - + private static final String PREFIX = "10.5072"; private static final String NAMESPACE_SEPARATOR = "dspaceUnitTests-"; @@ -63,8 +78,7 @@ public class DOIIdentifierProviderTest private static MockDOIConnector connector; private DOIIdentifierProvider provider; - public DOIIdentifierProviderTest() - { + public DOIIdentifierProviderTest() { } /** @@ -76,12 +90,10 @@ public class DOIIdentifierProviderTest */ @Before @Override - public void init() - { + public void init() { super.init(); - - try - { + + try { context.turnOffAuthorisationSystem(); // Create an environment for our test objects to live in. community = communityService.create(null, context); @@ -96,29 +108,27 @@ public class DOIIdentifierProviderTest config = DSpaceServicesFactory.getInstance().getConfigurationService(); // Configure the service under test. config.setProperty(DOIIdentifierProvider.CFG_PREFIX, PREFIX); - config.setProperty(DOIIdentifierProvider.CFG_NAMESPACE_SEPARATOR, - NAMESPACE_SEPARATOR); - + config.setProperty(DOIIdentifierProvider.CFG_NAMESPACE_SEPARATOR, + NAMESPACE_SEPARATOR); + connector = new MockDOIConnector(); - - provider = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(DOIIdentifierProvider.class.getName(), DOIIdentifierProvider.class); + + provider = DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(DOIIdentifierProvider.class.getName(), + DOIIdentifierProvider.class); provider.setConfigurationService(config); provider.setDOIConnector(connector); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); } - + } - - /** + + /** * This method will be run after every test as per @After. It will * clean resources initialized by the @Before methods. * @@ -127,8 +137,7 @@ public class DOIIdentifierProviderTest */ @After @Override - public void destroy() - { + public void destroy() { community = null; collection = null; connector.reset(); @@ -138,15 +147,15 @@ public class DOIIdentifierProviderTest } /** - * Create a fresh Item, installed in the repository. - * - * @throws SQLException if database error - * @throws AuthorizeException if authorization error - * @throws IOException if IO error - */ + * Create a fresh Item, installed in the repository. + * + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + * @throws IOException if IO error + */ private Item newItem() - throws SQLException, AuthorizeException, IOException, IllegalAccessException, IdentifierException, WorkflowException - { + throws SQLException, AuthorizeException, IOException, IllegalAccessException, IdentifierException, + WorkflowException { context.turnOffAuthorisationSystem(); WorkspaceItem wsItem = workspaceItemService.create(context, collection, false); @@ -163,273 +172,254 @@ public class DOIIdentifierProviderTest // gets automatically a DOI. We remove this DOI as it can make problems // with the tests. provider.delete(context, item); - + List metadata = itemService.getMetadata(item, - DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null); + DOIIdentifierProvider.MD_SCHEMA, + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null); List remainder = new ArrayList(); for (MetadataValue id : metadata) { - if (!id.getValue().startsWith(DOI.RESOLVER)) - { + if (!id.getValue().startsWith(DOI.RESOLVER)) { remainder.add(id.getValue()); } } itemService.clearMetadata(context, item, - DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null); + DOIIdentifierProvider.MD_SCHEMA, + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null); itemService.addMetadata(context, item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null, - remainder); - + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null, + remainder); + itemService.update(context, item); //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); return item; } - + public String createDOI(Item item, Integer status, boolean metadata) - throws SQLException, IdentifierException, AuthorizeException - { + throws SQLException, IdentifierException, AuthorizeException { return this.createDOI(item, status, metadata, null); } - + /** * Create a DOI to an item. - * @param item Item the DOI should be created for. - * @param status The status of the DOI. + * + * @param item Item the DOI should be created for. + * @param status The status of the DOI. * @param metadata Whether the DOI should be included in the metadata of the item. - * @param doi The doi or null if we should generate one. + * @param doi The doi or null if we should generate one. * @return the DOI * @throws SQLException if database error */ public String createDOI(Item item, Integer status, boolean metadata, String doi) - throws SQLException, IdentifierException, AuthorizeException - { + throws SQLException, IdentifierException, AuthorizeException { context.turnOffAuthorisationSystem(); // we need some random data. UUIDs would be bloated here Random random = new Random(); - if (null == doi) - { - doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR - + Long.toHexString(new Date().getTime()) + "-" - + random.nextInt(997); + if (null == doi) { + doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR + + Long.toHexString(new Date().getTime()) + "-" + + random.nextInt(997); } - + DOI doiRow = doiService.create(context); doiRow.setDoi(doi.substring(DOI.SCHEME.length())); doiRow.setDSpaceObject(item); doiRow.setStatus(status); doiService.update(context, doiRow); - - if (metadata) - { + + if (metadata) { itemService.addMetadata(context, item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null, - doiService.DOIToExternalForm(doi)); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null, + doiService.DOIToExternalForm(doi)); itemService.update(context, item); } - + //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); return doi; } - + /** * Test of supports method, of class DataCiteIdentifierProvider. */ @Test - public void testSupports_Class() - { + public void testSupports_Class() { Class identifier = DOI.class; assertTrue("DOI should be supported", provider.supports(identifier)); } - + @Test - public void testSupports_valid_String() - { + public void testSupports_valid_String() { String[] validDOIs = new String[] - { - "10.5072/123abc-lkj/kljl", - PREFIX + "/" + NAMESPACE_SEPARATOR + "lkjljasd1234", - DOI.SCHEME + "10.5072/123abc-lkj/kljl", - "http://dx.doi.org/10.5072/123abc-lkj/kljl", - DOI.RESOLVER + "/10.5072/123abc-lkj/kljl" - }; - - for (String doi : validDOIs) - { + { + "10.5072/123abc-lkj/kljl", + PREFIX + "/" + NAMESPACE_SEPARATOR + "lkjljasd1234", + DOI.SCHEME + "10.5072/123abc-lkj/kljl", + "http://dx.doi.org/10.5072/123abc-lkj/kljl", + DOI.RESOLVER + "/10.5072/123abc-lkj/kljl" + }; + + for (String doi : validDOIs) { assertTrue("DOI should be supported", provider.supports(doi)); } } - + @Test - public void testDoes_not_support_invalid_String() - { + public void testDoes_not_support_invalid_String() { String[] invalidDOIs = new String[] - { - "11.5072/123abc-lkj/kljl", - "http://hdl.handle.net/handle/10.5072/123abc-lkj/kljl", - "", - null - }; - - for (String notADoi : invalidDOIs) - { + { + "11.5072/123abc-lkj/kljl", + "http://hdl.handle.net/handle/10.5072/123abc-lkj/kljl", + "", + null + }; + + for (String notADoi : invalidDOIs) { assertFalse("Invalid DOIs shouldn't be supported", - provider.supports(notADoi)); + provider.supports(notADoi)); } } - + @Test public void testStore_DOI_as_item_metadata() - throws SQLException, AuthorizeException, IOException, IdentifierException, IllegalAccessException, WorkflowException - { + throws SQLException, AuthorizeException, IOException, IdentifierException, IllegalAccessException, + WorkflowException { Item item = newItem(); - String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR - + Long.toHexString(new Date().getTime()); + String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR + + Long.toHexString(new Date().getTime()); context.turnOffAuthorisationSystem(); provider.saveDOIToObject(context, item, doi); context.restoreAuthSystemState(); - + List metadata = itemService.getMetadata(item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null); boolean result = false; - for (MetadataValue id : metadata) - { - if (id.getValue().equals(doiService.DOIToExternalForm(doi))) - { + for (MetadataValue id : metadata) { + if (id.getValue().equals(doiService.DOIToExternalForm(doi))) { result = true; } } assertTrue("Cannot store DOI as item metadata value.", result); } - + @Test public void testGet_DOI_out_of_item_metadata() - throws SQLException, AuthorizeException, IOException, IdentifierException, IllegalAccessException, WorkflowException - { + throws SQLException, AuthorizeException, IOException, IdentifierException, IllegalAccessException, + WorkflowException { Item item = newItem(); - String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR - + Long.toHexString(new Date().getTime()); + String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR + + Long.toHexString(new Date().getTime()); context.turnOffAuthorisationSystem(); itemService.addMetadata(context, item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null, - doiService.DOIToExternalForm(doi)); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null, + doiService.DOIToExternalForm(doi)); itemService.update(context, item); context.restoreAuthSystemState(); - assertTrue("Failed to recognize DOI in item metadata.", - doi.equals(provider.getDOIOutOfObject(item))); + assertTrue("Failed to recognize DOI in item metadata.", + doi.equals(provider.getDOIOutOfObject(item))); } @Test public void testRemove_DOI_from_item_metadata() - throws SQLException, AuthorizeException, IOException, IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, AuthorizeException, IOException, IdentifierException, WorkflowException, + IllegalAccessException { Item item = newItem(); - String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR - + Long.toHexString(new Date().getTime()); + String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR + + Long.toHexString(new Date().getTime()); context.turnOffAuthorisationSystem(); itemService.addMetadata(context, item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null, - doiService.DOIToExternalForm(doi)); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null, + doiService.DOIToExternalForm(doi)); itemService.update(context, item); - + provider.removeDOIFromObject(context, item, doi); context.restoreAuthSystemState(); - + List metadata = itemService.getMetadata(item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null); boolean foundDOI = false; - for (MetadataValue id : metadata) - { - if (id.getValue().equals(doiService.DOIToExternalForm(doi))) - { + for (MetadataValue id : metadata) { + if (id.getValue().equals(doiService.DOIToExternalForm(doi))) { foundDOI = true; } } assertFalse("Cannot remove DOI from item metadata.", foundDOI); } - + @Test public void testGet_DOI_by_DSpaceObject() - throws SQLException, AuthorizeException, IOException, - IllegalArgumentException, IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, AuthorizeException, IOException, + IllegalArgumentException, IdentifierException, WorkflowException, IllegalAccessException { Item item = newItem(); String doi = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, false); - + String retrievedDOI = provider.getDOIByObject(context, item); - + assertNotNull("Failed to load DOI by DSpaceObject.", retrievedDOI); assertTrue("Loaded wrong DOI by DSpaceObject.", doi.equals(retrievedDOI)); } - + @Test public void testGet_DOI_lookup() - throws SQLException, AuthorizeException, IOException, - IllegalArgumentException, IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, AuthorizeException, IOException, + IllegalArgumentException, IdentifierException, WorkflowException, IllegalAccessException { Item item = newItem(); String doi = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, false); - + String retrievedDOI = provider.lookup(context, (DSpaceObject) item); - + assertNotNull("Failed to loookup doi.", retrievedDOI); assertTrue("Loaded wrong DOI on lookup.", doi.equals(retrievedDOI)); } - + @Test public void testGet_DSpaceObject_by_DOI() - throws SQLException, AuthorizeException, IOException, - IllegalArgumentException, IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, AuthorizeException, IOException, + IllegalArgumentException, IdentifierException, WorkflowException, IllegalAccessException { Item item = newItem(); String doi = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, false); - + DSpaceObject dso = provider.getObjectByDOI(context, doi); - + assertNotNull("Failed to load DSpaceObject by DOI.", dso); - if (item.getType() != dso.getType() || item.getID() != dso.getID()) - { + if (item.getType() != dso.getType() || ObjectUtils.notEqual(item.getID(), dso.getID())) { fail("Object loaded by DOI was another object then expected!"); } } @Test public void testResolve_DOI() - throws SQLException, AuthorizeException, IOException, - IllegalArgumentException, IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, AuthorizeException, IOException, + IllegalArgumentException, IdentifierException, WorkflowException, IllegalAccessException { Item item = newItem(); String doi = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, false); - + DSpaceObject dso = provider.resolve(context, doi); - + assertNotNull("Failed to resolve DOI.", dso); - if (item.getType() != dso.getType() || item.getID() != dso.getID()) - { + if (item.getType() != dso.getType() || ObjectUtils.notEqual(item.getID(), dso.getID())) { fail("Object return by DOI lookup was another object then expected!"); } } @@ -440,13 +430,13 @@ public class DOIIdentifierProviderTest */ @Test public void testRemove_two_DOIs_from_item_metadata() - throws SQLException, AuthorizeException, IOException, IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, AuthorizeException, IOException, IdentifierException, WorkflowException, + IllegalAccessException { // add two DOIs. Item item = newItem(); String doi1 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true); String doi2 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true); - + // remove one of it context.turnOffAuthorisationSystem(); provider.removeDOIFromObject(context, item, doi1); @@ -454,46 +444,40 @@ public class DOIIdentifierProviderTest // assure that the right one was removed List metadata = itemService.getMetadata(item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null); boolean foundDOI1 = false; boolean foundDOI2 = false; - for (MetadataValue id : metadata) - { - if (id.getValue().equals(doiService.DOIToExternalForm(doi1))) - { + for (MetadataValue id : metadata) { + if (id.getValue().equals(doiService.DOIToExternalForm(doi1))) { foundDOI1 = true; } - if (id.getValue().equals(doiService.DOIToExternalForm(doi2))) - { + if (id.getValue().equals(doiService.DOIToExternalForm(doi2))) { foundDOI2 = true; } } assertFalse("Cannot remove DOI from item metadata.", foundDOI1); assertTrue("Removed wrong DOI from item metadata.", foundDOI2); - + // remove the otherone as well. context.turnOffAuthorisationSystem(); provider.removeDOIFromObject(context, item, doi2); context.restoreAuthSystemState(); - + // check it metadata = itemService.getMetadata(item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null); foundDOI1 = false; foundDOI2 = false; - for (MetadataValue id : metadata) - { - if (id.getValue().equals(doiService.DOIToExternalForm(doi1))) - { + for (MetadataValue id : metadata) { + if (id.getValue().equals(doiService.DOIToExternalForm(doi1))) { foundDOI1 = true; } - if (id.getValue().equals(doiService.DOIToExternalForm(doi2))) - { + if (id.getValue().equals(doiService.DOIToExternalForm(doi2))) { foundDOI2 = true; } @@ -501,44 +485,39 @@ public class DOIIdentifierProviderTest assertFalse("Cannot remove DOI from item metadata.", foundDOI1); assertFalse("Cannot remove DOI from item metadata.", foundDOI2); } - + @Test - public void testMintDOI() throws SQLException, AuthorizeException, IOException, IllegalAccessException, IdentifierException, WorkflowException - { + public void testMintDOI() + throws SQLException, AuthorizeException, IOException, IllegalAccessException, IdentifierException, + WorkflowException { Item item = newItem(); String doi = null; - try - { + try { // get a DOI: doi = provider.mint(context, item); - } - catch(IdentifierException e) - { + } catch (IdentifierException e) { e.printStackTrace(); fail("Got an IdentifierException: " + e.getMessage()); } - + assertNotNull("Minted DOI is null!", doi); assertFalse("Minted DOI is empty!", doi.isEmpty()); - - try - { + + try { doiService.formatIdentifier(doi); - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); fail("Minted an unrecognizable DOI: " + e.getMessage()); } } - + @Test public void testMint_returns_existing_DOI() - throws SQLException, AuthorizeException, IOException, IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, AuthorizeException, IOException, IdentifierException, WorkflowException, + IllegalAccessException { Item item = newItem(); String doi = this.createDOI(item, null, true); - + String retrievedDOI = provider.mint(context, item); assertNotNull("Minted DOI is null?!", retrievedDOI); @@ -547,84 +526,80 @@ public class DOIIdentifierProviderTest @Test public void testReserve_DOI() - throws SQLException, SQLException, AuthorizeException, IOException, - IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, SQLException, AuthorizeException, IOException, + IdentifierException, WorkflowException, IllegalAccessException { Item item = newItem(); String doi = this.createDOI(item, null, true); - + provider.reserve(context, item, doi); - + DOI doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length())); assumeNotNull(doiRow); - + assertTrue("Reservation of DOI did not set the corret DOI status.", - DOIIdentifierProvider.TO_BE_RESERVED.equals(doiRow.getStatus())); + DOIIdentifierProvider.TO_BE_RESERVED.equals(doiRow.getStatus())); } - + @Test public void testRegister_unreserved_DOI() - throws SQLException, SQLException, AuthorizeException, IOException, - IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, SQLException, AuthorizeException, IOException, + IdentifierException, WorkflowException, IllegalAccessException { Item item = newItem(); String doi = this.createDOI(item, null, true); - + provider.register(context, item, doi); - + DOI doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length())); assumeNotNull(doiRow); - + assertTrue("Registration of DOI did not set the corret DOI status.", - DOIIdentifierProvider.TO_BE_REGISTERED.equals(doiRow.getStatus())); + DOIIdentifierProvider.TO_BE_REGISTERED.equals(doiRow.getStatus())); } @Test public void testRegister_reserved_DOI() - throws SQLException, SQLException, AuthorizeException, IOException, - IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, SQLException, AuthorizeException, IOException, + IdentifierException, WorkflowException, IllegalAccessException { Item item = newItem(); String doi = this.createDOI(item, DOIIdentifierProvider.IS_RESERVED, true); - + provider.register(context, item, doi); - + DOI doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length())); assumeNotNull(doiRow); - + assertTrue("Registration of DOI did not set the corret DOI status.", - DOIIdentifierProvider.TO_BE_REGISTERED.equals(doiRow.getStatus())); + DOIIdentifierProvider.TO_BE_REGISTERED.equals(doiRow.getStatus())); } - + @Test public void testCreate_and_Register_DOI() - throws SQLException, SQLException, AuthorizeException, IOException, - IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, SQLException, AuthorizeException, IOException, + IdentifierException, WorkflowException, IllegalAccessException { Item item = newItem(); - + String doi = provider.register(context, item); - + // we want the created DOI to be returned in the following format: // doi:10./. String formated_doi = doiService.formatIdentifier(doi); assertTrue("DOI was not in the expected format!", doi.equals(formated_doi)); - + DOI doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length())); assertNotNull("Created DOI was not stored in database.", doiRow); - + assertTrue("Registration of DOI did not set the corret DOI status.", - DOIIdentifierProvider.TO_BE_REGISTERED.equals(doiRow.getStatus())); + DOIIdentifierProvider.TO_BE_REGISTERED.equals(doiRow.getStatus())); } - + @Test public void testDelete_specified_DOI() - throws SQLException, AuthorizeException, IOException, IdentifierException, WorkflowException, IllegalAccessException - { + throws SQLException, AuthorizeException, IOException, IdentifierException, WorkflowException, + IllegalAccessException { Item item = newItem(); String doi1 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true); String doi2 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true); - + // remove one of it context.turnOffAuthorisationSystem(); provider.delete(context, item, doi1); @@ -632,43 +607,41 @@ public class DOIIdentifierProviderTest // assure that the right one was removed List metadata = itemService.getMetadata(item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null); boolean foundDOI1 = false; boolean foundDOI2 = false; - for (MetadataValue id : metadata) - { - if (id.getValue().equals(doiService.DOIToExternalForm(doi1))) - { + for (MetadataValue id : metadata) { + if (id.getValue().equals(doiService.DOIToExternalForm(doi1))) { foundDOI1 = true; } - if (id.getValue().equals(doiService.DOIToExternalForm(doi2))) - { + if (id.getValue().equals(doiService.DOIToExternalForm(doi2))) { foundDOI2 = true; } } assertFalse("Cannot remove DOI from item metadata.", foundDOI1); assertTrue("Removed wrong DOI from item metadata.", foundDOI2); - + DOI doiRow1 = doiService.findByDoi(context, doi1.substring(DOI.SCHEME.length())); assumeNotNull(doiRow1); assertTrue("Status of deleted DOI was not set correctly.", - DOIIdentifierProvider.TO_BE_DELETED.equals(doiRow1.getStatus())); + DOIIdentifierProvider.TO_BE_DELETED.equals(doiRow1.getStatus())); DOI doiRow2 = doiService.findByDoi(context, doi2.substring(DOI.SCHEME.length())); assumeNotNull(doiRow2); assertTrue("While deleting a DOI the status of another changed.", - DOIIdentifierProvider.IS_REGISTERED.equals(doiRow2.getStatus())); + DOIIdentifierProvider.IS_REGISTERED.equals(doiRow2.getStatus())); } - + @Test public void testDelete_all_DOIs() - throws SQLException, AuthorizeException, IOException, IdentifierException, IllegalAccessException, WorkflowException { + throws SQLException, AuthorizeException, IOException, IdentifierException, IllegalAccessException, + WorkflowException { Item item = newItem(); String doi1 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true); String doi2 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true); - + // remove one of it context.turnOffAuthorisationSystem(); provider.delete(context, item); @@ -676,40 +649,37 @@ public class DOIIdentifierProviderTest // assure that the right one was removed List metadata = itemService.getMetadata(item, DOIIdentifierProvider.MD_SCHEMA, - DOIIdentifierProvider.DOI_ELEMENT, - DOIIdentifierProvider.DOI_QUALIFIER, - null); + DOIIdentifierProvider.DOI_ELEMENT, + DOIIdentifierProvider.DOI_QUALIFIER, + null); boolean foundDOI1 = false; boolean foundDOI2 = false; - for (MetadataValue id : metadata) - { - if (id.getValue().equals(doiService.DOIToExternalForm(doi1))) - { + for (MetadataValue id : metadata) { + if (id.getValue().equals(doiService.DOIToExternalForm(doi1))) { foundDOI1 = true; } - if (id.getValue().equals(doiService.DOIToExternalForm(doi2))) - { + if (id.getValue().equals(doiService.DOIToExternalForm(doi2))) { foundDOI2 = true; } } assertFalse("Cannot remove DOI from item metadata.", foundDOI1); assertFalse("Did not removed all DOIs from item metadata.", foundDOI2); - + DOI doiRow1 = doiService.findByDoi(context, doi1.substring(DOI.SCHEME.length())); assumeNotNull(doiRow1); assertTrue("Status of deleted DOI was not set correctly.", - DOIIdentifierProvider.TO_BE_DELETED.equals(doiRow1.getStatus())); + DOIIdentifierProvider.TO_BE_DELETED.equals(doiRow1.getStatus())); DOI doiRow2 = doiService.findByDoi(context, doi1.substring(DOI.SCHEME.length())); assumeNotNull(doiRow2); assertTrue("Did not set the status of all deleted DOIs as expected.", - DOIIdentifierProvider.TO_BE_DELETED.equals(doiRow2.getStatus())); + DOIIdentifierProvider.TO_BE_DELETED.equals(doiRow2.getStatus())); } - + // test the following methods using the MockDOIConnector. // updateMetadataOnline // registerOnline // reserveOnline - -} \ No newline at end of file + +} diff --git a/dspace-api/src/test/java/org/dspace/identifier/EZIDIdentifierProviderTest.java b/dspace-api/src/test/java/org/dspace/identifier/EZIDIdentifierProviderTest.java index 72e0e03ffc..496620e941 100644 --- a/dspace-api/src/test/java/org/dspace/identifier/EZIDIdentifierProviderTest.java +++ b/dspace-api/src/test/java/org/dspace/identifier/EZIDIdentifierProviderTest.java @@ -8,24 +8,32 @@ package org.dspace.identifier; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.sql.SQLException; -import java.util.List; - import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; + import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.WorkspaceItem; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; import org.dspace.content.service.WorkspaceItemService; -import org.dspace.core.Context; import org.dspace.identifier.ezid.DateToYear; import org.dspace.identifier.ezid.Transform; import org.dspace.services.ConfigurationService; @@ -33,30 +41,39 @@ import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.workflow.WorkflowException; import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.factory.WorkflowServiceFactory; -import org.junit.*; - -import static org.junit.Assert.*; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; /** - * * @author mwood */ public class EZIDIdentifierProviderTest - extends AbstractUnitTest -{ - /** Name of the reserved EZID test authority. */ + extends AbstractUnitTest { + /** + * Name of the reserved EZID test authority. + */ private static final String TEST_SHOULDER = "10.5072/FK2"; - /** A sensible metadata crosswalk. */ + /** + * A sensible metadata crosswalk. + */ private static final Map aCrosswalk = new HashMap<>(); + static { aCrosswalk.put("datacite.creator", "dc.contributor.author"); aCrosswalk.put("datacite.title", "dc.title"); aCrosswalk.put("datacite.publisher", "dc.publisher"); aCrosswalk.put("datacite.publicationyear", "dc.date.issued"); } - /** A sensible set of metadata transforms. */ + + /** + * A sensible set of metadata transforms. + */ private static final Map crosswalkTransforms = new HashMap(); + static { crosswalkTransforms.put("datacite.publicationyear", new DateToYear()); } @@ -73,36 +90,36 @@ public class EZIDIdentifierProviderTest protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); - /** The most recently created test Item's ID */ + /** + * The most recently created test Item's ID + */ private static Item item; - public EZIDIdentifierProviderTest() - { + public EZIDIdentifierProviderTest() { } - private void dumpMetadata(Item eyetem) - { + private void dumpMetadata(Item eyetem) { List metadata = itemService.getMetadata(eyetem, "dc", Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue metadatum : metadata) + for (MetadataValue metadatum : metadata) { System.out.printf("Metadata: %s.%s.%s(%s) = %s\n", - metadatum.getMetadataField().getMetadataSchema().getName(), - metadatum.getMetadataField().getElement(), - metadatum.getMetadataField().getQualifier(), - metadatum.getLanguage(), - metadatum.getValue()); + metadatum.getMetadataField().getMetadataSchema().getName(), + metadatum.getMetadataField().getElement(), + metadatum.getMetadataField().getQualifier(), + metadatum.getLanguage(), + metadatum.getValue()); + } } /** * Create a fresh Item, installed in the repository. * - * @throws SQLException if database error + * @throws SQLException if database error * @throws AuthorizeException if authorization error - * @throws IOException if IO error + * @throws IOException if IO error */ private Item newItem() - throws SQLException, AuthorizeException, IOException, WorkflowException - { - //Install a fresh item + throws SQLException, AuthorizeException, IOException, WorkflowException { + //Install a fresh item context.turnOffAuthorisationSystem(); WorkspaceItem wsItem = workspaceItemService.create(context, collection, false); @@ -125,8 +142,7 @@ public class EZIDIdentifierProviderTest @BeforeClass public static void setUpClass() - throws Exception - { + throws Exception { // Find the configuration service config = DSpaceServicesFactory.getInstance().getConfigurationService(); @@ -142,22 +158,24 @@ public class EZIDIdentifierProviderTest instance.setCrosswalk(aCrosswalk); instance.setCrosswalkTransform(crosswalkTransforms); instance.setItemService(ContentServiceFactory.getInstance().getItemService()); - DSpaceServicesFactory.getInstance().getServiceManager().registerServiceNoAutowire(EZIDIdentifierProvider.class.getName(), instance); - assertNotNull(DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(EZIDIdentifierProvider.class.getName(), EZIDIdentifierProvider.class)); + DSpaceServicesFactory.getInstance().getServiceManager() + .registerServiceNoAutowire(EZIDIdentifierProvider.class.getName(), instance); + assertNotNull(DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(EZIDIdentifierProvider.class.getName(), + EZIDIdentifierProvider.class)); } @AfterClass public static void tearDownClass() - throws Exception - { - DSpaceServicesFactory.getInstance().getServiceManager().unregisterService(EZIDIdentifierProvider.class.getName()); + throws Exception { + DSpaceServicesFactory.getInstance().getServiceManager() + .unregisterService(EZIDIdentifierProvider.class.getName()); System.out.print("Tearing down\n\n"); } @Before public void setUp() - throws Exception - { + throws Exception { context.turnOffAuthorisationSystem(); // Create an environment for our test objects to live in. @@ -172,8 +190,7 @@ public class EZIDIdentifierProviderTest @After public void tearDown() - throws SQLException - { + throws SQLException { context.restoreAuthSystemState(); dumpMetadata(item); @@ -183,11 +200,12 @@ public class EZIDIdentifierProviderTest * Test of supports method, of class DataCiteIdentifierProvider. */ @Test - public void testSupports_Class() - { + public void testSupports_Class() { System.out.println("supports Class"); - EZIDIdentifierProvider instance = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(EZIDIdentifierProvider.class.getName(), EZIDIdentifierProvider.class); + EZIDIdentifierProvider instance = DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(EZIDIdentifierProvider.class.getName(), + EZIDIdentifierProvider.class); Class identifier = DOI.class; boolean result = instance.supports(identifier); @@ -198,11 +216,12 @@ public class EZIDIdentifierProviderTest * Test of supports method, of class DataCiteIdentifierProvider. */ @Test - public void testSupports_String() - { + public void testSupports_String() { System.out.println("supports String"); - EZIDIdentifierProvider instance = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(EZIDIdentifierProvider.class.getName(), EZIDIdentifierProvider.class); + EZIDIdentifierProvider instance = DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(EZIDIdentifierProvider.class.getName(), + EZIDIdentifierProvider.class); String identifier = "doi:" + TEST_SHOULDER; boolean result = instance.supports(identifier); @@ -404,44 +423,44 @@ public class EZIDIdentifierProviderTest /** * Test of crosswalkMetadata method, of class EZIDIdentifierProvider. + * * @throws Exception if error */ @Test public void testCrosswalkMetadata() - throws Exception - { + throws Exception { try { - System.out.println("crosswalkMetadata"); + System.out.println("crosswalkMetadata"); - // Set up the instance to be tested - EZIDIdentifierProvider instance = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(EZIDIdentifierProvider.class.getName(), EZIDIdentifierProvider.class); + // Set up the instance to be tested + EZIDIdentifierProvider instance = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName( + EZIDIdentifierProvider.class.getName(), EZIDIdentifierProvider.class); // instance.setConfigurationService(config); // instance.setCrosswalk(aCrosswalk); // instance.setCrosswalkTransform(crosswalkTransforms); - // Let's have a fresh Item to work with - DSpaceObject dso = newItem(); - String handle = dso.getHandle(); + // Let's have a fresh Item to work with + DSpaceObject dso = newItem(); + String handle = dso.getHandle(); - // Test! - Map metadata = instance.crosswalkMetadata(context, dso); + // Test! + Map metadata = instance.crosswalkMetadata(context, dso); - // Evaluate - String target = (String) metadata.get("_target"); - assertEquals("Generates correct _target metadatum", - config.getProperty("dspace.url") + "/handle/" + handle, - target); - assertTrue("Has title", metadata.containsKey("datacite.title")); - assertTrue("Has publication year", metadata.containsKey("datacite.publicationyear")); - assertTrue("Has publisher", metadata.containsKey("datacite.publisher")); - assertTrue("Has creator", metadata.containsKey("datacite.creator")); + // Evaluate + String target = (String) metadata.get("_target"); + assertEquals("Generates correct _target metadatum", + config.getProperty("dspace.url") + "/handle/" + handle, + target); + assertTrue("Has title", metadata.containsKey("datacite.title")); + assertTrue("Has publication year", metadata.containsKey("datacite.publicationyear")); + assertTrue("Has publisher", metadata.containsKey("datacite.publisher")); + assertTrue("Has creator", metadata.containsKey("datacite.creator")); - // Dump out the generated metadata for inspection - System.out.println("Results:"); - for (Entry metadatum : metadata.entrySet()) - { - System.out.printf(" %s : %s\n", metadatum.getKey(), metadatum.getValue()); - } + // Dump out the generated metadata for inspection + System.out.println("Results:"); + for (Entry metadatum : metadata.entrySet()) { + System.out.printf(" %s : %s\n", metadatum.getKey(), metadatum.getValue()); + } } catch (NullPointerException ex) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); diff --git a/dspace-api/src/test/java/org/dspace/identifier/HandleIdentifierProviderTest.java b/dspace-api/src/test/java/org/dspace/identifier/HandleIdentifierProviderTest.java index 550c0f5c34..ac75379ddd 100644 --- a/dspace-api/src/test/java/org/dspace/identifier/HandleIdentifierProviderTest.java +++ b/dspace-api/src/test/java/org/dspace/identifier/HandleIdentifierProviderTest.java @@ -7,9 +7,12 @@ */ package org.dspace.identifier; +import static org.junit.Assert.assertEquals; + import java.io.IOException; import java.util.Map; import java.util.Properties; + import org.dspace.AbstractDSpaceTest; import org.dspace.kernel.ServiceManager; import org.dspace.services.factory.DSpaceServicesFactory; @@ -23,8 +26,6 @@ import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import static org.junit.Assert.*; - /** * Test the HandleIdentifierProvider. *

    @@ -37,31 +38,32 @@ import static org.junit.Assert.*; * @author mwood */ public class HandleIdentifierProviderTest - extends AbstractDSpaceTest -{ - /** A name for our testing bean definition. */ + extends AbstractDSpaceTest { + /** + * A name for our testing bean definition. + */ private static final String BEAN_NAME = "test-HandleIdentifierProvider"; - /** Spring application context. */ + /** + * Spring application context. + */ private static AnnotationConfigApplicationContext applicationContext; - public HandleIdentifierProviderTest() - { + public HandleIdentifierProviderTest() { } /** * The special test bean for the target class is defined here. */ @BeforeClass - public static void setUpClass() - { + public static void setUpClass() { ServiceManager serviceManager = kernelImpl.getServiceManager(); // Get the normal ApplicationContext ApplicationContext parentApplicationContext - = (ApplicationContext) serviceManager.getServiceByName( - ApplicationContext.class.getName(), - ApplicationContext.class); + = (ApplicationContext) serviceManager.getServiceByName( + ApplicationContext.class.getName(), + ApplicationContext.class); // Wrap it in a new empty context that we can configure. applicationContext = new AnnotationConfigApplicationContext(); @@ -81,20 +83,17 @@ public class HandleIdentifierProviderTest * Clean up special test Spring stuff. */ @AfterClass - public static void tearDownClass() - { + public static void tearDownClass() { // Clean up testing ApplicationContext and any beans within. applicationContext.close(); } @Before - public void setUp() - { + public void setUp() { } @After - public void tearDown() - { + public void tearDown() { } /** @@ -123,18 +122,18 @@ public class HandleIdentifierProviderTest * The list is a .properties on the class path. */ @Test - public void testSupports_String() - { + public void testSupports_String() { System.out.println("supports(String)"); DSpaceServicesFactory.getInstance().getConfigurationService().setProperty("handle.prefix", "123456789"); - DSpaceServicesFactory.getInstance().getConfigurationService().setProperty("handle.additional.prefixes", "123456789.1,123456789.2"); - + DSpaceServicesFactory.getInstance().getConfigurationService() + .setProperty("handle.additional.prefixes", "123456789.1,123456789.2"); + // We have to get Spring to instantiate the provider as a Bean, because // the bean class has autowired fields. HandleIdentifierProvider instance = new HandleIdentifierProvider(); applicationContext.getAutowireCapableBeanFactory().autowireBeanProperties( - instance, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + instance, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); // Load the test cases Properties forms = new Properties(); @@ -146,14 +145,13 @@ public class HandleIdentifierProviderTest } // Test each case - for (Map.Entry entry : forms.entrySet()) - { - String identifier = (String)entry.getKey(); - boolean expResult = Boolean.parseBoolean((String)entry.getValue()); + for (Map.Entry entry : forms.entrySet()) { + String identifier = (String) entry.getKey(); + boolean expResult = Boolean.parseBoolean((String) entry.getValue()); boolean result = instance.supports(identifier); String message = expResult ? - "This provider should support " + identifier : - "This provider should not support " + identifier; + "This provider should support " + identifier : + "This provider should not support " + identifier; assertEquals(message, expResult, result); } } diff --git a/dspace-api/src/test/java/org/dspace/identifier/MockDOIConnector.java b/dspace-api/src/test/java/org/dspace/identifier/MockDOIConnector.java index 938b1ade8e..c3a9c84895 100644 --- a/dspace-api/src/test/java/org/dspace/identifier/MockDOIConnector.java +++ b/dspace-api/src/test/java/org/dspace/identifier/MockDOIConnector.java @@ -19,54 +19,46 @@ import org.dspace.identifier.doi.DOIConnector; import org.dspace.identifier.doi.DOIIdentifierException; /** - * * @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de) */ public class MockDOIConnector -extends MockUp -implements org.dspace.identifier.doi.DOIConnector -{ + extends MockUp + implements org.dspace.identifier.doi.DOIConnector { public Map reserved; public Map registered; - - public MockDOIConnector() - { + + public MockDOIConnector() { reserved = new HashMap(); registered = new HashMap(); } - - public void reset() - { + + public void reset() { reserved.clear(); registered.clear(); } - + @Override @Mock public boolean isDOIReserved(Context context, String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { return reserved.containsKey(doi); } @Override @Mock public boolean isDOIRegistered(Context context, String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { return registered.containsKey(doi); } @Override @Mock public void deleteDOI(Context context, String doi) - throws DOIIdentifierException - { - if (reserved.remove(doi) == null) - { + throws DOIIdentifierException { + if (reserved.remove(doi) == null) { throw new DOIIdentifierException("Trying to delete a DOI that was " - + "never reserved!", DOIIdentifierException.DOI_DOES_NOT_EXIST); + + "never reserved!", DOIIdentifierException.DOI_DOES_NOT_EXIST); } registered.remove(doi); } @@ -74,20 +66,15 @@ implements org.dspace.identifier.doi.DOIConnector @Override @Mock public void reserveDOI(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException - { + throws DOIIdentifierException { UUID itemId = reserved.get(doi); - if (null != itemId) - { - if (dso.getID().equals(itemId)) - { + if (null != itemId) { + if (dso.getID().equals(itemId)) { return; - } - else - { + } else { throw new DOIIdentifierException("Trying to reserve a DOI that " - + "is reserved for another object.", - DOIIdentifierException.MISMATCH); + + "is reserved for another object.", + DOIIdentifierException.MISMATCH); } } reserved.put(doi, dso.getID()); @@ -96,52 +83,42 @@ implements org.dspace.identifier.doi.DOIConnector @Override @Mock public void registerDOI(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException - { - if (!reserved.containsKey(doi)) - { + throws DOIIdentifierException { + if (!reserved.containsKey(doi)) { throw new DOIIdentifierException("Trying to register an unreserverd " - + "DOI.", DOIIdentifierException.RESERVE_FIRST); + + "DOI.", DOIIdentifierException.RESERVE_FIRST); } - - if (!reserved.get(doi).equals(dso.getID())) - { + + if (!reserved.get(doi).equals(dso.getID())) { throw new DOIIdentifierException("Trying to register a DOI that is" - + " reserved for another item.", DOIIdentifierException.MISMATCH); + + " reserved for another item.", DOIIdentifierException.MISMATCH); } - - if (registered.containsKey(doi)) - { - if (registered.get(doi).equals(dso.getID())) - { + + if (registered.containsKey(doi)) { + if (registered.get(doi).equals(dso.getID())) { return; - } - else - { + } else { throw new DOIIdentifierException("Trying to register a DOI that " - + "is registered for another item.", - DOIIdentifierException.MISMATCH); + + "is registered for another item.", + DOIIdentifierException.MISMATCH); } } - + registered.put(doi, dso.getID()); } @Override @Mock public void updateMetadata(Context context, DSpaceObject dso, String doi) - throws DOIIdentifierException - { - if (!reserved.containsKey(doi)) - { + throws DOIIdentifierException { + if (!reserved.containsKey(doi)) { throw new DOIIdentifierException("Trying to update a DOI that is not " - + "registered!", DOIIdentifierException.DOI_DOES_NOT_EXIST); + + "registered!", DOIIdentifierException.DOI_DOES_NOT_EXIST); } - if (!reserved.get(doi).equals(dso.getID())) - { + if (!reserved.get(doi).equals(dso.getID())) { throw new DOIIdentifierException("Trying to update metadata of an " - + "unreserved DOI.", DOIIdentifierException.DOI_DOES_NOT_EXIST); + + "unreserved DOI.", DOIIdentifierException.DOI_DOES_NOT_EXIST); } } - -} \ No newline at end of file + +} diff --git a/dspace-api/src/test/java/org/dspace/statistics/FakeDatabaseReader.java b/dspace-api/src/test/java/org/dspace/statistics/FakeDatabaseReader.java new file mode 100644 index 0000000000..f40a67f54c --- /dev/null +++ b/dspace-api/src/test/java/org/dspace/statistics/FakeDatabaseReader.java @@ -0,0 +1,118 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.statistics; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.maxmind.geoip2.DatabaseReader; +import com.maxmind.geoip2.model.CityResponse; +import com.maxmind.geoip2.record.City; +import com.maxmind.geoip2.record.Continent; +import com.maxmind.geoip2.record.Country; +import com.maxmind.geoip2.record.Location; +import com.maxmind.geoip2.record.MaxMind; +import com.maxmind.geoip2.record.Postal; +import com.maxmind.geoip2.record.RepresentedCountry; +import com.maxmind.geoip2.record.Subdivision; +import com.maxmind.geoip2.record.Traits; +import mockit.Deencapsulation; +import mockit.Mock; +import mockit.MockUp; + +/** + * Mock service to mock the location Lookup Service used by the SOLR statistics + * logger. + */ +public class FakeDatabaseReader + extends MockUp { + + FakeDatabaseReader() { + } + + public FakeDatabaseReader(Object object) { + } + + public FakeDatabaseReader $init(Builder builder) { + return this; + } + + /* + @Override + public Location getLocation(String str) { + Location location = new Location(); + location.countryCode = "US"; + location.countryName = "United States"; + location.region = "NY"; + location.city = "New York"; + location.postalCode = "10036"; + location.latitude = 40.760498F; + location.longitude = -73.9933F; + location.dma_code = 501; + location.area_code = 212; + location.metro_code = 501; + + return location; + } + */ + + @Mock + public CityResponse city(InetAddress address) { + List names = new ArrayList<>(1); + + names.add("New York"); + City city = new City(names, 1, 1, new HashMap()); + + Continent continent = new Continent(); + + names.clear(); + names.add("United States"); + Country country = new Country(names, 1, 1, "US", new HashMap()); + + Location location = new Location(1, 1, 40.760498D, -73.9933D, 501, 1, "EST"); + + MaxMind maxmind = new MaxMind(); + + Postal postal = new Postal("10036", 1); + + RepresentedCountry representedCountry = new RepresentedCountry(); + + ArrayList subdivisions = new ArrayList<>(0); + + Traits traits = new Traits(); + + CityResponse response = new CityResponse(city, continent, country, + location, maxmind, postal, country, representedCountry, + subdivisions, traits); + return response; + } + + public static class Builder + extends MockUp { + + public Builder() {} + + /** + * Fake constructor. + * @param file ignored. + */ + @Mock + public void $init(File file) { + } + + @Mock + public DatabaseReader build() + throws IOException { + return Deencapsulation.newUninitializedInstance(DatabaseReader.class); + } + } +} diff --git a/dspace-api/src/test/java/org/dspace/statistics/MockSolrLoggerServiceImpl.java b/dspace-api/src/test/java/org/dspace/statistics/MockSolrLoggerServiceImpl.java new file mode 100644 index 0000000000..9716fc8892 --- /dev/null +++ b/dspace-api/src/test/java/org/dspace/statistics/MockSolrLoggerServiceImpl.java @@ -0,0 +1,44 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.statistics; + +import java.io.File; + +import com.maxmind.geoip2.DatabaseReader; +import org.dspace.services.ConfigurationService; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Mock service that uses an embedded SOLR server for the statistics core. + */ +public class MockSolrLoggerServiceImpl + extends SolrLoggerServiceImpl + implements InitializingBean { + + @Autowired(required = true) + private ConfigurationService configurationService; + + public MockSolrLoggerServiceImpl() { + } + + @Override + public void afterPropertiesSet() throws Exception { + //We don't use SOLR in the tests of this module + solr = null; + + new FakeDatabaseReader(); // Activate fake + new FakeDatabaseReader.Builder(); // Activate fake + String locationDbPath = configurationService.getProperty("usage-statistics.dbfile"); + File locationDb = new File(locationDbPath); + locationDb.createNewFile(); + locationService = new DatabaseReader.Builder(locationDb).build(); + useProxies = configurationService.getBooleanProperty("useProxies"); + } + +} diff --git a/dspace-api/src/test/java/org/dspace/statistics/util/DummyHttpServletRequest.java b/dspace-api/src/test/java/org/dspace/statistics/util/DummyHttpServletRequest.java index 4257ac6525..7ebf4305f6 100644 --- a/dspace-api/src/test/java/org/dspace/statistics/util/DummyHttpServletRequest.java +++ b/dspace-api/src/test/java/org/dspace/statistics/util/DummyHttpServletRequest.java @@ -10,51 +10,64 @@ package org.dspace.statistics.util; import java.io.BufferedReader; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.security.Principal; +import java.util.Collection; import java.util.Enumeration; import java.util.Locale; import java.util.Map; +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; /** * A mock request for testing. * * @author mwood */ -class DummyHttpServletRequest implements HttpServletRequest -{ +class DummyHttpServletRequest implements HttpServletRequest { private String agent = null; private String address = null; private String remoteHost = null; - public void setAgent(String agent) - { + public void setAgent(String agent) { this.agent = agent; } - public void setAddress(String address) - { + public void setAddress(String address) { this.address = address; } - public void setRemoteHost(String host) - { + public void setRemoteHost(String host) { this.remoteHost = host; } + /* (non-Javadoc) + * @see javax.servlet.http.HttpServletRequest#changeSessionId + */ + @Override + public String changeSessionId() { + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see javax.servlet.http.HttpServletRequest#getAuthType() */ @Override - public String getAuthType() - { + public String getAuthType() { // TODO Auto-generated method stub return null; } @@ -63,8 +76,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getContextPath() */ @Override - public String getContextPath() - { + public String getContextPath() { // TODO Auto-generated method stub return null; } @@ -73,8 +85,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getCookies() */ @Override - public Cookie[] getCookies() - { + public Cookie[] getCookies() { // TODO Auto-generated method stub return null; } @@ -83,24 +94,28 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getDateHeader(java.lang.String) */ @Override - public long getDateHeader(String arg0) - { + public long getDateHeader(String arg0) { // TODO Auto-generated method stub return 0; } + /* (non-Javadoc) + * @see javax.servlet.http.HttpServletRequest#getDispatcherType() + */ + @Override + public DispatcherType getDispatcherType() { + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String) */ @Override - public String getHeader(String key) - { - if ("User-Agent".equals(key)) - { + public String getHeader(String key) { + if ("User-Agent".equals(key)) { return agent; - } - else - { + } else { return null; } } @@ -109,8 +124,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getHeaderNames() */ @Override - public Enumeration getHeaderNames() - { + public Enumeration getHeaderNames() { // TODO Auto-generated method stub return null; } @@ -119,8 +133,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getHeaders(java.lang.String) */ @Override - public Enumeration getHeaders(String arg0) - { + public Enumeration getHeaders(String arg0) { // TODO Auto-generated method stub return null; } @@ -129,8 +142,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getIntHeader(java.lang.String) */ @Override - public int getIntHeader(String arg0) - { + public int getIntHeader(String arg0) { // TODO Auto-generated method stub return 0; } @@ -139,8 +151,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getMethod() */ @Override - public String getMethod() - { + public String getMethod() { // TODO Auto-generated method stub return null; } @@ -149,8 +160,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getPathInfo() */ @Override - public String getPathInfo() - { + public String getPathInfo() { // TODO Auto-generated method stub return null; } @@ -159,8 +169,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getPathTranslated() */ @Override - public String getPathTranslated() - { + public String getPathTranslated() { // TODO Auto-generated method stub return null; } @@ -169,8 +178,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getQueryString() */ @Override - public String getQueryString() - { + public String getQueryString() { // TODO Auto-generated method stub return null; } @@ -179,8 +187,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getRemoteUser() */ @Override - public String getRemoteUser() - { + public String getRemoteUser() { // TODO Auto-generated method stub return null; } @@ -189,8 +196,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getRequestURI() */ @Override - public String getRequestURI() - { + public String getRequestURI() { // TODO Auto-generated method stub return null; } @@ -199,8 +205,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getRequestURL() */ @Override - public StringBuffer getRequestURL() - { + public StringBuffer getRequestURL() { // TODO Auto-generated method stub return null; } @@ -209,8 +214,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId() */ @Override - public String getRequestedSessionId() - { + public String getRequestedSessionId() { // TODO Auto-generated method stub return null; } @@ -219,8 +223,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getServletPath() */ @Override - public String getServletPath() - { + public String getServletPath() { // TODO Auto-generated method stub return null; } @@ -229,8 +232,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getSession() */ @Override - public HttpSession getSession() - { + public HttpSession getSession() { // TODO Auto-generated method stub return null; } @@ -239,8 +241,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getSession(boolean) */ @Override - public HttpSession getSession(boolean arg0) - { + public HttpSession getSession(boolean arg0) { // TODO Auto-generated method stub return null; } @@ -249,8 +250,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#getUserPrincipal() */ @Override - public Principal getUserPrincipal() - { + public Principal getUserPrincipal() { // TODO Auto-generated method stub return null; } @@ -259,8 +259,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie() */ @Override - public boolean isRequestedSessionIdFromCookie() - { + public boolean isRequestedSessionIdFromCookie() { // TODO Auto-generated method stub return false; } @@ -269,8 +268,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL() */ @Override - public boolean isRequestedSessionIdFromURL() - { + public boolean isRequestedSessionIdFromURL() { // TODO Auto-generated method stub return false; } @@ -279,18 +277,65 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl() */ @Override - public boolean isRequestedSessionIdFromUrl() - { + public boolean isRequestedSessionIdFromUrl() { // TODO Auto-generated method stub return false; } + /* (non-Javadoc) + * @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse) + */ + @Override + public boolean authenticate(HttpServletResponse httpServletResponse) { + return false; + } + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServletRequest#login(java.lang.String,java.lang.String) + */ + @Override + public void login(String s, String s1) { + return; + } + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServletRequest#logout() + */ + @Override + public void logout() { + return; + } + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String) + */ + @Override + public Part getPart(String arg0) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServletRequest#getParts() + */ + @Override + public Collection getParts() { + return null; + } + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServletRequest#upgrade(java.lang.Class) + */ + @Override + public T upgrade(Class aClass) throws IOException, ServletException { + return null; + } + /* (non-Javadoc) * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid() */ @Override - public boolean isRequestedSessionIdValid() - { + public boolean isRequestedSessionIdValid() { // TODO Auto-generated method stub return false; } @@ -299,8 +344,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String) */ @Override - public boolean isUserInRole(String arg0) - { + public boolean isUserInRole(String arg0) { // TODO Auto-generated method stub return false; } @@ -309,8 +353,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getAttribute(java.lang.String) */ @Override - public Object getAttribute(String arg0) - { + public Object getAttribute(String arg0) { // TODO Auto-generated method stub return null; } @@ -319,8 +362,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getAttributeNames() */ @Override - public Enumeration getAttributeNames() - { + public Enumeration getAttributeNames() { // TODO Auto-generated method stub return null; } @@ -329,8 +371,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getCharacterEncoding() */ @Override - public String getCharacterEncoding() - { + public String getCharacterEncoding() { // TODO Auto-generated method stub return null; } @@ -339,18 +380,24 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getContentLength() */ @Override - public int getContentLength() - { + public int getContentLength() { // TODO Auto-generated method stub return 0; } + /* (non-Javadoc) + * @see javax.servlet.ServletRequest#getContentLengthLong() + */ + @Override + public long getContentLengthLong() { + return 0; + } + /* (non-Javadoc) * @see javax.servlet.ServletRequest#getContentType() */ @Override - public String getContentType() - { + public String getContentType() { // TODO Auto-generated method stub return null; } @@ -359,8 +406,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getInputStream() */ @Override - public ServletInputStream getInputStream() throws IOException - { + public ServletInputStream getInputStream() throws IOException { // TODO Auto-generated method stub return null; } @@ -369,8 +415,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getLocale() */ @Override - public Locale getLocale() - { + public Locale getLocale() { // TODO Auto-generated method stub return null; } @@ -379,8 +424,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getLocales() */ @Override - public Enumeration getLocales() - { + public Enumeration getLocales() { // TODO Auto-generated method stub return null; } @@ -389,8 +433,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getParameter(java.lang.String) */ @Override - public String getParameter(String arg0) - { + public String getParameter(String arg0) { // TODO Auto-generated method stub return null; } @@ -399,8 +442,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getParameterMap() */ @Override - public Map getParameterMap() - { + public Map getParameterMap() { // TODO Auto-generated method stub return null; } @@ -409,8 +451,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getParameterNames() */ @Override - public Enumeration getParameterNames() - { + public Enumeration getParameterNames() { // TODO Auto-generated method stub return null; } @@ -419,8 +460,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getParameterValues(java.lang.String) */ @Override - public String[] getParameterValues(String arg0) - { + public String[] getParameterValues(String arg0) { // TODO Auto-generated method stub return null; } @@ -429,8 +469,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getProtocol() */ @Override - public String getProtocol() - { + public String getProtocol() { // TODO Auto-generated method stub return null; } @@ -439,8 +478,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getReader() */ @Override - public BufferedReader getReader() throws IOException - { + public BufferedReader getReader() throws IOException { // TODO Auto-generated method stub return null; } @@ -449,8 +487,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getRealPath(java.lang.String) */ @Override - public String getRealPath(String arg0) - { + public String getRealPath(String arg0) { // TODO Auto-generated method stub return null; } @@ -459,8 +496,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getRemoteAddr() */ @Override - public String getRemoteAddr() - { + public String getRemoteAddr() { return address; } @@ -468,8 +504,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getRemoteHost() */ @Override - public String getRemoteHost() - { + public String getRemoteHost() { return remoteHost; } @@ -477,8 +512,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String) */ @Override - public RequestDispatcher getRequestDispatcher(String arg0) - { + public RequestDispatcher getRequestDispatcher(String arg0) { // TODO Auto-generated method stub return null; } @@ -487,8 +521,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getScheme() */ @Override - public String getScheme() - { + public String getScheme() { // TODO Auto-generated method stub return null; } @@ -497,8 +530,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getServerName() */ @Override - public String getServerName() - { + public String getServerName() { // TODO Auto-generated method stub return null; } @@ -507,8 +539,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#getServerPort() */ @Override - public int getServerPort() - { + public int getServerPort() { // TODO Auto-generated method stub return 0; } @@ -517,8 +548,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#isSecure() */ @Override - public boolean isSecure() - { + public boolean isSecure() { // TODO Auto-generated method stub return false; } @@ -527,8 +557,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#removeAttribute(java.lang.String) */ @Override - public void removeAttribute(String arg0) - { + public void removeAttribute(String arg0) { throw new UnsupportedOperationException("Not supported yet."); } @@ -536,8 +565,7 @@ class DummyHttpServletRequest implements HttpServletRequest * @see javax.servlet.ServletRequest#setAttribute(java.lang.String, java.lang.Object) */ @Override - public void setAttribute(String arg0, Object arg1) - { + public void setAttribute(String arg0, Object arg1) { throw new UnsupportedOperationException("Not supported yet."); } @@ -546,33 +574,77 @@ class DummyHttpServletRequest implements HttpServletRequest */ @Override public void setCharacterEncoding(String arg0) - throws UnsupportedEncodingException - { + throws UnsupportedOperationException { + throw new UnsupportedOperationException("Not supported yet."); + } + + /* (non-Javadoc) + * @see javax.servlet.ServletRequest#startAsync + */ + @Override + public AsyncContext startAsync() throws IllegalStateException { + throw new IllegalStateException("Not supported yet."); + } + + /* (non-Javadoc) + * @see javax.servlet.ServletRequest#startAsync(javax.servlet.ServletRequest,javax.servlet.ServletResponse) + */ + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) + throws IllegalStateException { + throw new IllegalStateException("Not supported yet."); + } + + /* (non-Javadoc) + * @see javax.servlet.ServletRequest#isAsyncStarted + */ + @Override + public boolean isAsyncStarted() { + return false; + } + + /* (non-Javadoc) + * @see javax.servlet.ServletRequest#isAsyncSupported + */ + @Override + public boolean isAsyncSupported() { + return false; + } + + /* (non-Javadoc) + * @see javax.servlet.ServletRequest#getAsyncContext + */ + @Override + public AsyncContext getAsyncContext() { + return null; + } + + @Override + public int getRemotePort() { throw new UnsupportedOperationException("Not supported yet."); } @Override - public int getRemotePort() - { + public String getLocalName() { throw new UnsupportedOperationException("Not supported yet."); } @Override - public String getLocalName() - { + public String getLocalAddr() { throw new UnsupportedOperationException("Not supported yet."); } @Override - public String getLocalAddr() - { + public int getLocalPort() { throw new UnsupportedOperationException("Not supported yet."); } + /* (non-Javadoc) + * @see javax.servlet.ServletRequest#getServletContext + */ @Override - public int getLocalPort() - { - throw new UnsupportedOperationException("Not supported yet."); + public ServletContext getServletContext() { + return null; } } diff --git a/dspace-api/src/test/java/org/dspace/statistics/util/SpiderDetectorServiceImplTest.java b/dspace-api/src/test/java/org/dspace/statistics/util/SpiderDetectorServiceImplTest.java index 44bfb742d7..5566562580 100644 --- a/dspace-api/src/test/java/org/dspace/statistics/util/SpiderDetectorServiceImplTest.java +++ b/dspace-api/src/test/java/org/dspace/statistics/util/SpiderDetectorServiceImplTest.java @@ -7,6 +7,8 @@ */ package org.dspace.statistics.util; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import mockit.Mock; import mockit.MockUp; @@ -18,21 +20,14 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; - import org.mockito.runners.MockitoJUnitRunner; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import static org.mockito.Mockito.mock; - /** * @author mwood * @author frederic at atmire.com */ @RunWith(MockitoJUnitRunner.class) -public class SpiderDetectorServiceImplTest extends AbstractDSpaceTest -{ +public class SpiderDetectorServiceImplTest extends AbstractDSpaceTest { private static final String NOT_A_BOT_ADDRESS = "192.168.0.1"; private ConfigurationService configurationService; @@ -48,24 +43,22 @@ public class SpiderDetectorServiceImplTest extends AbstractDSpaceTest } @Test - public void testReadPatterns() - { + public void testReadPatterns() { // FIXME fail("Not yet implemented"); } @Test - public void testGetSpiderIpAddresses() - { + public void testGetSpiderIpAddresses() { // FIXME fail("Not yet implemented"); } /** * Test if Case Insitive matching option works + * * @throws Exception */ @Test - public void testCaseInsensitiveMatching() throws Exception - { + public void testCaseInsensitiveMatching() throws Exception { configurationService.setProperty("usage-statistics.bots.case-insensitive", true); spiderDetectorService = new SpiderDetectorServiceImpl(configurationService); @@ -103,11 +96,11 @@ public class SpiderDetectorServiceImplTest extends AbstractDSpaceTest } /** - * Test method for {@link org.dspace.statistics.util.SpiderDetectorService#isSpider(javax.servlet.http.HttpServletRequest)}. + * Test method for + * {@link org.dspace.statistics.util.SpiderDetectorService#isSpider(javax.servlet.http.HttpServletRequest)}. */ @Test - public void testIsSpiderHttpServletRequest() - { + public void testIsSpiderHttpServletRequest() { DummyHttpServletRequest req = new DummyHttpServletRequest(); req.setAddress(NOT_A_BOT_ADDRESS); // avoid surprises req.setRemoteHost("notabot.example.com"); // avoid surprises @@ -141,67 +134,66 @@ public class SpiderDetectorServiceImplTest extends AbstractDSpaceTest } /** - * Test method for {@link org.dspace.statistics.util.SpiderDetectorService#isSpider(java.lang.String, java.lang.String, java.lang.String, java.lang.String)}. + * Test method for + * {@link org.dspace.statistics.util.SpiderDetectorService#isSpider(java.lang.String, java.lang.String, java.lang.String, java.lang.String)}. */ @Test - public void testIsSpiderStringStringStringString() - { + public void testIsSpiderStringStringStringString() { String candidate; // Test IP patterns candidate = "192.168.2.1"; assertTrue(candidate + " did not match IP patterns", - spiderDetectorService.isSpider(candidate, null, null, null)); + spiderDetectorService.isSpider(candidate, null, null, null)); candidate = NOT_A_BOT_ADDRESS; assertFalse(candidate + " matched IP patterns", - spiderDetectorService.isSpider(candidate, null, null, null)); + spiderDetectorService.isSpider(candidate, null, null, null)); // Test DNS patterns candidate = "baiduspider-dspace-test.crawl.baidu.com"; assertTrue(candidate + " did not match DNS patterns", - spiderDetectorService.isSpider(NOT_A_BOT_ADDRESS, null, candidate, null)); + spiderDetectorService.isSpider(NOT_A_BOT_ADDRESS, null, candidate, null)); candidate = "wiki.dspace.org"; assertFalse(candidate + " matched DNS patterns", - spiderDetectorService.isSpider(NOT_A_BOT_ADDRESS, null, candidate, null)); + spiderDetectorService.isSpider(NOT_A_BOT_ADDRESS, null, candidate, null)); // Test agent patterns candidate = "msnbot is watching you"; assertTrue("'" + candidate + "' did not match agent patterns", - spiderDetectorService.isSpider(NOT_A_BOT_ADDRESS, null, null, candidate)); + spiderDetectorService.isSpider(NOT_A_BOT_ADDRESS, null, null, candidate)); candidate = "Firefox"; assertFalse("'" + candidate + "' matched agent patterns", - spiderDetectorService.isSpider(NOT_A_BOT_ADDRESS, null, null, candidate)); + spiderDetectorService.isSpider(NOT_A_BOT_ADDRESS, null, null, candidate)); } /** * Test method for {@link org.dspace.statistics.util.SpiderDetectorService#isSpider(java.lang.String)}. */ @Test - public void testIsSpiderString() - { + public void testIsSpiderString() { String candidate; candidate = "192.168.2.1"; assertTrue(candidate + " did not match IP patterns", - spiderDetectorService.isSpider(candidate, null, null, null)); + spiderDetectorService.isSpider(candidate, null, null, null)); candidate = NOT_A_BOT_ADDRESS; assertFalse(candidate + " matched IP patterns", - spiderDetectorService.isSpider(candidate, null, null, null)); + spiderDetectorService.isSpider(candidate, null, null, null)); } /** * Test if Case Sensitive matching still works after adding the option + * * @throws Exception */ @Test - public void testCaseSensitiveMatching() throws Exception - { + public void testCaseSensitiveMatching() throws Exception { DummyHttpServletRequest req = new DummyHttpServletRequest(); req.setAddress(NOT_A_BOT_ADDRESS); // avoid surprises @@ -334,39 +326,39 @@ public class SpiderDetectorServiceImplTest extends AbstractDSpaceTest } - /** * Method to make sure the SpiderDetector is using CaseSensitive matching again after each test + * * @throws Exception */ @After public void cleanup() throws Exception { spiderDetectorService = null; - configurationService.setProperty("usage-statistics.bots.case-insensitive", false);; + configurationService.setProperty("usage-statistics.bots.case-insensitive", false); + ; } - - /** * Dummy SolrLogger for testing. + * * @author mwood */ static public class MockSolrLogger - extends MockUp - { + extends MockUp { @Mock - public void $init() {} + public void $init() { + } @Mock - public void $clinit() {} + public void $clinit() { + } @Mock - public boolean isUseProxies() - { + public boolean isUseProxies() { return false; } } -} \ No newline at end of file +} diff --git a/dspace-api/src/test/java/org/dspace/statistics/util/SpiderDetectorTest.java b/dspace-api/src/test/java/org/dspace/statistics/util/SpiderDetectorTest.java index 5a8dab3d5c..4797f7f1e5 100644 --- a/dspace-api/src/test/java/org/dspace/statistics/util/SpiderDetectorTest.java +++ b/dspace-api/src/test/java/org/dspace/statistics/util/SpiderDetectorTest.java @@ -7,28 +7,26 @@ */ package org.dspace.statistics.util; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import mockit.Mock; import mockit.MockUp; import org.dspace.AbstractDSpaceTest; import org.dspace.statistics.SolrLoggerServiceImpl; import org.junit.Test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - /** * @author mwood */ -public class SpiderDetectorTest extends AbstractDSpaceTest -{ +public class SpiderDetectorTest extends AbstractDSpaceTest { private static final String NOT_A_BOT_ADDRESS = "192.168.0.1"; /** * Test method for {@link org.dspace.statistics.util.SpiderDetector#readPatterns(java.io.File)}. */ @Test - public void testReadPatterns() - { + public void testReadPatterns() { // FIXME fail("Not yet implemented"); } @@ -36,17 +34,16 @@ public class SpiderDetectorTest extends AbstractDSpaceTest * Test method for {@link org.dspace.statistics.util.SpiderDetector#getSpiderIpAddresses()}. */ @Test - public void testGetSpiderIpAddresses() - { + public void testGetSpiderIpAddresses() { // FIXME fail("Not yet implemented"); } /** - * Test method for {@link org.dspace.statistics.util.SpiderDetector#isSpider(javax.servlet.http.HttpServletRequest)}. + * Test method for + * {@link org.dspace.statistics.util.SpiderDetector#isSpider(javax.servlet.http.HttpServletRequest)}. */ @Test - public void testIsSpiderHttpServletRequest() - { + public void testIsSpiderHttpServletRequest() { DummyHttpServletRequest req = new DummyHttpServletRequest(); req.setAddress(NOT_A_BOT_ADDRESS); // avoid surprises req.setRemoteHost("notabot.example.com"); // avoid surprises @@ -80,75 +77,75 @@ public class SpiderDetectorTest extends AbstractDSpaceTest } /** - * Test method for {@link org.dspace.statistics.util.SpiderDetector#isSpider(java.lang.String, java.lang.String, java.lang.String, java.lang.String)}. + * Test method for + * {@link org.dspace.statistics.util.SpiderDetector#isSpider(java.lang.String, java.lang.String, java.lang.String, java.lang.String)}. */ @Test - public void testIsSpiderStringStringStringString() - { + public void testIsSpiderStringStringStringString() { String candidate; // Test IP patterns candidate = "192.168.2.1"; assertTrue(candidate + " did not match IP patterns", - SpiderDetector.isSpider(candidate, null, null, null)); + SpiderDetector.isSpider(candidate, null, null, null)); candidate = NOT_A_BOT_ADDRESS; assertFalse(candidate + " matched IP patterns", - SpiderDetector.isSpider(candidate, null, null, null)); + SpiderDetector.isSpider(candidate, null, null, null)); // Test DNS patterns candidate = "baiduspider-dspace-test.crawl.baidu.com"; assertTrue(candidate + " did not match DNS patterns", - SpiderDetector.isSpider(NOT_A_BOT_ADDRESS, null, candidate, null)); + SpiderDetector.isSpider(NOT_A_BOT_ADDRESS, null, candidate, null)); candidate = "wiki.dspace.org"; assertFalse(candidate + " matched DNS patterns", - SpiderDetector.isSpider(NOT_A_BOT_ADDRESS, null, candidate, null)); + SpiderDetector.isSpider(NOT_A_BOT_ADDRESS, null, candidate, null)); // Test agent patterns candidate = "msnbot is watching you"; assertTrue("'" + candidate + "' did not match agent patterns", - SpiderDetector.isSpider(NOT_A_BOT_ADDRESS, null, null, candidate)); + SpiderDetector.isSpider(NOT_A_BOT_ADDRESS, null, null, candidate)); candidate = "Firefox"; assertFalse("'" + candidate + "' matched agent patterns", - SpiderDetector.isSpider(NOT_A_BOT_ADDRESS, null, null, candidate)); + SpiderDetector.isSpider(NOT_A_BOT_ADDRESS, null, null, candidate)); } /** * Test method for {@link org.dspace.statistics.util.SpiderDetector#isSpider(java.lang.String)}. */ @Test - public void testIsSpiderString() - { + public void testIsSpiderString() { String candidate; candidate = "192.168.2.1"; assertTrue(candidate + " did not match IP patterns", - SpiderDetector.isSpider(candidate, null, null, null)); + SpiderDetector.isSpider(candidate, null, null, null)); candidate = NOT_A_BOT_ADDRESS; assertFalse(candidate + " matched IP patterns", - SpiderDetector.isSpider(candidate, null, null, null)); + SpiderDetector.isSpider(candidate, null, null, null)); } /** * Dummy SolrLogger for testing. + * * @author mwood */ static public class MockSolrLogger - extends MockUp - { + extends MockUp { @Mock - public void $init() {} + public void $init() { + } @Mock - public void $clinit() {} + public void $clinit() { + } @Mock - public boolean isUseProxies() - { + public boolean isUseProxies() { return false; } } diff --git a/dspace-api/src/test/java/org/dspace/statistics/util/TestLocationUtils.java b/dspace-api/src/test/java/org/dspace/statistics/util/TestLocationUtils.java index 937c3a4e25..74e131b2df 100644 --- a/dspace-api/src/test/java/org/dspace/statistics/util/TestLocationUtils.java +++ b/dspace-api/src/test/java/org/dspace/statistics/util/TestLocationUtils.java @@ -7,29 +7,29 @@ */ package org.dspace.statistics.util; -import java.util.Locale; -import org.dspace.AbstractDSpaceTest; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import java.util.Locale; + +import org.dspace.AbstractDSpaceTest; import org.dspace.core.I18nUtil; import org.junit.Test; /** * @author mwood */ -public class TestLocationUtils extends AbstractDSpaceTest -{ +public class TestLocationUtils extends AbstractDSpaceTest { private static final String UNKNOWN_CONTINENT = I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-continent"); private static final String UNKNOWN_COUNTRY = I18nUtil - .getMessage("org.dspace.statistics.util.LocationUtils.unknown-country"); + .getMessage("org.dspace.statistics.util.LocationUtils.unknown-country"); /** * Test method for {@link org.dspace.statistics.util.LocationUtils#getContinentCode(java.lang.String)}. */ @Test - public void testGetContinentCode() - { + public void testGetContinentCode() { assertEquals(LocationUtils.getContinentCode("US"), "NA"); assertTrue(LocationUtils.getContinentCode(null).length() > 2); // message assertTrue(LocationUtils.getContinentCode("xyz").length() > 2); // message @@ -39,42 +39,40 @@ public class TestLocationUtils extends AbstractDSpaceTest * Test method for {@link org.dspace.statistics.util.LocationUtils#getContinentName(java.lang.String)}. */ @Test - public void testGetContinentNameString() - { + public void testGetContinentNameString() { assertEquals("North America", LocationUtils.getContinentName("NA")); assertEquals(UNKNOWN_CONTINENT, LocationUtils.getContinentName(null)); assertEquals(UNKNOWN_CONTINENT, LocationUtils.getContinentName("XXXX")); } /** - * Test method for {@link org.dspace.statistics.util.LocationUtils#getContinentName(java.lang.String, java.util.Locale)}. + * Test method for + * {@link org.dspace.statistics.util.LocationUtils#getContinentName(java.lang.String, java.util.Locale)}. */ @Test - public void testGetContinentNameStringLocale() - { + public void testGetContinentNameStringLocale() { assertEquals("North America", LocationUtils.getContinentName( - "NA", Locale.ENGLISH)); + "NA", Locale.ENGLISH)); } /** * Test method for {@link org.dspace.statistics.util.LocationUtils#getCountryName(java.lang.String)}. */ @Test - public void testGetCountryNameString() - { + public void testGetCountryNameString() { assertEquals(Locale.US.getDisplayCountry(), LocationUtils.getCountryName( - "US")); + "US")); assertEquals(UNKNOWN_COUNTRY, LocationUtils.getCountryName(null)); assertEquals("XX", LocationUtils.getCountryName("XX")); } /** - * Test method for {@link org.dspace.statistics.util.LocationUtils#getCountryName(java.lang.String, java.util.Locale)}. + * Test method for + * {@link org.dspace.statistics.util.LocationUtils#getCountryName(java.lang.String, java.util.Locale)}. */ @Test - public void testGetCountryNameStringLocale() - { + public void testGetCountryNameStringLocale() { assertEquals("United States", LocationUtils.getCountryName( - "US", Locale.ENGLISH)); + "US", Locale.ENGLISH)); } } diff --git a/dspace-api/src/test/java/org/dspace/util/MultiFormatDateParserTest.java b/dspace-api/src/test/java/org/dspace/util/MultiFormatDateParserTest.java index 7f2ea04f6e..d7157b8b05 100644 --- a/dspace-api/src/test/java/org/dspace/util/MultiFormatDateParserTest.java +++ b/dspace-api/src/test/java/org/dspace/util/MultiFormatDateParserTest.java @@ -8,9 +8,17 @@ package org.dspace.util; +import static org.junit.Assert.assertEquals; + import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; import org.junit.After; import org.junit.AfterClass; @@ -20,8 +28,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import static org.junit.Assert.*; - /** * Drive the MultiFormatDateParser from a table of test formats and sample data * using JUnit's Parameterized runner. @@ -29,9 +35,8 @@ import static org.junit.Assert.*; * @author mhwood */ @RunWith(Parameterized.class) -public class MultiFormatDateParserTest -{ - private static Locale vmLocale; +public class MultiFormatDateParserTest { + private static Locale vmLocale; private final String testMessage; private final String toParseDate; private final String expectedFormat; @@ -42,53 +47,54 @@ public class MultiFormatDateParserTest * JUnit will instantiate this class repeatedly with data from {@link #dateFormatsToTest}. */ public MultiFormatDateParserTest(String testMessage, String toParseDate, - String expectedFormat, boolean expectedResult) - { + String expectedFormat, boolean expectedResult) { this.testMessage = testMessage; this.toParseDate = toParseDate; this.expectedFormat = expectedFormat; this.expectedResult = expectedResult; } - /** Date formats and samples to drive the parameterized test. */ + /** + * Date formats and samples to drive the parameterized test. + */ @Parameterized.Parameters public static Collection dateFormatsToTest() { - return Arrays.asList(new Object[][]{ - {"Should parse: yyyyMMdd", "19570127", "yyyyMMdd", true}, - {"Should parse: dd-MM-yyyy", "27-01-1957", "dd-MM-yyyy", true}, - {"Should parse: yyyy-MM-dd", "1957-01-27", "yyyy-MM-dd", true}, - {"Should parse: MM/dd/yyyy", "01/27/1957", "MM/dd/yyyy", true}, - {"Should parse: yyyy/MM/dd", "1957/01/27", "yyyy/MM/dd", true}, - {"Should parse: yyyyMMddHHmm", "195701272006", "yyyyMMddHHmm", true}, - {"Should parse: yyyyMMdd HHmm", "19570127 2006", "yyyyMMdd HHmm", true}, - {"Should parse: dd-MM-yyyy HH:mm", "27-01-1957 20:06", "dd-MM-yyyy HH:mm", true}, - {"Should parse: yyyy-MM-dd HH:mm", "1957-01-27 20:06", "yyyy-MM-dd HH:mm", true}, - {"Should parse: MM/dd/yyyy HH:mm", "01/27/1957 20:06", "MM/dd/yyyy HH:mm", true}, - {"Should parse: yyyy/MM/dd HH:mm", "1957/01/27 20:06", "yyyy/MM/dd HH:mm", true}, - {"Should parse: yyyyMMddHHmmss", "19570127200620", "yyyyMMddHHmmss", true}, - {"Should parse: yyyyMMdd HHmmss", "19570127 200620", "yyyyMMdd HHmmss", true}, - {"Should parse: dd-MM-yyyy HH:mm:ss", "27-01-1957 20:06:20", "dd-MM-yyyy HH:mm:ss", true}, - {"Should parse: MM/dd/yyyy HH:mm:ss", "01/27/1957 20:06:20", "MM/dd/yyyy HH:mm:ss", true}, - {"Should parse: yyyy/MM/dd HH:mm:ss", "1957/01/27 20:06:20", "yyyy/MM/dd HH:mm:ss", true}, - {"Should parse: yyyy MMM dd", "1957 Jan 27", "yyyy MMM dd", true}, - {"Should parse: yyyy-MM", "1957-01", "yyyy-MM", true}, - {"Should parse: yyyyMM", "195701", "yyyyMM", true}, - {"Should parse: yyyy", "1957", "yyyy", true}, - {"Should parse: yyyy-MM-dd'T'HH:mm:ss'Z'", "1957-01-27T12:34:56Z", "yyyy-MM-dd'T'HH:mm:ss'Z'", true}, - {"Should parse: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "1957-01-27T12:34:56.789Z", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", true}, - {"Shouldn't parse: yyyy/MM/ddHH:mm:ss", "1957/01/2720:06:20", "yyyy/MM/ddHH:mm:ss", false} - }); + return Arrays.asList(new Object[][] { + {"Should parse: yyyyMMdd", "19570127", "yyyyMMdd", true}, + {"Should parse: dd-MM-yyyy", "27-01-1957", "dd-MM-yyyy", true}, + {"Should parse: yyyy-MM-dd", "1957-01-27", "yyyy-MM-dd", true}, + {"Should parse: MM/dd/yyyy", "01/27/1957", "MM/dd/yyyy", true}, + {"Should parse: yyyy/MM/dd", "1957/01/27", "yyyy/MM/dd", true}, + {"Should parse: yyyyMMddHHmm", "195701272006", "yyyyMMddHHmm", true}, + {"Should parse: yyyyMMdd HHmm", "19570127 2006", "yyyyMMdd HHmm", true}, + {"Should parse: dd-MM-yyyy HH:mm", "27-01-1957 20:06", "dd-MM-yyyy HH:mm", true}, + {"Should parse: yyyy-MM-dd HH:mm", "1957-01-27 20:06", "yyyy-MM-dd HH:mm", true}, + {"Should parse: MM/dd/yyyy HH:mm", "01/27/1957 20:06", "MM/dd/yyyy HH:mm", true}, + {"Should parse: yyyy/MM/dd HH:mm", "1957/01/27 20:06", "yyyy/MM/dd HH:mm", true}, + {"Should parse: yyyyMMddHHmmss", "19570127200620", "yyyyMMddHHmmss", true}, + {"Should parse: yyyyMMdd HHmmss", "19570127 200620", "yyyyMMdd HHmmss", true}, + {"Should parse: dd-MM-yyyy HH:mm:ss", "27-01-1957 20:06:20", "dd-MM-yyyy HH:mm:ss", true}, + {"Should parse: MM/dd/yyyy HH:mm:ss", "01/27/1957 20:06:20", "MM/dd/yyyy HH:mm:ss", true}, + {"Should parse: yyyy/MM/dd HH:mm:ss", "1957/01/27 20:06:20", "yyyy/MM/dd HH:mm:ss", true}, + {"Should parse: yyyy MMM dd", "1957 Jan 27", "yyyy MMM dd", true}, + {"Should parse: yyyy-MM", "1957-01", "yyyy-MM", true}, + {"Should parse: yyyyMM", "195701", "yyyyMM", true}, + {"Should parse: yyyy", "1957", "yyyy", true}, + {"Should parse: yyyy-MM-dd'T'HH:mm:ss'Z'", "1957-01-27T12:34:56Z", "yyyy-MM-dd'T'HH:mm:ss'Z'", true}, + {"Should parse: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "1957-01-27T12:34:56.789Z", "yyyy-MM-dd'T'HH:mm:ss" + + ".SSS'Z'", true}, + {"Shouldn't parse: yyyy/MM/ddHH:mm:ss", "1957/01/2720:06:20", "yyyy/MM/ddHH:mm:ss", false} + }); } @BeforeClass - public static void setUpClass() - { - // store default locale of the environment - vmLocale = Locale.getDefault(); - // set default locale to English just for the test of this class - Locale.setDefault(Locale.ENGLISH); + public static void setUpClass() { + // store default locale of the environment + vmLocale = Locale.getDefault(); + // set default locale to English just for the test of this class + Locale.setDefault(Locale.ENGLISH); Map formats = new HashMap<>(32); - formats.put("\\d{8}" ,"yyyyMMdd"); + formats.put("\\d{8}", "yyyyMMdd"); formats.put("\\d{1,2}-\\d{1,2}-\\d{4}", "dd-MM-yyyy"); formats.put("\\d{4}-\\d{1,2}-\\d{1,2}", "yyyy-MM-dd"); formats.put("\\d{4}-\\d{1,2}", "yyyy-MM"); @@ -122,28 +128,24 @@ public class MultiFormatDateParserTest } @AfterClass - public static void tearDownClass() - { - // restore locale - Locale.setDefault(vmLocale); + public static void tearDownClass() { + // restore locale + Locale.setDefault(vmLocale); } @Before - public void setUp() - { + public void setUp() { } @After - public void tearDown() - { + public void tearDown() { } /** * Test of parse method, of class MultiFormatDateParser. */ @Test - public void testParse() throws ParseException - { + public void testParse() throws ParseException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat(expectedFormat); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); Date result = MultiFormatDateParser.parse(toParseDate); diff --git a/dspace-api/src/test/java/org/dspace/workflowbasic/BasicWorkflowAuthorizationIT.java b/dspace-api/src/test/java/org/dspace/workflowbasic/BasicWorkflowAuthorizationIT.java index 870c34ecab..1bf2bc1ba8 100644 --- a/dspace-api/src/test/java/org/dspace/workflowbasic/BasicWorkflowAuthorizationIT.java +++ b/dspace-api/src/test/java/org/dspace/workflowbasic/BasicWorkflowAuthorizationIT.java @@ -7,6 +7,11 @@ */ package org.dspace.workflowbasic; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; + import org.apache.log4j.Logger; import org.dspace.AbstractDSpaceTest; import org.dspace.AbstractIntegrationTest; @@ -44,54 +49,48 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; - /** - * This is an integration test to ensure that the basic workflow system - * -including methods of the collection service dealing with it- works properly + * This is an integration test to ensure that the basic workflow system + * -including methods of the collection service dealing with it- works properly * together with the authorization service. + * * @author Pascal-Nicolas Becker * @author Terry Brady */ public class BasicWorkflowAuthorizationIT -extends AbstractIntegrationTest -{ - /** log4j category */ + extends AbstractIntegrationTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(BasicWorkflowAuthorizationIT.class); - + protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); - protected BasicWorkflowItemService basicWorkflowItemService = BasicWorkflowServiceFactory.getInstance().getBasicWorkflowItemService(); - protected BasicWorkflowService basicWorkflowService = BasicWorkflowServiceFactory.getInstance().getBasicWorkflowService(); + protected BasicWorkflowItemService basicWorkflowItemService = + BasicWorkflowServiceFactory.getInstance().getBasicWorkflowItemService(); + protected BasicWorkflowService basicWorkflowService = BasicWorkflowServiceFactory.getInstance() + .getBasicWorkflowService(); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - + protected Community owningCommunity; protected Collection collection; protected Group group; protected EPerson member; - - public BasicWorkflowAuthorizationIT() - { + + public BasicWorkflowAuthorizationIT() { owningCommunity = null; collection = null; group = null; member = null; } - + /** * This method will be run before every test as per @Before. It will * initialize resources required for the tests. @@ -101,35 +100,27 @@ extends AbstractIntegrationTest */ @Before @Override - public void init() - { + public void init() { super.init(); - - try - { + + try { //we have to create a new community in the database configurationService.setProperty("workflow.notify.returned.tasks", false); context.turnOffAuthorisationSystem(); - + this.owningCommunity = communityService.create(null, context); this.collection = collectionService.create(context, owningCommunity); this.member = ePersonService.create(context); this.group = groupService.create(context); groupService.addMember(context, group, member); groupService.update(context, group); - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); Assert.fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); Assert.fail("SQL Error in init: " + ex.getMessage()); - } - finally - { + } finally { // restore the authorization system as tests expect it to be in place context.restoreAuthSystemState(); } @@ -147,7 +138,7 @@ extends AbstractIntegrationTest public void destroy() { try { context.turnOffAuthorisationSystem(); - + // reload collection, community, group and eperson if (collection != null) { try { @@ -165,9 +156,8 @@ extends AbstractIntegrationTest } owningCommunity = null; } - - if (member != null) - { + + if (member != null) { if (group != null) { try { groupService.removeMember(context, group, member); @@ -181,36 +171,33 @@ extends AbstractIntegrationTest } group = null; } - try{ + try { ePersonService.delete(context, member); } catch (Exception e) { log.error("deleting user", e); - } + } } - } - finally - { + } finally { // restore the authorization system context.restoreAuthSystemState(); } super.destroy(); } - - private void setWorkflowGroup(Collection collection, Context context, int step, Group group) throws SQLException, AuthorizeException { + + private void setWorkflowGroup(Collection collection, Context context, int step, Group group) + throws SQLException, AuthorizeException { collection.setWorkflowGroup(context, step, group); //collection.setWorkflowGroup(step, group); } - - + /** - * Test if setWorkflowGroup method sets the appropriate policies for the + * Test if setWorkflowGroup method sets the appropriate policies for the * new workflow group. */ @Test - public void testsetWorkflowGroupSetsPermission() throws SQLException, AuthorizeException - { + public void testsetWorkflowGroupSetsPermission() throws SQLException, AuthorizeException { int step = 1; try { context.turnOffAuthorisationSystem(); @@ -219,18 +206,19 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - Assert.assertThat("testsetWorkflowGroupSetsPermission 0", collectionService.getWorkflowGroup(collection, step), CoreMatchers.equalTo(group)); + Assert.assertThat("testsetWorkflowGroupSetsPermission 0", collectionService.getWorkflowGroup(collection, step), + CoreMatchers.equalTo(group)); Assert.assertTrue(groupService.isDirectMember(group, member)); - Assert.assertTrue("testsetWorkflowGroupSetsPermission 1", authorizeService.authorizeActionBoolean(context, member, collection, Constants.WORKFLOW_STEP_1, true)); + Assert.assertTrue("testsetWorkflowGroupSetsPermission 1", authorizeService + .authorizeActionBoolean(context, member, collection, Constants.WORKFLOW_STEP_1, true)); } - + /** - * Test if setWorkflowGroup method revokes policies when a workflow group + * Test if setWorkflowGroup method revokes policies when a workflow group * is removed. */ @Test - public void testsetWorkflowGroupRevokesPermission() throws SQLException, AuthorizeException - { + public void testsetWorkflowGroupRevokesPermission() throws SQLException, AuthorizeException { int step = 1; try { context.turnOffAuthorisationSystem(); @@ -239,9 +227,12 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - Assert.assertThat("testsetWorkflowGroupRevokesPermission 0", collectionService.getWorkflowGroup(collection, step), CoreMatchers - .equalTo(group)); - Assert.assertTrue("testsetWorkflowGroupRevokesPermission 1", authorizeService.authorizeActionBoolean(context, member, collection, Constants.WORKFLOW_STEP_1, true)); + Assert + .assertThat("testsetWorkflowGroupRevokesPermission 0", collectionService.getWorkflowGroup(collection, step), + CoreMatchers + .equalTo(group)); + Assert.assertTrue("testsetWorkflowGroupRevokesPermission 1", authorizeService + .authorizeActionBoolean(context, member, collection, Constants.WORKFLOW_STEP_1, true)); try { context.turnOffAuthorisationSystem(); setWorkflowGroup(collection, context, step, null); @@ -249,19 +240,21 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - Assert.assertThat("testsetWorkflowGroupRevokesPermission 2", collectionService.getWorkflowGroup(collection, step), CoreMatchers - .nullValue()); - Assert.assertFalse("testsetWorkflowGroupRevokesPermission 3", authorizeService.authorizeActionBoolean(context, member, collection, Constants.WORKFLOW_STEP_1, true)); + Assert + .assertThat("testsetWorkflowGroupRevokesPermission 2", collectionService.getWorkflowGroup(collection, step), + CoreMatchers + .nullValue()); + Assert.assertFalse("testsetWorkflowGroupRevokesPermission 3", authorizeService + .authorizeActionBoolean(context, member, collection, Constants.WORKFLOW_STEP_1, true)); } - + /** * Test that a member of a worfklow step group can claim a task and get the * appropriate policies. */ @Test public void testReviewerPermissions() - throws SQLException, AuthorizeException, IOException, WorkflowException - { + throws SQLException, AuthorizeException, IOException, WorkflowException { BasicWorkflowItem wfi = null; try { // prepare a task to claim @@ -277,7 +270,7 @@ extends AbstractIntegrationTest bundleService.update(context, bundle); itemService.update(context, item); workspaceItemService.update(context, wsi); - + wfi = basicWorkflowService.startWithoutNotify(context, wsi); basicWorkflowItemService.update(context, wfi); } finally { @@ -288,31 +281,30 @@ extends AbstractIntegrationTest wfi = basicWorkflowItemService.find(context, wfi.getID()); basicWorkflowService.claim(context, wfi, member); Item item = wfi.getItem(); - + int i = 0; // check item policies - for (int action : new int[] {Constants.READ, Constants.WRITE, Constants.ADD, Constants.REMOVE, Constants.DELETE}) - { + for (int action : new int[] {Constants.READ, Constants.WRITE, Constants.ADD, Constants.REMOVE, Constants + .DELETE}) { Assert.assertTrue("testReviewerPermissions 1-" + i++, - authorizeService.authorizeActionBoolean(context, member, item, action, false)); + authorizeService.authorizeActionBoolean(context, member, item, action, false)); } - + // ensure we can read the original bundle and its bitstream Bundle bundle = itemService.getBundles(item, "ORIGINAL").get(0); Bitstream bitstream = bundle.getBitstreams().get(0); Assert.assertTrue("testReviewerPermissions 2-1", - authorizeService.authorizeActionBoolean(context, member, bundle, Constants.READ, false)); + authorizeService.authorizeActionBoolean(context, member, bundle, Constants.READ, false)); Assert.assertTrue("testReviewerPermissions 2-2" + i++, - authorizeService.authorizeActionBoolean(context, member, bitstream, Constants.READ, false)); + authorizeService.authorizeActionBoolean(context, member, bitstream, Constants.READ, false)); } - + /** * Test that a eperson not a member of a workflow step group can't claim a task. */ - @Test(expected=AuthorizeException.class) + @Test(expected = AuthorizeException.class) public void testNonWorkflowGroupMemberCannotClaimTask() - throws SQLException, AuthorizeException, IOException, WorkflowException - { + throws SQLException, AuthorizeException, IOException, WorkflowException { BasicWorkflowItem wfi = null; EPerson someone = null; try { @@ -330,7 +322,7 @@ extends AbstractIntegrationTest bundleService.update(context, bundle); itemService.update(context, item); workspaceItemService.update(context, wsi); - + wfi = basicWorkflowService.startWithoutNotify(context, wsi); basicWorkflowItemService.update(context, wfi); } finally { @@ -341,9 +333,9 @@ extends AbstractIntegrationTest wfi = basicWorkflowItemService.find(context, wfi.getID()); basicWorkflowService.claim(context, wfi, someone); Assert.fail("Someone, not part of a workflow step group was able to claim a " - + "task without an AUthorizeException."); + + "task without an AUthorizeException."); } - + /** * Test that the submitter of an item who is not member of the appropriate * workflow step group cannot claim the task of his/her own submission. @@ -351,10 +343,9 @@ extends AbstractIntegrationTest * need to test that they are still not able to claim tasks for there own * items. */ - @Test(expected=AuthorizeException.class) + @Test(expected = AuthorizeException.class) public void testNonWorkflowGroupSubmitterCannotClaimTask() - throws SQLException, AuthorizeException, IOException, WorkflowException - { + throws SQLException, AuthorizeException, IOException, WorkflowException { BasicWorkflowItem wfi = null; EPerson submitter = null; try { @@ -373,7 +364,7 @@ extends AbstractIntegrationTest bundleService.update(context, bundle); itemService.update(context, item); workspaceItemService.update(context, wsi); - + wfi = basicWorkflowService.startWithoutNotify(context, wsi); basicWorkflowItemService.update(context, wfi); } finally { @@ -384,7 +375,7 @@ extends AbstractIntegrationTest wfi = basicWorkflowItemService.find(context, wfi.getID()); basicWorkflowService.claim(context, wfi, submitter); Assert.fail("A submitter was able to claim a task without being a member of the " - + "appropriate workflow step group. Expected: AuthorizeException."); + + "appropriate workflow step group. Expected: AuthorizeException."); } } diff --git a/dspace-api/src/test/java/org/dspace/workflowbasic/BasicWorkflowAuthorizationRolesIT.java b/dspace-api/src/test/java/org/dspace/workflowbasic/BasicWorkflowAuthorizationRolesIT.java index 1c32ef117e..cdaf38077d 100644 --- a/dspace-api/src/test/java/org/dspace/workflowbasic/BasicWorkflowAuthorizationRolesIT.java +++ b/dspace-api/src/test/java/org/dspace/workflowbasic/BasicWorkflowAuthorizationRolesIT.java @@ -8,12 +8,19 @@ package org.dspace.workflowbasic; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Date; +import java.util.HashMap; +import java.util.UUID; + import org.apache.log4j.Logger; import org.dspace.AbstractDSpaceTest; import org.dspace.AbstractIntegrationTest; import org.dspace.authorize.AuthorizeException; -import org.dspace.authorize.ResourcePolicy; -import org.dspace.content.Bitstream; import org.dspace.content.Bundle; import org.dspace.content.Collection; import org.dspace.content.Community; @@ -37,52 +44,44 @@ import org.dspace.eperson.service.GroupService; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.workflow.WorkflowException; -import org.dspace.workflow.WorkflowItem; import org.dspace.workflowbasic.factory.BasicWorkflowServiceFactory; import org.dspace.workflowbasic.service.BasicWorkflowItemService; import org.dspace.workflowbasic.service.BasicWorkflowService; -import org.hamcrest.CoreMatchers; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.UUID; - /** - * This is an integration test to ensure that the basic workflow system - * -including methods of the collection service dealing with it- works properly + * This is an integration test to ensure that the basic workflow system + * -including methods of the collection service dealing with it- works properly * together with the authorization service. + * * @author Pascal-Nicolas Becker * @author Terry Brady */ public class BasicWorkflowAuthorizationRolesIT -extends AbstractIntegrationTest -{ - /** log4j category */ + extends AbstractIntegrationTest { + /** + * log4j category + */ private static final Logger log = Logger.getLogger(BasicWorkflowAuthorizationIT.class); - + protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); - protected BasicWorkflowItemService basicWorkflowItemService = BasicWorkflowServiceFactory.getInstance().getBasicWorkflowItemService(); - protected BasicWorkflowService basicWorkflowService = BasicWorkflowServiceFactory.getInstance().getBasicWorkflowService(); + protected BasicWorkflowItemService basicWorkflowItemService = + BasicWorkflowServiceFactory.getInstance().getBasicWorkflowItemService(); + protected BasicWorkflowService basicWorkflowService = BasicWorkflowServiceFactory.getInstance() + .getBasicWorkflowService(); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - + protected Community owningCommunity; protected Collection collection; protected Item item; @@ -90,12 +89,13 @@ extends AbstractIntegrationTest protected Group mgroup; protected EPerson member; protected WorkspaceItem wsi; - protected enum ROLE {ADMIN,SUB,STEP1,STEP2,STEP3;} - protected HashMap roleGroups = new HashMap<>(); - protected HashMap roleEPersons = new HashMap<>(); - - public BasicWorkflowAuthorizationRolesIT() - { + + protected enum ROLE { ADMIN, SUB, STEP1, STEP2, STEP3 } + + protected HashMap roleGroups = new HashMap<>(); + protected HashMap roleEPersons = new HashMap<>(); + + public BasicWorkflowAuthorizationRolesIT() { owningCommunity = null; collection = null; item = null; @@ -106,7 +106,7 @@ extends AbstractIntegrationTest roleGroups.clear(); roleEPersons.clear(); } - + /** * This method will be run before every test as per @Before. It will * initialize resources required for the tests. @@ -116,16 +116,14 @@ extends AbstractIntegrationTest */ @Before @Override - public void init() - { + public void init() { super.init(); - - try - { + + try { //we have to create a new community in the database configurationService.setProperty("workflow.notify.returned.tasks", false); context.turnOffAuthorisationSystem(); - + long date = new Date().getTime(); this.owningCommunity = communityService.create(null, context); this.collection = collectionService.create(context, owningCommunity); @@ -137,11 +135,11 @@ extends AbstractIntegrationTest groupService.addMember(context, mgroup, member); groupService.setName(mgroup, String.format("Member Group %d", date)); groupService.update(context, mgroup); - for(ROLE role: ROLE.values()) { + for (ROLE role : ROLE.values()) { EPerson person = ePersonService.create(context); person.setFirstName(context, String.format("%d", date)); person.setLastName(context, String.format("Role %s", role.toString())); - person.setEmail(String.format("basicwf-test-%s-%d@example.org",role.toString(),date)); + person.setEmail(String.format("basicwf-test-%s-%d@example.org", role.toString(), date)); ePersonService.update(context, person); roleEPersons.put(role, person); Group pgroup = groupService.create(context); @@ -149,21 +147,16 @@ extends AbstractIntegrationTest groupService.setName(pgroup, String.format("Group %s %d", role.toString(), date)); groupService.addMember(context, pgroup, person); groupService.update(context, pgroup); - log.info(String.format("Create ROLE %s GROUP %s PERSON %s", role.toString(), pgroup.getName(), person.getFullName())); + log.info(String.format("Create ROLE %s GROUP %s PERSON %s", role.toString(), pgroup.getName(), + person.getFullName())); } - } - catch (AuthorizeException ex) - { + } catch (AuthorizeException ex) { log.error("Authorization Error in init", ex); Assert.fail("Authorization Error in init: " + ex.getMessage()); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQL Error in init", ex); Assert.fail("SQL Error in init: " + ex.getMessage()); - } - finally - { + } finally { // restore the authorization system as tests expect it to be in place context.restoreAuthSystemState(); } @@ -172,12 +165,12 @@ extends AbstractIntegrationTest private void contextReload() { try { if (context.isValid()) { - context.commit(); + context.commit(); } else { context.abort(); } context = new Context(); - owningCommunity= context.reloadEntity(owningCommunity); + owningCommunity = context.reloadEntity(owningCommunity); collection = context.reloadEntity(collection); member = context.reloadEntity(member); mgroup = context.reloadEntity(mgroup); @@ -192,7 +185,7 @@ extends AbstractIntegrationTest context.uncacheEntity(wfi); wfi = basicWorkflowItemService.find(context, wfid); } - for(ROLE role: ROLE.values()) { + for (ROLE role : ROLE.values()) { EPerson eperson = roleEPersons.get(role); eperson = ePersonService.find(context, eperson.getID()); Assert.assertNotNull(eperson); @@ -202,10 +195,10 @@ extends AbstractIntegrationTest } catch (SQLException e) { log.error("Error reloading context", e); } - + } - - + + /** * This method will be run after every test as per @After. It will * clean resources initialized by the @Before methods. @@ -218,16 +211,17 @@ extends AbstractIntegrationTest public void destroy() { try { super.destroy(); - } catch(Exception e) { + } catch (Exception e) { log.error("Error in super destroy", e); } } - + /* * Prepare a workspace item for subsequent tests */ - private void setupItemAndStartWorkflow() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { + private void setupItemAndStartWorkflow() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { context.setCurrentUser(roleEPersons.get(ROLE.SUB)); wsi = workspaceItemService.create(context, collection, false); item = wsi.getItem(); @@ -237,7 +231,7 @@ extends AbstractIntegrationTest bundleService.update(context, bundle); itemService.update(context, item); workspaceItemService.update(context, wsi); - + wfi = basicWorkflowService.startWithoutNotify(context, wsi); basicWorkflowItemService.update(context, wfi); } @@ -246,13 +240,13 @@ extends AbstractIntegrationTest collection.setWorkflowGroup(context, step, group); //collection.setWorkflowGroup(step, group); } - + /* * Model the permission set up for a collection with basic workflow. * The last group to advance the item seems to need Add rights * SUB has add rights. */ - private void setStepPermissions(ROLE step1, ROLE step2, ROLE step3) throws SQLException, AuthorizeException { + private void setStepPermissions(ROLE step1, ROLE step2, ROLE step3) throws SQLException, AuthorizeException { authorizeService.addPolicy(context, collection, Constants.ADMIN, roleGroups.get(ROLE.ADMIN)); Group last = null; if (step1 != null) { @@ -270,20 +264,21 @@ extends AbstractIntegrationTest setWorkflowGroup(context, 3, group); last = group; } - + authorizeService.addPolicy(context, collection, Constants.ADD, last); collectionService.update(context, collection); } - + /** * Test that appropriate claim and advance permissions are enforced for a workflow with only Step 1. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep1AllRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep1AllRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, null, null); @@ -291,7 +286,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -299,19 +294,19 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); - + attemptItemUnclaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); contextReload(); attemptItemClaim(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvanceFinal(ROLE.STEP1); contextReload(); @@ -325,13 +320,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim permissions are enforced for a workflow with only Step 1. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep1AllRolesClaim() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep1AllRolesClaim() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, null, null); @@ -339,7 +335,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -347,19 +343,19 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); - + attemptItemUnclaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); contextReload(); attemptItemClaim(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvanceFinal(ROLE.STEP1, false); contextReload(); @@ -373,13 +369,14 @@ extends AbstractIntegrationTest /** * Test that expected transitions succeed for a workflow with only Step 1. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep1ExpectedRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep1ExpectedRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, null, null); @@ -387,7 +384,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -395,19 +392,19 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); - + attemptItemUnclaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); contextReload(); attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvanceFinal(ROLE.STEP1, false); contextReload(); @@ -421,13 +418,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a submitter in a workflow with only Step 1. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep1Submitter() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep1Submitter() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, null, null); @@ -435,7 +433,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -443,13 +441,13 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); - + attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); - + attemptItemUnclaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); @@ -457,7 +455,7 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvanceFinal(ROLE.SUB, true); attemptItemAdvanceFinal(ROLE.STEP1, false); @@ -472,13 +470,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a workflow with only Step 2. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep2AllRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep2AllRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, ROLE.STEP2, null); @@ -486,7 +485,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); @@ -494,10 +493,10 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP2); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); - + contextReload(); attemptItemUnclaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); @@ -519,13 +518,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim permissions are enforced for a workflow with only Step 2. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep2AllRolesClaim() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep2AllRolesClaim() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, ROLE.STEP2, null); @@ -533,7 +533,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); @@ -541,10 +541,10 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP2); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); - + contextReload(); attemptItemUnclaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); @@ -566,13 +566,14 @@ extends AbstractIntegrationTest /** * Test that expected permissions are valid for a workflow with only Step 2. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep2ExpectedRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep2ExpectedRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, ROLE.STEP2, null); @@ -580,7 +581,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); @@ -588,10 +589,10 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); - + contextReload(); attemptItemUnclaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); @@ -613,13 +614,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a submitter in a workflow with only Step 2. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep2Submitter() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep2Submitter() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, ROLE.STEP2, null); @@ -627,7 +629,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); @@ -635,11 +637,11 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); - + attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); - + contextReload(); attemptItemUnclaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); @@ -660,15 +662,17 @@ extends AbstractIntegrationTest throw e; } } + /** * Test that appropriate claim and advance permissions are enforced for a workflow with only Step 3. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep3AllRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep3AllRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, null, ROLE.STEP3); @@ -676,22 +680,22 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); Assert.assertNull(collection.getWorkflowStep2()); Assert.assertEquals(collection.getWorkflowStep3(), roleGroups.get(ROLE.STEP3)); - + Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP3); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); - + contextReload(); attemptItemUnclaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP3); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); @@ -709,13 +713,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim permissions are enforced for a workflow with only Step 3. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep3AllRolesClaim() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep3AllRolesClaim() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, null, ROLE.STEP3); @@ -723,22 +728,22 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); Assert.assertNull(collection.getWorkflowStep2()); Assert.assertEquals(collection.getWorkflowStep3(), roleGroups.get(ROLE.STEP3)); - + Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP3); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); - + contextReload(); attemptItemUnclaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP3); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); @@ -756,13 +761,14 @@ extends AbstractIntegrationTest /** * Test that expected permissions are valid for a workflow with only Step 3. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep3ExpectedRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep3ExpectedRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, null, ROLE.STEP3); @@ -770,22 +776,22 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); Assert.assertNull(collection.getWorkflowStep2()); Assert.assertEquals(collection.getWorkflowStep3(), roleGroups.get(ROLE.STEP3)); - + Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); - + contextReload(); attemptItemUnclaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); @@ -800,16 +806,17 @@ extends AbstractIntegrationTest throw e; } } - + /** * Test that appropriate claim and advance permissions are enforced for a submitter in a workflow with only Step 3. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithStep3Submitter() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithStep3Submitter() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, null, ROLE.STEP3); @@ -817,23 +824,23 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); Assert.assertNull(collection.getWorkflowStep2()); Assert.assertEquals(collection.getWorkflowStep3(), roleGroups.get(ROLE.STEP3)); - + Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); - + contextReload(); attemptItemUnclaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP3, false); @@ -850,15 +857,17 @@ extends AbstractIntegrationTest throw e; } } + /** * Test that appropriate claim and advance permissions are enforced for a 2 step workflow (1 & 2). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps12AllRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps12AllRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, ROLE.STEP2, null); @@ -866,7 +875,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -874,10 +883,10 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); @@ -899,13 +908,14 @@ extends AbstractIntegrationTest /** * Test that expected permissions are valid for a 2 step workflow (1 & 2). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps12ExpectedRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps12ExpectedRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, ROLE.STEP2, null); @@ -913,7 +923,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -921,10 +931,10 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); - + attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); @@ -946,13 +956,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a submitter in a 2 step workflow (1 & 2). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps12Submitter() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps12Submitter() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, ROLE.STEP2, null); @@ -960,7 +971,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -968,11 +979,11 @@ extends AbstractIntegrationTest Assert.assertNull(collection.getWorkflowStep3()); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1POOL, wfi.getState()); - + attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.SUB, true); attemptItemAdvance(ROLE.STEP1, false); @@ -998,13 +1009,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a 2 step workflow (1 & 3). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps13AllRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps13AllRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, null, ROLE.STEP3); @@ -1012,7 +1024,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -1023,11 +1035,11 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP3); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); @@ -1045,13 +1057,14 @@ extends AbstractIntegrationTest /** * Test that expected permissions are valid for a 2 step workflow (1 & 3). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps13ExpectedRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps13ExpectedRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, null, ROLE.STEP3); @@ -1059,7 +1072,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -1070,11 +1083,11 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); @@ -1090,16 +1103,17 @@ extends AbstractIntegrationTest } } - + /** * Test that appropriate claim and advance permissions are enforced for a submitter in a 2 step workflow (1 & 3). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps13Submitter() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps13Submitter() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, null, ROLE.STEP3); @@ -1107,7 +1121,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -1119,12 +1133,12 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.SUB, true); attemptItemAdvance(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP3, false); @@ -1144,21 +1158,22 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a 2 step workflow (2 & 3). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps23AllRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps23AllRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, ROLE.STEP2, ROLE.STEP3); setupItemAndStartWorkflow(); - } finally { + } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); @@ -1169,11 +1184,11 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.STEP2); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.STEP2); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP3); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); @@ -1191,21 +1206,22 @@ extends AbstractIntegrationTest /** * Test that expected permissions are valid for a 2 step workflow (2 & 3). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps23ExpectedRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps23ExpectedRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, ROLE.STEP2, ROLE.STEP3); setupItemAndStartWorkflow(); - } finally { + } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); @@ -1216,11 +1232,11 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP3, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3, wfi.getState()); @@ -1238,21 +1254,22 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a submitter in a 2 step workflow (2 & 3). - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps23Submitter() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps23Submitter() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(null, ROLE.STEP2, ROLE.STEP3); setupItemAndStartWorkflow(); - } finally { + } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertNull(collection.getWorkflowStep1()); @@ -1264,12 +1281,12 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.SUB, true); attemptItemAdvance(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP3POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP3, false); @@ -1289,13 +1306,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a 3 step workflow. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps123AllRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps123AllRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, ROLE.STEP2, ROLE.STEP3); @@ -1303,7 +1321,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -1314,11 +1332,11 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.STEP1); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP2); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); @@ -1344,13 +1362,14 @@ extends AbstractIntegrationTest /** * Test that expected permissions are valid for a 3 step workflow. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps123ExpectedRoles() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps123ExpectedRoles() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, ROLE.STEP2, ROLE.STEP3); @@ -1358,7 +1377,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -1369,11 +1388,11 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.STEP2, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2, wfi.getState()); @@ -1399,13 +1418,14 @@ extends AbstractIntegrationTest /** * Test that appropriate claim and advance permissions are enforced for a submitter in a 3 step workflow. - * @throws IOException - * @throws FileNotFoundException - * @throws WorkflowException + * + * @throws IOException + * @throws FileNotFoundException + * @throws WorkflowException */ @Test - public void testsetWorkflowWithSteps123Submitter() throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException - { + public void testsetWorkflowWithSteps123Submitter() + throws SQLException, AuthorizeException, FileNotFoundException, IOException, WorkflowException { try { context.turnOffAuthorisationSystem(); setStepPermissions(ROLE.STEP1, ROLE.STEP2, ROLE.STEP3); @@ -1413,7 +1433,7 @@ extends AbstractIntegrationTest } finally { context.restoreAuthSystemState(); } - + try { contextReload(); Assert.assertEquals(collection.getWorkflowStep1(), roleGroups.get(ROLE.STEP1)); @@ -1425,12 +1445,12 @@ extends AbstractIntegrationTest attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP1, wfi.getState()); - + contextReload(); attemptItemAdvance(ROLE.SUB, true); attemptItemAdvance(ROLE.STEP1, false); Assert.assertEquals(BasicWorkflowService.WFSTATE_STEP2POOL, wfi.getState()); - + contextReload(); attemptItemClaim(ROLE.SUB, true); attemptItemClaim(ROLE.STEP2, false); @@ -1457,12 +1477,13 @@ extends AbstractIntegrationTest throw e; } } -/* + + /* * Each user in ROLE.values() will attempt to claim an item. * Only the user with roleValid should succeed. */ public void attemptItemClaim(ROLE roleValid) throws SQLException, AuthorizeException, IOException { - for(ROLE role: ROLE.values()) { + for (ROLE role : ROLE.values()) { if (role == ROLE.ADMIN || role == roleValid) { continue; } @@ -1478,7 +1499,7 @@ extends AbstractIntegrationTest * Only the user with roleValid should succeed. */ public void attemptItemAdvance(ROLE roleValid) throws SQLException, AuthorizeException, IOException { - for(ROLE role: ROLE.values()) { + for (ROLE role : ROLE.values()) { if (role == ROLE.ADMIN || role == roleValid) { continue; } @@ -1494,7 +1515,7 @@ extends AbstractIntegrationTest * Only the user with roleValid should succeed. */ public void attemptItemAdvanceFinal(ROLE roleValid) throws SQLException, AuthorizeException, IOException { - for(ROLE role: ROLE.values()) { + for (ROLE role : ROLE.values()) { if (role == ROLE.ADMIN || role == roleValid) { continue; } @@ -1504,12 +1525,13 @@ extends AbstractIntegrationTest attemptItemAdvanceFinal(roleValid, false); } } - - /* - * User role will attempt to claim an item. - * expectFail indicates whether or not the action should succeed. - */ - public void attemptItemClaim(ROLE role, boolean expectAuthFail) throws SQLException, AuthorizeException, IOException { + + /* + * User role will attempt to claim an item. + * expectFail indicates whether or not the action should succeed. + */ + public void attemptItemClaim(ROLE role, boolean expectAuthFail) + throws SQLException, AuthorizeException, IOException { EPerson eperson = roleEPersons.get(role); context.setCurrentUser(eperson); @@ -1518,9 +1540,9 @@ extends AbstractIntegrationTest try { basicWorkflowService.claim(context, wfi, eperson); //If exception is not thrown, owner will be set and state will change - } catch(AuthorizeException e) { + } catch (AuthorizeException e) { context.abort(); - } catch(Exception e) { + } catch (Exception e) { //handle hibernate exception triggered by database rule context.abort(); } @@ -1529,72 +1551,79 @@ extends AbstractIntegrationTest eperson = roleEPersons.get(role); if (state != wfi.getState()) { - log.error(String.format("USER[%-20s] is able to claim task (state %d -> %d) (unexpected)", eperson.getFullName(), state, wfi.getState()), new Exception()); + log.error(String.format("USER[%-20s] is able to claim task (state %d -> %d) (unexpected)", + eperson.getFullName(), state, wfi.getState()), new Exception()); } - Assert.assertEquals(state, wfi.getState()); + Assert.assertEquals(state, wfi.getState()); Assert.assertNull(wfi.getOwner()); } else { basicWorkflowService.claim(context, wfi, eperson); contextReload(); eperson = roleEPersons.get(role); if (state == wfi.getState()) { - log.error(String.format("USER[%-20s] is unable to claim task (state %d -> %d) (unexpected)", eperson.getFullName(), state, wfi.getState()), new Exception()); + log.error(String.format("USER[%-20s] is unable to claim task (state %d -> %d) (unexpected)", + eperson.getFullName(), state, wfi.getState()), new Exception()); } - Assert.assertNotEquals(state, wfi.getState()); + Assert.assertNotEquals(state, wfi.getState()); Assert.assertNotNull(wfi.getOwner()); } Assert.assertFalse(wfi.getItem().isArchived()); } /* - * User role will attempt to claim an item. + * User role will attempt to claim an item. * expectFail indicates whether or not the action should succeed. */ - public void attemptItemUnclaim(ROLE role, boolean expectAuthFail) throws SQLException, AuthorizeException, IOException { - EPerson eperson = roleEPersons.get(role); - context.setCurrentUser(eperson); + public void attemptItemUnclaim(ROLE role, boolean expectAuthFail) + throws SQLException, AuthorizeException, IOException { + EPerson eperson = roleEPersons.get(role); + context.setCurrentUser(eperson); - int state = wfi.getState(); - if (expectAuthFail) { - try { - basicWorkflowService.unclaim(context, wfi, eperson); - //If exception is not thrown, owner will be set and state will change - } catch(AuthorizeException e) { - context.abort(); - } catch(Exception e) { - //handle hibernate exception triggered by database rule - context.abort(); - } + int state = wfi.getState(); + if (expectAuthFail) { + try { + basicWorkflowService.unclaim(context, wfi, eperson); + //If exception is not thrown, owner will be set and state will change + } catch (AuthorizeException e) { + context.abort(); + } catch (Exception e) { + //handle hibernate exception triggered by database rule + context.abort(); + } - contextReload(); + contextReload(); - eperson = roleEPersons.get(role); - if (state != wfi.getState()) { - log.error(String.format("USER[%-20s] is able to unclaim task (state %d -> %d) (unexpected)", eperson.getFullName(), state, wfi.getState()), new Exception()); - } + eperson = roleEPersons.get(role); + if (state != wfi.getState()) { + log.error(String.format("USER[%-20s] is able to unclaim task (state %d -> %d) (unexpected)", + eperson.getFullName(), state, wfi.getState()), new Exception()); + } - Assert.assertEquals(state, wfi.getState()); - Assert.assertNotNull(wfi.getOwner()); - } else { - basicWorkflowService.unclaim(context, wfi, eperson); - contextReload(); - eperson = roleEPersons.get(role); - if (state == wfi.getState()) { - log.error(String.format("USER[%-20s] is unable to unclaim task (state %d -> %d) (unexpected)", eperson.getFullName(), state, wfi.getState()), new Exception()); - } + Assert.assertEquals(state, wfi.getState()); + Assert.assertNotNull(wfi.getOwner()); + } else { + basicWorkflowService.unclaim(context, wfi, eperson); + contextReload(); + eperson = roleEPersons.get(role); + if (state == wfi.getState()) { + log.error(String.format("USER[%-20s] is unable to unclaim task (state %d -> %d) (unexpected)", + eperson.getFullName(), state, wfi.getState()), new Exception()); + } + + Assert.assertNotEquals(state, wfi.getState()); + Assert.assertNull(wfi.getOwner()); + } + Assert.assertFalse(wfi.getItem().isArchived()); + } - Assert.assertNotEquals(state, wfi.getState()); - Assert.assertNull(wfi.getOwner()); - } - Assert.assertFalse(wfi.getItem().isArchived()); - } /* - * User role will attempt to advance an item. + * User role will attempt to advance an item. * expectFail indicates whether or not the action should succeed. */ - public void attemptItemAdvance(ROLE role, boolean expectAuthFail) throws SQLException, AuthorizeException, IOException { + public void attemptItemAdvance(ROLE role, boolean expectAuthFail) + throws SQLException, AuthorizeException, IOException { EPerson eperson = roleEPersons.get(role); context.setCurrentUser(eperson); int state = wfi.getState(); @@ -1603,9 +1632,9 @@ extends AbstractIntegrationTest try { basicWorkflowService.advance(context, wfi, eperson); //If exception is not thrown, owner will be unset and state will change - } catch(AuthorizeException e) { + } catch (AuthorizeException e) { context.abort(); - } catch(Exception e) { + } catch (Exception e) { //handle hibernate exception triggered by database rule context.abort(); } @@ -1613,7 +1642,8 @@ extends AbstractIntegrationTest owner = ePersonService.find(context, owner.getID()); eperson = roleEPersons.get(role); if (state != wfi.getState()) { - log.error(String.format("USER[%-20s] is able to advance task (state %d -> %d) (unexpected)", eperson.getFullName(), state, wfi.getState()), new Exception()); + log.error(String.format("USER[%-20s] is able to advance task (state %d -> %d) (unexpected)", + eperson.getFullName(), state, wfi.getState()), new Exception()); } Assert.assertEquals(state, wfi.getState()); Assert.assertEquals(owner, wfi.getOwner()); @@ -1622,7 +1652,8 @@ extends AbstractIntegrationTest contextReload(); eperson = roleEPersons.get(role); if (state == wfi.getState()) { - log.error(String.format("USER[%-20s] is unable to advance task (state %d -> %d) (unexpected)", eperson.getFullName(), state, wfi.getState()), new Exception()); + log.error(String.format("USER[%-20s] is unable to advance task (state %d -> %d) (unexpected)", + eperson.getFullName(), state, wfi.getState()), new Exception()); } Assert.assertNotEquals(state, wfi.getState()); Assert.assertNull(wfi.getOwner()); @@ -1630,45 +1661,49 @@ extends AbstractIntegrationTest Assert.assertFalse(wfi.getItem().isArchived()); } - /* - * User role will attempt to advance an item. - * expectFail indicates whether or not the action should succeed. - */ - public void attemptItemAdvanceFinal(ROLE role, boolean expectAuthFail) throws SQLException, AuthorizeException, IOException { - EPerson eperson = roleEPersons.get(role); - context.setCurrentUser(eperson); - int state = wfi.getState(); - EPerson owner = wfi.getOwner(); - if (expectAuthFail) { - try { - basicWorkflowService.advance(context, wfi, eperson); - //If exception is not thrown, owner will be unset and state will change - } catch(AuthorizeException e) { - context.abort(); - } catch(Exception e) { - //handle hibernate exception triggered by database rule - context.abort(); - } - contextReload(); - owner = ePersonService.find(context, owner.getID()); - eperson = roleEPersons.get(role); - if (wfi == null) { - log.error(String.format("USER[%-20s] is able to advance task to completion from state %d (unexpected)", eperson.getFullName(), state), new Exception()); - } - Assert.assertNotNull(wfi); - Assert.assertEquals(state, wfi.getState()); - Assert.assertEquals(owner, wfi.getOwner()); - Assert.assertFalse(wfi.getItem().isArchived()); - } else { - basicWorkflowService.advance(context, wfi, eperson); - contextReload(); - eperson = roleEPersons.get(role); - if (wfi != null) { - log.error(String.format("USER[%-20s] is unable to advance task to completion from state %d (unexpected)", eperson.getFullName(), state), new Exception()); - } - Assert.assertNull(wfi); - Assert.assertTrue(item.isArchived()); - } - } + /* + * User role will attempt to advance an item. + * expectFail indicates whether or not the action should succeed. + */ + public void attemptItemAdvanceFinal(ROLE role, boolean expectAuthFail) + throws SQLException, AuthorizeException, IOException { + EPerson eperson = roleEPersons.get(role); + context.setCurrentUser(eperson); + int state = wfi.getState(); + EPerson owner = wfi.getOwner(); + if (expectAuthFail) { + try { + basicWorkflowService.advance(context, wfi, eperson); + //If exception is not thrown, owner will be unset and state will change + } catch (AuthorizeException e) { + context.abort(); + } catch (Exception e) { + //handle hibernate exception triggered by database rule + context.abort(); + } + contextReload(); + owner = ePersonService.find(context, owner.getID()); + eperson = roleEPersons.get(role); + if (wfi == null) { + log.error(String.format("USER[%-20s] is able to advance task to completion from state %d (unexpected)", + eperson.getFullName(), state), new Exception()); + } + Assert.assertNotNull(wfi); + Assert.assertEquals(state, wfi.getState()); + Assert.assertEquals(owner, wfi.getOwner()); + Assert.assertFalse(wfi.getItem().isArchived()); + } else { + basicWorkflowService.advance(context, wfi, eperson); + contextReload(); + eperson = roleEPersons.get(role); + if (wfi != null) { + log.error(String + .format("USER[%-20s] is unable to advance task to completion from state %d (unexpected)", + eperson.getFullName(), state), new Exception()); + } + Assert.assertNull(wfi); + Assert.assertTrue(item.isArchived()); + } + } } diff --git a/dspace-api/src/test/resources/log4j.properties b/dspace-api/src/test/resources/log4j.properties index db62b5dc01..93a4ec7ff5 100644 --- a/dspace-api/src/test/resources/log4j.properties +++ b/dspace-api/src/test/resources/log4j.properties @@ -13,7 +13,7 @@ ########################################################################### # This is a copy of the log4j configuration file for DSpace, to avoid -# getting errors when running tests. +# getting errors when running tests. # Set root category priority to INFO and its only appender to A1. log4j.rootCategory=INFO, A1 diff --git a/dspace-api/src/test/resources/org/dspace/identifier/handle-forms.properties b/dspace-api/src/test/resources/org/dspace/identifier/handle-forms.properties index e29a3962ef..e0902ebb10 100644 --- a/dspace-api/src/test/resources/org/dspace/identifier/handle-forms.properties +++ b/dspace-api/src/test/resources/org/dspace/identifier/handle-forms.properties @@ -6,7 +6,7 @@ http://dx.doi.org/10.14279/depositonce-5383 = false # Note: This next one only succeeds because handle.prefix=123456789 in Test Framework 123456789/1 = true -# Note: This next one only succeeds because handle.additional.prefixes=123456789.1,123456789.2 in Test +# Note: This next one only succeeds because handle.additional.prefixes=123456789.1,123456789.2 in Test 123456789.1/1 = true 123456789.2/1 = true 123456789.3/1 = false diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index c66b5fd84a..136b8fc1dc 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 dspace-oai war @@ -15,7 +16,6 @@ ${basedir}/.. - 3.2.5.RELEASE 3.2.10 2.0.1 @@ -104,8 +104,8 @@ xml-apis - org.apache.commons - commons-lang3 + org.apache.commons + commons-lang3 @@ -143,10 +143,6 @@ jtwig-spring ${jtwig.version} - - org.ow2.asm - asm - com.google.guava guava @@ -156,8 +152,12 @@ javassist - org.apache.commons - commons-lang3 + org.apache.commons + commons-lang3 + + + javax.servlet + servlet-api @@ -184,7 +184,7 @@ javax.servlet - servlet-api + javax.servlet-api provided @@ -223,10 +223,12 @@ junit test + + org.hamcrest - hamcrest-core - test + hamcrest-all + compile org.mockito diff --git a/dspace-oai/src/main/java/org/dspace/utils/DSpaceWebapp.java b/dspace-oai/src/main/java/org/dspace/utils/DSpaceWebapp.java index 7c3d10d4d3..8154bf1582 100644 --- a/dspace-oai/src/main/java/org/dspace/utils/DSpaceWebapp.java +++ b/dspace-oai/src/main/java/org/dspace/utils/DSpaceWebapp.java @@ -16,17 +16,13 @@ import org.dspace.app.util.AbstractDSpaceWebapp; * @author Christian Scheible (christian.scheible at uni-konstanz dot de) */ public class DSpaceWebapp - extends AbstractDSpaceWebapp -{ - public DSpaceWebapp() - { + extends AbstractDSpaceWebapp { + public DSpaceWebapp() { super("OAI"); } @Override - public boolean isUI() - { + public boolean isUI() { return false; } } - diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/BasicConfiguration.java b/dspace-oai/src/main/java/org/dspace/xoai/app/BasicConfiguration.java index 7454b9490a..2edac1ce43 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/app/BasicConfiguration.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/app/BasicConfiguration.java @@ -7,16 +7,12 @@ */ package org.dspace.xoai.app; -import org.dspace.xoai.services.impl.DSpaceFieldResolver; -import org.dspace.xoai.services.impl.DSpaceHandleResolver; -import org.dspace.xoai.services.impl.DSpaceEarliestDateResolver; -import org.dspace.xoai.services.impl.DSpaceCollectionsService; -import org.dspace.xoai.services.api.EarliestDateResolver; -import org.dspace.xoai.services.api.CollectionsService; -import org.dspace.xoai.services.api.HandleResolver; -import org.dspace.xoai.services.api.FieldResolver; import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; import org.apache.log4j.Logger; +import org.dspace.xoai.services.api.CollectionsService; +import org.dspace.xoai.services.api.EarliestDateResolver; +import org.dspace.xoai.services.api.FieldResolver; +import org.dspace.xoai.services.api.HandleResolver; import org.dspace.xoai.services.api.cache.XOAICacheService; import org.dspace.xoai.services.api.cache.XOAIItemCacheService; import org.dspace.xoai.services.api.cache.XOAILastCompilationCacheService; @@ -30,6 +26,10 @@ import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver; import org.dspace.xoai.services.api.xoai.IdentifyResolver; import org.dspace.xoai.services.api.xoai.ItemRepositoryResolver; import org.dspace.xoai.services.api.xoai.SetRepositoryResolver; +import org.dspace.xoai.services.impl.DSpaceCollectionsService; +import org.dspace.xoai.services.impl.DSpaceEarliestDateResolver; +import org.dspace.xoai.services.impl.DSpaceFieldResolver; +import org.dspace.xoai.services.impl.DSpaceHandleResolver; import org.dspace.xoai.services.impl.cache.DSpaceEmptyCacheService; import org.dspace.xoai.services.impl.cache.DSpaceXOAICacheService; import org.dspace.xoai.services.impl.cache.DSpaceXOAIItemCacheService; @@ -63,7 +63,7 @@ public class BasicConfiguration { @Bean - public SolrServerResolver solrServerResolver () { + public SolrServerResolver solrServerResolver() { return new DSpaceSolrServerResolver(); } @@ -82,17 +82,18 @@ public class BasicConfiguration { log.error("Not able to start XOAI normal cache service.", e); return new DSpaceEmptyCacheService(); } - } else + } else { return new DSpaceEmptyCacheService(); + } } @Bean - public XOAILastCompilationCacheService xoaiLastCompilationCacheService () { + public XOAILastCompilationCacheService xoaiLastCompilationCacheService() { return new DSpaceXOAILastCompilationCacheService(); } @Bean - public XOAIItemCacheService xoaiItemCacheService () { + public XOAIItemCacheService xoaiItemCacheService() { return new DSpaceXOAIItemCacheService(); } @@ -103,47 +104,47 @@ public class BasicConfiguration { } @Bean - public FieldResolver databaseService () { + public FieldResolver databaseService() { return new DSpaceFieldResolver(); } @Bean - public EarliestDateResolver earliestDateResolver () { + public EarliestDateResolver earliestDateResolver() { return new DSpaceEarliestDateResolver(); } @Bean - public ItemRepositoryResolver itemRepositoryResolver () { + public ItemRepositoryResolver itemRepositoryResolver() { return new DSpaceItemRepositoryResolver(); } @Bean - public SetRepositoryResolver setRepositoryResolver () { + public SetRepositoryResolver setRepositoryResolver() { return new DSpaceSetRepositoryResolver(); } @Bean - public IdentifyResolver identifyResolver () { + public IdentifyResolver identifyResolver() { return new DSpaceIdentifyResolver(); } @Bean - public DSpaceFilterResolver dSpaceFilterResolver () { + public DSpaceFilterResolver dSpaceFilterResolver() { return new BaseDSpaceFilterResolver(); } @Bean - public HandleResolver handleResolver () { + public HandleResolver handleResolver() { return new DSpaceHandleResolver(); } @Bean - public CollectionsService collectionsService () { + public CollectionsService collectionsService() { return new DSpaceCollectionsService(); } @Bean - public SolrQueryResolver solrQueryResolver () { + public SolrQueryResolver solrQueryResolver() { return new DSpaceSolrQueryResolver(); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/DSpaceWebappConfiguration.java b/dspace-oai/src/main/java/org/dspace/xoai/app/DSpaceWebappConfiguration.java index 5f4cfecd21..8ad41abb65 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/app/DSpaceWebappConfiguration.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/app/DSpaceWebappConfiguration.java @@ -7,6 +7,8 @@ */ package org.dspace.xoai.app; +import static java.lang.Integer.MAX_VALUE; + import com.lyncode.jtwig.mvc.JtwigViewResolver; import org.dspace.xoai.services.api.xoai.ItemRepositoryResolver; import org.dspace.xoai.services.impl.xoai.DSpaceItemRepositoryResolver; @@ -20,10 +22,8 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; -import static java.lang.Integer.MAX_VALUE; - -@Import({ - BasicConfiguration.class +@Import( { + BasicConfiguration.class }) @Configuration @EnableWebMvc @@ -53,6 +53,7 @@ public class DSpaceWebappConfiguration extends WebMvcConfigurerAdapter { return viewResolver; } + @Bean public ItemRepositoryResolver xoaiItemRepositoryResolver() { return new DSpaceItemRepositoryResolver(); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java index f7c1cdca7e..aff9195264 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java @@ -7,6 +7,25 @@ */ package org.dspace.xoai.app; +import static com.lyncode.xoai.dataprovider.core.Granularity.Second; +import static org.dspace.xoai.util.ItemUtils.retrieveMetadata; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.sql.SQLException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +import javax.xml.stream.XMLStreamException; + import com.lyncode.xoai.dataprovider.exceptions.ConfigurationException; import com.lyncode.xoai.dataprovider.exceptions.MetadataBindException; import com.lyncode.xoai.dataprovider.exceptions.WritingXmlException; @@ -23,17 +42,21 @@ import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrInputDocument; +import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +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.Constants; import org.dspace.core.Context; -import org.dspace.core.Utils; -import org.dspace.handle.Handle; import org.dspace.xoai.exceptions.CompilingException; import org.dspace.xoai.services.api.CollectionsService; import org.dspace.xoai.services.api.cache.XOAICacheService; @@ -47,17 +70,6 @@ import org.dspace.xoai.solr.exceptions.DSpaceSolrIndexerException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import javax.xml.stream.XMLStreamException; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.ConnectException; -import java.sql.SQLException; -import java.text.ParseException; -import java.util.*; - -import static com.lyncode.xoai.dataprovider.core.Granularity.Second; -import static org.dspace.xoai.util.ItemUtils.retrieveMetadata; - /** * @author Lyncode Development Team (dspace at lyncode dot com) */ @@ -133,15 +145,16 @@ public class XOAI { result = this.indexAll(); } else { SolrQuery solrParams = new SolrQuery("*:*") - .addField("item.lastmodified") - .addSortField("item.lastmodified", ORDER.desc).setRows(1); + .addField("item.lastmodified") + .addSortField("item.lastmodified", ORDER.desc).setRows(1); SolrDocumentList results = DSpaceSolrSearch.query(solrServerResolver.getServer(), solrParams); if (results.getNumFound() == 0) { System.out.println("There are no indexed documents, using full import."); result = this.indexAll(); - } else + } else { result = this.index((Date) results.get(0).getFieldValue("item.lastmodified")); + } } solrServerResolver.getServer().commit(); @@ -163,51 +176,133 @@ public class XOAI { private int index(Date last) throws DSpaceSolrIndexerException { System.out - .println("Incremental import. Searching for documents modified after: " - + last.toString()); - // Index both in_archive items AND withdrawn items. Withdrawn items will be flagged withdrawn - // (in order to notify external OAI harvesters of their new status) + .println("Incremental import. Searching for documents modified after: " + + last.toString()); + /* + * Index all changed or new items or items whose visibility is viable to + * change due to an embargo. + */ try { - Iterator iterator = itemService.findInArchiveOrWithdrawnDiscoverableModifiedSince( - context, last); - return this.index(iterator); + Iterator discoverableChangedItems = itemService + .findInArchiveOrWithdrawnDiscoverableModifiedSince(context, last); + Iterator nonDiscoverableChangedItems = itemService + .findInArchiveOrWithdrawnNonDiscoverableModifiedSince(context, last); + Iterator possiblyChangedItems = getItemsWithPossibleChangesBefore(last); + return this.index(discoverableChangedItems) + this.index(nonDiscoverableChangedItems) + + this.index(possiblyChangedItems); } catch (SQLException ex) { throw new DSpaceSolrIndexerException(ex.getMessage(), ex); } } + /** + * Get all items already in the index which are viable to change visibility + * due to an embargo. Only consider those which haven't been modified + * anyways since the last update, so they aren't updated twice in one import + * run. + * + * @param last + * maximum date for an item to be considered for an update + * @return Iterator over list of items which might have changed their + * visibility since the last update. + * @throws DSpaceSolrIndexerException + */ + private Iterator getItemsWithPossibleChangesBefore(Date last) throws DSpaceSolrIndexerException { + try { + SolrQuery params = new SolrQuery("item.willChangeStatus:true").addField("item.id"); + SolrDocumentList documents = DSpaceSolrSearch.query(solrServerResolver.getServer(), params); + List items = new LinkedList(); + for (int i = 0; i < documents.getNumFound(); i++) { + Item item = itemService.find(context, + UUID.fromString((String) documents.get(i).getFieldValue("item.id"))); + if (item.getLastModified().before(last)) { + items.add(item); + } + } + return items.iterator(); + } catch (SolrServerException | SQLException | DSpaceSolrException ex) { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + } + private int indexAll() throws DSpaceSolrIndexerException { System.out.println("Full import"); try { - // Index both in_archive items AND withdrawn items. Withdrawn items will be flagged withdrawn + // Index both in_archive items AND withdrawn items. Withdrawn items + // will be flagged withdrawn // (in order to notify external OAI harvesters of their new status) - Iterator iterator = itemService.findInArchiveOrWithdrawnDiscoverableModifiedSince( - context, null); - return this.index(iterator); + Iterator discoverableItems = itemService.findInArchiveOrWithdrawnDiscoverableModifiedSince(context, + null); + Iterator nonDiscoverableItems = itemService + .findInArchiveOrWithdrawnNonDiscoverableModifiedSince(context, null); + return this.index(discoverableItems) + this.index(nonDiscoverableItems); } catch (SQLException ex) { throw new DSpaceSolrIndexerException(ex.getMessage(), ex); } } + /** + * Check if an item is already indexed. Using this, it is possible to check + * if withdrawn or nondiscoverable items have to be indexed at all. + * + * @param item + * Item that should be checked for its presence in the index. + * @return has it been indexed? + */ + private boolean checkIfIndexed(Item item) { + SolrQuery params = new SolrQuery("item.id:" + item.getID().toString()).addField("item.id"); + try { + SolrDocumentList documents = DSpaceSolrSearch.query(solrServerResolver.getServer(), params); + return documents.getNumFound() == 1; + } catch (DSpaceSolrException | SolrServerException e) { + return false; + } + } + /** + * Check if an item is flagged visible in the index. + * + * @param item + * Item that should be checked for its presence in the index. + * @return has it been indexed? + */ + private boolean checkIfVisibleInOAI(Item item) { + SolrQuery params = new SolrQuery("item.id:" + item.getID().toString()).addField("item.public"); + try { + SolrDocumentList documents = DSpaceSolrSearch.query(solrServerResolver.getServer(), params); + if (documents.getNumFound() == 1) { + return (boolean) documents.get(0).getFieldValue("item.public"); + } else { + return false; + } + } catch (DSpaceSolrException | SolrServerException e) { + return false; + } + } + private int index(Iterator iterator) - throws DSpaceSolrIndexerException { + throws DSpaceSolrIndexerException { try { int i = 0; SolrServer server = solrServerResolver.getServer(); while (iterator.hasNext()) { try { Item item = iterator.next(); - server.add(this.index(item)); - + if (item.getHandle() == null) { + log.warn("Skipped item without handle: " + item.getID()); + } else { + server.add(this.index(item)); + } //Uncache the item to keep memory consumption low context.uncacheEntity(item); } catch (SQLException | MetadataBindException | ParseException - | XMLStreamException | WritingXmlException ex) { + | XMLStreamException | WritingXmlException ex) { log.error(ex.getMessage(), ex); } i++; - if (i % 100 == 0) System.out.println(i + " items imported so far..."); + if (i % 100 == 0) { + System.out.println(i + " items imported so far..."); + } } System.out.println("Total: " + i + " items"); server.commit(); @@ -217,32 +312,112 @@ public class XOAI { } } - private SolrInputDocument index(Item item) throws SQLException, MetadataBindException, ParseException, XMLStreamException, WritingXmlException { + /** + * Method to get the most recent date on which the item changed concerning + * the OAI deleted status (policy start and end dates for all anonymous READ + * policies and the standard last modification date) + * + * @param item + * Item + * @return date + * @throws SQLException + */ + private Date getMostRecentModificationDate(Item item) throws SQLException { + List dates = new LinkedList(); + List policies = authorizeService.getPoliciesActionFilter(context, item, Constants.READ); + for (ResourcePolicy policy : policies) { + if (policy.getGroup().getName().equals("Anonymous")) { + if (policy.getStartDate() != null) { + dates.add(policy.getStartDate()); + } + if (policy.getEndDate() != null) { + dates.add(policy.getEndDate()); + } + } + } + dates.add(item.getLastModified()); + Collections.sort(dates); + Date now = new Date(); + Date lastChange = null; + for (Date d : dates) { + if (d.before(now)) { + lastChange = d; + } + } + return lastChange; + } + + private SolrInputDocument index(Item item) + throws SQLException, MetadataBindException, ParseException, XMLStreamException, WritingXmlException { SolrInputDocument doc = new SolrInputDocument(); doc.addField("item.id", item.getID()); - boolean pub = this.isPublic(item); - doc.addField("item.public", pub); + String handle = item.getHandle(); doc.addField("item.handle", handle); - doc.addField("item.lastmodified", item.getLastModified()); + + boolean isEmbargoed = !this.isPublic(item); + boolean isCurrentlyVisible = this.checkIfVisibleInOAI(item); + boolean isIndexed = this.checkIfIndexed(item); + + /* + * If the item is not under embargo, it should be visible. If it is, + * make it invisible if this is the first time it is indexed. For + * subsequent index runs, keep the current status, so that if the item + * is embargoed again, it is flagged as deleted instead and does not + * just disappear, or if it is still under embargo, it won't become + * visible and be known to harvesters as deleted before it gets + * disseminated for the first time. The item has to be indexed directly + * after publication even if it is still embargoed, because its + * lastModified date will not change when the embargo end date (or start + * date) is reached. To circumvent this, an item which will change its + * status in the future will be marked as such. + */ + + boolean isPublic = isEmbargoed ? (isIndexed ? isCurrentlyVisible : false) : true; + doc.addField("item.public", isPublic); + + // if the visibility of the item will change in the future due to an + // embargo, mark it as such. + + doc.addField("item.willChangeStatus", willChangeStatus(item)); + + /* + * Mark an item as deleted not only if it is withdrawn, but also if it + * is made private, because items should not simply disappear from OAI + * with a transient deletion policy. Do not set the flag for still + * invisible embargoed items, because this will override the item.public + * flag. + */ + + doc.addField("item.deleted", + (item.isWithdrawn() || !item.isDiscoverable() || (isEmbargoed ? isPublic : false))); + + /* + * An item that is embargoed will potentially not be harvested by + * incremental harvesters if the from and until params do not encompass + * both the standard lastModified date and the anonymous-READ resource + * policy start date. The same is true for the end date, where + * harvesters might not get a tombstone record. Therefore, consider all + * relevant policy dates and the standard lastModified date and take the + * most recent of those which have already passed. + */ + doc.addField("item.lastmodified", this.getMostRecentModificationDate(item)); + if (item.getSubmitter() != null) { doc.addField("item.submitter", item.getSubmitter().getEmail()); } - doc.addField("item.deleted", item.isWithdrawn() ? "true" : "false"); - for (Collection col : item.getCollections()) - doc.addField("item.collections", - "col_" + col.getHandle().replace("/", "_")); - for (Community com : collectionsService.flatParentCommunities(context, item)) - doc.addField("item.communities", - "com_" + com.getHandle().replace("/", "_")); - List allData = itemService.getMetadata(item, - Item.ANY, Item.ANY, Item.ANY, Item.ANY); + for (Collection col: item.getCollections()) { + doc.addField("item.collections", "col_" + col.getHandle().replace("/", "_")); + } + for (Community com : collectionsService.flatParentCommunities(context, item)) { + doc.addField("item.communities", "com_" + com.getHandle().replace("/", "_")); + } + + List allData = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); for (MetadataValue dc : allData) { MetadataField field = dc.getMetadataField(); - String key = "metadata." - + field.getMetadataSchema().getName() + "." - + field.getElement(); + String key = "metadata." + field.getMetadataSchema().getName() + "." + field.getElement(); if (field.getQualifier() != null) { key += "." + field.getQualifier(); } @@ -265,16 +440,33 @@ public class XOAI { doc.addField("item.compile", out.toString()); if (verbose) { - println("Item with handle " + handle + " indexed"); + println(String.format("Item %s with handle %s indexed", + item.getID().toString(), handle)); } return doc; } + private boolean willChangeStatus(Item item) throws SQLException { + List policies = authorizeService.getPoliciesActionFilter(context, item, Constants.READ); + for (ResourcePolicy policy : policies) { + if (policy.getGroup().getName().equals("Anonymous")) { + + if (policy.getStartDate() != null && policy.getStartDate().after(new Date())) { + return true; + } + if (policy.getEndDate() != null && policy.getEndDate().after(new Date())) { + return true; + } + } + } + return false; + } + private boolean isPublic(Item item) { boolean pub = false; try { - //Check if READ access allowed on this Item + // Check if READ access allowed on this Item pub = authorizeService.authorizeActionBoolean(context, item, Constants.READ); } catch (SQLException ex) { log.error(ex.getMessage()); @@ -286,8 +478,8 @@ public class XOAI { private static boolean getKnownExplanation(Throwable t) { if (t instanceof ConnectException) { System.err.println("Solr server (" - + ConfigurationManager.getProperty("oai", "solr.url") - + ") is down, turn it on."); + + ConfigurationManager.getProperty("oai", "solr.url") + + ") is down, turn it on."); return true; } @@ -295,10 +487,12 @@ public class XOAI { } private static boolean searchForReason(Throwable t) { - if (getKnownExplanation(t)) + if (getKnownExplanation(t)) { return true; - if (t.getCause() != null) + } + if (t.getCause() != null) { return searchForReason(t.getCause()); + } return false; } @@ -313,7 +507,8 @@ public class XOAI { } } - private static void cleanCache(XOAIItemCacheService xoaiItemCacheService, XOAICacheService xoaiCacheService) throws IOException { + private static void cleanCache(XOAIItemCacheService xoaiItemCacheService, XOAICacheService xoaiCacheService) + throws IOException { System.out.println("Purging cached OAI responses."); xoaiItemCacheService.deleteAll(); xoaiCacheService.deleteAll(); @@ -327,8 +522,8 @@ public class XOAI { public static void main(String[] argv) throws IOException, ConfigurationException { - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(new Class[]{ - BasicConfiguration.class + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(new Class[] { + BasicConfiguration.class }); ConfigurationService configurationService = applicationContext.getBean(ConfigurationService.class); @@ -342,7 +537,7 @@ public class XOAI { Options options = new Options(); options.addOption("c", "clear", false, "Clear index before indexing"); options.addOption("o", "optimize", false, - "Optimize index at the end"); + "Optimize index at the end"); options.addOption("v", "verbose", false, "Verbose output"); options.addOption("h", "help", false, "Shows some help"); options.addOption("n", "number", true, "FOR DEVELOPMENT MUST DELETE"); @@ -378,14 +573,16 @@ public class XOAI { if (COMMAND_IMPORT.equals(command)) { ctx = new Context(Context.Mode.READ_ONLY); XOAI indexer = new XOAI(ctx, - line.hasOption('o'), - line.hasOption('c'), - line.hasOption('v')); + line.hasOption('o'), + line.hasOption('c'), + line.hasOption('v')); applicationContext.getAutowireCapableBeanFactory().autowireBean(indexer); int imported = indexer.index(); - if (imported > 0) cleanCache(itemCacheService, cacheService); + if (imported > 0) { + cleanCache(itemCacheService, cacheService); + } } else if (COMMAND_CLEAN_CACHE.equals(command)) { cleanCache(itemCacheService, cacheService); } else if (COMMAND_COMPILE_ITEMS.equals(command)) { @@ -403,8 +600,8 @@ public class XOAI { } System.out.println("OAI 2.0 manager action ended. It took " - + ((System.currentTimeMillis() - start) / 1000) - + " seconds."); + + ((System.currentTimeMillis() - start) / 1000) + + " seconds."); } else { usage(); } @@ -413,12 +610,11 @@ public class XOAI { ex.printStackTrace(); } log.error(ex.getMessage(), ex); - } - finally - { + } finally { // Abort our context, if still open - if(ctx!=null && ctx.isValid()) + if (ctx != null && ctx.isValid()) { ctx.abort(); + } } } @@ -442,7 +638,9 @@ public class XOAI { while (iterator.hasNext()) { Item item = iterator.next(); - if (verbose) System.out.println("Compiling item with handle: " + item.getHandle()); + if (verbose) { + System.out.println("Compiling item with handle: " + item.getHandle()); + } xoaiItemCacheService.put(item, retrieveMetadata(context, item)); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java b/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java index 89c876306d..456785c1e4 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java @@ -7,6 +7,21 @@ */ package org.dspace.xoai.controller; +import static java.util.Arrays.asList; +import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; +import static org.apache.log4j.Logger.getLogger; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.stream.XMLStreamException; + import com.lyncode.xoai.dataprovider.OAIDataProvider; import com.lyncode.xoai.dataprovider.OAIRequestParameters; import com.lyncode.xoai.dataprovider.core.XOAIManager; @@ -30,41 +45,30 @@ import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.stream.XMLStreamException; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static java.util.Arrays.asList; -import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; -import static org.apache.log4j.Logger.getLogger; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ @Controller -public class DSpaceOAIDataProvider -{ +public class DSpaceOAIDataProvider { private static final Logger log = getLogger(DSpaceOAIDataProvider.class); - @Autowired XOAICacheService cacheService; - @Autowired ContextService contextService; - @Autowired XOAIManagerResolver xoaiManagerResolver; - @Autowired ItemRepositoryResolver itemRepositoryResolver; - @Autowired IdentifyResolver identifyResolver; - @Autowired SetRepositoryResolver setRepositoryResolver; + @Autowired + XOAICacheService cacheService; + @Autowired + ContextService contextService; + @Autowired + XOAIManagerResolver xoaiManagerResolver; + @Autowired + ItemRepositoryResolver itemRepositoryResolver; + @Autowired + IdentifyResolver identifyResolver; + @Autowired + SetRepositoryResolver setRepositoryResolver; private DSpaceResumptionTokenFormatter resumptionTokenFormat = new DSpaceResumptionTokenFormatter(); @RequestMapping("/") - public String indexAction (HttpServletResponse response, Model model) throws ServletException { + public String indexAction(HttpServletResponse response, Model model) throws ServletException { try { XOAIManager manager = xoaiManagerResolver.getManager(); model.addAttribute("contexts", manager.getContextManager().getContexts()); @@ -77,7 +81,8 @@ public class DSpaceOAIDataProvider } @RequestMapping("/{context}") - public String contextAction (Model model, HttpServletRequest request, HttpServletResponse response, @PathVariable("context") String xoaiContext) throws IOException, ServletException { + public String contextAction(Model model, HttpServletRequest request, HttpServletResponse response, + @PathVariable("context") String xoaiContext) throws IOException, ServletException { Context context = null; try { request.setCharacterEncoding("UTF-8"); @@ -86,25 +91,28 @@ public class DSpaceOAIDataProvider XOAIManager manager = xoaiManagerResolver.getManager(); OAIDataProvider dataProvider = new OAIDataProvider(manager, xoaiContext, - identifyResolver.getIdentify(), - setRepositoryResolver.getSetRepository(), - itemRepositoryResolver.getItemRepository(), - resumptionTokenFormat); + identifyResolver.getIdentify(), + setRepositoryResolver.getSetRepository(), + itemRepositoryResolver.getItemRepository(), + resumptionTokenFormat); OutputStream out = response.getOutputStream(); OAIRequestParameters parameters = new OAIRequestParameters(buildParametersMap(request)); - response.setContentType("application/xml"); + response.setContentType("text/xml"); response.setCharacterEncoding("UTF-8"); String identification = xoaiContext + parameters.requestID(); if (cacheService.isActive()) { - if (!cacheService.hasCache(identification)) + if (!cacheService.hasCache(identification)) { cacheService.store(identification, dataProvider.handle(parameters)); + } cacheService.handle(identification, out); - } else dataProvider.handle(parameters, out); + } else { + dataProvider.handle(parameters, out); + } out.flush(); @@ -119,24 +127,25 @@ public class DSpaceOAIDataProvider log.error(e.getMessage(), e); closeContext(context); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Unexpected error while writing the output. For more information visit the log files."); + "Unexpected error while writing the output. For more information visit the log files."); } catch (XOAIManagerResolverException e) { - throw new ServletException("OAI 2.0 wasn't correctly initialized, please check the log for previous errors", e); + throw new ServletException("OAI 2.0 wasn't correctly initialized, please check the log for previous errors", + e); } catch (OAIException e) { log.error(e.getMessage(), e); closeContext(context); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Unexpected error. For more information visit the log files."); + "Unexpected error. For more information visit the log files."); } catch (WritingXmlException e) { log.error(e.getMessage(), e); closeContext(context); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Unexpected error while writing the output. For more information visit the log files."); + "Unexpected error while writing the output. For more information visit the log files."); } catch (XMLStreamException e) { log.error(e.getMessage(), e); closeContext(context); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Unexpected error while writing the output. For more information visit the log files."); + "Unexpected error while writing the output. For more information visit the log files."); } finally { closeContext(context); } @@ -145,20 +154,21 @@ public class DSpaceOAIDataProvider } private void closeContext(Context context) { - if (context != null && context.isValid()) + if (context != null && context.isValid()) { context.abort(); + } } - private Map> buildParametersMap( - HttpServletRequest request) { - Map> map = new HashMap>(); - Enumeration names = request.getParameterNames(); - while (names.hasMoreElements()) { - String name = (String) names.nextElement(); - String[] values = request.getParameterValues(name); - map.put(name, asList(values)); - } - return map; - } + private Map> buildParametersMap( + HttpServletRequest request) { + Map> map = new HashMap>(); + Enumeration names = request.getParameterNames(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + String[] values = request.getParameterValues(name); + map.put(name, asList(values)); + } + return map; + } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceItem.java b/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceItem.java index 8536288740..267449be07 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceItem.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceItem.java @@ -7,6 +7,10 @@ */ package org.dspace.xoai.data; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; @@ -16,101 +20,108 @@ import com.lyncode.xoai.dataprovider.xml.xoai.Element; import com.lyncode.xoai.dataprovider.xml.xoai.Element.Field; import org.dspace.core.ConfigurationManager; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public abstract class DSpaceItem implements Item -{ - private static List filter (List input, String name) { - return Lists.newArrayList(Collections2.filter(input, new MetadataNamePredicate(name))); - } - - private static List flat (List input) { - List elems = new ArrayList(); - for (Element e : input) { - if (e.getElement() != null) { - elems.addAll(e.getElement()); - } - } - return elems; - } - - private static List values (List input) { - List elems = new ArrayList(); - for (Element e : input) - if (e.getElement() != null && !e.getElement().isEmpty() && e.getElement().get(0).getField() != null) - for (Field f : e.getElement().get(0).getField()) - if (f.getName() != null && f.getName().equals("value")) - elems.add(f.getValue()); - return elems; - } - - - private List getMetadata (String schema, String element) { - List metadata = this.getMetadata().getMetadata().getElement(); - return values(filter(flat(filter(metadata, schema)), element)); - } - - private List getMetadata (String schema, String element, String qualifier) { - List metadata = this.getMetadata().getMetadata().getElement(); - return values(filter(flat(filter(flat(filter(metadata, schema)), element)), qualifier)); +public abstract class DSpaceItem implements Item { + private static List filter(List input, String name) { + return Lists.newArrayList(Collections2.filter(input, new MetadataNamePredicate(name))); } - + private static List flat(List input) { + List elems = new ArrayList(); + for (Element e : input) { + if (e.getElement() != null) { + elems.addAll(e.getElement()); + } + } + return elems; + } + + private static List values(List input) { + List elems = new ArrayList(); + for (Element e : input) { + if (e.getElement() != null && !e.getElement().isEmpty() && e.getElement().get(0).getField() != null) { + for (Field f : e.getElement().get(0).getField()) { + if (f.getName() != null && f.getName().equals("value")) { + elems.add(f.getValue()); + } + } + } + } + return elems; + } + + + private List getMetadata(String schema, String element) { + List metadata = this.getMetadata().getMetadata().getElement(); + return values(filter(flat(filter(metadata, schema)), element)); + } + + private List getMetadata(String schema, String element, String qualifier) { + List metadata = this.getMetadata().getMetadata().getElement(); + return values(filter(flat(filter(flat(filter(metadata, schema)), element)), qualifier)); + } + + private static String _prefix = null; - public static String buildIdentifier (String handle) { - if (_prefix == null) - { + + public static String buildIdentifier(String handle) { + if (_prefix == null) { _prefix = ConfigurationManager.getProperty("oai", - "identifier.prefix"); + "identifier.prefix"); } return "oai:" + _prefix + ":" + handle; } - public static String parseHandle (String oaiIdentifier) { - String[] parts = oaiIdentifier.split(Pattern.quote(":")); - if (parts.length > 0) return parts[parts.length - 1]; - else return null; // Contract + + public static String parseHandle(String oaiIdentifier) { + String[] parts = oaiIdentifier.split(Pattern.quote(":")); + if (parts.length > 0) { + return parts[parts.length - 1]; + } else { + return null; // Contract + } } - - public List getMetadata(String field) - { + + public List getMetadata(String field) { String[] parts = field.split(Pattern.quote(".")); - if (parts.length == 2) return this.getMetadata(parts[0], parts[1]); - else if (parts.length == 3) return this.getMetadata(parts[0], parts[1], parts[2]); - else return new ArrayList(); + if (parts.length == 2) { + return this.getMetadata(parts[0], parts[1]); + } else if (parts.length == 3) { + return this.getMetadata(parts[0], parts[1], parts[2]); + } else { + return new ArrayList(); + } } - - @Override - public List getAbout() - { - return new ArrayList(); - } - - protected abstract String getHandle (); @Override - public String getIdentifier() - { - return buildIdentifier(getHandle()); + public List getAbout() { + return new ArrayList(); + } + + protected abstract String getHandle(); + + @Override + public String getIdentifier() { + return buildIdentifier(getHandle()); } private static class MetadataNamePredicate implements Predicate { private String name; - public MetadataNamePredicate (String n) { + public MetadataNamePredicate(String n) { name = n; } @Override public boolean apply(Element arg0) { - if (name == null) return false; - else if (name.equals(org.dspace.content.Item.ANY)) return true; - else return (name.toLowerCase().equals(arg0.getName().toLowerCase())); + if (name == null) { + return false; + } else if (name.equals(org.dspace.content.Item.ANY)) { + return true; + } else { + return (name.toLowerCase().equals(arg0.getName().toLowerCase())); + } } } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceSet.java b/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceSet.java index a193e707bb..b9f9f6a6f1 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceSet.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceSet.java @@ -7,38 +7,37 @@ */ package org.dspace.xoai.data; +import com.lyncode.xoai.dataprovider.core.Set; import org.dspace.content.Collection; import org.dspace.content.Community; -import com.lyncode.xoai.dataprovider.core.Set; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ public class DSpaceSet extends Set { - private static final String DefaultName = "undefined"; + private static final String DefaultName = "undefined"; - public static String checkName(String name) { - if (name != null && !name.trim().equals("")) - return name; - return DefaultName; - } + public static String checkName(String name) { + if (name != null && !name.trim().equals("")) { + return name; + } + return DefaultName; + } - public static Set newDSpaceCommunitySet(String handle, String name) { + public static Set newDSpaceCommunitySet(String handle, String name) { - return new Set("com_" + handle.replace('/', '_'), checkName(name)); - } + return new Set("com_" + handle.replace('/', '_'), checkName(name)); + } - public static Set newDSpaceCollectionSet(String handle, String name) { - return new Set("col_" + handle.replace('/', '_'), checkName(name)); - } + public static Set newDSpaceCollectionSet(String handle, String name) { + return new Set("col_" + handle.replace('/', '_'), checkName(name)); + } - public DSpaceSet(Community c) { - super("com_" + c.getHandle().replace('/', '_'), checkName(c.getName())); - } + public DSpaceSet(Community c) { + super("com_" + c.getHandle().replace('/', '_'), checkName(c.getName())); + } - public DSpaceSet(Collection c) { - super("col_" + c.getHandle().replace('/', '_'), checkName(c.getName())); - } + public DSpaceSet(Collection c) { + super("col_" + c.getHandle().replace('/', '_'), checkName(c.getName())); + } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceSolrItem.java b/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceSolrItem.java index 7f5fd52581..a9b5818f3d 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceSolrItem.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/data/DSpaceSolrItem.java @@ -8,26 +8,23 @@ package org.dspace.xoai.data; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.List; +import com.lyncode.xoai.dataprovider.core.ItemMetadata; +import com.lyncode.xoai.dataprovider.core.ReferenceSet; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.solr.common.SolrDocument; -import com.lyncode.xoai.dataprovider.core.ItemMetadata; -import com.lyncode.xoai.dataprovider.core.ReferenceSet; -import java.util.Collection; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DSpaceSolrItem extends DSpaceItem -{ +public class DSpaceSolrItem extends DSpaceItem { private static final Logger log = LogManager - .getLogger(DSpaceSolrItem.class); - + .getLogger(DSpaceSolrItem.class); + private final String unparsedMD; private ItemMetadata metadata; private final String handle; @@ -35,8 +32,8 @@ public class DSpaceSolrItem extends DSpaceItem private final List sets; private final boolean deleted; - public DSpaceSolrItem (SolrDocument doc) { - log.debug("Creating OAI Item from Solr source"); + public DSpaceSolrItem(SolrDocument doc) { + log.debug("Creating OAI Item from Solr source"); unparsedMD = (String) doc.getFieldValue("item.compile"); handle = (String) doc.getFieldValue("item.handle"); lastMod = (Date) doc.getFieldValue("item.lastmodified"); @@ -45,21 +42,24 @@ public class DSpaceSolrItem extends DSpaceItem Collection fieldValues; fieldValues = doc.getFieldValues("item.communities"); - if (null != fieldValues) - for (Object obj : fieldValues) + if (null != fieldValues) { + for (Object obj : fieldValues) { sets.add(new ReferenceSet((String) obj)); + } + } fieldValues = doc.getFieldValues("item.collections"); - if (null != fieldValues) - for (Object obj : fieldValues) + if (null != fieldValues) { + for (Object obj : fieldValues) { sets.add(new ReferenceSet((String) obj)); + } + } deleted = (Boolean) doc.getFieldValue("item.deleted"); } @Override - public ItemMetadata getMetadata() - { + public ItemMetadata getMetadata() { if (metadata == null) { metadata = new ItemMetadata(unparsedMD); } @@ -67,26 +67,22 @@ public class DSpaceSolrItem extends DSpaceItem } @Override - public Date getDatestamp() - { + public Date getDatestamp() { return lastMod; } @Override - public List getSets() - { + public List getSets() { return sets; } @Override - public boolean isDeleted() - { + public boolean isDeleted() { return deleted; } @Override - protected String getHandle() - { + protected String getHandle() { return handle; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/exceptions/CompilingException.java b/dspace-oai/src/main/java/org/dspace/xoai/exceptions/CompilingException.java index 96ff6a0bcd..b5857d96a3 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/exceptions/CompilingException.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/exceptions/CompilingException.java @@ -9,29 +9,23 @@ package org.dspace.xoai.exceptions; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ @SuppressWarnings("serial") -public class CompilingException extends Exception -{ +public class CompilingException extends Exception { - public CompilingException() - { + public CompilingException() { } - public CompilingException(String arg0) - { + public CompilingException(String arg0) { super(arg0); } - public CompilingException(Throwable arg0) - { + public CompilingException(Throwable arg0) { super(arg0); } - public CompilingException(String arg0, Throwable arg1) - { + public CompilingException(String arg0, Throwable arg1) { super(arg0, arg1); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/exceptions/InvalidMetadataFieldException.java b/dspace-oai/src/main/java/org/dspace/xoai/exceptions/InvalidMetadataFieldException.java index 4dadc2d3d9..6d11f14505 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/exceptions/InvalidMetadataFieldException.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/exceptions/InvalidMetadataFieldException.java @@ -8,11 +8,9 @@ package org.dspace.xoai.exceptions; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class InvalidMetadataFieldException extends Exception -{ +public class InvalidMetadataFieldException extends Exception { private static final long serialVersionUID = 5187555092904394914L; diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/AndFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/AndFilter.java index 32486b73ce..e57aa6b6ef 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/AndFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/AndFilter.java @@ -22,7 +22,8 @@ public class AndFilter extends DSpaceFilter { @Override public SolrFilterResult buildSolrQuery() { - return new SolrFilterResult("("+left.buildSolrQuery().getQuery()+") AND ("+right.buildSolrQuery().getQuery()+")"); + return new SolrFilterResult( + "(" + left.buildSolrQuery().getQuery() + ") AND (" + right.buildSolrQuery().getQuery() + ")"); } @Override diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceAtLeastOneMetadataFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceAtLeastOneMetadataFilter.java index 9b0aabd378..b84868cf23 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceAtLeastOneMetadataFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceAtLeastOneMetadataFilter.java @@ -11,6 +11,11 @@ package org.dspace.xoai.filter; import java.util.ArrayList; import java.util.List; +import com.google.common.base.Function; +import com.lyncode.builder.ListBuilder; +import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.ParameterList; +import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.ParameterValue; +import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.SimpleType; import org.apache.commons.lang.StringUtils; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; @@ -19,12 +24,6 @@ import org.dspace.xoai.data.DSpaceItem; import org.dspace.xoai.filter.data.DSpaceMetadataFilterOperator; import org.dspace.xoai.filter.results.SolrFilterResult; -import com.google.common.base.Function; -import com.lyncode.builder.ListBuilder; -import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.ParameterList; -import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.ParameterValue; -import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.SimpleType; - /** * @author Lyncode Development Team (dspace at lyncode dot com) */ @@ -45,72 +44,87 @@ public class DSpaceAtLeastOneMetadataFilter extends DSpaceFilter { private List getValues() { if (values == null) { ParameterValue parameterValue = getConfiguration().get("value"); - if (parameterValue == null) parameterValue = getConfiguration().get("values"); + if (parameterValue == null) { + parameterValue = getConfiguration().get("values"); + } if (parameterValue instanceof SimpleType) { values = new ArrayList<>(); values.add(((SimpleType) parameterValue).asString()); } else if (parameterValue instanceof ParameterList) { values = new ListBuilder() - .add(parameterValue.asParameterList().getValues()) - .build(new Function() { - @Override - public String apply(ParameterValue elem) { - return elem.asSimpleType().asString(); - } - }); - } else values = new ArrayList<>(); + .add(parameterValue.asParameterList().getValues()) + .build(new Function() { + @Override + public String apply(ParameterValue elem) { + return elem.asSimpleType().asString(); + } + }); + } else { + values = new ArrayList<>(); + } } return values; } private DSpaceMetadataFilterOperator getOperator() { - if (operator == DSpaceMetadataFilterOperator.UNDEF) + if (operator == DSpaceMetadataFilterOperator.UNDEF) { operator = DSpaceMetadataFilterOperator.valueOf(getConfiguration() - .get("operator").asSimpleType().asString().toUpperCase()); + .get("operator").asSimpleType().asString() + .toUpperCase()); + } return operator; } @Override public boolean isShown(DSpaceItem item) { - if (this.getField() == null) + if (this.getField() == null) { return true; + } List values = item.getMetadata(this.getField()); for (String praticalValue : values) { for (String theoreticValue : this.getValues()) { switch (this.getOperator()) { case STARTS_WITH: - if (praticalValue.startsWith(theoreticValue)) + if (praticalValue.startsWith(theoreticValue)) { return true; + } break; case ENDS_WITH: - if (praticalValue.endsWith(theoreticValue)) + if (praticalValue.endsWith(theoreticValue)) { return true; + } break; case EQUAL: - if (praticalValue.equals(theoreticValue)) + if (praticalValue.equals(theoreticValue)) { return true; + } break; case GREATER: - if (praticalValue.compareTo(theoreticValue) > 0) + if (praticalValue.compareTo(theoreticValue) > 0) { return true; + } break; case GREATER_OR_EQUAL: - if (praticalValue.compareTo(theoreticValue) >= 0) + if (praticalValue.compareTo(theoreticValue) >= 0) { return true; + } break; case LOWER: - if (praticalValue.compareTo(theoreticValue) < 0) + if (praticalValue.compareTo(theoreticValue) < 0) { return true; + } break; case LOWER_OR_EQUAL: - if (praticalValue.compareTo(theoreticValue) <= 0) + if (praticalValue.compareTo(theoreticValue) <= 0) { return true; + } break; case CONTAINS: default: - if (praticalValue.contains(theoreticValue)) + if (praticalValue.contains(theoreticValue)) { return true; + } break; } } @@ -123,12 +137,13 @@ public class DSpaceAtLeastOneMetadataFilter extends DSpaceFilter { String field = this.getField(); List parts = new ArrayList<>(); if (this.getField() != null) { - for (String v : this.getValues()) + for (String v : this.getValues()) { this.buildQuery("metadata." + field, - ClientUtils.escapeQueryChars(v), parts); + ClientUtils.escapeQueryChars(v), parts); + } if (parts.size() > 0) { return new SolrFilterResult(StringUtils.join(parts.iterator(), - " OR ")); + " OR ")); } } return new SolrFilterResult(); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceAuthorizationFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceAuthorizationFilter.java index 25996aaaaa..5b6bd3d1b4 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceAuthorizationFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceAuthorizationFilter.java @@ -22,46 +22,41 @@ import org.dspace.xoai.data.DSpaceItem; import org.dspace.xoai.filter.results.SolrFilterResult; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DSpaceAuthorizationFilter extends DSpaceFilter -{ +public class DSpaceAuthorizationFilter extends DSpaceFilter { private static final Logger log = LogManager.getLogger(DSpaceAuthorizationFilter.class); private static final AuthorizeService authorizeService - = AuthorizeServiceFactory.getInstance().getAuthorizeService(); + = AuthorizeServiceFactory.getInstance().getAuthorizeService(); private static final HandleService handleService - = HandleServiceFactory.getInstance().getHandleService(); + = HandleServiceFactory.getInstance().getHandleService(); @Override - public boolean isShown(DSpaceItem item) - { + public boolean isShown(DSpaceItem item) { boolean pub = false; - try - { + try { // If Handle or Item are not found, return false String handle = DSpaceItem.parseHandle(item.getIdentifier()); - if (handle == null) + if (handle == null) { return false; + } Item dspaceItem = (Item) handleService.resolveToObject(context, handle); - if (dspaceItem == null) + if (dspaceItem == null) { return false; + } // Check if READ access allowed on Item pub = authorizeService.authorizeActionBoolean(context, dspaceItem, Constants.READ); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error(ex.getMessage(), ex); } return pub; } @Override - public SolrFilterResult buildSolrQuery() - { + public SolrFilterResult buildSolrQuery() { return new SolrFilterResult("item.public:true"); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceFilter.java index 8a3694bbf5..2ea29bae7d 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceFilter.java @@ -10,35 +10,37 @@ package org.dspace.xoai.filter; import com.lyncode.xoai.dataprovider.data.Filter; import com.lyncode.xoai.dataprovider.data.ItemIdentifier; import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.ParameterMap; - import org.dspace.core.Context; import org.dspace.xoai.data.DSpaceItem; import org.dspace.xoai.filter.results.SolrFilterResult; import org.dspace.xoai.services.api.FieldResolver; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public abstract class DSpaceFilter implements Filter -{ - /** The configuration from xoai.xml file */ +public abstract class DSpaceFilter implements Filter { + /** + * The configuration from xoai.xml file + */ protected ParameterMap configuration; - /** The configuration from xoai.xml file */ + /** + * The configuration from xoai.xml file + */ protected FieldResolver fieldResolver; - /** The oai context */ + /** + * The oai context + */ protected Context context; public abstract SolrFilterResult buildSolrQuery(); + public abstract boolean isShown(DSpaceItem item); @Override - public boolean isItemShown(ItemIdentifier item) - { - if (item instanceof DSpaceItem) - { + public boolean isItemShown(ItemIdentifier item) { + if (item instanceof DSpaceItem) { return isShown((DSpaceItem) item); } return false; @@ -47,51 +49,42 @@ public abstract class DSpaceFilter implements Filter /** * @return the configuration map if defined in xoai.xml, otherwise null. */ - public ParameterMap getConfiguration() - { + public ParameterMap getConfiguration() { return configuration; } /** - * @param configuration - * the configuration map to set + * @param configuration the configuration map to set */ - public void setConfiguration(ParameterMap configuration) - { + public void setConfiguration(ParameterMap configuration) { this.configuration = configuration; } /** * @return the fieldResolver */ - public FieldResolver getFieldResolver() - { + public FieldResolver getFieldResolver() { return fieldResolver; } /** - * @param fieldResolver - * the fieldResolver to set + * @param fieldResolver the fieldResolver to set */ - public void setFieldResolver(FieldResolver fieldResolver) - { + public void setFieldResolver(FieldResolver fieldResolver) { this.fieldResolver = fieldResolver; } /** * @return the context */ - public Context getContext() - { + public Context getContext() { return context; } /** - * @param context - * the context to set + * @param context the context to set */ - public void setContext(Context context) - { + public void setContext(Context context) { this.context = context; } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceMetadataExistsFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceMetadataExistsFilter.java index 45989cc8bd..bad0c4975a 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceMetadataExistsFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceMetadataExistsFilter.java @@ -10,14 +10,13 @@ package org.dspace.xoai.filter; import java.util.ArrayList; import java.util.List; +import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.ParameterValue; +import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.SimpleType; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.dspace.xoai.data.DSpaceItem; import org.dspace.xoai.filter.results.SolrFilterResult; -import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.ParameterValue; -import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.SimpleType; - /** * This filter allows one to retrieve (from the data source) those items * which contains at least one metadata field value defined, it allows @@ -30,22 +29,25 @@ import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.SimpleType; */ public class DSpaceMetadataExistsFilter extends DSpaceFilter { private static final Logger log = LogManager - .getLogger(DSpaceMetadataExistsFilter.class); + .getLogger(DSpaceMetadataExistsFilter.class); private List fields; private List getFields() { if (this.fields == null) { ParameterValue fields = getConfiguration().get("fields"); - if (fields == null) fields = getConfiguration().get("field"); + if (fields == null) { + fields = getConfiguration().get("field"); + } if (fields instanceof SimpleType) { this.fields = new ArrayList(); this.fields.add(((SimpleType) fields).asString()); } else { this.fields = new ArrayList(); - for (ParameterValue val : fields.asParameterList().getValues()) + for (ParameterValue val : fields.asParameterList().getValues()) { this.fields.add(val.asSimpleType().asString()); + } } } @@ -56,8 +58,9 @@ public class DSpaceMetadataExistsFilter extends DSpaceFilter { public boolean isShown(DSpaceItem item) { for (String field : this.getFields()) { //do we have a match? if yes, our job is done - if (item.getMetadata(field).size() > 0) + if (item.getMetadata(field).size() > 0) { return true; + } } return false; } @@ -68,8 +71,9 @@ public class DSpaceMetadataExistsFilter extends DSpaceFilter { List fields = this.getFields(); for (int i = 0; i < fields.size(); i++) { cond.append("metadata.").append(fields.get(i)).append(":[* TO *]"); - if (i < fields.size() - 1) + if (i < fields.size() - 1) { cond.append(" OR "); + } } cond.append(")"); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceSetSpecFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceSetSpecFilter.java index 46faff78d5..502653a39c 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceSetSpecFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceSetSpecFilter.java @@ -18,57 +18,45 @@ import org.dspace.xoai.services.api.HandleResolver; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DSpaceSetSpecFilter extends DSpaceFilter -{ +public class DSpaceSetSpecFilter extends DSpaceFilter { private static final Logger log = LogManager.getLogger(DSpaceSetSpecFilter.class); private final String setSpec; private final HandleResolver handleResolver; private final CollectionsService collectionsService; - public DSpaceSetSpecFilter(CollectionsService collectionsService, HandleResolver handleResolver, String spec) - { + public DSpaceSetSpecFilter(CollectionsService collectionsService, HandleResolver handleResolver, String spec) { this.collectionsService = collectionsService; this.handleResolver = handleResolver; this.setSpec = spec; } @Override - public boolean isShown(DSpaceItem item) - { - for (ReferenceSet s : item.getSets()) - if (s.getSetSpec().equals(setSpec)) + public boolean isShown(DSpaceItem item) { + for (ReferenceSet s : item.getSets()) { + if (s.getSetSpec().equals(setSpec)) { return true; + } + } return false; } @Override - public SolrFilterResult buildSolrQuery() - { - if (setSpec.startsWith("col_")) - { - try - { + public SolrFilterResult buildSolrQuery() { + if (setSpec.startsWith("col_")) { + try { return new SolrFilterResult("item.collections:" - + ClientUtils.escapeQueryChars(setSpec)); - } - catch (Exception ex) - { + + ClientUtils.escapeQueryChars(setSpec)); + } catch (Exception ex) { log.error(ex.getMessage(), ex); } - } - else if (setSpec.startsWith("com_")) - { - try - { + } else if (setSpec.startsWith("com_")) { + try { return new SolrFilterResult("item.communities:" - + ClientUtils.escapeQueryChars(setSpec)); - } - catch (Exception e) - { + + ClientUtils.escapeQueryChars(setSpec)); + } catch (Exception e) { log.error(e.getMessage(), e); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceWithdrawnFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceWithdrawnFilter.java index 75b9c8b1a7..9a5b309b6b 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceWithdrawnFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/DSpaceWithdrawnFilter.java @@ -18,14 +18,13 @@ import org.dspace.xoai.filter.results.SolrFilterResult; * http://www.openarchives.org/OAI/openarchivesprotocol.html#deletion *

    * (Don't worry, a tombstone doesn't display the withdrawn item's metadata or files.) - * + * * @author Tim Donohue */ public class DSpaceWithdrawnFilter extends DSpaceFilter { @Override - public boolean isShown(DSpaceItem item) - { + public boolean isShown(DSpaceItem item) { // For DSpace, if an Item is withdrawn, "isDeleted()" will be true. // In this scenario, we want a withdrawn item to be *shown* so that // we can properly respond with a "deleted" status via OAI-PMH. @@ -35,8 +34,7 @@ public class DSpaceWithdrawnFilter extends DSpaceFilter { } @Override - public SolrFilterResult buildSolrQuery() - { + public SolrFilterResult buildSolrQuery() { // In Solr, we store withdrawn items as "deleted". // See org.dspace.xoai.app.XOAI, index(Item) method. return new SolrFilterResult("item.deleted:true"); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/DateFromFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/DateFromFilter.java index 0c2a0f466a..57716d12ea 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/DateFromFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/DateFromFilter.java @@ -7,6 +7,8 @@ */ package org.dspace.xoai.filter; +import java.util.Date; + import com.lyncode.builder.DateBuilder; import com.lyncode.xoai.dataprovider.services.api.DateProvider; import com.lyncode.xoai.dataprovider.services.impl.BaseDateProvider; @@ -14,36 +16,31 @@ import org.apache.solr.client.solrj.util.ClientUtils; import org.dspace.xoai.data.DSpaceItem; import org.dspace.xoai.filter.results.SolrFilterResult; -import java.util.Date; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ public class DateFromFilter extends DSpaceFilter { private static final DateProvider dateProvider = new BaseDateProvider(); private final Date date; - public DateFromFilter(Date date) - { + public DateFromFilter(Date date) { this.date = new DateBuilder(date).setMinMilliseconds().build(); } @Override - public boolean isShown(DSpaceItem item) - { - if (item.getDatestamp().compareTo(date) >= 0) + public boolean isShown(DSpaceItem item) { + if (item.getDatestamp().compareTo(date) >= 0) { return true; + } return false; } @Override - public SolrFilterResult buildSolrQuery() - { + public SolrFilterResult buildSolrQuery() { String format = dateProvider.format(date).replace("Z", ".000Z"); // Tweak to set the milliseconds return new SolrFilterResult("item.lastmodified:[" - + ClientUtils.escapeQueryChars(format) - + " TO *]"); + + ClientUtils.escapeQueryChars(format) + + " TO *]"); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/DateUntilFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/DateUntilFilter.java index cd564e044d..3735cbfc7f 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/DateUntilFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/DateUntilFilter.java @@ -7,6 +7,8 @@ */ package org.dspace.xoai.filter; +import java.util.Date; + import com.lyncode.builder.DateBuilder; import com.lyncode.xoai.dataprovider.services.api.DateProvider; import com.lyncode.xoai.dataprovider.services.impl.BaseDateProvider; @@ -14,41 +16,34 @@ import org.apache.solr.client.solrj.util.ClientUtils; import org.dspace.xoai.data.DSpaceItem; import org.dspace.xoai.filter.results.SolrFilterResult; -import java.util.Date; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DateUntilFilter extends DSpaceFilter -{ +public class DateUntilFilter extends DSpaceFilter { private static final DateProvider dateProvider = new BaseDateProvider(); private final Date date; - public DateUntilFilter(Date date) - { + public DateUntilFilter(Date date) { this.date = new DateBuilder(date).setMaxMilliseconds().build(); } @Override - public boolean isShown(DSpaceItem item) - { - if (item.getDatestamp().compareTo(date) <= 0) + public boolean isShown(DSpaceItem item) { + if (item.getDatestamp().compareTo(date) <= 0) { return true; + } return false; } @Override - public SolrFilterResult buildSolrQuery() - { + public SolrFilterResult buildSolrQuery() { String format = dateProvider.format(date).replace("Z", ".999Z"); // Tweak to set the milliseconds // if date has timestamp of 00:00:00, switch it to refer to end of day - if (format.substring(11, 19).equals("00:00:00")) - { + if (format.substring(11, 19).equals("00:00:00")) { format = format.substring(0, 11) + "23:59:59" + format.substring(19); } return new SolrFilterResult("item.lastmodified:[* TO " - + ClientUtils.escapeQueryChars(format) + "]"); + + ClientUtils.escapeQueryChars(format) + "]"); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/OrFilter.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/OrFilter.java index c9dcf1a376..e479f93c5f 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/OrFilter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/OrFilter.java @@ -22,7 +22,8 @@ public class OrFilter extends DSpaceFilter { @Override public SolrFilterResult buildSolrQuery() { - return new SolrFilterResult("("+left.buildSolrQuery().getQuery()+") OR ("+right.buildSolrQuery().getQuery()+")"); + return new SolrFilterResult( + "(" + left.buildSolrQuery().getQuery() + ") OR (" + right.buildSolrQuery().getQuery() + ")"); } @Override diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/SolrFilterResult.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/SolrFilterResult.java index 386d5fb971..37aa1b1c13 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/SolrFilterResult.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/SolrFilterResult.java @@ -11,35 +11,29 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class SolrFilterResult -{ - private static Logger log = LogManager.getLogger(SolrFilterResult.class); +public class SolrFilterResult { + private static Logger log = LogManager.getLogger(SolrFilterResult.class); private String _where; private boolean _nothing; - public SolrFilterResult() - { + public SolrFilterResult() { _nothing = true; } - public SolrFilterResult(String query) - { - log.debug("XOAI SolrQuery: "+ query); + public SolrFilterResult(String query) { + log.debug("XOAI SolrQuery: " + query); _nothing = false; _where = query; } - public boolean hasResult() - { + public boolean hasResult() { return !_nothing; } - public String getQuery() - { + public String getQuery() { return _where; } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/data/DSpaceMetadataFilterOperator.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/data/DSpaceMetadataFilterOperator.java index 36876c4a99..6f32dbf2d9 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/data/DSpaceMetadataFilterOperator.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/data/DSpaceMetadataFilterOperator.java @@ -9,7 +9,6 @@ package org.dspace.xoai.filter.data; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ public enum DSpaceMetadataFilterOperator { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/filter/results/SolrFilterResult.java b/dspace-oai/src/main/java/org/dspace/xoai/filter/results/SolrFilterResult.java index 63211ecf5c..38d0716950 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/filter/results/SolrFilterResult.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/filter/results/SolrFilterResult.java @@ -11,35 +11,29 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class SolrFilterResult -{ - private static Logger log = LogManager.getLogger(SolrFilterResult.class); +public class SolrFilterResult { + private static Logger log = LogManager.getLogger(SolrFilterResult.class); private String _where; private boolean _nothing; - public SolrFilterResult() - { + public SolrFilterResult() { _nothing = true; } - public SolrFilterResult(String query) - { - log.debug("XOAI SolrQuery: "+ query); + public SolrFilterResult(String query) { + log.debug("XOAI SolrQuery: " + query); _nothing = false; _where = query; } - public boolean hasResult() - { + public boolean hasResult() { return !_nothing; } - public String getQuery() - { + public String getQuery() { return _where; } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/CollectionsService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/CollectionsService.java index 50b593443c..c76de9f9cd 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/CollectionsService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/CollectionsService.java @@ -7,19 +7,22 @@ */ package org.dspace.xoai.services.api; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.core.Context; import org.dspace.xoai.services.api.context.ContextService; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; - public interface CollectionsService { List getAllSubCollections(ContextService contextService, UUID communityId) throws SQLException; + List flatParentCommunities(Collection collection) throws SQLException; + List flatParentCommunities(Community community) throws SQLException; + List flatParentCommunities(Context context, Item item) throws SQLException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/EarliestDateResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/EarliestDateResolver.java index b3d5eadeb4..d973cc6208 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/EarliestDateResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/EarliestDateResolver.java @@ -7,12 +7,12 @@ */ package org.dspace.xoai.services.api; -import org.dspace.core.Context; -import org.dspace.xoai.exceptions.InvalidMetadataFieldException; - import java.sql.SQLException; import java.util.Date; +import org.dspace.core.Context; +import org.dspace.xoai.exceptions.InvalidMetadataFieldException; + public interface EarliestDateResolver { - public Date getEarliestDate (Context context) throws InvalidMetadataFieldException, SQLException; + public Date getEarliestDate(Context context) throws InvalidMetadataFieldException, SQLException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/FieldResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/FieldResolver.java index d8599cbd57..664c67e64f 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/FieldResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/FieldResolver.java @@ -7,11 +7,11 @@ */ package org.dspace.xoai.services.api; +import java.sql.SQLException; + import org.dspace.core.Context; import org.dspace.xoai.exceptions.InvalidMetadataFieldException; -import java.sql.SQLException; - public interface FieldResolver { int getFieldID(Context context, String field) throws InvalidMetadataFieldException, SQLException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/HandleResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/HandleResolver.java index 02e0537f1a..4c9cba3220 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/HandleResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/HandleResolver.java @@ -10,6 +10,7 @@ package org.dspace.xoai.services.api; import org.dspace.content.DSpaceObject; public interface HandleResolver { - DSpaceObject resolve (String handle) throws HandleResolverException; - String getHandle (DSpaceObject object) throws HandleResolverException; + DSpaceObject resolve(String handle) throws HandleResolverException; + + String getHandle(DSpaceObject object) throws HandleResolverException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/ServiceResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/ServiceResolver.java index 9551004ca5..f315f86823 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/ServiceResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/ServiceResolver.java @@ -8,5 +8,5 @@ package org.dspace.xoai.services.api; public interface ServiceResolver { - T getService (Class type); + T getService(Class type); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAICacheService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAICacheService.java index 337d183327..17a7a23e6c 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAICacheService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAICacheService.java @@ -7,17 +7,22 @@ */ package org.dspace.xoai.services.api.cache; -import com.lyncode.xoai.dataprovider.xml.oaipmh.OAIPMH; - import java.io.IOException; import java.io.OutputStream; +import com.lyncode.xoai.dataprovider.xml.oaipmh.OAIPMH; + public interface XOAICacheService { - boolean isActive (); - boolean hasCache (String requestID); - void handle (String requestID, OutputStream out) throws IOException; - void store (String requestID, OAIPMH response) throws IOException; - void delete (String requestID); - void deleteAll () throws IOException; + boolean isActive(); + + boolean hasCache(String requestID); + + void handle(String requestID, OutputStream out) throws IOException; + + void store(String requestID, OAIPMH response) throws IOException; + + void delete(String requestID); + + void deleteAll() throws IOException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAIItemCacheService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAIItemCacheService.java index 7644e91565..8f25d5abef 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAIItemCacheService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAIItemCacheService.java @@ -7,16 +7,20 @@ */ package org.dspace.xoai.services.api.cache; +import java.io.IOException; + import com.lyncode.xoai.dataprovider.xml.xoai.Metadata; import org.dspace.content.Item; -import java.io.IOException; - public interface XOAIItemCacheService { - boolean hasCache (Item item); - Metadata get (Item item) throws IOException; - void put (Item item, Metadata metadata) throws IOException; - void delete (Item item); + boolean hasCache(Item item); + + Metadata get(Item item) throws IOException; + + void put(Item item, Metadata metadata) throws IOException; + + void delete(Item item); + void deleteAll() throws IOException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAILastCompilationCacheService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAILastCompilationCacheService.java index 33ac9523d7..d64b10ff5c 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAILastCompilationCacheService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/cache/XOAILastCompilationCacheService.java @@ -12,7 +12,9 @@ import java.util.Date; public interface XOAILastCompilationCacheService { - boolean hasCache (); - void put (Date date) throws IOException; - Date get () throws IOException; + boolean hasCache(); + + void put(Date date) throws IOException; + + Date get() throws IOException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/ConfigurationService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/ConfigurationService.java index 178cbdafcf..30a09e5c62 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/ConfigurationService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/ConfigurationService.java @@ -8,7 +8,9 @@ package org.dspace.xoai.services.api.config; public interface ConfigurationService { - String getProperty (String key); - String getProperty (String module, String key); + String getProperty(String key); + + String getProperty(String module, String key); + boolean getBooleanProperty(String module, String key, boolean defaultValue); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/XOAIManagerResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/XOAIManagerResolver.java index 7268fd1338..40be4dd0ef 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/XOAIManagerResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/XOAIManagerResolver.java @@ -10,5 +10,5 @@ package org.dspace.xoai.services.api.config; import com.lyncode.xoai.dataprovider.core.XOAIManager; public interface XOAIManagerResolver { - XOAIManager getManager () throws XOAIManagerResolverException; + XOAIManager getManager() throws XOAIManagerResolverException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/XOAIManagerResolverException.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/XOAIManagerResolverException.java index a4a0e6d160..f8e96c8138 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/XOAIManagerResolverException.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/config/XOAIManagerResolverException.java @@ -8,7 +8,8 @@ package org.dspace.xoai.services.api.config; public class XOAIManagerResolverException extends Exception { - public XOAIManagerResolverException() {} + public XOAIManagerResolverException() { + } public XOAIManagerResolverException(String message) { super(message); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/set/SetSpecResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/set/SetSpecResolver.java index 97f68fcc11..4a92b2e5fc 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/set/SetSpecResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/set/SetSpecResolver.java @@ -14,7 +14,9 @@ import org.dspace.content.DSpaceObject; import org.dspace.xoai.exceptions.InvalidSetSpecException; public interface SetSpecResolver { - String toSetSpec (Community community) throws InvalidSetSpecException; - String toSetSpec (Collection collection) throws InvalidSetSpecException; - DSpaceObject fromSetSpec (String setSpec) throws InvalidSetSpecException; + String toSetSpec(Community community) throws InvalidSetSpecException; + + String toSetSpec(Collection collection) throws InvalidSetSpecException; + + DSpaceObject fromSetSpec(String setSpec) throws InvalidSetSpecException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/solr/SolrQueryResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/solr/SolrQueryResolver.java index 50050a5c6d..c0b40265aa 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/solr/SolrQueryResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/solr/SolrQueryResolver.java @@ -7,10 +7,10 @@ */ package org.dspace.xoai.services.api.solr; -import com.lyncode.xoai.dataprovider.filter.ScopedFilter; - import java.util.List; +import com.lyncode.xoai.dataprovider.filter.ScopedFilter; + public interface SolrQueryResolver { - String buildQuery (List filters); + String buildQuery(List filters); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/solr/SolrServerResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/solr/SolrServerResolver.java index 0d4365ed82..cbb2fcd639 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/solr/SolrServerResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/solr/SolrServerResolver.java @@ -11,5 +11,5 @@ import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServerException; public interface SolrServerResolver { - SolrServer getServer () throws SolrServerException; + SolrServer getServer() throws SolrServerException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/DSpaceFilterResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/DSpaceFilterResolver.java index 526e439683..fe779bca1b 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/DSpaceFilterResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/DSpaceFilterResolver.java @@ -7,7 +7,6 @@ */ package org.dspace.xoai.services.api.xoai; - import com.lyncode.xoai.dataprovider.filter.Scope; import com.lyncode.xoai.dataprovider.filter.conditions.Condition; import com.lyncode.xoai.dataprovider.services.api.FilterResolver; diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/ItemRepositoryResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/ItemRepositoryResolver.java index 5f73e48956..0da90ea437 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/ItemRepositoryResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/ItemRepositoryResolver.java @@ -11,5 +11,5 @@ import com.lyncode.xoai.dataprovider.services.api.ItemRepository; import org.dspace.xoai.services.api.context.ContextServiceException; public interface ItemRepositoryResolver { - ItemRepository getItemRepository () throws ContextServiceException; + ItemRepository getItemRepository() throws ContextServiceException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/SetRepositoryResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/SetRepositoryResolver.java index f2ddf6aded..7530f3340d 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/SetRepositoryResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/api/xoai/SetRepositoryResolver.java @@ -11,5 +11,5 @@ import com.lyncode.xoai.dataprovider.services.api.SetRepository; import org.dspace.xoai.services.api.context.ContextServiceException; public interface SetRepositoryResolver { - SetRepository getSetRepository () throws ContextServiceException; + SetRepository getSetRepository() throws ContextServiceException; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceCollectionsService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceCollectionsService.java index 182ad1ec50..1dc1bd8937 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceCollectionsService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceCollectionsService.java @@ -7,32 +7,31 @@ */ package org.dspace.xoai.services.impl; -import org.dspace.content.Collection; -import org.dspace.content.Community; -import org.dspace.content.Item; -import org.dspace.core.Context; -import org.dspace.xoai.services.api.context.ContextService; -import org.dspace.xoai.services.api.context.ContextServiceException; -import org.dspace.xoai.services.api.CollectionsService; - import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.UUID; + +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CommunityService; +import org.dspace.core.Context; +import org.dspace.xoai.services.api.CollectionsService; +import org.dspace.xoai.services.api.context.ContextService; +import org.dspace.xoai.services.api.context.ContextServiceException; public class DSpaceCollectionsService implements CollectionsService { private static final CommunityService communityService - = ContentServiceFactory.getInstance().getCommunityService(); + = ContentServiceFactory.getInstance().getCommunityService(); @Override public List getAllSubCollections(ContextService contextService, UUID communityId) - throws SQLException - { + throws SQLException { Queue comqueue = new LinkedList<>(); List list = new ArrayList<>(); try { @@ -40,35 +39,38 @@ public class DSpaceCollectionsService implements CollectionsService { } catch (ContextServiceException e) { throw new SQLException(e); } - while (!comqueue.isEmpty()) - { + while (!comqueue.isEmpty()) { Community c = comqueue.poll(); - for (Community sub : c.getSubcommunities()) + for (Community sub : c.getSubcommunities()) { comqueue.add(sub); - for (Collection col : c.getCollections()) - if (!list.contains(col.getID())) + } + for (Collection col : c.getCollections()) { + if (!list.contains(col.getID())) { list.add(col.getID()); + } + } } return list; } @Override public List flatParentCommunities(Collection c) - throws SQLException - { + throws SQLException { Queue queue = new LinkedList<>(); List result = new ArrayList<>(); - for (Community com : c.getCommunities()) + for (Community com : c.getCommunities()) { queue.add(com); + } - while (!queue.isEmpty()) - { + while (!queue.isEmpty()) { Community p = queue.poll(); List par = p.getParentCommunities(); - if (par != null) + if (par != null) { queue.addAll(par); - if (!result.contains(p)) + } + if (!result.contains(p)) { result.add(p); + } } return result; @@ -76,21 +78,21 @@ public class DSpaceCollectionsService implements CollectionsService { @Override public List flatParentCommunities(Community c) - throws SQLException - { + throws SQLException { Queue queue = new LinkedList<>(); List result = new ArrayList<>(); queue.add(c); - while (!queue.isEmpty()) - { + while (!queue.isEmpty()) { Community p = queue.poll(); List par = p.getParentCommunities(); - if (par != null) + if (par != null) { queue.addAll(par); - if (!result.contains(p)) + } + if (!result.contains(p)) { result.add(p); + } } return result; @@ -98,22 +100,23 @@ public class DSpaceCollectionsService implements CollectionsService { @Override public List flatParentCommunities(Context context, Item c) - throws SQLException - { + throws SQLException { Queue queue = new LinkedList<>(); List result = new ArrayList<>(); - for (Collection collection : c.getCollections()) + for (Collection collection : c.getCollections()) { queue.addAll(communityService.getAllParents(context, collection)); + } - while (!queue.isEmpty()) - { + while (!queue.isEmpty()) { Community p = queue.poll(); List par = p.getParentCommunities(); - if (par != null) + if (par != null) { queue.addAll(par); - if (!result.contains(p)) + } + if (!result.contains(p)) { result.add(p); + } } return result; diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceEarliestDateResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceEarliestDateResolver.java index 797b7b0448..01ec853539 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceEarliestDateResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceEarliestDateResolver.java @@ -7,8 +7,14 @@ */ package org.dspace.xoai.services.impl; +import java.sql.SQLException; +import java.util.Date; + import org.apache.log4j.LogManager; import org.apache.log4j.Logger; +import org.dspace.content.MetadataValue; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.MetadataValueService; import org.dspace.core.Context; import org.dspace.xoai.exceptions.InvalidMetadataFieldException; import org.dspace.xoai.services.api.EarliestDateResolver; @@ -16,12 +22,6 @@ import org.dspace.xoai.services.api.FieldResolver; import org.dspace.xoai.util.DateUtils; import org.springframework.beans.factory.annotation.Autowired; -import java.sql.SQLException; -import java.util.Date; -import org.dspace.content.MetadataValue; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.MetadataValueService; - public class DSpaceEarliestDateResolver implements EarliestDateResolver { private static final Logger log = LogManager.getLogger(DSpaceEarliestDateResolver.class); @@ -34,17 +34,15 @@ public class DSpaceEarliestDateResolver implements EarliestDateResolver { MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService(); MetadataValue minimum = metadataValueService.getMinimum(context, - fieldResolver.getFieldID(context, "dc.date.available")); - if (null != minimum) - { + fieldResolver.getFieldID(context, "dc.date.available")); + if (null != minimum) { String str = minimum.getValue(); - try - { + try { Date d = DateUtils.parse(str); - if (d != null) return d; - } - catch (Exception e) - { + if (d != null) { + return d; + } + } catch (Exception e) { log.error(e.getMessage(), e); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceFieldResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceFieldResolver.java index 995638e17a..0fdd6c1f48 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceFieldResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceFieldResolver.java @@ -7,6 +7,9 @@ */ package org.dspace.xoai.services.impl; +import java.sql.SQLException; +import java.util.regex.Pattern; + import org.dspace.content.MetadataField; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.MetadataFieldService; @@ -14,41 +17,37 @@ import org.dspace.core.Context; import org.dspace.xoai.exceptions.InvalidMetadataFieldException; import org.dspace.xoai.services.api.FieldResolver; -import java.sql.SQLException; -import java.util.regex.Pattern; - public class DSpaceFieldResolver implements FieldResolver { private MetadataFieldCache metadataFieldCache = null; private static final MetadataFieldService metadataFieldService - = ContentServiceFactory.getInstance().getMetadataFieldService(); + = ContentServiceFactory.getInstance().getMetadataFieldService(); @Override public int getFieldID(Context context, String field) throws InvalidMetadataFieldException, SQLException { - if (metadataFieldCache == null) + if (metadataFieldCache == null) { metadataFieldCache = new MetadataFieldCache(); - if (!metadataFieldCache.hasField(field)) - { + } + if (!metadataFieldCache.hasField(field)) { String[] pieces = field.split(Pattern.quote(".")); - if (pieces.length > 1) - { + if (pieces.length > 1) { String schema = pieces[0]; String element = pieces[1]; String qualifier = null; - if (pieces.length > 2) + if (pieces.length > 2) { qualifier = pieces[2]; + } MetadataField metadataField = metadataFieldService.findByElement(context, schema, element, qualifier); - if (null != metadataField) - { + if (null != metadataField) { metadataFieldCache.add(field, metadataField.getID()); - } - else + } else { throw new InvalidMetadataFieldException(); + } - } - else + } else { throw new InvalidMetadataFieldException(); + } } return metadataFieldCache.getField(field); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceHandleResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceHandleResolver.java index 553b576d7b..6ed44bdcc2 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceHandleResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceHandleResolver.java @@ -9,13 +9,14 @@ package org.dspace.xoai.services.impl; import java.sql.SQLException; import javax.inject.Inject; + import org.dspace.content.DSpaceObject; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; -import org.dspace.xoai.services.api.context.ContextService; -import org.dspace.xoai.services.api.context.ContextServiceException; import org.dspace.xoai.services.api.HandleResolver; import org.dspace.xoai.services.api.HandleResolverException; +import org.dspace.xoai.services.api.context.ContextService; +import org.dspace.xoai.services.api.context.ContextServiceException; public class DSpaceHandleResolver implements HandleResolver { @Inject @@ -23,8 +24,7 @@ public class DSpaceHandleResolver implements HandleResolver { private final HandleService handleService; - public DSpaceHandleResolver() - { + public DSpaceHandleResolver() { handleService = HandleServiceFactory.getInstance().getHandleService(); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceServiceResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceServiceResolver.java index 2e613633b4..d14326aca1 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceServiceResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceServiceResolver.java @@ -7,6 +7,8 @@ */ package org.dspace.xoai.services.impl; +import java.util.Map; + import com.lyncode.builder.MapBuilder; import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; import org.dspace.xoai.services.api.ServiceResolver; @@ -14,13 +16,11 @@ import org.dspace.xoai.services.api.config.ConfigurationService; import org.dspace.xoai.services.impl.config.DSpaceConfigurationService; import org.dspace.xoai.services.impl.resources.DSpaceResourceResolver; -import java.util.Map; - public class DSpaceServiceResolver implements ServiceResolver { private Map services = new MapBuilder() - .withPair(ConfigurationService.class.getName(), new DSpaceConfigurationService()) - .withPair(ResourceResolver.class.getName(), new DSpaceResourceResolver()) - .build(); + .withPair(ConfigurationService.class.getName(), new DSpaceConfigurationService()) + .withPair(ResourceResolver.class.getName(), new DSpaceResourceResolver()) + .build(); @Override public T getService(Class type) { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/MetadataFieldCache.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/MetadataFieldCache.java index 9ce4b0da7b..bdcab2bbf4 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/MetadataFieldCache.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/MetadataFieldCache.java @@ -7,40 +7,34 @@ */ package org.dspace.xoai.services.impl; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - import java.util.HashMap; import java.util.Map; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class MetadataFieldCache -{ +public class MetadataFieldCache { private static Logger log = LogManager - .getLogger(MetadataFieldCache.class); + .getLogger(MetadataFieldCache.class); private Map fields; - public MetadataFieldCache() - { + public MetadataFieldCache() { fields = new HashMap(); } - public boolean hasField(String field) - { + public boolean hasField(String field) { return fields.containsKey(field); } - public int getField(String field) - { + public int getField(String field) { return fields.get(field).intValue(); } - public void add(String field, int id) - { + public void add(String field, int id) { fields.put(field, new Integer(id)); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceEmptyCacheService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceEmptyCacheService.java index 0ce30a3f7d..44b0e4784e 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceEmptyCacheService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceEmptyCacheService.java @@ -7,12 +7,12 @@ */ package org.dspace.xoai.services.impl.cache; -import com.lyncode.xoai.dataprovider.xml.oaipmh.OAIPMH; -import org.dspace.xoai.services.api.cache.XOAICacheService; - import java.io.IOException; import java.io.OutputStream; +import com.lyncode.xoai.dataprovider.xml.oaipmh.OAIPMH; +import org.dspace.xoai.services.api.cache.XOAICacheService; + public class DSpaceEmptyCacheService implements XOAICacheService { @Override public boolean isActive() { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAICacheService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAICacheService.java index 1dfe7df5a3..5072895387 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAICacheService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAICacheService.java @@ -7,6 +7,20 @@ */ package org.dspace.xoai.services.impl.cache; +import static com.lyncode.xoai.dataprovider.core.Granularity.Second; +import static org.apache.commons.io.FileUtils.deleteDirectory; +import static org.apache.commons.io.IOUtils.copy; +import static org.apache.commons.io.IOUtils.write; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Date; +import javax.xml.stream.XMLStreamException; + import com.lyncode.xoai.dataprovider.core.XOAIManager; import com.lyncode.xoai.dataprovider.exceptions.WritingXmlException; import com.lyncode.xoai.dataprovider.xml.XmlOutputContext; @@ -19,15 +33,6 @@ import org.dspace.xoai.services.api.config.ConfigurationService; import org.dspace.xoai.util.DateUtils; import org.springframework.beans.factory.annotation.Autowired; -import javax.xml.stream.XMLStreamException; -import java.io.*; -import java.util.Date; - -import static com.lyncode.xoai.dataprovider.core.Granularity.Second; -import static org.apache.commons.io.FileUtils.deleteDirectory; -import static org.apache.commons.io.IOUtils.copy; -import static org.apache.commons.io.IOUtils.write; - public class DSpaceXOAICacheService implements XOAICacheService { private static final String REQUEST_DIR = File.separator + "requests"; @@ -43,12 +48,15 @@ public class DSpaceXOAICacheService implements XOAICacheService { } private static String getStaticHead(XOAIManager manager, Date date) { - if (staticHead == null) + if (staticHead == null) { staticHead = "" - + ((manager.hasStyleSheet()) ? ("") : "") - + ""; + + ((manager.hasStyleSheet()) ? ("") : "") + + ""; + } return staticHead + "" + DateUtils.format(date) + ""; } @@ -64,8 +72,9 @@ public class DSpaceXOAICacheService implements XOAICacheService { private File getCacheFile(String id) { File dir = new File(getBaseDir()); - if (!dir.exists()) + if (!dir.exists()) { dir.mkdirs(); + } String name = File.separator + Base64Utils.encode(id); return new File(getBaseDir() + name); @@ -103,8 +112,9 @@ public class DSpaceXOAICacheService implements XOAICacheService { // Cutting the header (to allow one to change the response time) String end = ""; int pos = xoaiResponse.indexOf(end); - if (pos > 0) + if (pos > 0) { xoaiResponse = xoaiResponse.substring(pos + (end.length())); + } FileUtils.write(this.getCacheFile(requestID), xoaiResponse); } catch (XMLStreamException e) { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAIItemCacheService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAIItemCacheService.java index 0f1a387a52..b50d73e1f4 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAIItemCacheService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAIItemCacheService.java @@ -7,6 +7,15 @@ */ package org.dspace.xoai.services.impl.cache; +import static com.lyncode.xoai.dataprovider.core.Granularity.Second; +import static org.apache.commons.io.FileUtils.deleteDirectory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import javax.xml.stream.XMLStreamException; + import com.lyncode.xoai.dataprovider.exceptions.WritingXmlException; import com.lyncode.xoai.dataprovider.xml.XmlOutputContext; import com.lyncode.xoai.dataprovider.xml.xoai.Metadata; @@ -17,15 +26,6 @@ import org.dspace.xoai.services.api.cache.XOAIItemCacheService; import org.dspace.xoai.services.api.config.ConfigurationService; import org.springframework.beans.factory.annotation.Autowired; -import javax.xml.stream.XMLStreamException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; - -import static com.lyncode.xoai.dataprovider.core.Granularity.Second; -import static org.apache.commons.io.FileUtils.deleteDirectory; - public class DSpaceXOAIItemCacheService implements XOAIItemCacheService { private static final String ITEMDIR = File.separator + "items"; @@ -35,36 +35,31 @@ public class DSpaceXOAIItemCacheService implements XOAIItemCacheService { private String baseDir; - private String getBaseDir() - { - if (baseDir == null) + private String getBaseDir() { + if (baseDir == null) { baseDir = configurationService.getProperty("oai", "cache.dir") + ITEMDIR; + } return baseDir; } - private File getMetadataCache(Item item) - { + private File getMetadataCache(Item item) { File dir = new File(getBaseDir()); - if (!dir.exists()) + if (!dir.exists()) { dir.mkdirs(); + } String name = File.separator + item.getHandle().replace('/', '_'); return new File(getBaseDir() + name); } - - @Override public boolean hasCache(Item item) { return getMetadataCache(item).exists(); } - - - @Override public Metadata get(Item item) throws IOException { System.out.println(FileUtils.readFileToString(getMetadataCache(item))); @@ -76,14 +71,11 @@ public class DSpaceXOAIItemCacheService implements XOAIItemCacheService { throw new IOException(e); } input.close(); - + return metadata; } - - - @Override public void put(Item item, Metadata metadata) throws IOException { FileOutputStream output = new FileOutputStream(getMetadataCache(item)); @@ -92,7 +84,7 @@ public class DSpaceXOAIItemCacheService implements XOAIItemCacheService { metadata.write(context); context.getWriter().flush(); context.getWriter().close(); - + output.close(); } catch (XMLStreamException e) { throw new IOException(e); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAILastCompilationCacheService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAILastCompilationCacheService.java index 56a8b71ebb..5ddacae4b7 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAILastCompilationCacheService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/cache/DSpaceXOAILastCompilationCacheService.java @@ -7,10 +7,6 @@ */ package org.dspace.xoai.services.impl.cache; -import org.apache.commons.io.FileUtils; -import org.dspace.core.ConfigurationManager; -import org.dspace.xoai.services.api.cache.XOAILastCompilationCacheService; - import java.io.File; import java.io.IOException; import java.text.DateFormat; @@ -18,23 +14,25 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import org.apache.commons.io.FileUtils; +import org.dspace.core.ConfigurationManager; +import org.dspace.xoai.services.api.cache.XOAILastCompilationCacheService; + public class DSpaceXOAILastCompilationCacheService implements XOAILastCompilationCacheService { - private static final ThreadLocal format = new ThreadLocal(){ - @Override - protected DateFormat initialValue() { - return new SimpleDateFormat(); - } - }; + private static final ThreadLocal format = new ThreadLocal() { + @Override + protected DateFormat initialValue() { + return new SimpleDateFormat(); + } + }; private static final String DATEFILE = File.separator + "date.file"; private static File file = null; - private static File getFile() - { - if (file == null) - { + private static File getFile() { + if (file == null) { String dir = ConfigurationManager.getProperty("oai", "cache.dir") + DATEFILE; file = new File(dir); } @@ -48,18 +46,12 @@ public class DSpaceXOAILastCompilationCacheService implements XOAILastCompilatio } - - - @Override public void put(Date date) throws IOException { FileUtils.write(getFile(), format.get().format(date)); } - - - @Override public Date get() throws IOException { try { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/config/DSpaceConfigurationService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/config/DSpaceConfigurationService.java index c844a2cd00..f010808531 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/config/DSpaceConfigurationService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/config/DSpaceConfigurationService.java @@ -17,7 +17,7 @@ public class DSpaceConfigurationService implements ConfigurationService { } @Override - public String getProperty(String module, String key) { + public String getProperty(String module, String key) { return ConfigurationManager.getProperty(module, key); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/context/DSpaceContextService.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/context/DSpaceContextService.java index 3501a59a75..904b7f8885 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/context/DSpaceContextService.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/context/DSpaceContextService.java @@ -7,20 +7,21 @@ */ package org.dspace.xoai.services.impl.context; +import javax.servlet.http.HttpServletRequest; + import org.dspace.core.Context; import org.dspace.xoai.services.api.context.ContextService; import org.dspace.xoai.services.api.context.ContextServiceException; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import javax.servlet.http.HttpServletRequest; - public class DSpaceContextService implements ContextService { private static final String OAI_CONTEXT = "OAI_CONTEXT"; @Override public Context getContext() throws ContextServiceException { - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) + .getRequest(); Object value = request.getAttribute(OAI_CONTEXT); if (value == null || !(value instanceof Context)) { request.setAttribute(OAI_CONTEXT, new Context()); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/context/DSpaceXOAIManagerResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/context/DSpaceXOAIManagerResolver.java index b293782410..ebd378f749 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/context/DSpaceXOAIManagerResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/context/DSpaceXOAIManagerResolver.java @@ -7,6 +7,8 @@ */ package org.dspace.xoai.services.impl.context; +import static com.lyncode.xoai.dataprovider.xml.xoaiconfig.Configuration.readConfiguration; + import com.lyncode.xoai.dataprovider.core.XOAIManager; import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; import org.dspace.xoai.services.api.config.XOAIManagerResolver; @@ -14,12 +16,12 @@ import org.dspace.xoai.services.api.config.XOAIManagerResolverException; import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver; import org.springframework.beans.factory.annotation.Autowired; -import static com.lyncode.xoai.dataprovider.xml.xoaiconfig.Configuration.readConfiguration; - public class DSpaceXOAIManagerResolver implements XOAIManagerResolver { public static final String XOAI_CONFIGURATION_FILE = "xoai.xml"; - @Autowired ResourceResolver resourceResolver; - @Autowired DSpaceFilterResolver filterResolver; + @Autowired + ResourceResolver resourceResolver; + @Autowired + DSpaceFilterResolver filterResolver; private XOAIManager manager; @@ -27,7 +29,8 @@ public class DSpaceXOAIManagerResolver implements XOAIManagerResolver { public XOAIManager getManager() throws XOAIManagerResolverException { if (manager == null) { try { - manager = new XOAIManager(filterResolver, resourceResolver, readConfiguration(resourceResolver.getResource(XOAI_CONFIGURATION_FILE))); + manager = new XOAIManager(filterResolver, resourceResolver, + readConfiguration(resourceResolver.getResource(XOAI_CONFIGURATION_FILE))); } catch (Exception e) { throw new XOAIManagerResolverException(e); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/DSpaceResourceResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/DSpaceResourceResolver.java index e0b3d2022a..1738373420 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/DSpaceResourceResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/resources/DSpaceResourceResolver.java @@ -11,35 +11,30 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; - import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamSource; +import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; import org.dspace.core.ConfigurationManager; -import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; - -public class DSpaceResourceResolver implements ResourceResolver -{ +public class DSpaceResourceResolver implements ResourceResolver { private static final TransformerFactory transformerFactory = TransformerFactory - .newInstance(); + .newInstance(); private final String basePath = ConfigurationManager.getProperty("oai", - "config.dir"); + "config.dir"); @Override - public InputStream getResource(String path) throws IOException - { + public InputStream getResource(String path) throws IOException { return new FileInputStream(new File(basePath, path)); } @Override public Transformer getTransformer(String path) throws IOException, - TransformerConfigurationException - { + TransformerConfigurationException { // construct a Source that reads from an InputStream Source mySrc = new StreamSource(getResource(path)); // specify a system ID (the path to the XSLT-file on the filesystem) diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/set/DSpaceSetSpecResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/set/DSpaceSetSpecResolver.java index 368cc11834..7e5cad61c6 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/set/DSpaceSetSpecResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/set/DSpaceSetSpecResolver.java @@ -8,20 +8,20 @@ package org.dspace.xoai.services.impl.set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; import org.dspace.xoai.exceptions.InvalidSetSpecException; -import org.dspace.xoai.services.api.config.ConfigurationService; -import org.dspace.xoai.services.api.context.ContextService; import org.dspace.xoai.services.api.HandleResolver; import org.dspace.xoai.services.api.HandleResolverException; +import org.dspace.xoai.services.api.config.ConfigurationService; +import org.dspace.xoai.services.api.context.ContextService; import org.dspace.xoai.services.api.set.SetSpecResolver; import org.springframework.beans.factory.annotation.Autowired; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - public class DSpaceSetSpecResolver implements SetSpecResolver { private static final String HANDLE_PREFIX = "{handle-prefix}"; private static final String LOCAL_ID = "{local-id}"; @@ -40,7 +40,9 @@ public class DSpaceSetSpecResolver implements SetSpecResolver { public String toSetSpec(Community community) throws InvalidSetSpecException { String handle = community.getHandle(); String[] split = handle.split("/"); - if (split.length != 2) throw new InvalidSetSpecException("Invalid handle "+handle); + if (split.length != 2) { + throw new InvalidSetSpecException("Invalid handle " + handle); + } return format(getSetSpecFormat(Community.class), split[0], split[1]); } @@ -49,7 +51,9 @@ public class DSpaceSetSpecResolver implements SetSpecResolver { public String toSetSpec(Collection collection) throws InvalidSetSpecException { String handle = collection.getHandle(); String[] split = handle.split("/"); - if (split.length != 2) throw new InvalidSetSpecException("Invalid handle "+handle); + if (split.length != 2) { + throw new InvalidSetSpecException("Invalid handle " + handle); + } return String.format(getSetSpecFormat(Community.class), split[0], split[1]); } @@ -59,12 +63,13 @@ public class DSpaceSetSpecResolver implements SetSpecResolver { String communityPattern = getPattern(Community.class); String collectionPattern = getPattern(Collection.class); String pattern; - if (setSpec.matches(communityPattern)) + if (setSpec.matches(communityPattern)) { pattern = communityPattern; - else if (setSpec.matches(collectionPattern)) + } else if (setSpec.matches(collectionPattern)) { pattern = collectionPattern; - else + } else { throw new InvalidSetSpecException("Unknown set spec"); + } Matcher matcher = Pattern.compile(pattern).matcher(setSpec); @@ -83,11 +88,12 @@ public class DSpaceSetSpecResolver implements SetSpecResolver { } private String getPattern(Class clazz) { - return "^"+getSetSpecFormat(clazz).replace(HANDLE_PREFIX, "([0-9]+)").replace(LOCAL_ID, "([0-9]+)")+"$"; + return "^" + getSetSpecFormat(clazz).replace(HANDLE_PREFIX, "([0-9]+)").replace(LOCAL_ID, "([0-9]+)") + "$"; } private String getSetSpecFormat(Class clazz) { - String property = configurationService.getProperty("oai", clazz.getSimpleName().toLowerCase() + ".setSpecFormat"); + String property = configurationService + .getProperty("oai", clazz.getSimpleName().toLowerCase() + ".setSpecFormat"); return property == null ? DEFAULT_FORMAT : property; } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/solr/DSpaceSolrQueryResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/solr/DSpaceSolrQueryResolver.java index 1e2e578443..de58edd542 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/solr/DSpaceSolrQueryResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/solr/DSpaceSolrQueryResolver.java @@ -7,6 +7,9 @@ */ package org.dspace.xoai.services.impl.solr; +import java.util.ArrayList; +import java.util.List; + import com.lyncode.xoai.dataprovider.filter.Scope; import com.lyncode.xoai.dataprovider.filter.ScopedFilter; import com.lyncode.xoai.dataprovider.filter.conditions.Condition; @@ -15,9 +18,6 @@ import org.dspace.xoai.services.api.solr.SolrQueryResolver; import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.List; - public class DSpaceSolrQueryResolver implements SolrQueryResolver { @Autowired DSpaceFilterResolver filterResolver; @@ -25,18 +25,20 @@ public class DSpaceSolrQueryResolver implements SolrQueryResolver { @Override public String buildQuery(List filters) { List whereCond = new ArrayList(); - for (ScopedFilter filter : filters) + for (ScopedFilter filter : filters) { whereCond.add(buildQuery(filter.getScope(), filter.getCondition())); + } - if (whereCond.isEmpty()) + if (whereCond.isEmpty()) { whereCond.add("*:*"); + } String where = "(" + StringUtils.join(whereCond.iterator(), ") AND (") + ")"; return where; } - private String buildQuery (Scope scope, Condition condition) { + private String buildQuery(Scope scope, Condition condition) { return filterResolver.buildSolrQuery(scope, condition); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/solr/DSpaceSolrServerResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/solr/DSpaceSolrServerResolver.java index 524b6b97eb..fe71aacad7 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/solr/DSpaceSolrServerResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/solr/DSpaceSolrServerResolver.java @@ -24,17 +24,12 @@ public class DSpaceSolrServerResolver implements SolrServerResolver { private ConfigurationService configurationService; @Override - public SolrServer getServer() throws SolrServerException - { - if (server == null) - { - try - { + public SolrServer getServer() throws SolrServerException { + if (server == null) { + try { server = new HttpSolrServer(configurationService.getProperty("oai", "solr.url")); log.debug("Solr Server Initialized"); - } - catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/BaseDSpaceFilterResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/BaseDSpaceFilterResolver.java index 15bb5333e2..43df0dca82 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/BaseDSpaceFilterResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/BaseDSpaceFilterResolver.java @@ -7,21 +7,28 @@ */ package org.dspace.xoai.services.impl.xoai; +import static com.lyncode.xoai.dataprovider.filter.Scope.MetadataFormat; + import com.lyncode.xoai.dataprovider.data.Filter; import com.lyncode.xoai.dataprovider.filter.Scope; -import com.lyncode.xoai.dataprovider.filter.conditions.*; +import com.lyncode.xoai.dataprovider.filter.conditions.AndCondition; +import com.lyncode.xoai.dataprovider.filter.conditions.Condition; +import com.lyncode.xoai.dataprovider.filter.conditions.CustomCondition; +import com.lyncode.xoai.dataprovider.filter.conditions.NotCondition; +import com.lyncode.xoai.dataprovider.filter.conditions.OrCondition; import com.lyncode.xoai.dataprovider.xml.xoaiconfig.parameters.ParameterMap; import org.apache.log4j.Logger; -import org.dspace.xoai.filter.*; +import org.dspace.xoai.filter.AndFilter; +import org.dspace.xoai.filter.DSpaceFilter; +import org.dspace.xoai.filter.NotFilter; +import org.dspace.xoai.filter.OrFilter; import org.dspace.xoai.filter.results.SolrFilterResult; +import org.dspace.xoai.services.api.FieldResolver; import org.dspace.xoai.services.api.context.ContextService; import org.dspace.xoai.services.api.context.ContextServiceException; -import org.dspace.xoai.services.api.FieldResolver; import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver; import org.springframework.beans.factory.annotation.Autowired; -import static com.lyncode.xoai.dataprovider.filter.Scope.MetadataFormat; - public class BaseDSpaceFilterResolver implements DSpaceFilterResolver { private static final Logger LOGGER = Logger.getLogger(BaseDSpaceFilterResolver.class); @@ -31,11 +38,14 @@ public class BaseDSpaceFilterResolver implements DSpaceFilterResolver { @Autowired ContextService contextService; - public DSpaceFilter getFilter (Condition condition) { - if (condition instanceof AndCondition) return (DSpaceFilter) getFilter((AndCondition) condition); - else if (condition instanceof OrCondition) return (DSpaceFilter) getFilter((OrCondition) condition); - else if (condition instanceof NotCondition) return (DSpaceFilter) getFilter((NotCondition) condition); - else if (condition instanceof CustomCondition) { + public DSpaceFilter getFilter(Condition condition) { + if (condition instanceof AndCondition) { + return (DSpaceFilter) getFilter((AndCondition) condition); + } else if (condition instanceof OrCondition) { + return (DSpaceFilter) getFilter((OrCondition) condition); + } else if (condition instanceof NotCondition) { + return (DSpaceFilter) getFilter((NotCondition) condition); + } else if (condition instanceof CustomCondition) { CustomCondition customCondition = (CustomCondition) condition; return (DSpaceFilter) customCondition.getFilter(); } else { @@ -47,13 +57,13 @@ public class BaseDSpaceFilterResolver implements DSpaceFilterResolver { public String buildSolrQuery(Scope scope, Condition condition) { DSpaceFilter filter = getFilter(condition); SolrFilterResult result = filter.buildSolrQuery(); - if (result.hasResult()) - { - if (scope == MetadataFormat) + if (result.hasResult()) { + if (scope == MetadataFormat) { return "(item.deleted:true OR (" - + result.getQuery() + "))"; - else + + result.getQuery() + "))"; + } else { return "(" + result.getQuery() + ")"; + } } return "true"; } @@ -61,22 +71,18 @@ public class BaseDSpaceFilterResolver implements DSpaceFilterResolver { @Override public Filter getFilter(Class filterClass, ParameterMap configuration) { Filter result = null; - try - { + try { result = filterClass.newInstance(); - if (result instanceof DSpaceFilter) - { + if (result instanceof DSpaceFilter) { // add the DSpace filter specific objects ((DSpaceFilter) result).setConfiguration(configuration); ((DSpaceFilter) result).setContext(contextService.getContext()); ((DSpaceFilter) result).setFieldResolver(fieldResolver); } - } - catch (InstantiationException | IllegalAccessException - | ContextServiceException e) - { + } catch (InstantiationException | IllegalAccessException + | ContextServiceException e) { LOGGER.error("Filter " + filterClass.getName() - + " could not be instantiated", e); + + " could not be instantiated", e); } return result; } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceIdentifyResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceIdentifyResolver.java index 19cc1edc80..12f6c17459 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceIdentifyResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceIdentifyResolver.java @@ -8,10 +8,10 @@ package org.dspace.xoai.services.impl.xoai; import com.lyncode.xoai.dataprovider.services.api.RepositoryConfiguration; +import org.dspace.xoai.services.api.EarliestDateResolver; import org.dspace.xoai.services.api.config.ConfigurationService; import org.dspace.xoai.services.api.context.ContextService; import org.dspace.xoai.services.api.context.ContextServiceException; -import org.dspace.xoai.services.api.EarliestDateResolver; import org.dspace.xoai.services.api.xoai.IdentifyResolver; import org.springframework.beans.factory.annotation.Autowired; @@ -25,6 +25,7 @@ public class DSpaceIdentifyResolver implements IdentifyResolver { @Override public RepositoryConfiguration getIdentify() throws ContextServiceException { - return new DSpaceRepositoryConfiguration(earliestDateResolver, configurationService, contextService.getContext()); + return new DSpaceRepositoryConfiguration(earliestDateResolver, configurationService, + contextService.getContext()); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemRepository.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemRepository.java index 091a48a247..4e6b693c4d 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemRepository.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemRepository.java @@ -7,6 +7,9 @@ */ package org.dspace.xoai.services.impl.xoai; +import java.util.Date; +import java.util.List; + import com.lyncode.xoai.dataprovider.core.ListItemIdentifiersResult; import com.lyncode.xoai.dataprovider.core.ListItemsResults; import com.lyncode.xoai.dataprovider.data.Filter; @@ -21,15 +24,10 @@ import org.dspace.xoai.filter.DateUntilFilter; import org.dspace.xoai.services.api.CollectionsService; import org.dspace.xoai.services.api.HandleResolver; -import java.util.Date; -import java.util.List; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public abstract class DSpaceItemRepository implements ItemRepository -{ +public abstract class DSpaceItemRepository implements ItemRepository { private CollectionsService collectionsService; private HandleResolver handleResolver; @@ -40,24 +38,21 @@ public abstract class DSpaceItemRepository implements ItemRepository @Override public ListItemIdentifiersResult getItemIdentifiers( - List filters, int offset, int length, Date from) throws OAIException - { + List filters, int offset, int length, Date from) throws OAIException { filters.add(new ScopedFilter(getDateFromCondition(from), Scope.Query)); return this.getItemIdentifiers(filters, offset, length); } @Override public ListItemIdentifiersResult getItemIdentifiers( - List filters, int offset, int length, String setSpec) throws OAIException - { + List filters, int offset, int length, String setSpec) throws OAIException { filters.add(new ScopedFilter(getDSpaceSetSpecFilter(setSpec), Scope.Query)); return this.getItemIdentifiers(filters, offset, length); } @Override - public ListItemIdentifiersResult getItemIdentifiers( - List filters, int offset, int length, Date from, Date until) throws OAIException - { + public ListItemIdentifiersResult getItemIdentifiers( + List filters, int offset, int length, Date from, Date until) throws OAIException { filters.add(new ScopedFilter(getDateFromCondition(from), Scope.Query)); filters.add(new ScopedFilter(getDateUntilFilter(until), Scope.Query)); return this.getItemIdentifiers(filters, offset, length); @@ -65,67 +60,60 @@ public abstract class DSpaceItemRepository implements ItemRepository @Override public ListItemIdentifiersResult getItemIdentifiers( - List filters, int offset, int length, String setSpec, - Date from) throws OAIException - { + List filters, int offset, int length, String setSpec, + Date from) throws OAIException { filters.add(new ScopedFilter(getDateFromCondition(from), Scope.Query)); filters.add(new ScopedFilter(getDSpaceSetSpecFilter(setSpec), - Scope.Query)); + Scope.Query)); return this.getItemIdentifiers(filters, offset, length); } @Override public ListItemIdentifiersResult getItemIdentifiers( - List filters, int offset, int length, String setSpec, - Date from, Date until) throws OAIException - { + List filters, int offset, int length, String setSpec, + Date from, Date until) throws OAIException { filters.add(new ScopedFilter(getDateFromCondition(from), Scope.Query)); filters.add(new ScopedFilter(getDateUntilFilter(until), Scope.Query)); filters.add(new ScopedFilter(getDSpaceSetSpecFilter(setSpec), - Scope.Query)); + Scope.Query)); return this.getItemIdentifiers(filters, offset, length); } @Override public ListItemIdentifiersResult getItemIdentifiersUntil( - List filters, int offset, int length, Date until) throws OAIException - { + List filters, int offset, int length, Date until) throws OAIException { filters.add(new ScopedFilter(getDateUntilFilter(until), Scope.Query)); return this.getItemIdentifiers(filters, offset, length); } @Override public ListItemIdentifiersResult getItemIdentifiersUntil( - List filters, int offset, int length, String setSpec, - Date until) throws OAIException - { + List filters, int offset, int length, String setSpec, + Date until) throws OAIException { filters.add(new ScopedFilter(getDateUntilFilter(until), Scope.Query)); filters.add(new ScopedFilter(getDSpaceSetSpecFilter(setSpec), - Scope.Query)); + Scope.Query)); return this.getItemIdentifiers(filters, offset, length); } @Override public ListItemsResults getItems(List filters, int offset, - int length, Date from) throws OAIException - { + int length, Date from) throws OAIException { filters.add(new ScopedFilter(getDateFromCondition(from), Scope.Query)); return this.getItems(filters, offset, length); } @Override public ListItemsResults getItems(List filters, int offset, - int length, String setSpec) throws OAIException - { + int length, String setSpec) throws OAIException { filters.add(new ScopedFilter(getDSpaceSetSpecFilter(setSpec), - Scope.Query)); + Scope.Query)); return this.getItems(filters, offset, length); } @Override public ListItemsResults getItems(List filters, int offset, - int length, Date from, Date until) throws OAIException - { + int length, Date from, Date until) throws OAIException { filters.add(new ScopedFilter(getDateFromCondition(from), Scope.Query)); filters.add(new ScopedFilter(getDateUntilFilter(until), Scope.Query)); return this.getItems(filters, offset, length); @@ -133,40 +121,36 @@ public abstract class DSpaceItemRepository implements ItemRepository @Override public ListItemsResults getItems(List filters, int offset, - int length, String setSpec, Date from) throws OAIException - { + int length, String setSpec, Date from) throws OAIException { filters.add(new ScopedFilter(getDateFromCondition(from), Scope.Query)); filters.add(new ScopedFilter(getDSpaceSetSpecFilter(setSpec), - Scope.Query)); + Scope.Query)); return this.getItems(filters, offset, length); } @Override public ListItemsResults getItems(List filters, int offset, - int length, String setSpec, Date from, Date until) throws OAIException - { + int length, String setSpec, Date from, Date until) throws OAIException { filters.add(new ScopedFilter(getDateFromCondition(from), Scope.Query)); filters.add(new ScopedFilter(getDateUntilFilter(until), Scope.Query)); filters.add(new ScopedFilter(getDSpaceSetSpecFilter(setSpec), - Scope.Query)); + Scope.Query)); return this.getItems(filters, offset, length); } @Override public ListItemsResults getItemsUntil(List filters, int offset, - int length, Date until) throws OAIException - { + int length, Date until) throws OAIException { filters.add(new ScopedFilter(getDateUntilFilter(until), Scope.Query)); return this.getItems(filters, offset, length); } @Override public ListItemsResults getItemsUntil(List filters, int offset, - int length, String setSpec, Date from) throws OAIException - { + int length, String setSpec, Date from) throws OAIException { filters.add(new ScopedFilter(getDateUntilFilter(from), Scope.Query)); filters.add(new ScopedFilter(getDSpaceSetSpecFilter(setSpec), - Scope.Query)); + Scope.Query)); return this.getItems(filters, offset, length); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemRepositoryResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemRepositoryResolver.java index 9c74a7a895..1e7f822720 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemRepositoryResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemRepositoryResolver.java @@ -9,11 +9,11 @@ package org.dspace.xoai.services.impl.xoai; import com.lyncode.xoai.dataprovider.services.api.ItemRepository; import org.apache.solr.client.solrj.SolrServerException; +import org.dspace.xoai.services.api.CollectionsService; +import org.dspace.xoai.services.api.HandleResolver; import org.dspace.xoai.services.api.config.ConfigurationService; import org.dspace.xoai.services.api.context.ContextService; import org.dspace.xoai.services.api.context.ContextServiceException; -import org.dspace.xoai.services.api.CollectionsService; -import org.dspace.xoai.services.api.HandleResolver; import org.dspace.xoai.services.api.solr.SolrQueryResolver; import org.dspace.xoai.services.api.solr.SolrServerResolver; import org.dspace.xoai.services.api.xoai.ItemRepositoryResolver; @@ -41,10 +41,10 @@ public class DSpaceItemRepositoryResolver implements ItemRepositoryResolver { if (itemRepository == null) { try { itemRepository = new DSpaceItemSolrRepository( - solrServerResolver.getServer(), - collectionsService, - handleResolver, - solrQueryResolver); + solrServerResolver.getServer(), + collectionsService, + handleResolver, + solrQueryResolver); } catch (SolrServerException e) { throw new ContextServiceException(e.getMessage(), e); } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemSolrRepository.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemSolrRepository.java index 4fb5e00f3a..1836444369 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemSolrRepository.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceItemSolrRepository.java @@ -7,6 +7,10 @@ */ package org.dspace.xoai.services.impl.xoai; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + import com.google.common.base.Function; import com.lyncode.builder.ListBuilder; import com.lyncode.xoai.dataprovider.core.ListItemIdentifiersResult; @@ -29,22 +33,16 @@ import org.dspace.xoai.solr.DSpaceSolrSearch; import org.dspace.xoai.solr.exceptions.DSpaceSolrException; import org.dspace.xoai.solr.exceptions.SolrSearchEmptyException; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DSpaceItemSolrRepository extends DSpaceItemRepository -{ +public class DSpaceItemSolrRepository extends DSpaceItemRepository { private static Logger log = LogManager.getLogger(DSpaceItemSolrRepository.class); private SolrServer server; private SolrQueryResolver solrQueryResolver; - public DSpaceItemSolrRepository(SolrServer server, CollectionsService collectionsService, HandleResolver handleResolver, SolrQueryResolver solrQueryResolver) - { + public DSpaceItemSolrRepository(SolrServer server, CollectionsService collectionsService, + HandleResolver handleResolver, SolrQueryResolver solrQueryResolver) { super(collectionsService, handleResolver); this.server = server; this.solrQueryResolver = solrQueryResolver; @@ -52,17 +50,15 @@ public class DSpaceItemSolrRepository extends DSpaceItemRepository @Override public Item getItem(String identifier) throws IdDoesNotExistException { - if (identifier == null) throw new IdDoesNotExistException(); + if (identifier == null) { + throw new IdDoesNotExistException(); + } String parts[] = identifier.split(Pattern.quote(":")); - if (parts.length == 3) - { - try - { + if (parts.length == 3) { + try { SolrQuery params = new SolrQuery("item.handle:" + parts[2]); return new DSpaceSolrItem(DSpaceSolrSearch.querySingle(server, params)); - } - catch (SolrSearchEmptyException ex) - { + } catch (SolrSearchEmptyException ex) { throw new IdDoesNotExistException(ex); } } @@ -71,23 +67,19 @@ public class DSpaceItemSolrRepository extends DSpaceItemRepository @Override public ListItemIdentifiersResult getItemIdentifiers( - List filters, int offset, int length) - { - try - { + List filters, int offset, int length) { + try { QueryResult queryResult = retrieveItems(filters, offset, length); List identifierList = new ListBuilder() - .add(queryResult.getResults()) - .build(new Function() { - @Override - public ItemIdentifier apply(Item elem) { - return elem; - } - }); + .add(queryResult.getResults()) + .build(new Function() { + @Override + public ItemIdentifier apply(Item elem) { + return elem; + } + }); return new ListItemIdentifiersResult(queryResult.hasMore(), identifierList, queryResult.getTotal()); - } - catch (DSpaceSolrException ex) - { + } catch (DSpaceSolrException ex) { log.error(ex.getMessage(), ex); return new ListItemIdentifiersResult(false, new ArrayList()); } @@ -95,29 +87,27 @@ public class DSpaceItemSolrRepository extends DSpaceItemRepository @Override public ListItemsResults getItems(List filters, int offset, - int length) - { - try - { + int length) { + try { QueryResult queryResult = retrieveItems(filters, offset, length); return new ListItemsResults(queryResult.hasMore(), queryResult.getResults(), queryResult.getTotal()); - } - catch (DSpaceSolrException ex) - { + } catch (DSpaceSolrException ex) { log.error(ex.getMessage(), ex); return new ListItemsResults(false, new ArrayList()); } } - private QueryResult retrieveItems (List filters, int offset, int length) throws DSpaceSolrException { + private QueryResult retrieveItems(List filters, int offset, int length) throws DSpaceSolrException { List list = new ArrayList(); SolrQuery params = new SolrQuery(solrQueryResolver.buildQuery(filters)) - .setRows(length) - .setStart(offset); + .setRows(length) + .setStart(offset); SolrDocumentList solrDocuments = DSpaceSolrSearch.query(server, params); - for (SolrDocument doc : solrDocuments) + for (SolrDocument doc : solrDocuments) { list.add(new DSpaceSolrItem(doc)); - return new QueryResult(list, (solrDocuments.getNumFound() > offset + length), (int) solrDocuments.getNumFound()); + } + return new QueryResult(list, (solrDocuments.getNumFound() > offset + length), + (int) solrDocuments.getNumFound()); } private class QueryResult { diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceRepositoryConfiguration.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceRepositoryConfiguration.java index 408fc6b43b..d6cc49c286 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceRepositoryConfiguration.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceRepositoryConfiguration.java @@ -7,6 +7,14 @@ */ package org.dspace.xoai.services.impl.xoai; +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import javax.servlet.http.HttpServletRequest; + import com.lyncode.xoai.dataprovider.core.DeleteMethod; import com.lyncode.xoai.dataprovider.core.Granularity; import com.lyncode.xoai.dataprovider.services.api.RepositoryConfiguration; @@ -15,26 +23,16 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.dspace.core.Context; import org.dspace.xoai.exceptions.InvalidMetadataFieldException; -import org.dspace.xoai.services.api.config.ConfigurationService; import org.dspace.xoai.services.api.EarliestDateResolver; +import org.dspace.xoai.services.api.config.ConfigurationService; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import javax.servlet.http.HttpServletRequest; -import java.io.File; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - /** - * * @author Lyncode Development Team (dspace at lyncode dot com) * @author Domingo Iglesias (diglesias at ub dot edu) */ -public class DSpaceRepositoryConfiguration implements RepositoryConfiguration -{ +public class DSpaceRepositoryConfiguration implements RepositoryConfiguration { private static Logger log = LogManager.getLogger(DSpaceRepositoryConfiguration.class); private List emails = null; @@ -44,126 +42,120 @@ public class DSpaceRepositoryConfiguration implements RepositoryConfiguration private EarliestDateResolver dateResolver; private ConfigurationService configurationService; - public DSpaceRepositoryConfiguration(EarliestDateResolver dateResolver, ConfigurationService configurationService, Context context) - { + public DSpaceRepositoryConfiguration(EarliestDateResolver dateResolver, ConfigurationService configurationService, + Context context) { this.dateResolver = dateResolver; this.configurationService = configurationService; this.context = context; } @Override - public List getAdminEmails() - { - if (emails == null) - { + public List getAdminEmails() { + if (emails == null) { emails = new ArrayList(); String result = configurationService.getProperty("mail.admin"); - if (result == null) - { - log.warn("{ OAI 2.0 :: DSpace } Not able to retrieve the mail.admin property from the configuration file"); - } - else + if (result == null) { + log.warn( + "{ OAI 2.0 :: DSpace } Not able to retrieve the mail.admin property from the configuration file"); + } else { emails.add(result); + } } return emails; } @Override - public String getBaseUrl() - { - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); - if (baseUrl == null) - { + public String getBaseUrl() { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) + .getRequest(); + if (baseUrl == null) { baseUrl = configurationService.getProperty("oai.url"); if (baseUrl == null) { - log.warn("{ OAI 2.0 :: DSpace } Not able to retrieve the oai.url property from oai.cfg. Falling back to request address"); + log.warn( + "{ OAI 2.0 :: DSpace } Not able to retrieve the oai.url property from oai.cfg. Falling back to " + + "request address"); baseUrl = request.getRequestURL().toString() - .replace(request.getPathInfo(), ""); + .replace(request.getPathInfo(), ""); } } return baseUrl + request.getPathInfo(); } @Override - public DeleteMethod getDeleteMethod() - { + public DeleteMethod getDeleteMethod() { return DeleteMethod.TRANSIENT; } @Override - public Date getEarliestDate() - { + public Date getEarliestDate() { // Look at the database! - try - { + try { return dateResolver.getEarliestDate(context); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error(e.getMessage(), e); - } - catch (InvalidMetadataFieldException e) - { + } catch (InvalidMetadataFieldException e) { log.error(e.getMessage(), e); } return new Date(); } @Override - public Granularity getGranularity() - { + public Granularity getGranularity() { return Granularity.Second; } @Override - public String getRepositoryName() - { - if (name == null) - { + public String getRepositoryName() { + if (name == null) { name = configurationService.getProperty("dspace.name"); - if (name == null) - { - log.warn("{ OAI 2.0 :: DSpace } Not able to retrieve the dspace.name property from the configuration file"); + if (name == null) { + log.warn( + "{ OAI 2.0 :: DSpace } Not able to retrieve the dspace.name property from the configuration file"); name = "OAI Repository"; } } return name; } - @Override - public List getDescription() { - List result = new ArrayList(); - String descriptionFile = configurationService.getProperty("oai", "description.file"); - if (descriptionFile == null) { - // Try indexed - boolean stop = false; - List descriptionFiles = new ArrayList(); - for (int i=0;!stop;i++) { - String tmp = configurationService.getProperty("oai", "description.file."+i); - if (tmp == null) stop = true; - else descriptionFiles.add(tmp); - } - - for (String path : descriptionFiles) { - try { - File f = new File(path); - if (f.exists()) - result.add(FileUtils.readFileToString(f)); - } catch (IOException e) { - log.debug(e.getMessage(), e); - } - } - - } else { - try { - File f = new File(descriptionFile); - if (f.exists()) - result.add(FileUtils.readFileToString(f)); - } catch (IOException e) { - log.debug(e.getMessage(), e); - } - } - return result; - } + @Override + public List getDescription() { + List result = new ArrayList(); + String descriptionFile = configurationService.getProperty("oai", "description.file"); + if (descriptionFile == null) { + // Try indexed + boolean stop = false; + List descriptionFiles = new ArrayList(); + for (int i = 0; !stop; i++) { + String tmp = configurationService.getProperty("oai", "description.file." + i); + if (tmp == null) { + stop = true; + } else { + descriptionFiles.add(tmp); + } + } + + for (String path : descriptionFiles) { + try { + File f = new File(path); + if (f.exists()) { + result.add(FileUtils.readFileToString(f)); + } + } catch (IOException e) { + log.debug(e.getMessage(), e); + } + } + + } else { + try { + File f = new File(descriptionFile); + if (f.exists()) { + result.add(FileUtils.readFileToString(f)); + } + } catch (IOException e) { + log.debug(e.getMessage(), e); + } + } + return result; + } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceResumptionTokenFormatter.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceResumptionTokenFormatter.java index e177f932b1..f79cd873ee 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceResumptionTokenFormatter.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceResumptionTokenFormatter.java @@ -7,6 +7,8 @@ */ package org.dspace.xoai.services.impl.xoai; +import java.util.Date; + import com.lyncode.xoai.dataprovider.core.ResumptionToken; import com.lyncode.xoai.dataprovider.exceptions.BadResumptionToken; import com.lyncode.xoai.dataprovider.services.api.ResumptionTokenFormatter; @@ -14,12 +16,10 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.dspace.xoai.util.DateUtils; -import java.util.Date; - public class DSpaceResumptionTokenFormatter implements ResumptionTokenFormatter { private static Logger log = LogManager - .getLogger(DSpaceResumptionTokenFormatter.class); + .getLogger(DSpaceResumptionTokenFormatter.class); public DSpaceResumptionTokenFormatter() { // TODO Auto-generated constructor stub @@ -27,10 +27,13 @@ public class DSpaceResumptionTokenFormatter implements ResumptionTokenFormatter @Override public ResumptionToken parse(String resumptionToken) throws BadResumptionToken { - if (resumptionToken == null) return new ResumptionToken(); + if (resumptionToken == null) { + return new ResumptionToken(); + } String[] res = resumptionToken.split("/", -1); - if (res.length != 5) throw new BadResumptionToken(); - else { + if (res.length != 5) { + throw new BadResumptionToken(); + } else { try { int offset = Integer.parseInt(res[4]); String prefix = (res[0].equals("")) ? null : res[0]; @@ -49,17 +52,21 @@ public class DSpaceResumptionTokenFormatter implements ResumptionTokenFormatter @Override public String format(ResumptionToken resumptionToken) { String result = ""; - if (resumptionToken.hasMetadataPrefix()) + if (resumptionToken.hasMetadataPrefix()) { result += resumptionToken.getMetadataPrefix(); + } result += "/"; - if (resumptionToken.hasFrom()) + if (resumptionToken.hasFrom()) { result += DateUtils.format(resumptionToken.getFrom()); + } result += "/"; - if (resumptionToken.hasUntil()) + if (resumptionToken.hasUntil()) { result += DateUtils.format(resumptionToken.getUntil()); + } result += "/"; - if (resumptionToken.hasSet()) + if (resumptionToken.hasSet()) { result += resumptionToken.getSet(); + } result += "/"; result += resumptionToken.getOffset(); return result; diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceSetRepository.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceSetRepository.java index dbda548163..859f2390a8 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceSetRepository.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceSetRepository.java @@ -7,6 +7,10 @@ */ package org.dspace.xoai.services.impl.xoai; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + import com.lyncode.xoai.dataprovider.core.ListSetsResult; import com.lyncode.xoai.dataprovider.core.Set; import com.lyncode.xoai.dataprovider.services.api.SetRepository; @@ -15,24 +19,18 @@ import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; -import org.dspace.core.Context; -import org.dspace.xoai.data.DSpaceSet; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; 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.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; +import org.dspace.xoai.data.DSpaceSet; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DSpaceSetRepository implements SetRepository -{ +public class DSpaceSetRepository implements SetRepository { private static final Logger log = LogManager.getLogger(DSpaceSetRepository.class); private final Context _context; @@ -41,39 +39,30 @@ public class DSpaceSetRepository implements SetRepository private final CommunityService communityService; private final CollectionService collectionService; - public DSpaceSetRepository(Context context) - { + public DSpaceSetRepository(Context context) { _context = context; handleService = HandleServiceFactory.getInstance().getHandleService(); communityService = ContentServiceFactory.getInstance().getCommunityService(); collectionService = ContentServiceFactory.getInstance().getCollectionService(); } - private int getCommunityCount() - { - try - { + private int getCommunityCount() { + try { List communityList = communityService.findAll(_context); return communityList.size(); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error(e.getMessage(), e); } return 0; } - private int getCollectionCount() - { - try - { + private int getCollectionCount() { + try { List collectionList = collectionService.findAll(_context); return collectionList.size(); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error(e.getMessage(), e); } return 0; @@ -87,23 +76,18 @@ public class DSpaceSetRepository implements SetRepository * @param length return up to this many Sets. * @return some Sets representing the Community list segment. */ - private List community(int offset, int length) - { + private List community(int offset, int length) { List array = new ArrayList(); - try - { + try { List communityList = communityService.findAll(_context, length, offset); - for(Community community : communityList) - { + for (Community community : communityList) { array.add(DSpaceSet.newDSpaceCommunitySet( - community.getHandle(), - community.getName())); + community.getHandle(), + community.getName())); } - } - catch (SQLException e) - { + } catch (SQLException e) { log.error(e.getMessage(), e); } return array; @@ -117,31 +101,25 @@ public class DSpaceSetRepository implements SetRepository * @param length return up to this many Sets. * @return some Sets representing the Collection list segment. */ - private List collection(int offset, int length) - { + private List collection(int offset, int length) { List array = new ArrayList(); - try - { + try { List collectionList = collectionService.findAll(_context, length, offset); - for(Collection collection : collectionList) - { + for (Collection collection : collectionList) { array.add(DSpaceSet.newDSpaceCollectionSet( - collection.getHandle(), - collection.getName())); + collection.getHandle(), + collection.getName())); } - } - catch (SQLException e) - { + } catch (SQLException e) { log.error(e.getMessage(), e); } return array; } @Override - public ListSetsResult retrieveSets(int offset, int length) - { + public ListSetsResult retrieveSets(int offset, int length) { // Only database sets (virtual sets are added by lyncode common library) log.debug("Querying sets. Offset: " + offset + " - Length: " + length); List array = new ArrayList(); @@ -150,66 +128,53 @@ public class DSpaceSetRepository implements SetRepository int collectionCount = this.getCollectionCount(); log.debug("Collections: " + collectionCount); - if (offset < communityCount) - { - if (offset + length > communityCount) - { + if (offset < communityCount) { + if (offset + length > communityCount) { // Add some collections List tmp = community(offset, length); array.addAll(tmp); array.addAll(collection(0, length - tmp.size())); - } - else + } else { array.addAll(community(offset, length)); - } - else if (offset < communityCount + collectionCount) - { + } + } else if (offset < communityCount + collectionCount) { array.addAll(collection(offset - communityCount, length)); } log.debug("Has More Results: " - + ((offset + length < communityCount + collectionCount) ? "Yes" - : "No")); + + ((offset + length < communityCount + collectionCount) ? "Yes" + : "No")); return new ListSetsResult(offset + length < communityCount - + collectionCount, array, communityCount + collectionCount); + + collectionCount, array, communityCount + collectionCount); } @Override - public boolean supportSets() - { + public boolean supportSets() { return true; } @Override - public boolean exists(String setSpec) - { - if (setSpec.startsWith("col_")) - { - try - { + public boolean exists(String setSpec) { + if (setSpec.startsWith("col_")) { + try { DSpaceObject dso = handleService.resolveToObject(_context, - setSpec.replace("col_", "").replace("_", "/")); - if (dso == null || !(dso instanceof Collection)) + setSpec.replace("col_", "").replace("_", "/")); + if (dso == null || !(dso instanceof Collection)) { return false; + } return true; - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error(ex.getMessage(), ex); } - } - else if (setSpec.startsWith("com_")) - { - try - { + } else if (setSpec.startsWith("com_")) { + try { DSpaceObject dso = handleService.resolveToObject(_context, - setSpec.replace("com_", "").replace("_", "/")); - if (dso == null || !(dso instanceof Community)) + setSpec.replace("com_", "").replace("_", "/")); + if (dso == null || !(dso instanceof Community)) { return false; + } return true; - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error(ex.getMessage(), ex); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/solr/DSpaceSolrSearch.java b/dspace-oai/src/main/java/org/dspace/xoai/solr/DSpaceSolrSearch.java index 894050bd34..9eb0cb2272 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/solr/DSpaceSolrSearch.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/solr/DSpaceSolrSearch.java @@ -19,40 +19,37 @@ import org.dspace.xoai.solr.exceptions.DSpaceSolrException; import org.dspace.xoai.solr.exceptions.SolrSearchEmptyException; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DSpaceSolrSearch -{ +public class DSpaceSolrSearch { + + /** + * Default constructor + */ + private DSpaceSolrSearch() { } + public static SolrDocumentList query(SolrServer server, SolrQuery solrParams) - throws DSpaceSolrException - { - try - { + throws DSpaceSolrException { + try { solrParams.addSortField("item.id", ORDER.asc); QueryResponse response = server.query(solrParams); return response.getResults(); - } - catch (SolrServerException ex) - { + } catch (SolrServerException ex) { throw new DSpaceSolrException(ex.getMessage(), ex); } } public static SolrDocument querySingle(SolrServer server, SolrQuery solrParams) - throws SolrSearchEmptyException - { - try - { + throws SolrSearchEmptyException { + try { solrParams.addSortField("item.id", ORDER.asc); QueryResponse response = server.query(solrParams); - if (response.getResults().getNumFound() > 0) + if (response.getResults().getNumFound() > 0) { return response.getResults().get(0); - else + } else { throw new SolrSearchEmptyException(); - } - catch (SolrServerException ex) - { + } + } catch (SolrServerException ex) { throw new SolrSearchEmptyException(ex.getMessage(), ex); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/solr/DSpaceSolrServer.java b/dspace-oai/src/main/java/org/dspace/xoai/solr/DSpaceSolrServer.java index 5cebef156c..975bb8ada6 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/solr/DSpaceSolrServer.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/solr/DSpaceSolrServer.java @@ -16,27 +16,25 @@ import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.dspace.core.ConfigurationManager; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DSpaceSolrServer -{ +public class DSpaceSolrServer { private static Logger log = LogManager.getLogger(DSpaceSolrServer.class); private static SolrServer _server = null; - public static SolrServer getServer() throws SolrServerException - { - if (_server == null) - { - try - { + /** + * Default constructor + */ + private DSpaceSolrServer() { } + + public static SolrServer getServer() throws SolrServerException { + if (_server == null) { + try { _server = new HttpSolrServer( - ConfigurationManager.getProperty("oai", "solr.url")); + ConfigurationManager.getProperty("oai", "solr.url")); log.debug("Solr Server Initialized"); - } - catch (Exception e) - { + } catch (Exception e) { log.error(e.getMessage(), e); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrException.java b/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrException.java index 63a2aa93d8..60fb157209 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrException.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrException.java @@ -8,35 +8,29 @@ package org.dspace.xoai.solr.exceptions; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ @SuppressWarnings("serial") -public class DSpaceSolrException extends Exception -{ +public class DSpaceSolrException extends Exception { /** * Creates a new instance of DSpaceSolrException without detail * message. */ - public DSpaceSolrException() - { + public DSpaceSolrException() { } /** * Constructs an instance of DSpaceSolrException with the * specified detail message. - * - * @param msg - * the detail message. + * + * @param msg the detail message. */ - public DSpaceSolrException(String msg) - { + public DSpaceSolrException(String msg) { super(msg); } - public DSpaceSolrException(String msg, Throwable t) - { + public DSpaceSolrException(String msg, Throwable t) { super(msg, t); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrIndexerException.java b/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrIndexerException.java index c72bbb80c5..dd7004dd4e 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrIndexerException.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrIndexerException.java @@ -9,34 +9,28 @@ package org.dspace.xoai.solr.exceptions; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ @SuppressWarnings("serial") -public class DSpaceSolrIndexerException extends Exception -{ +public class DSpaceSolrIndexerException extends Exception { /** * Creates a new instance of DSpaceSolrException without detail * message. */ - public DSpaceSolrIndexerException() - { + public DSpaceSolrIndexerException() { } /** * Constructs an instance of DSpaceSolrException with the * specified detail message. - * - * @param msg - * the detail message. + * + * @param msg the detail message. */ - public DSpaceSolrIndexerException(String msg) - { + public DSpaceSolrIndexerException(String msg) { super(msg); } - public DSpaceSolrIndexerException(String msg, Throwable t) - { + public DSpaceSolrIndexerException(String msg, Throwable t) { super(msg, t); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/SolrSearchEmptyException.java b/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/SolrSearchEmptyException.java index d1db3e59c3..036b79e3bf 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/SolrSearchEmptyException.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/solr/exceptions/SolrSearchEmptyException.java @@ -9,35 +9,29 @@ package org.dspace.xoai.solr.exceptions; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ @SuppressWarnings("serial") -public class SolrSearchEmptyException extends Exception -{ +public class SolrSearchEmptyException extends Exception { /** * Creates a new instance of SolrSearchEmptyException without * detail message. */ - public SolrSearchEmptyException() - { + public SolrSearchEmptyException() { } /** * Constructs an instance of SolrSearchEmptyException with the * specified detail message. - * - * @param msg - * the detail message. + * + * @param msg the detail message. */ - public SolrSearchEmptyException(String msg) - { + public SolrSearchEmptyException(String msg) { super(msg); } - public SolrSearchEmptyException(String msg, Throwable t) - { + public SolrSearchEmptyException(String msg, Throwable t) { super(msg, t); } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/util/DateUtils.java b/dspace-oai/src/main/java/org/dspace/xoai/util/DateUtils.java index b269ad7a39..611d0692f7 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/util/DateUtils.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/util/DateUtils.java @@ -7,24 +7,26 @@ */ package org.dspace.xoai.util; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class DateUtils -{ +public class DateUtils { private static Logger log = LogManager.getLogger(DateUtils.class); + /** + * Default constructor + */ + private DateUtils() { } /** * Format a Date object as a valid UTC Date String, per OAI-PMH guidelines @@ -33,73 +35,57 @@ public class DateUtils * @param date Date object * @return UTC date string */ - public static String format(Date date) - { + public static String format(Date date) { // NOTE: OAI-PMH REQUIRES that all dates be expressed in UTC format // as YYYY-MM-DDThh:mm:ssZ For more details, see // http://www.openarchives.org/OAI/openarchivesprotocol.html#DatestampsResponses SimpleDateFormat sdf = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss'Z'"); - // We indicate that the returned date is in Zulu time (UTC) so we have + "yyyy-MM-dd'T'HH:mm:ss'Z'"); + // We indicate that the returned date is in UTC so we have // to set the time zone of sdf correctly - sdf.setTimeZone(TimeZone.getTimeZone("ZULU")); + sdf.setTimeZone(TimeZone.getTimeZone("UTC")); String ret = sdf.format(date); return ret; } /** * Parse a string into a Date object + * * @param date string to parse * @return Date */ - public static Date parse(String date) - { + public static Date parse(String date) { // First try to parse as a full UTC date/time, e.g. 2008-01-01T00:00:00Z SimpleDateFormat format = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss'Z'"); - format.setTimeZone(TimeZone.getTimeZone("ZULU")); + "yyyy-MM-dd'T'HH:mm:ss'Z'"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); Date ret; - try - { + try { ret = format.parse(date); return ret; - } - catch (ParseException ex) - { + } catch (ParseException ex) { // If a parse exception, try other logical date/time formats // based on the local timezone format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", - Locale.getDefault()); - try - { + Locale.getDefault()); + try { return format.parse(date); - } - catch (ParseException e1) - { + } catch (ParseException e1) { format = new SimpleDateFormat("yyyy-MM-dd", - Locale.getDefault()); - try - { + Locale.getDefault()); + try { return format.parse(date); - } - catch (ParseException e2) - { + } catch (ParseException e2) { format = new SimpleDateFormat("yyyy-MM", - Locale.getDefault()); - try - { + Locale.getDefault()); + try { return format.parse(date); - } - catch (ParseException e3) - { + } catch (ParseException e3) { format = new SimpleDateFormat("yyyy", - Locale.getDefault()); - try - { + Locale.getDefault()); + try { return format.parse(date); - } - catch (ParseException e4) - { + } catch (ParseException e4) { log.error(e4.getMessage(), e4); } } @@ -109,19 +95,15 @@ public class DateUtils return new Date(); } - public static Date parseFromSolrDate(String date) - { + public static Date parseFromSolrDate(String date) { SimpleDateFormat format = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss'Z'"); - format.setTimeZone(TimeZone.getTimeZone("ZULU")); + "yyyy-MM-dd'T'HH:mm:ss'Z'"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); Date ret; - try - { + try { ret = format.parse(date); return ret; - } - catch (ParseException e) - { + } catch (ParseException e) { log.error(e.getMessage(), e); } return new Date(); diff --git a/dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java b/dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java index 316c9dbe93..1faee45890 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java @@ -7,123 +7,124 @@ */ package org.dspace.xoai.util; -import com.lyncode.xoai.dataprovider.xml.xoai.Element; -import com.lyncode.xoai.dataprovider.xml.xoai.Metadata; -import com.lyncode.xoai.util.Base64Utils; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; -import org.dspace.content.authority.Choices; -import org.dspace.core.ConfigurationManager; -import org.dspace.core.Constants; -import org.dspace.core.Utils; -import org.dspace.xoai.data.DSpaceItem; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import java.util.List; + +import com.lyncode.xoai.dataprovider.xml.xoai.Element; +import com.lyncode.xoai.dataprovider.xml.xoai.Metadata; +import com.lyncode.xoai.util.Base64Utils; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; import org.dspace.app.util.factory.UtilServiceFactory; import org.dspace.app.util.service.MetadataExposureService; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataValue; +import org.dspace.content.authority.Choices; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.ItemService; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; import org.dspace.core.Context; +import org.dspace.core.Utils; +import org.dspace.xoai.data.DSpaceItem; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ @SuppressWarnings("deprecation") -public class ItemUtils -{ +public class ItemUtils { private static final Logger log = LogManager.getLogger(ItemUtils.class); - + private static final MetadataExposureService metadataExposureService - = UtilServiceFactory.getInstance().getMetadataExposureService(); + = UtilServiceFactory.getInstance().getMetadataExposureService(); private static final ItemService itemService - = ContentServiceFactory.getInstance().getItemService(); + = ContentServiceFactory.getInstance().getItemService(); private static final BitstreamService bitstreamService - = ContentServiceFactory.getInstance().getBitstreamService(); + = ContentServiceFactory.getInstance().getBitstreamService(); - private static Element getElement(List list, String name) - { - for (Element e : list) - if (name.equals(e.getName())) + /** + * Default constructor + */ + private ItemUtils() { } + + private static Element getElement(List list, String name) { + for (Element e : list) { + if (name.equals(e.getName())) { return e; + } + } return null; } - private static Element create(String name) - { + + private static Element create(String name) { Element e = new Element(); e.setName(name); return e; } private static Element.Field createValue( - String name, String value) - { + String name, String value) { Element.Field e = new Element.Field(); e.setValue(value); e.setName(name); return e; } - public static Metadata retrieveMetadata (Context context, Item item) { + + public static Metadata retrieveMetadata(Context context, Item item) { Metadata metadata; // read all metadata into Metadata Object metadata = new Metadata(); List vals = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue val : vals) - { + for (MetadataValue val : vals) { MetadataField field = val.getMetadataField(); - + // Don't expose fields that are hidden by configuration try { if (metadataExposureService.isHidden(context, - field.getMetadataSchema().getName(), - field.getElement(), - field.getQualifier())) - { + field.getMetadataSchema().getName(), + field.getElement(), + field.getQualifier())) { continue; } - } catch(SQLException se) { + } catch (SQLException se) { throw new RuntimeException(se); } Element valueElem = null; Element schema = getElement(metadata.getElement(), field.getMetadataSchema().getName()); - if (schema == null) - { + if (schema == null) { schema = create(field.getMetadataSchema().getName()); metadata.getElement().add(schema); } valueElem = schema; // Has element.. with XOAI one could have only schema and value - if (field.getElement() != null && !field.getElement().equals("")) - { + if (field.getElement() != null && !field.getElement().equals("")) { Element element = getElement(schema.getElement(), - field.getElement()); - if (element == null) - { + field.getElement()); + if (element == null) { element = create(field.getElement()); schema.getElement().add(element); } valueElem = element; // Qualified element? - if (field.getQualifier() != null && !field.getQualifier().equals("")) - { + if (field.getQualifier() != null && !field.getQualifier().equals("")) { Element qualifier = getElement(element.getElement(), - field.getQualifier()); - if (qualifier == null) - { + field.getQualifier()); + if (qualifier == null) { qualifier = create(field.getQualifier()); element.getElement().add(qualifier); } @@ -132,23 +133,18 @@ public class ItemUtils } // Language? - if (val.getLanguage() != null && !val.getLanguage().equals("")) - { + if (val.getLanguage() != null && !val.getLanguage().equals("")) { Element language = getElement(valueElem.getElement(), - val.getLanguage()); - if (language == null) - { + val.getLanguage()); + if (language == null) { language = create(val.getLanguage()); valueElem.getElement().add(language); } valueElem = language; - } - else - { + } else { Element language = getElement(valueElem.getElement(), - "none"); - if (language == null) - { + "none"); + if (language == null) { language = create("none"); valueElem.getElement().add(language); } @@ -158,8 +154,9 @@ public class ItemUtils valueElem.getField().add(createValue("value", val.getValue())); if (val.getAuthority() != null) { valueElem.getField().add(createValue("authority", val.getAuthority())); - if (val.getConfidence() != Choices.CF_NOVALUE) + if (val.getConfidence() != Choices.CF_NOVALUE) { valueElem.getField().add(createValue("confidence", val.getConfidence() + "")); + } } } // Done! Metadata has been read! @@ -168,55 +165,46 @@ public class ItemUtils metadata.getElement().add(bundles); List bs; - try - { + try { bs = item.getBundles(); - for (Bundle b : bs) - { + for (Bundle b : bs) { Element bundle = create("bundle"); bundles.getElement().add(bundle); bundle.getField() - .add(createValue("name", b.getName())); + .add(createValue("name", b.getName())); Element bitstreams = create("bitstreams"); bundle.getElement().add(bitstreams); List bits = b.getBitstreams(); - for (Bitstream bit : bits) - { + for (Bitstream bit : bits) { Element bitstream = create("bitstream"); bitstreams.getElement().add(bitstream); String url = ""; String bsName = bit.getName(); String sid = String.valueOf(bit.getSequenceID()); String baseUrl = ConfigurationManager.getProperty("oai", - "bitstream.baseUrl"); + "bitstream.baseUrl"); String handle = null; // get handle of parent Item of this bitstream, if there // is one: List bn = bit.getBundles(); - if (!bn.isEmpty()) - { + if (!bn.isEmpty()) { List bi = bn.get(0).getItems(); - if (!bi.isEmpty()) - { + if (!bi.isEmpty()) { handle = bi.get(0).getHandle(); } } - if (bsName == null) - { + if (bsName == null) { List ext = bit.getFormat(context).getExtensions(); bsName = "bitstream_" + sid - + (ext.isEmpty() ? "" : ext.get(0)); + + (ext.isEmpty() ? "" : ext.get(0)); } - if (handle != null && baseUrl != null) - { + if (handle != null && baseUrl != null) { url = baseUrl + "/bitstream/" - + handle + "/" - + sid + "/" - + URLUtils.encode(bsName); - } - else - { + + handle + "/" + + sid + "/" + + URLUtils.encode(bsName); + } else { url = URLUtils.encode(bsName); } @@ -226,96 +214,89 @@ public class ItemUtils String name = bit.getName(); String description = bit.getDescription(); - if (name != null) + if (name != null) { bitstream.getField().add( - createValue("name", name)); - if (oname != null) + createValue("name", name)); + } + if (oname != null) { bitstream.getField().add( - createValue("originalName", name)); - if (description != null) + createValue("originalName", name)); + } + if (description != null) { bitstream.getField().add( - createValue("description", description)); + createValue("description", description)); + } bitstream.getField().add( - createValue("format", bit.getFormat(context) - .getMIMEType())); + createValue("format", bit.getFormat(context) + .getMIMEType())); bitstream.getField().add( - createValue("size", "" + bit.getSize())); + createValue("size", "" + bit.getSizeBytes())); bitstream.getField().add(createValue("url", url)); bitstream.getField().add( - createValue("checksum", cks)); + createValue("checksum", cks)); bitstream.getField().add( - createValue("checksumAlgorithm", cka)); + createValue("checksumAlgorithm", cka)); bitstream.getField().add( - createValue("sid", bit.getSequenceID() - + "")); + createValue("sid", bit.getSequenceID() + + "")); } } - } - catch (SQLException e1) - { + } catch (SQLException e1) { e1.printStackTrace(); } - + // Other info Element other = create("others"); other.getField().add( - createValue("handle", item.getHandle())); + createValue("handle", item.getHandle())); other.getField().add( - createValue("identifier", DSpaceItem.buildIdentifier(item.getHandle()))); + createValue("identifier", DSpaceItem.buildIdentifier(item.getHandle()))); other.getField().add( - createValue("lastModifyDate", item - .getLastModified().toString())); + createValue("lastModifyDate", item + .getLastModified().toString())); metadata.getElement().add(other); // Repository Info Element repository = create("repository"); repository.getField().add( - createValue("name", + createValue("name", ConfigurationManager.getProperty("dspace.name"))); repository.getField().add( - createValue("mail", + createValue("mail", ConfigurationManager.getProperty("mail.admin"))); metadata.getElement().add(repository); // Licensing info Element license = create("license"); List licBundles; - try - { + try { licBundles = itemService.getBundles(item, Constants.LICENSE_BUNDLE_NAME); - if (!licBundles.isEmpty()) - { + if (!licBundles.isEmpty()) { Bundle licBundle = licBundles.get(0); List licBits = licBundle.getBitstreams(); - if (!licBits.isEmpty()) - { + if (!licBits.isEmpty()) { Bitstream licBit = licBits.get(0); InputStream in; - try - { + try { in = bitstreamService.retrieve(context, licBit); ByteArrayOutputStream out = new ByteArrayOutputStream(); Utils.bufferedCopy(in, out); license.getField().add( - createValue("bin", + createValue("bin", Base64Utils.encode(out.toString()))); metadata.getElement().add(license); - } - catch (AuthorizeException | IOException | SQLException e) - { + } catch (AuthorizeException | IOException | SQLException e) { log.warn(e.getMessage(), e); } } } - } - catch (SQLException e1) - { + } catch (SQLException e1) { log.warn(e1.getMessage(), e1); } - + return metadata; } } diff --git a/dspace-oai/src/main/java/org/dspace/xoai/util/URLUtils.java b/dspace-oai/src/main/java/org/dspace/xoai/util/URLUtils.java index df0fcb9f85..c0ddf3e701 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/util/URLUtils.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/util/URLUtils.java @@ -7,28 +7,29 @@ */ package org.dspace.xoai.util; +import java.io.UnsupportedEncodingException; + import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.dspace.app.util.Util; import org.dspace.core.Constants; -import java.io.UnsupportedEncodingException; /** - * * @author Lyncode Development Team (dspace at lyncode dot com) */ -public class URLUtils -{ +public class URLUtils { private static Logger log = LogManager.getLogger(URLUtils.class); - public static String encode (String value) { - try - { - return Util.encodeBitstreamName(value, Constants.DEFAULT_ENCODING); + /** + * Default constructor + */ + private URLUtils() { } - } - catch (UnsupportedEncodingException e) - { + public static String encode(String value) { + try { + return Util.encodeBitstreamName(value, Constants.DEFAULT_ENCODING); + + } catch (UnsupportedEncodingException e) { log.warn(e.getMessage(), e); return value; } diff --git a/dspace-oai/src/main/webapp/WEB-INF/spring/applicationContext.xml b/dspace-oai/src/main/webapp/WEB-INF/spring/applicationContext.xml index b941b564a0..0b6f2cde61 100644 --- a/dspace-oai/src/main/webapp/WEB-INF/spring/applicationContext.xml +++ b/dspace-oai/src/main/webapp/WEB-INF/spring/applicationContext.xml @@ -8,36 +8,34 @@ http://www.dspace.org/license/ --> - + - - + + - - - + + + - + - + - + diff --git a/dspace-oai/src/main/webapp/WEB-INF/web.xml b/dspace-oai/src/main/webapp/WEB-INF/web.xml index 37de4376f9..54d207c099 100644 --- a/dspace-oai/src/main/webapp/WEB-INF/web.xml +++ b/dspace-oai/src/main/webapp/WEB-INF/web.xml @@ -8,17 +8,17 @@ http://www.dspace.org/license/ --> - - - XOAI Data Provider + - - The location of the DSpace home directory - dspace.dir - ${dspace.dir} - + XOAI Data Provider + + + The location of the DSpace home directory + dspace.dir + ${dspace.dir} + @@ -36,7 +36,7 @@ - org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener + org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener @@ -50,7 +50,7 @@ org.springframework.web.context.ContextLoaderListener - + oai org.springframework.web.servlet.DispatcherServlet - + diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index b254ab405d..6e5284b85c 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.dspace dspace-rdf @@ -45,25 +46,25 @@ dspace-services - - - org.springframework - spring-core - - - - org.springframework - spring-context - - - - org.springframework - spring-web - + + + org.springframework + spring-core + + + + org.springframework + spring-context + + + + org.springframework + spring-web + javax.servlet - servlet-api + javax.servlet-api provided diff --git a/dspace-rdf/src/main/java/org/dspace/rdf/providing/DataProviderServlet.java b/dspace-rdf/src/main/java/org/dspace/rdf/providing/DataProviderServlet.java index 3ddc0bec0f..1e07364187 100644 --- a/dspace-rdf/src/main/java/org/dspace/rdf/providing/DataProviderServlet.java +++ b/dspace-rdf/src/main/java/org/dspace/rdf/providing/DataProviderServlet.java @@ -8,7 +8,6 @@ package org.dspace.rdf.providing; -import com.hp.hpl.jena.rdf.model.Model; import java.io.IOException; import java.io.PrintWriter; import java.sql.SQLException; @@ -16,6 +15,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import com.hp.hpl.jena.rdf.model.Model; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.DSpaceObject; @@ -26,15 +27,14 @@ import org.dspace.rdf.RDFUtil; import org.dspace.services.factory.DSpaceServicesFactory; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class DataProviderServlet extends HttpServlet { protected static final String DEFAULT_LANG = "TURTLE"; - + private static final Logger log = Logger.getLogger(DataProviderServlet.class); - + protected final transient HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); /** @@ -42,14 +42,13 @@ public class DataProviderServlet extends HttpServlet { * GET and * POST methods. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException - { + throws ServletException, IOException { // set all incoming encoding to UTF-8 request.setCharacterEncoding("UTF-8"); @@ -58,25 +57,24 @@ public class DataProviderServlet extends HttpServlet { String lang = this.detectLanguage(request); String cType = this.detectContentType(request, lang); String pathInfo = request.getPathInfo(); - + log.debug("lang = " + lang + ", cType = " + cType + " and pathInfo: " + pathInfo); - if (StringUtils.isEmpty(pathInfo) || StringUtils.countMatches(pathInfo, "/") < 2) - { - String dspaceURI = - DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.url"); + if (StringUtils.isEmpty(pathInfo) || StringUtils.countMatches(pathInfo, "/") < 2) { + String dspaceURI = + DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("dspace.url"); this.serveNamedGraph(dspaceURI, lang, cType, response); return; } - + // remove trailing slash of the path info and split it. String[] path = request.getPathInfo().substring(1).split("/"); // if we have 2 slashes or less, we sent repository information (see above) assert path.length >= 2; - + String handle = path[0] + "/" + path[1]; - + log.debug("Handle: " + handle + "."); - + // As we offer a public sparql endpoint, all information that we stored // in the triplestore is public. It is important to check whether a // DSpaceObject is readable for a anonym user before storing it in the @@ -85,53 +83,43 @@ public class DataProviderServlet extends HttpServlet { // by RDFizer and RDFUtil we do not have to take care for permissions here! Context context = null; DSpaceObject dso = null; - try - { + try { context = new Context(Context.Mode.READ_ONLY); dso = handleService.resolveToObject(context, handle); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQLException: " + ex.getMessage(), ex); context.abort(); // probably a problem with the db connection => send Service Unavailable response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; - } - catch (IllegalStateException ex) - { - log.error("Cannot resolve handle " + handle - + ". IllegalStateException:" + ex.getMessage(), ex); + } catch (IllegalStateException ex) { + log.error("Cannot resolve handle " + handle + + ". IllegalStateException:" + ex.getMessage(), ex); context.abort(); response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } - if (dso == null) - { + if (dso == null) { log.info("Cannot resolve handle '" + handle + "' to dso. => 404"); context.abort(); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } - + String identifier = null; - try - { + try { identifier = RDFUtil.generateIdentifier(context, dso); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQLException: " + ex.getMessage(), ex); context.abort(); // probably a problem with the db connection => send Service Unavailable response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } - if (identifier == null) - { + if (identifier == null) { // cannot generate identifier for dso?! - log.error("Cannot generate identifier for UUID " - + dso.getID().toString() + "!"); + log.error("Cannot generate identifier for UUID " + + dso.getID().toString() + "!"); context.abort(); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; @@ -139,69 +127,82 @@ public class DataProviderServlet extends HttpServlet { log.debug("Loading and sending named graph " + identifier + "."); context.abort(); this.serveNamedGraph(identifier, lang, cType, response); - + } - - protected void serveNamedGraph(String uri, String lang, String contentType, - HttpServletResponse response) - throws ServletException, IOException - { + + protected void serveNamedGraph(String uri, String lang, String contentType, + HttpServletResponse response) + throws ServletException, IOException { Model result = null; result = RDFUtil.loadModel(uri); - if (result == null || result.isEmpty()) - { + if (result == null || result.isEmpty()) { response.sendError(HttpServletResponse.SC_NOT_FOUND); - if (result != null) result.close(); + if (result != null) { + result.close(); + } log.info("Sent 404 Not Found, as the loaded model was null or " - + "empty (URI: " + uri + ")."); + + "empty (URI: " + uri + ")."); return; } - + response.setContentType(contentType); PrintWriter out = response.getWriter(); log.debug("Set content-type to " + contentType + "."); try { result.write(out, lang); - } - finally - { + } finally { result.close(); out.close(); } } - - protected String detectContentType(HttpServletRequest request, String lang) - { + + protected String detectContentType(HttpServletRequest request, String lang) { // It is usefull to be able to overwrite the content type, to see the // request result directly in the browser. If a parameter "text" is part // of the request, we send the result with the content type "text/plain". - if (request.getParameter("text") != null) return "text/plain;charset=UTF-8"; - - if (lang.equalsIgnoreCase("TURTLE")) return "text/turtle;charset=UTF-8"; - if (lang.equalsIgnoreCase("n3")) return "text/n3;charset=UTF-8"; - if (lang.equalsIgnoreCase("RDF/XML")) return "application/rdf+xml;charset=UTF-8"; - if (lang.equalsIgnoreCase("N-TRIPLE")) return "application/n-triples;charset=UTF-8"; - + if (request.getParameter("text") != null) { + return "text/plain;charset=UTF-8"; + } + + if (lang.equalsIgnoreCase("TURTLE")) { + return "text/turtle;charset=UTF-8"; + } + if (lang.equalsIgnoreCase("n3")) { + return "text/n3;charset=UTF-8"; + } + if (lang.equalsIgnoreCase("RDF/XML")) { + return "application/rdf+xml;charset=UTF-8"; + } + if (lang.equalsIgnoreCase("N-TRIPLE")) { + return "application/n-triples;charset=UTF-8"; + } + throw new IllegalStateException("Cannot set content type for unknown language."); } - - protected String detectLanguage(HttpServletRequest request) - { + + protected String detectLanguage(HttpServletRequest request) { String pathInfo = request.getPathInfo(); - if (StringUtils.isEmpty(pathInfo)) return DEFAULT_LANG; + if (StringUtils.isEmpty(pathInfo)) { + return DEFAULT_LANG; + } String[] path = request.getPathInfo().split("/"); String lang = path[(path.length - 1)]; - - if (StringUtils.endsWithIgnoreCase(lang, "ttl")) return "TURTLE"; - if (StringUtils.equalsIgnoreCase(lang, "n3")) return "N3"; - if (StringUtils.equalsIgnoreCase(lang, "rdf") - || StringUtils.equalsIgnoreCase(lang, "xml")) - { + + if (StringUtils.endsWithIgnoreCase(lang, "ttl")) { + return "TURTLE"; + } + if (StringUtils.equalsIgnoreCase(lang, "n3")) { + return "N3"; + } + if (StringUtils.equalsIgnoreCase(lang, "rdf") + || StringUtils.equalsIgnoreCase(lang, "xml")) { return "RDF/XML"; } - if (StringUtils.endsWithIgnoreCase(lang, "nt")) return "N-TRIPLE"; + if (StringUtils.endsWithIgnoreCase(lang, "nt")) { + return "N-TRIPLE"; + } return DEFAULT_LANG; } @@ -210,13 +211,13 @@ public class DataProviderServlet extends HttpServlet { * Handles the HTTP * GET method. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { processRequest(request, response); } @@ -224,13 +225,13 @@ public class DataProviderServlet extends HttpServlet { * Handles the HTTP * POST method. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { processRequest(request, response); } diff --git a/dspace-rdf/src/main/java/org/dspace/rdf/providing/LocalURIRedirectionServlet.java b/dspace-rdf/src/main/java/org/dspace/rdf/providing/LocalURIRedirectionServlet.java index 133fe44d6a..33b4107128 100644 --- a/dspace-rdf/src/main/java/org/dspace/rdf/providing/LocalURIRedirectionServlet.java +++ b/dspace-rdf/src/main/java/org/dspace/rdf/providing/LocalURIRedirectionServlet.java @@ -13,6 +13,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.DSpaceObject; @@ -22,15 +23,13 @@ import org.dspace.handle.service.HandleService; import org.dspace.rdf.negotiation.Negotiator; /** - * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ -public class LocalURIRedirectionServlet extends HttpServlet -{ +public class LocalURIRedirectionServlet extends HttpServlet { public static final String ACCEPT_HEADER_NAME = "Accept"; - + private final static Logger log = Logger.getLogger(LocalURIRedirectionServlet.class); - + protected final transient HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); /** @@ -38,25 +37,23 @@ public class LocalURIRedirectionServlet extends HttpServlet * GET and * POST methods. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException - { + throws ServletException, IOException { // we expect a path in the form /resource//. String pathInfo = request.getPathInfo(); - + log.debug("Pathinfo: " + pathInfo); - if (StringUtils.isEmpty(pathInfo) || StringUtils.countMatches(pathInfo, "/") < 2) - { + if (StringUtils.isEmpty(pathInfo) || StringUtils.countMatches(pathInfo, "/") < 2) { log.debug("Path does not contain the expected number of slashes."); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } - + // remove trailing slash of the path info and split it. String[] path = request.getPathInfo().substring(1).split("/"); @@ -64,56 +61,50 @@ public class LocalURIRedirectionServlet extends HttpServlet // Prepare content negotiation int requestedMimeType = Negotiator.negotiate(request.getHeader(ACCEPT_HEADER_NAME)); - + Context context = null; DSpaceObject dso = null; - try - { + try { context = new Context(Context.Mode.READ_ONLY); dso = handleService.resolveToObject(context, handle); - } - catch (SQLException ex) - { + } catch (SQLException ex) { log.error("SQLException: " + ex.getMessage(), ex); context.abort(); // probably a problem with the db connection => send Service Unavailable response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; - } - catch (IllegalStateException ex) - { - log.error("Cannot resolve handle " + handle - + ". IllegalStateException:" + ex.getMessage(), ex); + } catch (IllegalStateException ex) { + log.error("Cannot resolve handle " + handle + + ". IllegalStateException:" + ex.getMessage(), ex); context.abort(); response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } - if (dso == null) - { + if (dso == null) { log.info("Cannot resolve handle '" + handle + "' to dso. => 404"); context.abort(); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } - + // close the context and send forward. context.abort(); Negotiator.sendRedirect(response, handle, "", requestedMimeType, true); } - + /** * Handles the HTTP * GET method. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { processRequest(request, response); } @@ -121,14 +112,14 @@ public class LocalURIRedirectionServlet extends HttpServlet * Handles the HTTP * POST method. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { processRequest(request, response); } diff --git a/dspace-rdf/src/main/java/org/dspace/utils/DSpaceWebapp.java b/dspace-rdf/src/main/java/org/dspace/utils/DSpaceWebapp.java index d6ff2e5bb8..2cac63f702 100644 --- a/dspace-rdf/src/main/java/org/dspace/utils/DSpaceWebapp.java +++ b/dspace-rdf/src/main/java/org/dspace/utils/DSpaceWebapp.java @@ -2,7 +2,7 @@ * 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,16 +15,13 @@ import org.dspace.app.util.AbstractDSpaceWebapp; * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class DSpaceWebapp -extends AbstractDSpaceWebapp -{ - public DSpaceWebapp() - { + extends AbstractDSpaceWebapp { + public DSpaceWebapp() { super("RDF"); } @Override - public boolean isUI() - { + public boolean isUI() { return false; } } diff --git a/dspace-rdf/src/main/webapp/WEB-INF/web.xml b/dspace-rdf/src/main/webapp/WEB-INF/web.xml index fea7e06121..65f22b637b 100644 --- a/dspace-rdf/src/main/webapp/WEB-INF/web.xml +++ b/dspace-rdf/src/main/webapp/WEB-INF/web.xml @@ -8,11 +8,9 @@ http://www.dspace.org/license/ --> - + RDF Data Provider @@ -46,7 +44,7 @@ rdf-serialization org.dspace.rdf.providing.DataProviderServlet - + local-uri-redirection org.dspace.rdf.providing.LocalURIRedirectionServlet @@ -57,7 +55,7 @@ rdf-serialization /handle/* - + local-uri-redirection /resource/* diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml index c7917fe257..b4f54dbd32 100644 --- a/dspace-rest/pom.xml +++ b/dspace-rest/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.dspace dspace-rest @@ -51,22 +52,33 @@ org.glassfish.jersey.core jersey-server - 2.22.1 + ${jersey.version} org.glassfish.jersey.containers jersey-container-servlet - 2.22.1 + ${jersey.version} org.glassfish.jersey.media jersey-media-json-jackson - 2.22.1 + ${jersey.version} - com.fasterxml.jackson.core - jackson-annotations + jackson-module-jaxb-annotations + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations @@ -74,7 +86,22 @@ com.fasterxml.jackson.core jackson-annotations - 2.5.4 + ${jackson.version} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + ${jackson.version} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${jackson.version} + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + ${jackson.version} @@ -82,22 +109,22 @@ org.springframework spring-core - + org.springframework spring-context - + org.springframework spring-web - + org.glassfish.jersey.ext - jersey-spring3 - 2.22.1 + jersey-spring4 + ${jersey.version} org.springframework @@ -193,7 +220,6 @@ javax.servlet javax.servlet-api - 3.1.0 provided diff --git a/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java b/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java index 724eb536d5..eb96a53185 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java @@ -14,7 +14,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.UUID; - import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -58,14 +57,16 @@ import org.dspace.usage.UsageEvent; // Every DSpace class used without namespace is from package // org.dspace.rest.common.*. Otherwise namespace is defined. @Path("/bitstreams") -public class BitstreamResource extends Resource -{ +public class BitstreamResource extends Resource { protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); - protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); - protected BitstreamStorageService bitstreamStorageService = StorageServiceFactory.getInstance().getBitstreamStorageService(); - protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); + protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); + protected BitstreamStorageService bitstreamStorageService = StorageServiceFactory.getInstance() + .getBitstreamStorageService(); + protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance() + .getResourcePolicyService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); private static Logger log = Logger.getLogger(BitstreamResource.class); @@ -78,72 +79,60 @@ public class BitstreamResource extends Resource * logged into the DSpace context does not have the permission to access the * bitstream. Server error when something went wrong. * - * @param bitstreamId - * Id of bitstream in DSpace. - * @param expand - * This string defines which additional optional fields will be added - * to bitstream response. Individual options are separated by commas without - * spaces. The options are: "all", "parent". - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * @param bitstreamId Id of bitstream in DSpace. + * @param expand This string defines which additional optional fields will be added + * to bitstream response. Individual options are separated by commas without + * spaces. The options are: "all", "parent". + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return If user is allowed to read bitstream, it returns instance of - * bitstream. Otherwise, it throws WebApplicationException with - * response code UNAUTHORIZED. - * @throws WebApplicationException - * It can happen on: Bad request, unauthorized, SQL exception - * and context exception(could not create context). + * bitstream. Otherwise, it throws WebApplicationException with + * response code UNAUTHORIZED. + * @throws WebApplicationException It can happen on: Bad request, unauthorized, SQL exception + * and context exception(could not create context). */ @GET @Path("/{bitstream_id}") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Bitstream getBitstream(@PathParam("bitstream_id") String bitstreamId, @QueryParam("expand") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading bitstream(id=" + bitstreamId + ") metadata."); org.dspace.core.Context context = null; Bitstream bitstream = null; - try - { + try { context = createContext(); - org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.READ); + org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, + org.dspace.core.Constants.READ); writeStats(dspaceBitstream, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); bitstream = new Bitstream(dspaceBitstream, servletContext, expand, context); context.complete(); log.trace("Bitstream(id=" + bitstreamId + ") was successfully read."); - } - catch (SQLException e) - { - processException("Someting went wrong while reading bitstream(id=" + bitstreamId + ") from database! Message: " + e, - context); - } - catch (ContextException e) - { - processException("Someting went wrong while reading bitstream(id=" + bitstreamId + "), ContextException. Message: " + } catch (SQLException e) { + processException( + "Someting went wrong while reading bitstream(id=" + bitstreamId + ") from database! Message: " + e, + context); + } catch (ContextException e) { + processException( + "Someting went wrong while reading bitstream(id=" + bitstreamId + "), ContextException. Message: " + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -154,46 +143,38 @@ public class BitstreamResource extends Resource * Return all bitstream resource policies from all bundles, in which * the bitstream is present. * - * @param bitstreamId - * Id of bitstream in DSpace. - * @param headers - * If you want to access the item as the user logged into the context. - * The header "rest-dspace-token" with the token passed - * from the login method must be set. + * @param bitstreamId Id of bitstream in DSpace. + * @param headers If you want to access the item as the user logged into the context. + * The header "rest-dspace-token" with the token passed + * from the login method must be set. * @return Returns an array of ResourcePolicy objects. */ @GET @Path("/{bitstream_id}/policy") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public ResourcePolicy[] getBitstreamPolicies(@PathParam("bitstream_id") String bitstreamId, @Context HttpHeaders headers) - { + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResourcePolicy[] getBitstreamPolicies(@PathParam("bitstream_id") String bitstreamId, + @Context HttpHeaders headers) { log.info("Reading bitstream(id=" + bitstreamId + ") policies."); org.dspace.core.Context context = null; ResourcePolicy[] policies = null; - try - { + try { context = createContext(); - org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.READ); + org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, + org.dspace.core.Constants.READ); policies = new Bitstream(dspaceBitstream, servletContext, "policies", context).getPolicies(); context.complete(); log.trace("Policies for bitstream(id=" + bitstreamId + ") was successfully read."); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Someting went wrong while reading policies of bitstream(id=" + bitstreamId - + "), SQLException! Message: " + e, context); - } - catch (ContextException e) - { + + "), SQLException! Message: " + e, context); + } catch (ContextException e) { processException("Someting went wrong while reading policies of bitstream(id=" + bitstreamId - + "), ContextException. Message: " + e.getMessage(), context); - } - finally - { + + "), ContextException. Message: " + e.getMessage(), context); + } finally { processFinally(context); } @@ -205,71 +186,60 @@ public class BitstreamResource extends Resource * code INTERNAL_SERVER_ERROR(500), if there was problem while reading * bitstreams from database. * - * @param expand - * This string defines which additional optional fields will be added - * to bitstream response. Individual options are separated by commas without - * spaces. The options are: "all", "parent". - * @param limit - * How many bitstreams will be in the list. Default value is 100. - * @param offset - * On which offset (item) the list starts. Default value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The header "rest-dspace-token" with the token passed - * from the login method must be set. - * @param request - * Servlet's HTTP request object. + * @param expand This string defines which additional optional fields will be added + * to bitstream response. Individual options are separated by commas without + * spaces. The options are: "all", "parent". + * @param limit How many bitstreams will be in the list. Default value is 100. + * @param offset On which offset (item) the list starts. Default value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The header "rest-dspace-token" with the token passed + * from the login method must be set. + * @param request Servlet's HTTP request object. * @return Returns an array of bistreams. Array doesn't contain bitstreams for - * which the user doesn't have read permission. - * @throws WebApplicationException - * Thrown in case of a problem with reading the database or with - * creating a context. + * which the user doesn't have read permission. + * @throws WebApplicationException Thrown in case of a problem with reading the database or with + * creating a context. */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Bitstream[] getBitstreams(@QueryParam("expand") String expand, - @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("limit") @DefaultValue("100") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading bitstreams.(offset=" + offset + ",limit=" + limit + ")"); org.dspace.core.Context context = null; List bitstreams = new ArrayList(); - try - { + try { context = createContext(); List dspaceBitstreams = bitstreamService.findAll(context); - if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) - { + if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) { log.warn("Paging was badly set."); limit = 100; offset = 0; } // TODO If bitstream doesn't exist, throws exception. - for (int i = offset; (i < (offset + limit)) && (i < dspaceBitstreams.size()); i++) - { - if (authorizeService.authorizeActionBoolean(context, dspaceBitstreams.get(i), org.dspace.core.Constants.READ)) - { - if (bitstreamService.getParentObject(context, dspaceBitstreams.get(i)) != null) - { // To eliminate bitstreams which cause exception, because of - // reading under administrator permissions + for (int i = offset; (i < (offset + limit)) && (i < dspaceBitstreams.size()); i++) { + if (authorizeService + .authorizeActionBoolean(context, dspaceBitstreams.get(i), org.dspace.core.Constants.READ)) { + if (bitstreamService.getParentObject(context, dspaceBitstreams + .get(i)) != null) { // To eliminate bitstreams which cause exception, because of + // reading under administrator permissions bitstreams.add(new Bitstream(dspaceBitstreams.get(i), servletContext, expand, context)); writeStats(dspaceBitstreams.get(i), UsageEvent.Action.VIEW, user_ip, user_agent, - xforwardedfor, headers, request, context); + xforwardedfor, headers, request, context); } } } @@ -277,18 +247,13 @@ public class BitstreamResource extends Resource context.complete(); log.trace("Bitstreams were successfully read."); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Something went wrong while reading bitstreams from database!. Message: " + e, context); - } - catch (ContextException e) - { - processException("Something went wrong while reading bitstreams, ContextException. Message: " + e.getMessage(), - context); - } - finally - { + } catch (ContextException e) { + processException( + "Something went wrong while reading bitstreams, ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -302,38 +267,32 @@ public class BitstreamResource extends Resource * a problem while reading from database. And AuthorizeException if there was * a problem with authorization of user logged to DSpace context. * - * @param bitstreamId - * Id of the bitstream, whose data will be read. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The header "rest-dspace-token" with the token passed - * from the login method must be set. - * @param request - * Servlet's HTTP request object. + * @param bitstreamId Id of the bitstream, whose data will be read. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The header "rest-dspace-token" with the token passed + * from the login method must be set. + * @param request Servlet's HTTP request object. * @return Returns response with data with file content type. It can - * return the NOT_FOUND(404) response code in case of wrong bitstream - * id. Or response code UNAUTHORIZED(401) if user is not - * allowed to read bitstream. - * @throws WebApplicationException - * Thrown if there was a problem: reading the file data; or reading - * the database; or creating the context; or with authorization. + * return the NOT_FOUND(404) response code in case of wrong bitstream + * id. Or response code UNAUTHORIZED(401) if user is not + * allowed to read bitstream. + * @throws WebApplicationException Thrown if there was a problem: reading the file data; or reading + * the database; or creating the context; or with authorization. */ @GET @Path("/{bitstream_id}/retrieve") public javax.ws.rs.core.Response getBitstreamData(@PathParam("bitstream_id") String bitstreamId, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading data of bitstream(id=" + bitstreamId + ")."); org.dspace.core.Context context = null; @@ -341,13 +300,13 @@ public class BitstreamResource extends Resource String type = null; String name = null; - try - { + try { context = createContext(); - org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.READ); + org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, + org.dspace.core.Constants.READ); writeStats(dspaceBitstream, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); log.trace("Bitstream(id=" + bitstreamId + ") data was successfully read."); inputStream = bitstreamService.retrieve(context, dspaceBitstream); @@ -355,106 +314,88 @@ public class BitstreamResource extends Resource name = dspaceBitstream.getName(); context.complete(); - } - catch (IOException e) - { + } catch (IOException e) { processException("Could not read file of bitstream(id=" + bitstreamId + ")! Message: " + e, context); - } - catch (SQLException e) - { - processException("Something went wrong while reading bitstream(id=" + bitstreamId + ") from database! Message: " + e, - context); - } - catch (AuthorizeException e) - { - processException("Could not retrieve file of bitstream(id=" + bitstreamId + "), AuthorizeException! Message: " + e, - context); - } - catch (ContextException e) - { + } catch (SQLException e) { processException( - "Could not retrieve file of bitstream(id=" + bitstreamId + "), ContextException! Message: " + e.getMessage(), - context); - } - finally - { + "Something went wrong while reading bitstream(id=" + bitstreamId + ") from database! Message: " + e, + context); + } catch (AuthorizeException e) { + processException( + "Could not retrieve file of bitstream(id=" + bitstreamId + "), AuthorizeException! Message: " + e, + context); + } catch (ContextException e) { + processException( + "Could not retrieve file of bitstream(id=" + bitstreamId + "), ContextException! Message: " + e + .getMessage(), + context); + } finally { processFinally(context); } return Response.ok(inputStream).type(type) - .header("Content-Disposition", "attachment; filename=\"" + name + "\"") - .build(); + .header("Content-Disposition", "attachment; filename=\"" + name + "\"") + .build(); } /** * Add bitstream policy to all bundles containing the bitstream. * - * @param bitstreamId - * Id of bitstream in DSpace. - * @param policy - * Policy to be added. The following attributes are not - * applied: epersonId, - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The header "rest-dspace-token" with the token passed - * from the login method must be set. - * @param request - * Servlet's HTTP request object. + * @param bitstreamId Id of bitstream in DSpace. + * @param policy Policy to be added. The following attributes are not + * applied: epersonId, + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The header "rest-dspace-token" with the token passed + * from the login method must be set. + * @param request Servlet's HTTP request object. * @return Returns ok, if all was ok. Otherwise status code 500. */ @POST @Path("/{bitstream_id}/policy") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public javax.ws.rs.core.Response addBitstreamPolicy(@PathParam("bitstream_id") String bitstreamId, ResourcePolicy policy, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public javax.ws.rs.core.Response addBitstreamPolicy(@PathParam("bitstream_id") String bitstreamId, + ResourcePolicy policy, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { - log.info("Adding bitstream(id=" + bitstreamId + ") " + policy.getAction() + " policy with permission for group(id=" + policy.getGroupId() - + ")."); + log.info("Adding bitstream(id=" + bitstreamId + ") " + policy + .getAction() + " policy with permission for group(id=" + policy.getGroupId() + + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.WRITE); + org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, + org.dspace.core.Constants.WRITE); writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); addPolicyToBitstream(context, policy, dspaceBitstream); context.complete(); log.trace("Policy for bitstream(id=" + bitstreamId + ") was successfully added."); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId - + "), SQLException! Message: " + e, context); - } - catch (ContextException e) - { + + "), SQLException! Message: " + e, context); + } catch (ContextException e) { processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId - + "), ContextException. Message: " + e.getMessage(), context); - } - catch (AuthorizeException e) - { + + "), ContextException. Message: " + e.getMessage(), context); + } catch (AuthorizeException e) { processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId - + "), AuthorizeException! Message: " + e, context); - } - finally - { + + "), AuthorizeException! Message: " + e, context); + } finally { processFinally(context); } return Response.status(Status.OK).build(); @@ -466,81 +407,69 @@ public class BitstreamResource extends Resource * SQLException, if there was a problem with the database. AuthorizeException if * there was a problem with the authorization to edit bitstream metadata. * - * @param bitstreamId - * Id of bistream to be updated. - * @param bitstream - * Bitstream with will be placed. It must have filled user - * credentials. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The header "rest-dspace-token" with the token passed - * from the login method must be set. - * @param request - * Servlet's HTTP request object. + * @param bitstreamId Id of bistream to be updated. + * @param bitstream Bitstream with will be placed. It must have filled user + * credentials. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The header "rest-dspace-token" with the token passed + * from the login method must be set. + * @param request Servlet's HTTP request object. * @return Return response codes: OK(200), NOT_FOUND(404) if bitstream does - * not exist and UNAUTHORIZED(401) if user is not allowed to write - * to bitstream. - * @throws WebApplicationException - * Thrown when: Error reading from database; or error - * creating context; or error regarding bitstream authorization. + * not exist and UNAUTHORIZED(401) if user is not allowed to write + * to bitstream. + * @throws WebApplicationException Thrown when: Error reading from database; or error + * creating context; or error regarding bitstream authorization. */ @PUT @Path("/{bitstream_id}") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response updateBitstream(@PathParam("bitstream_id") String bitstreamId, Bitstream bitstream, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Updating bitstream(id=" + bitstreamId + ") metadata."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.WRITE); + org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, + org.dspace.core.Constants.WRITE); writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); log.trace("Updating bitstream metadata."); dspaceBitstream.setDescription(context, bitstream.getDescription()); - if (getMimeType(bitstream.getName()) == null) - { + if (getMimeType(bitstream.getName()) == null) { BitstreamFormat unknownFormat = bitstreamFormatService.findUnknown(context); bitstreamService.setFormat(context, dspaceBitstream, unknownFormat); - } - else - { - BitstreamFormat guessedFormat = bitstreamFormatService.findByMIMEType(context, getMimeType(bitstream.getName())); + } else { + BitstreamFormat guessedFormat = bitstreamFormatService + .findByMIMEType(context, getMimeType(bitstream.getName())); bitstreamService.setFormat(context, dspaceBitstream, guessedFormat); } dspaceBitstream.setName(context, bitstream.getName()); Integer sequenceId = bitstream.getSequenceId(); - if (sequenceId != null && sequenceId.intValue() != -1) - { + if (sequenceId != null && sequenceId.intValue() != -1) { dspaceBitstream.setSequenceID(sequenceId); } bitstreamService.update(context, dspaceBitstream); - if (bitstream.getPolicies() != null) - { + if (bitstream.getPolicies() != null) { log.trace("Updating bitstream policies."); // Remove all old bitstream policies. - authorizeService.removeAllPolicies(context,dspaceBitstream); + authorizeService.removeAllPolicies(context, dspaceBitstream); // Add all new bitstream policies for (ResourcePolicy policy : bitstream.getPolicies()) { @@ -550,24 +479,19 @@ public class BitstreamResource extends Resource context.complete(); - } - catch (SQLException e) - { - processException("Could not update bitstream(id=" + bitstreamId + ") metadata, SQLException. Message: " + e, context); - } - catch (AuthorizeException e) - { - processException("Could not update bitstream(id=" + bitstreamId + ") metadata, AuthorizeException. Message: " + e, - context); - } - catch (ContextException e) - { + } catch (SQLException e) { + processException("Could not update bitstream(id=" + bitstreamId + ") metadata, SQLException. Message: " + e, + context); + } catch (AuthorizeException e) { processException( - "Could not update bitstream(id=" + bitstreamId + ") metadata, ContextException. Message: " + e.getMessage(), - context); - } - finally - { + "Could not update bitstream(id=" + bitstreamId + ") metadata, AuthorizeException. Message: " + e, + context); + } catch (ContextException e) { + processException( + "Could not update bitstream(id=" + bitstreamId + ") metadata, ContextException. Message: " + e + .getMessage(), + context); + } finally { processFinally(context); } @@ -582,75 +506,62 @@ public class BitstreamResource extends Resource * a problem with reading from InputStream, Exception if there was another * problem. * - * @param bitstreamId - * Id of bistream to be updated. - * @param is - * InputStream filled with new data. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The header "rest-dspace-token" with the token passed - * from the login method must be set. - * @param request - * Servlet's HTTP request object. + * @param bitstreamId Id of bistream to be updated. + * @param is InputStream filled with new data. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The header "rest-dspace-token" with the token passed + * from the login method must be set. + * @param request Servlet's HTTP request object. * @return Return response if bitstream was updated. Response codes: - * OK(200), NOT_FOUND(404) if id of bitstream was bad. And - * UNAUTHORIZED(401) if user is not allowed to update bitstream. - * @throws WebApplicationException - * This exception can be thrown in this cases: Problem with - * reading or writing to database. Or problem with reading from - * InputStream. + * OK(200), NOT_FOUND(404) if id of bitstream was bad. And + * UNAUTHORIZED(401) if user is not allowed to update bitstream. + * @throws WebApplicationException This exception can be thrown in this cases: Problem with + * reading or writing to database. Or problem with reading from + * InputStream. */ // TODO Change to better logic, without editing database. @PUT @Path("/{bitstream_id}/data") public Response updateBitstreamData(@PathParam("bitstream_id") String bitstreamId, InputStream is, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Updating bitstream(id=" + bitstreamId + ") data."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.WRITE); + org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, + org.dspace.core.Constants.WRITE); writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); log.trace("Creating new bitstream."); UUID newBitstreamId = bitstreamStorageService.store(context, dspaceBitstream, is); log.trace("Bitstream data stored: " + newBitstreamId); - - } - catch (SQLException e) - { - processException("Could not update bitstream(id=" + bitstreamId + ") data, SQLException. Message: " + e, context); - } - catch (IOException e) - { - processException("Could not update bitstream(id=" + bitstreamId + ") data, IOException. Message: " + e, context); - } - catch (ContextException e) - { + context.complete(); + } catch (SQLException e) { + processException("Could not update bitstream(id=" + bitstreamId + ") data, SQLException. Message: " + e, + context); + } catch (IOException e) { + processException("Could not update bitstream(id=" + bitstreamId + ") data, IOException. Message: " + e, + context); + } catch (ContextException e) { processException( - "Could not update bitstream(id=" + bitstreamId + ") data, ContextException. Message: " + e.getMessage(), - context); - } - finally - { + "Could not update bitstream(id=" + bitstreamId + ") data, ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -665,74 +576,61 @@ public class BitstreamResource extends Resource * from database. AuthorizeException, if user doesn't have permission to delete * the bitstream or file. IOException, if there was a problem deleting the file. * - * @param bitstreamId - * Id of bitstream to be deleted. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The header "rest-dspace-token" with the token passed - * from the login method must be set. - * @param request - * Servlet's HTTP request object. + * @param bitstreamId Id of bitstream to be deleted. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The header "rest-dspace-token" with the token passed + * from the login method must be set. + * @param request Servlet's HTTP request object. * @return Return response codes: OK(200), NOT_FOUND(404) if bitstream of - * that id does not exist and UNAUTHORIZED(401) if user is not - * allowed to delete bitstream. - * @throws WebApplicationException - * Can be thrown if there was a problem reading or editing - * the database. Or problem deleting the file. Or problem with - * authorization to bitstream and bundles. Or problem with - * creating context. + * that id does not exist and UNAUTHORIZED(401) if user is not + * allowed to delete bitstream. + * @throws WebApplicationException Can be thrown if there was a problem reading or editing + * the database. Or problem deleting the file. Or problem with + * authorization to bitstream and bundles. Or problem with + * creating context. */ @DELETE @Path("/{bitstream_id}") public Response deleteBitstream(@PathParam("bitstream_id") String bitstreamId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting bitstream(id=" + bitstreamId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.DELETE); + org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, + org.dspace.core.Constants.DELETE); writeStats(dspaceBitstream, UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); log.trace("Deleting bitstream from all bundles."); bitstreamService.delete(context, dspaceBitstream); context.complete(); - } - catch (SQLException e) - { - processException("Could not delete bitstream(id=" + bitstreamId + "), SQLException. Message: " + e, context); - } - catch (AuthorizeException e) - { - processException("Could not delete bitstream(id=" + bitstreamId + "), AuthorizeException. Message: " + e, context); - } - catch (IOException e) - { + } catch (SQLException e) { + processException("Could not delete bitstream(id=" + bitstreamId + "), SQLException. Message: " + e, + context); + } catch (AuthorizeException e) { + processException("Could not delete bitstream(id=" + bitstreamId + "), AuthorizeException. Message: " + e, + context); + } catch (IOException e) { processException("Could not delete bitstream(id=" + bitstreamId + "), IOException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not delete bitstream(id=" + bitstreamId + "), ContextException. Message:" + e.getMessage(), - context); - } - finally - { + } catch (ContextException e) { + processException( + "Could not delete bitstream(id=" + bitstreamId + "), ContextException. Message:" + e.getMessage(), + context); + } finally { processFinally(context); } @@ -743,70 +641,65 @@ public class BitstreamResource extends Resource /** * Delete policy. * - * @param bitstreamId - * Id of the DSpace bitstream whose policy will be deleted. - * @param policyId - * Id of the policy to delete. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The header "rest-dspace-token" with the token passed - * from the login method must be set. - * @param request - * Servlet's HTTP request object. + * @param bitstreamId Id of the DSpace bitstream whose policy will be deleted. + * @param policyId Id of the policy to delete. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The header "rest-dspace-token" with the token passed + * from the login method must be set. + * @param request Servlet's HTTP request object. * @return It returns Ok, if all was ok. Otherwise status code 500. */ @DELETE @Path("/{bitstream_id}/policy/{policy_id}") public javax.ws.rs.core.Response deleteBitstreamPolicy(@PathParam("bitstream_id") String bitstreamId, - @PathParam("policy_id") Integer policyId, @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @PathParam("policy_id") Integer policyId, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting policy(id=" + policyId + ") from bitstream(id=" + bitstreamId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.WRITE); + org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, + org.dspace.core.Constants.WRITE); writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); org.dspace.authorize.ResourcePolicy resourcePolicy = resourcePolicyService.find(context, policyId); - if(resourcePolicy.getdSpaceObject().getID().equals(dspaceBitstream.getID()) && authorizeService.authorizeActionBoolean(context, dspaceBitstream, org.dspace.core.Constants.REMOVE)) { + if (resourcePolicy.getdSpaceObject().getID().equals(dspaceBitstream.getID()) && authorizeService + .authorizeActionBoolean(context, dspaceBitstream, org.dspace.core.Constants.REMOVE)) { try { resourcePolicyService.delete(context, resourcePolicy); } catch (AuthorizeException e) { - processException("Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId + processException( + "Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId + "), AuthorizeException! Message: " + e, context); } log.trace("Policy for bitstream(id=" + bitstreamId + ") was successfully removed."); } - } - catch (SQLException e) - { - processException("Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId + context.complete(); + } catch (SQLException e) { + processException( + "Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId + "), SQLException! Message: " + e, context); - } - catch (ContextException e) - { - processException("Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId + } catch (ContextException e) { + processException( + "Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId + "), ContextException. Message: " + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -816,27 +709,26 @@ public class BitstreamResource extends Resource /** * Return the MIME type of the file, by file extension. * - * @param name - * Name of file. + * @param name Name of file. * @return String filled with type of file in MIME style. */ - static String getMimeType(String name) - { + static String getMimeType(String name) { return URLConnection.guessContentTypeFromName(name); } /** * Add policy(org.dspace.rest.common.ResourcePolicy) to bitstream. - * @param context Context to create DSpace ResourcePolicy. - * @param policy Policy which will be added to bitstream. + * + * @param context Context to create DSpace ResourcePolicy. + * @param policy Policy which will be added to bitstream. * @param dspaceBitstream DSpace Bitstream object. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws AuthorizeException - * Exception indicating the current user of the context does not have permission - * to perform a particular action. + * @throws SQLException An exception that provides information on a database access error or other errors. + * @throws AuthorizeException Exception indicating the current user of the context does not have permission + * to perform a particular action. */ - private void addPolicyToBitstream(org.dspace.core.Context context, ResourcePolicy policy, org.dspace.content.Bitstream dspaceBitstream) throws SQLException, AuthorizeException { + private void addPolicyToBitstream(org.dspace.core.Context context, ResourcePolicy policy, + org.dspace.content.Bitstream dspaceBitstream) + throws SQLException, AuthorizeException { org.dspace.authorize.ResourcePolicy dspacePolicy = resourcePolicyService.create(context); dspacePolicy.setAction(policy.getActionInt()); dspacePolicy.setGroup(groupService.findByIdOrLegacyId(context, policy.getGroupId())); @@ -854,49 +746,36 @@ public class BitstreamResource extends Resource * org.dspace.content.Bitstream.find method with a check whether the item exists and * whether the user logged into the context has permission to preform the requested action. * - * @param context - * Context of actual logged user. - * @param id - * Id of bitstream in DSpace. - * @param action - * Constant from org.dspace.core.Constants. + * @param context Context of actual logged user. + * @param id Id of bitstream in DSpace. + * @param action Constant from org.dspace.core.Constants. * @return Returns DSpace bitstream. - * @throws WebApplicationException - * Is thrown when item with passed id is not exists and if user - * has no permission to do passed action. + * @throws WebApplicationException Is thrown when item with passed id is not exists and if user + * has no permission to do passed action. */ private org.dspace.content.Bitstream findBitstream(org.dspace.core.Context context, String id, int action) - throws WebApplicationException - { + throws WebApplicationException { org.dspace.content.Bitstream bitstream = null; - try - { + try { bitstream = bitstreamService.findByIdOrLegacyId(context, id); - if ((bitstream == null) || (bitstreamService.getParentObject(context, bitstream) == null)) - { + if ((bitstream == null) || (bitstreamService.getParentObject(context, bitstream) == null)) { context.abort(); log.warn("Bitstream(id=" + id + ") was not found!"); throw new WebApplicationException(Response.Status.NOT_FOUND); - } - else if (!authorizeService.authorizeActionBoolean(context, bitstream, action)) - { + } else if (!authorizeService.authorizeActionBoolean(context, bitstream, action)) { context.abort(); - if (context.getCurrentUser() != null) - { + if (context.getCurrentUser() != null) { log.error("User(" + context.getCurrentUser().getEmail() + ") doesn't have the permission to " - + getActionString(action) + " bitstream!"); - } - else - { - log.error("User(anonymous) doesn't have the permission to " + getActionString(action) + " bitsteam!"); + + getActionString(action) + " bitstream!"); + } else { + log.error( + "User(anonymous) doesn't have the permission to " + getActionString(action) + " bitsteam!"); } throw new WebApplicationException(Response.Status.UNAUTHORIZED); } - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Something went wrong while finding bitstream. SQLException, Message:" + e, context); } return bitstream; diff --git a/dspace-rest/src/main/java/org/dspace/rest/CollectionsResource.java b/dspace-rest/src/main/java/org/dspace/rest/CollectionsResource.java index 73eac6e6da..7d5fd4c015 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/CollectionsResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/CollectionsResource.java @@ -12,7 +12,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; - import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -36,7 +35,6 @@ import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; -import org.dspace.content.service.InstallItemService; import org.dspace.content.service.ItemService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Constants; @@ -51,12 +49,11 @@ import org.dspace.workflow.factory.WorkflowServiceFactory; /** * This class provides all CRUD operation over collections. - * + * * @author Rostislav Novak (Computing and Information Centre, CTU in Prague) */ @Path("/collections") -public class CollectionsResource extends Resource -{ +public class CollectionsResource extends Resource { protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); @@ -68,81 +65,71 @@ public class CollectionsResource extends Resource /** * Return instance of collection with passed id. You can add more properties * through expand parameter. - * - * @param collectionId - * Id of collection in DSpace. - * @param expand - * String in which is what you want to add to returned instance - * of collection. Options are: "all", "parentCommunityList", - * "parentCommunity", "items", "license" and "logo". If you want - * to use multiple options, it must be separated by commas. - * @param limit - * Limit value for items in list in collection. Default value is - * 100. - * @param offset - * Offset of start index in list of items of collection. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param collectionId Id of collection in DSpace. + * @param expand String in which is what you want to add to returned instance + * of collection. Options are: "all", "parentCommunityList", + * "parentCommunity", "items", "license" and "logo". If you want + * to use multiple options, it must be separated by commas. + * @param limit Limit value for items in list in collection. Default value is + * 100. + * @param offset Offset of start index in list of items of collection. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return instance of collection. It can also return status code - * NOT_FOUND(404) if id of collection is incorrect or status code - * UNATHORIZED(401) if user has no permission to read collection. - * @throws WebApplicationException - * It is thrown when was problem with database reading - * (SQLException) or problem with creating - * context(ContextException). It is thrown by NOT_FOUND and - * UNATHORIZED status codes, too. + * NOT_FOUND(404) if id of collection is incorrect or status code + * UNATHORIZED(401) if user has no permission to read collection. + * @throws WebApplicationException It is thrown when was problem with database reading + * (SQLException) or problem with creating + * context(ContextException). It is thrown by NOT_FOUND and + * UNATHORIZED status codes, too. */ @GET @Path("/{collection_id}") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public org.dspace.rest.common.Collection getCollection(@PathParam("collection_id") String collectionId, - @QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit, - @QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("expand") String expand, + @QueryParam("limit") @DefaultValue("100") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading collection(id=" + collectionId + ")."); org.dspace.core.Context context = null; Collection collection = null; - try - { + try { context = createContext(); - org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, org.dspace.core.Constants.READ); + org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, + org.dspace.core.Constants.READ); writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); collection = new Collection(dspaceCollection, servletContext, expand, context, limit, offset); context.complete(); - } - catch (SQLException e) - { - processException("Could not read collection(id=" + collectionId + "), SQLException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not read collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(), - context); - } - finally - { + } catch (SQLException e) { + processException("Could not read collection(id=" + collectionId + "), SQLException. Message: " + e, + context); + } catch (ContextException e) { + processException( + "Could not read collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -153,88 +140,75 @@ public class CollectionsResource extends Resource /** * Return array of all collections in DSpace. You can add more properties * through expand parameter. - * - * @param expand - * String in which is what you want to add to returned instance - * of collection. Options are: "all", "parentCommunityList", - * "parentCommunity", "items", "license" and "logo". If you want - * to use multiple options, it must be separated by commas. - * @param limit - * Limit value for items in list in collection. Default value is - * 100. - * @param offset - * Offset of start index in list of items of collection. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collections as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param expand String in which is what you want to add to returned instance + * of collection. Options are: "all", "parentCommunityList", + * "parentCommunity", "items", "license" and "logo". If you want + * to use multiple options, it must be separated by commas. + * @param limit Limit value for items in list in collection. Default value is + * 100. + * @param offset Offset of start index in list of items of collection. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collections as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of collection, on which has logged user permission - * to view. - * @throws WebApplicationException - * It is thrown when was problem with database reading - * (SQLException) or problem with creating - * context(ContextException). + * to view. + * @throws WebApplicationException It is thrown when was problem with database reading + * (SQLException) or problem with creating + * context(ContextException). */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public org.dspace.rest.common.Collection[] getCollections(@QueryParam("expand") String expand, - @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("limit") @DefaultValue("100") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading all collections.(offset=" + offset + ",limit=" + limit + ")"); org.dspace.core.Context context = null; List collections = new ArrayList(); - try - { + try { context = createContext(); - if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) - { + if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) { log.warn("Paging was badly set."); limit = 100; offset = 0; } List dspaceCollections = collectionService.findAll(context, limit, offset); - for(org.dspace.content.Collection dspaceCollection : dspaceCollections) - { - if (authorizeService.authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) - { - Collection collection = new org.dspace.rest.common.Collection(dspaceCollection, servletContext, null, context, limit, - offset); + for (org.dspace.content.Collection dspaceCollection : dspaceCollections) { + if (authorizeService + .authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) { + Collection collection = new org.dspace.rest.common.Collection(dspaceCollection, servletContext, + null, context, limit, + offset); collections.add(collection); writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent, - xforwardedfor, headers, request, context); + xforwardedfor, headers, request, context); } } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Something went wrong while reading collections from database. Message: " + e, context); - } - catch (ContextException e) - { - processException("Something went wrong while reading collections, ContextError. Message: " + e.getMessage(), context); - } - finally - { + } catch (ContextException e) { + processException("Something went wrong while reading collections, ContextError. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -245,95 +219,80 @@ public class CollectionsResource extends Resource /** * Return array of items in collection. You can add more properties to items * with expand parameter. - * - * @param collectionId - * Id of collection in DSpace. - * @param expand - * String which define, what additional properties will be in - * returned item. Options are separeted by commas and are: "all", - * "metadata", "parentCollection", "parentCollectionList", - * "parentCommunityList" and "bitstreams". - * @param limit - * Limit value for items in array. Default value is 100. - * @param offset - * Offset of start index in array of items of collection. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param collectionId Id of collection in DSpace. + * @param expand String which define, what additional properties will be in + * returned item. Options are separeted by commas and are: "all", + * "metadata", "parentCollection", "parentCollectionList", + * "parentCommunityList" and "bitstreams". + * @param limit Limit value for items in array. Default value is 100. + * @param offset Offset of start index in array of items of collection. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of items, on which has logged user permission to - * read. It can also return status code NOT_FOUND(404) if id of - * collection is incorrect or status code UNATHORIZED(401) if user - * has no permission to read collection. - * @throws WebApplicationException - * It is thrown when was problem with database reading - * (SQLException) or problem with creating - * context(ContextException). It is thrown by NOT_FOUND and - * UNATHORIZED status codes, too. + * read. It can also return status code NOT_FOUND(404) if id of + * collection is incorrect or status code UNATHORIZED(401) if user + * has no permission to read collection. + * @throws WebApplicationException It is thrown when was problem with database reading + * (SQLException) or problem with creating + * context(ContextException). It is thrown by NOT_FOUND and + * UNATHORIZED status codes, too. */ @GET @Path("/{collection_id}/items") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public org.dspace.rest.common.Item[] getCollectionItems(@PathParam("collection_id") String collectionId, - @QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit, - @QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("expand") String expand, + @QueryParam("limit") @DefaultValue("100") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading collection(id=" + collectionId + ") items."); org.dspace.core.Context context = null; List items = null; - try - { + try { context = createContext(); - org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, org.dspace.core.Constants.READ); + org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, + org.dspace.core.Constants.READ); writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); items = new ArrayList(); Iterator dspaceItems = itemService.findByCollection(context, dspaceCollection); - for (int i = 0; (dspaceItems.hasNext()) && (i < (limit + offset)); i++) - { + for (int i = 0; (dspaceItems.hasNext()) && (i < (limit + offset)); i++) { org.dspace.content.Item dspaceItem = dspaceItems.next(); - if (i >= offset) - { - if (itemService.isItemListedForUser(context, dspaceItem)) - { + if (i >= offset) { + if (itemService.isItemListedForUser(context, dspaceItem)) { items.add(new Item(dspaceItem, servletContext, expand, context)); writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); } } } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read collection items, SQLException. Message: " + e, context); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Could not read collection items, ContextException. Message: " + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -343,194 +302,173 @@ public class CollectionsResource extends Resource /** * Create item in collection. Item can be without filled metadata. - * - * @param collectionId - * Id of collection in which will be item created. - * @param item - * Item filled only with metadata, other variables are ignored. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param collectionId Id of collection in which will be item created. + * @param item Item filled only with metadata, other variables are ignored. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return status code with item. Return status (OK)200 if item was - * created. NOT_FOUND(404) if id of collection does not exists. - * UNAUTHORIZED(401) if user have not permission to write items in - * collection. - * @throws WebApplicationException - * It is thrown when was problem with database reading or - * writing (SQLException) or problem with creating - * context(ContextException) or problem with authorization to - * collection or IOException or problem with index item into - * browse index. It is thrown by NOT_FOUND and UNATHORIZED - * status codes, too. - * + * created. NOT_FOUND(404) if id of collection does not exists. + * UNAUTHORIZED(401) if user have not permission to write items in + * collection. + * @throws WebApplicationException It is thrown when was problem with database reading or + * writing (SQLException) or problem with creating + * context(ContextException) or problem with authorization to + * collection or IOException or problem with index item into + * browse index. It is thrown by NOT_FOUND and UNATHORIZED + * status codes, too. */ @POST @Path("/{collection_id}/items") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Item addCollectionItem(@PathParam("collection_id") String collectionId, Item item, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Create item in collection(id=" + collectionId + ")."); org.dspace.core.Context context = null; Item returnItem = null; - try - { + try { context = createContext(); org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, - org.dspace.core.Constants.WRITE); + org.dspace.core.Constants.WRITE); writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); log.trace("Creating item in collection(id=" + collectionId + ")."); - org.dspace.content.WorkspaceItem workspaceItem = workspaceItemService.create(context, dspaceCollection, false); + org.dspace.content.WorkspaceItem workspaceItem = workspaceItemService + .create(context, dspaceCollection, false); org.dspace.content.Item dspaceItem = workspaceItem.getItem(); log.trace("Adding metadata to item(id=" + dspaceItem.getID() + ")."); - if (item.getMetadata() != null) - { - for (MetadataEntry entry : item.getMetadata()) - { + if (item.getMetadata() != null) { + for (MetadataEntry entry : item.getMetadata()) { String data[] = mySplit(entry.getKey()); - itemService.addMetadata(context, dspaceItem, data[0], data[1], data[2], entry.getLanguage(), entry.getValue()); + itemService.addMetadata(context, dspaceItem, data[0], data[1], data[2], entry.getLanguage(), + entry.getValue()); } } workspaceItemService.update(context, workspaceItem); - try - { + try { // Must insert the item into workflow log.trace("Starting workflow for item(id=" + dspaceItem.getID() + ")."); workflowService.start(context, workspaceItem); - } - catch (Exception e) - { - log.error(LogManager.getHeader(context, "Error while starting workflow", "Item id: " + dspaceItem.getID()), e); + } catch (Exception e) { + log.error( + LogManager.getHeader(context, "Error while starting workflow", "Item id: " + dspaceItem.getID()), + e); throw new ContextException("Error while starting workflow for item(id=" + dspaceItem.getID() + ")", e); } - returnItem = new Item(workspaceItem.getItem(), servletContext, "",context); + returnItem = new Item(workspaceItem.getItem(), servletContext, "", context); context.complete(); - } - catch (SQLException e) - { - processException("Could not add item into collection(id=" + collectionId + "), SQLException. Message: " + e, context); - } - catch (AuthorizeException e) - { - processException("Could not add item into collection(id=" + collectionId + "), AuthorizeException. Message: " + e, - context); - } - catch (ContextException e) - { + } catch (SQLException e) { + processException("Could not add item into collection(id=" + collectionId + "), SQLException. Message: " + e, + context); + } catch (AuthorizeException e) { processException( - "Could not add item into collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(), - context); - } - finally - { + "Could not add item into collection(id=" + collectionId + "), AuthorizeException. Message: " + e, + context); + } catch (ContextException e) { + processException( + "Could not add item into collection(id=" + collectionId + "), ContextException. Message: " + e + .getMessage(), + context); + } finally { processFinally(context); } - log.info("Item successfully created in collection(id=" + collectionId + "). Item handle=" + returnItem.getHandle()); + log.info( + "Item successfully created in collection(id=" + collectionId + "). Item handle=" + returnItem.getHandle()); return returnItem; } /** * Update collection. It replace all properties. - * - * @param collectionId - * Id of collection in DSpace. - * @param collection - * Collection which will replace properties of actual collection. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param collectionId Id of collection in DSpace. + * @param collection Collection which will replace properties of actual collection. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response 200 if was everything all right. Otherwise 400 - * when id of community was incorrect or 401 if was problem with - * permission to write into collection. - * @throws WebApplicationException - * It is thrown when was problem with database reading or - * writing. Or problem with authorization to collection. Or - * problem with creating context. + * when id of community was incorrect or 401 if was problem with + * permission to write into collection. + * @throws WebApplicationException It is thrown when was problem with database reading or + * writing. Or problem with authorization to collection. Or + * problem with creating context. */ @PUT @Path("/{collection_id}") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response updateCollection(@PathParam("collection_id") String collectionId, - org.dspace.rest.common.Collection collection, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + org.dspace.rest.common.Collection collection, @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Updating collection(id=" + collectionId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, - org.dspace.core.Constants.WRITE); + org.dspace.core.Constants.WRITE); writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); collectionService.setMetadata(context, dspaceCollection, "name", collection.getName()); collectionService.setMetadata(context, dspaceCollection, "license", collection.getLicense()); // dspaceCollection.setLogo(collection.getLogo()); // TODO Add this option. - collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.COPYRIGHT_TEXT, collection.getCopyrightText()); - collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.INTRODUCTORY_TEXT, collection.getIntroductoryText()); - collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.SHORT_DESCRIPTION, collection.getShortDescription()); - collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.SIDEBAR_TEXT, collection.getSidebarText()); + collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.COPYRIGHT_TEXT, + collection.getCopyrightText()); + collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.INTRODUCTORY_TEXT, + collection.getIntroductoryText()); + collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.SHORT_DESCRIPTION, + collection.getShortDescription()); + collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.SIDEBAR_TEXT, + collection.getSidebarText()); collectionService.update(context, dspaceCollection); context.complete(); - } - catch (ContextException e) - { - processException("Could not update collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(), - context); - } - catch (SQLException e) - { - processException("Could not update collection(id=" + collectionId + "), SQLException. Message: " + e, context); + } catch (ContextException e) { + processException( + "Could not update collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(), + context); + } catch (SQLException e) { + processException("Could not update collection(id=" + collectionId + "), SQLException. Message: " + e, + context); } catch (AuthorizeException e) { - processException("Could not update collection(id=" + collectionId + "), AuthorizeException. Message: " + e, context); - } finally - { + processException("Could not update collection(id=" + collectionId + "), AuthorizeException. Message: " + e, + context); + } finally { processFinally(context); } @@ -540,76 +478,65 @@ public class CollectionsResource extends Resource /** * Delete collection. - * - * @param collectionId - * Id of collection which will be deleted. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param collectionId Id of collection which will be deleted. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response code OK(200) if was everything all right. - * Otherwise return NOT_FOUND(404) if was id of community or - * collection incorrect. Or (UNAUTHORIZED)401 if was problem with - * permission to community or collection. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading or writing. Or problem with deleting - * collection caused by IOException or authorization. + * Otherwise return NOT_FOUND(404) if was id of community or + * collection incorrect. Or (UNAUTHORIZED)401 if was problem with + * permission to community or collection. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading or writing. Or problem with deleting + * collection caused by IOException or authorization. */ @DELETE @Path("/{collection_id}") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response deleteCollection(@PathParam("collection_id") String collectionId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response deleteCollection(@PathParam("collection_id") String collectionId, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Delete collection(id=" + collectionId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, - org.dspace.core.Constants.DELETE); + org.dspace.core.Constants.DELETE); writeStats(dspaceCollection, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); collectionService.delete(context, dspaceCollection); collectionService.update(context, dspaceCollection); context.complete(); - } - catch (ContextException e) - { + } catch (ContextException e) { processException( - "Could not delete collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(), context); - } - catch (SQLException e) - { - processException("Could not delete collection(id=" + collectionId + "), SQLException. Message: " + e, context); - } - catch (AuthorizeException e) - { - processException("Could not delete collection(id=" + collectionId + "), AuthorizeException. Message: " + e, context); - } - catch (IOException e) - { - processException("Could not delete collection(id=" + collectionId + "), IOException. Message: " + e, context); - } - finally { + "Could not delete collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(), + context); + } catch (SQLException e) { + processException("Could not delete collection(id=" + collectionId + "), SQLException. Message: " + e, + context); + } catch (AuthorizeException e) { + processException("Could not delete collection(id=" + collectionId + "), AuthorizeException. Message: " + e, + context); + } catch (IOException e) { + processException("Could not delete collection(id=" + collectionId + "), IOException. Message: " + e, + context); + } finally { processFinally(context); } @@ -619,78 +546,70 @@ public class CollectionsResource extends Resource /** * Delete item in collection. - * - * @param collectionId - * Id of collection which will be deleted. - * @param itemId - * Id of item in colletion. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param collectionId Id of collection which will be deleted. + * @param itemId Id of item in colletion. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return It returns status code: OK(200). NOT_FOUND(404) if item or - * collection was not found, UNAUTHORIZED(401) if user is not - * allowed to delete item or permission to write into collection. - * @throws WebApplicationException - * It can be thrown by: SQLException, when was problem with - * database reading or writting. AuthorizeException, when was - * problem with authorization to item or collection. - * IOException, when was problem with removing item. - * ContextException, when was problem with creating context of - * DSpace. + * collection was not found, UNAUTHORIZED(401) if user is not + * allowed to delete item or permission to write into collection. + * @throws WebApplicationException It can be thrown by: SQLException, when was problem with + * database reading or writting. AuthorizeException, when was + * problem with authorization to item or collection. + * IOException, when was problem with removing item. + * ContextException, when was problem with creating context of + * DSpace. */ @DELETE @Path("/{collection_id}/items/{item_id}") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response deleteCollectionItem(@PathParam("collection_id") String collectionId, @PathParam("item_id") String itemId, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response deleteCollectionItem(@PathParam("collection_id") String collectionId, + @PathParam("item_id") String itemId, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Delete item(id=" + itemId + ") in collection(id=" + collectionId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Collection dspaceCollection = collectionService.findByIdOrLegacyId(context, collectionId); + org.dspace.content.Collection dspaceCollection = collectionService + .findByIdOrLegacyId(context, collectionId); org.dspace.content.Item item = itemService.findByIdOrLegacyId(context, itemId); - if(dspaceCollection == null) { + if (dspaceCollection == null) { //throw collection not exist log.warn("Collection(id=" + itemId + ") was not found!"); throw new WebApplicationException(Response.Status.NOT_FOUND); } - if(item == null) { + if (item == null) { //throw item not exist log.warn("Item(id=" + itemId + ") was not found!"); throw new WebApplicationException(Response.Status.NOT_FOUND); } - if(!authorizeService.authorizeActionBoolean(context, item, Constants.REMOVE) - || !authorizeService.authorizeActionBoolean(context, dspaceCollection, Constants.REMOVE)) { + if (!authorizeService.authorizeActionBoolean(context, item, Constants.REMOVE) + || !authorizeService.authorizeActionBoolean(context, dspaceCollection, Constants.REMOVE)) { //throw auth - if (context.getCurrentUser() != null) - { - log.error("User(" + context.getCurrentUser().getEmail() + ") does not have permission to delete item!"); - } - else - { + if (context.getCurrentUser() != null) { + log.error( + "User(" + context.getCurrentUser().getEmail() + ") does not have permission to delete item!"); + } else { log.error("User(anonymous) has not permission to delete item!"); } throw new WebApplicationException(Response.Status.UNAUTHORIZED); @@ -701,33 +620,24 @@ public class CollectionsResource extends Resource itemService.update(context, item); writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); writeStats(item, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor, headers, request, context); context.complete(); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId - + "), ContextException. Message: " + e.getMessage(), context); - } - catch (SQLException e) - { + + "), ContextException. Message: " + e.getMessage(), context); + } catch (SQLException e) { processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId - + "), SQLException. Message: " + e, context); - } - catch (AuthorizeException e) - { + + "), SQLException. Message: " + e, context); + } catch (AuthorizeException e) { processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId - + "), AuthorizeException. Message: " + e, context); - } - catch (IOException e) - { + + "), AuthorizeException. Message: " + e, context); + } catch (IOException e) { processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId - + "), IOException. Message: " + e, context); - } - finally { + + "), IOException. Message: " + e, context); + } finally { processFinally(context); } @@ -737,41 +647,34 @@ public class CollectionsResource extends Resource /** * Search for first collection with passed name. - * - * @param name - * Name of collection. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. + * + * @param name Name of collection. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. * @return It returns null if collection was not found. Otherwise returns - * first founded collection. - * @throws WebApplicationException - * A general exception a servlet can throw when it encounters difficulty. + * first founded collection. + * @throws WebApplicationException A general exception a servlet can throw when it encounters difficulty. */ @POST @Path("/find-collection") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Collection findCollectionByName(String name, @Context HttpHeaders headers) throws WebApplicationException - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Collection findCollectionByName(String name, @Context HttpHeaders headers) throws WebApplicationException { log.info("Searching for first collection with name=" + name + "."); org.dspace.core.Context context = null; Collection collection = null; - try - { + try { context = createContext(); List dspaceCollections = collectionService.findAll(context); //TODO, this would be more efficient with a findByName query - for (org.dspace.content.Collection dspaceCollection : dspaceCollections) - { - if (authorizeService.authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) - { - if (dspaceCollection.getName().equals(name)) - { + for (org.dspace.content.Collection dspaceCollection : dspaceCollections) { + if (authorizeService + .authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) { + if (dspaceCollection.getName().equals(name)) { collection = new Collection(dspaceCollection, servletContext, "", context, 100, 0); break; } @@ -780,28 +683,21 @@ public class CollectionsResource extends Resource context.complete(); - } - catch (SQLException e) - { - processException("Something went wrong while searching for collection(name=" + name + ") from database. Message: " + } catch (SQLException e) { + processException( + "Something went wrong while searching for collection(name=" + name + ") from database. Message: " + e, context); - } - catch (ContextException e) - { - processException("Something went wrong while searching for collection(name=" + name + "), ContextError. Message: " + } catch (ContextException e) { + processException( + "Something went wrong while searching for collection(name=" + name + "), ContextError. Message: " + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } - if (collection == null) - { + if (collection == null) { log.info("Collection was not found."); - } - else - { + } else { log.info("Collection was found with id(" + collection.getUUID() + ")."); } return collection; @@ -811,51 +707,38 @@ public class CollectionsResource extends Resource * Find collection from DSpace database. It is encapsulation of method * org.dspace.content.Collection.find with checking if item exist and if * user logged into context has permission to do passed action. - * - * @param context - * Context of actual logged user. - * @param id - * Id of collection in DSpace. - * @param action - * Constant from org.dspace.core.Constants. + * + * @param context Context of actual logged user. + * @param id Id of collection in DSpace. + * @param action Constant from org.dspace.core.Constants. * @return It returns DSpace collection. - * @throws WebApplicationException - * Is thrown when item with passed id is not exists and if user - * has no permission to do passed action. + * @throws WebApplicationException Is thrown when item with passed id is not exists and if user + * has no permission to do passed action. */ private org.dspace.content.Collection findCollection(org.dspace.core.Context context, String id, int action) - throws WebApplicationException - { + throws WebApplicationException { org.dspace.content.Collection collection = null; - try - { + try { collection = collectionService.findByIdOrLegacyId(context, id); - if (collection == null) - { + if (collection == null) { context.abort(); log.warn("Collection(id=" + id + ") was not found!"); throw new WebApplicationException(Response.Status.NOT_FOUND); - } - else if (!authorizeService.authorizeActionBoolean(context, collection, action)) - { + } else if (!authorizeService.authorizeActionBoolean(context, collection, action)) { context.abort(); - if (context.getCurrentUser() != null) - { + if (context.getCurrentUser() != null) { log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to " - + getActionString(action) + " collection!"); - } - else - { + + getActionString(action) + " collection!"); + } else { log.error("User(anonymous) has not permission to " + getActionString(action) + " collection!"); } throw new WebApplicationException(Response.Status.UNAUTHORIZED); } - } - catch (SQLException e) - { - processException("Something get wrong while finding collection(id=" + id + "). SQLException, Message: " + e, context); + } catch (SQLException e) { + processException("Something get wrong while finding collection(id=" + id + "). SQLException, Message: " + e, + context); } return collection; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/CommunitiesResource.java b/dspace-rest/src/main/java/org/dspace/rest/CommunitiesResource.java index 78ea7e3fd6..331ae4cfd5 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/CommunitiesResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/CommunitiesResource.java @@ -7,6 +7,27 @@ */ package org.dspace.rest; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.factory.AuthorizeServiceFactory; @@ -19,26 +40,13 @@ import org.dspace.rest.common.Community; import org.dspace.rest.exceptions.ContextException; import org.dspace.usage.UsageEvent; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /** * Class which provides CRUD methods over communities. - * + * * @author Rostislav Novak (Computing and Information Centre, CTU in Prague) - * */ @Path("/communities") -public class CommunitiesResource extends Resource -{ +public class CommunitiesResource extends Resource { protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); @@ -48,71 +56,58 @@ public class CommunitiesResource extends Resource /** * Returns community with basic properties. If you want more, use expand * parameter or method for community collections or subcommunities. - * - * @param communityId - * Id of community in DSpace. - * @param expand - * String in which is what you want to add to returned instance - * of community. Options are: "all", "parentCommunity", - * "collections", "subCommunities" and "logo". If you want to use - * multiple options, it must be separated by commas. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param communityId Id of community in DSpace. + * @param expand String in which is what you want to add to returned instance + * of community. Options are: "all", "parentCommunity", + * "collections", "subCommunities" and "logo". If you want to use + * multiple options, it must be separated by commas. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return instance of org.dspace.rest.common.Community. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading. Also if id of community is incorrect - * or logged user into context has no permission to read. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading. Also if id of community is incorrect + * or logged user into context has no permission to read. */ @GET @Path("/{community_id}") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Community getCommunity(@PathParam("community_id") String communityId, @QueryParam("expand") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading community(id=" + communityId + ")."); org.dspace.core.Context context = null; Community community = null; - try - { + try { context = createContext(); - org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, org.dspace.core.Constants.READ); + org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, + org.dspace.core.Constants.READ); writeStats(dspaceCommunity, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); community = new Community(dspaceCommunity, servletContext, expand, context); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read community(id=" + communityId + "), SQLException. Message:" + e, context); - } - catch (ContextException e) - { - processException("Could not read community(id=" + communityId + "), ContextException. Message:" + e.getMessage(), - context); - } - finally - { + } catch (ContextException e) { + processException( + "Could not read community(id=" + communityId + "), ContextException. Message:" + e.getMessage(), + context); + } finally { processFinally(context); } @@ -123,86 +118,69 @@ public class CommunitiesResource extends Resource /** * Return all communities in DSpace. - * - * @param expand - * String in which is what you want to add to returned instance - * of community. Options are: "all", "parentCommunity", - * "collections", "subCommunities" and "logo". If you want to use - * multiple options, it must be separated by commas. - * @param limit - * Maximum communities in array. Default value is 100. - * @param offset - * Index from which will start array of communities. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param expand String in which is what you want to add to returned instance + * of community. Options are: "all", "parentCommunity", + * "collections", "subCommunities" and "logo". If you want to use + * multiple options, it must be separated by commas. + * @param limit Maximum communities in array. Default value is 100. + * @param offset Index from which will start array of communities. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of communities. - * @throws WebApplicationException - * It can be caused by creating context or while was problem - * with reading community from database(SQLException). + * @throws WebApplicationException It can be caused by creating context or while was problem + * with reading community from database(SQLException). */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Community[] getCommunities(@QueryParam("expand") String expand, - @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("limit") @DefaultValue("100") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading all communities.(offset=" + offset + " ,limit=" + limit + ")."); org.dspace.core.Context context = null; ArrayList communities = null; - try - { + try { context = createContext(); List dspaceCommunities = communityService.findAll(context); communities = new ArrayList(); - if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) - { + if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) { log.warn("Paging was badly set, using default values."); limit = 100; offset = 0; } - for (int i = offset; (i < (offset + limit)) && i < dspaceCommunities.size(); i++) - { - if (authorizeService.authorizeActionBoolean(context, dspaceCommunities.get(i), org.dspace.core.Constants.READ)) - { + for (int i = offset; (i < (offset + limit)) && i < dspaceCommunities.size(); i++) { + if (authorizeService + .authorizeActionBoolean(context, dspaceCommunities.get(i), org.dspace.core.Constants.READ)) { Community community = new Community(dspaceCommunities.get(i), servletContext, expand, context); writeStats(dspaceCommunities.get(i), UsageEvent.Action.VIEW, user_ip, user_agent, - xforwardedfor, headers, request, context); + xforwardedfor, headers, request, context); communities.add(community); } } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read communities, SQLException. Message:" + e, context); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Could not read communities, ContextException. Message:" + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -213,88 +191,72 @@ public class CommunitiesResource extends Resource /** * Return all top communities in DSpace. Top communities are communities on * the root of tree. - * - * @param expand - * String in which is what you want to add to returned instance - * of community. Options are: "all", "parentCommunity", - * "collections", "subCommunities" and "logo". If you want to use - * multiple options, it must be separated by commas. - * @param limit - * Maximum communities in array. Default value is 100. - * @param offset - * Index from which will start array of communities. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param expand String in which is what you want to add to returned instance + * of community. Options are: "all", "parentCommunity", + * "collections", "subCommunities" and "logo". If you want to use + * multiple options, it must be separated by commas. + * @param limit Maximum communities in array. Default value is 100. + * @param offset Index from which will start array of communities. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of top communities. - * @throws WebApplicationException - * It can be caused by creating context or while was problem - * with reading community from database(SQLException). + * @throws WebApplicationException It can be caused by creating context or while was problem + * with reading community from database(SQLException). */ @GET @Path("/top-communities") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Community[] getTopCommunities(@QueryParam("expand") String expand, - @QueryParam("limit") @DefaultValue("20") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("limit") @DefaultValue("20") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading all top communities.(offset=" + offset + " ,limit=" + limit + ")."); org.dspace.core.Context context = null; ArrayList communities = null; - try - { + try { context = createContext(); List dspaceCommunities = communityService.findAllTop(context); communities = new ArrayList(); - if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) - { + if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) { log.warn("Paging was badly set, using default values."); limit = 100; offset = 0; } - for (int i = offset; (i < (offset + limit)) && i < dspaceCommunities.size(); i++) - { - if (authorizeService.authorizeActionBoolean(context, dspaceCommunities.get(i), org.dspace.core.Constants.READ)) - { + for (int i = offset; (i < (offset + limit)) && i < dspaceCommunities.size(); i++) { + if (authorizeService + .authorizeActionBoolean(context, dspaceCommunities.get(i), org.dspace.core.Constants.READ)) { Community community = new Community(dspaceCommunities.get(i), servletContext, expand, context); writeStats(dspaceCommunities.get(i), UsageEvent.Action.VIEW, user_ip, user_agent, - xforwardedfor, headers, request, context); + xforwardedfor, headers, request, context); communities.add(community); } } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read top communities, SQLException. Message:" + e, context); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Could not read top communities, ContextException. Message:" + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -304,63 +266,55 @@ public class CommunitiesResource extends Resource /** * Return all collections of community. - * - * @param communityId - * Id of community in DSpace. - * @param expand - * String in which is what you want to add to returned instance - * of collection. Options are: "all", "parentCommunityList", - * "parentCommunity", "items", "license" and "logo". If you want - * to use multiple options, it must be separated by commas. - * @param limit - * Maximum collection in array. Default value is 100. - * @param offset - * Index from which will start array of collections. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param communityId Id of community in DSpace. + * @param expand String in which is what you want to add to returned instance + * of collection. Options are: "all", "parentCommunityList", + * "parentCommunity", "items", "license" and "logo". If you want + * to use multiple options, it must be separated by commas. + * @param limit Maximum collection in array. Default value is 100. + * @param offset Index from which will start array of collections. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of collections of community. - * @throws WebApplicationException - * It can be caused by creating context or while was problem - * with reading community from database(SQLException). + * @throws WebApplicationException It can be caused by creating context or while was problem + * with reading community from database(SQLException). */ @GET @Path("/{community_id}/collections") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Collection[] getCommunityCollections(@PathParam("community_id") String communityId, - @QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit, - @QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("expand") String expand, + @QueryParam("limit") @DefaultValue("100") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading community(id=" + communityId + ") collections."); org.dspace.core.Context context = null; ArrayList collections = null; - try - { + try { context = createContext(); - org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, org.dspace.core.Constants.READ); + org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, + org.dspace.core.Constants.READ); writeStats(dspaceCommunity, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); - if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) - { + if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) { log.warn("Pagging was badly set, using default values."); limit = 100; offset = 0; @@ -368,30 +322,25 @@ public class CommunitiesResource extends Resource collections = new ArrayList(); List dspaceCollections = dspaceCommunity.getCollections(); - for (int i = offset; (i < (offset + limit)) && (i < dspaceCollections.size()); i++) - { - if (authorizeService.authorizeActionBoolean(context, dspaceCollections.get(i), org.dspace.core.Constants.READ)) - { + for (int i = offset; (i < (offset + limit)) && (i < dspaceCollections.size()); i++) { + if (authorizeService + .authorizeActionBoolean(context, dspaceCollections.get(i), org.dspace.core.Constants.READ)) { collections.add(new Collection(dspaceCollections.get(i), servletContext, expand, context, 20, 0)); writeStats(dspaceCollections.get(i), UsageEvent.Action.VIEW, user_ip, user_agent, - xforwardedfor, headers, request, context); + xforwardedfor, headers, request, context); } } context.complete(); - } - catch (SQLException e) - { - processException("Could not read community(id=" + communityId + ") collections, SQLException. Message:" + e, context); - } - catch (ContextException e) - { + } catch (SQLException e) { + processException("Could not read community(id=" + communityId + ") collections, SQLException. Message:" + e, + context); + } catch (ContextException e) { processException( - "Could not read community(id=" + communityId + ") collections, ContextException. Message:" + e.getMessage(), - context); - } - finally - { + "Could not read community(id=" + communityId + ") collections, ContextException. Message:" + e + .getMessage(), + context); + } finally { processFinally(context); } @@ -401,63 +350,55 @@ public class CommunitiesResource extends Resource /** * Return all subcommunities of community. - * - * @param communityId - * Id of community in DSpace. - * @param expand - * String in which is what you want to add to returned instance - * of community. Options are: "all", "parentCommunity", - * "collections", "subCommunities" and "logo". If you want to use - * multiple options, it must be separated by commas. - * @param limit - * Maximum communities in array. Default value is 20. - * @param offset - * Index from which will start array of communities. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param communityId Id of community in DSpace. + * @param expand String in which is what you want to add to returned instance + * of community. Options are: "all", "parentCommunity", + * "collections", "subCommunities" and "logo". If you want to use + * multiple options, it must be separated by commas. + * @param limit Maximum communities in array. Default value is 20. + * @param offset Index from which will start array of communities. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of subcommunities of community. - * @throws WebApplicationException - * It can be caused by creating context or while was problem - * with reading community from database(SQLException). + * @throws WebApplicationException It can be caused by creating context or while was problem + * with reading community from database(SQLException). */ @GET @Path("/{community_id}/communities") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Community[] getCommunityCommunities(@PathParam("community_id") String communityId, - @QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("20") Integer limit, - @QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("expand") String expand, + @QueryParam("limit") @DefaultValue("20") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading community(id=" + communityId + ") subcommunities."); org.dspace.core.Context context = null; ArrayList communities = null; - try - { + try { context = createContext(); - org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, org.dspace.core.Constants.READ); + org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, + org.dspace.core.Constants.READ); writeStats(dspaceCommunity, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); - if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) - { + if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) { log.warn("Pagging was badly set, using default values."); limit = 100; offset = 0; @@ -465,31 +406,25 @@ public class CommunitiesResource extends Resource communities = new ArrayList(); List dspaceCommunities = dspaceCommunity.getSubcommunities(); - for (int i = offset; (i < (offset + limit)) && (i < dspaceCommunities.size()); i++) - { - if (authorizeService.authorizeActionBoolean(context, dspaceCommunities.get(i), org.dspace.core.Constants.READ)) - { + for (int i = offset; (i < (offset + limit)) && (i < dspaceCommunities.size()); i++) { + if (authorizeService + .authorizeActionBoolean(context, dspaceCommunities.get(i), org.dspace.core.Constants.READ)) { communities.add(new Community(dspaceCommunities.get(i), servletContext, expand, context)); writeStats(dspaceCommunities.get(i), UsageEvent.Action.VIEW, user_ip, user_agent, - xforwardedfor, headers, request, context); + xforwardedfor, headers, request, context); } } context.complete(); - } - catch (SQLException e) - { - processException("Could not read community(id=" + communityId + ") subcommunities, SQLException. Message:" + e, - context); - } - catch (ContextException e) - { + } catch (SQLException e) { processException( - "Could not read community(id=" + communityId + ") subcommunities, ContextException. Message:" - + e.getMessage(), context); - } - finally - { + "Could not read community(id=" + communityId + ") subcommunities, SQLException. Message:" + e, + context); + } catch (ContextException e) { + processException( + "Could not read community(id=" + communityId + ") subcommunities, ContextException. Message:" + + e.getMessage(), context); + } finally { processFinally(context); } @@ -500,49 +435,40 @@ public class CommunitiesResource extends Resource /** * Create community at top level. Creating community at top level has * permission only admin. - * - * @param community - * Community which will be created at top level of communities. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param community Community which will be created at top level of communities. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Returns response with handle of community, if was all ok. - * @throws WebApplicationException - * It can be thrown by SQLException, AuthorizeException and - * ContextException. + * @throws WebApplicationException It can be thrown by SQLException, AuthorizeException and + * ContextException. */ @POST - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Community createCommunity(Community community, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Creating community at top level."); org.dspace.core.Context context = null; Community retCommunity = null; - try - { + try { context = createContext(); - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { context.abort(); String user = "anonymous"; - if (context.getCurrentUser() != null) - { + if (context.getCurrentUser() != null) { user = context.getCurrentUser().getEmail(); } log.error("User(" + user + ") has not permission to create community!"); @@ -551,32 +477,30 @@ public class CommunitiesResource extends Resource org.dspace.content.Community dspaceCommunity = communityService.create(null, context); writeStats(dspaceCommunity, UsageEvent.Action.CREATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); communityService.setMetadata(context, dspaceCommunity, "name", community.getName()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.COPYRIGHT_TEXT, community.getCopyrightText()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.INTRODUCTORY_TEXT, community.getIntroductoryText()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SHORT_DESCRIPTION, community.getShortDescription()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SIDEBAR_TEXT, community.getSidebarText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.COPYRIGHT_TEXT, + community.getCopyrightText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.INTRODUCTORY_TEXT, + community.getIntroductoryText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SHORT_DESCRIPTION, + community.getShortDescription()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SIDEBAR_TEXT, + community.getSidebarText()); communityService.update(context, dspaceCommunity); retCommunity = new Community(dspaceCommunity, servletContext, "", context); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not create new top community, SQLException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not create new top community, ContextException. Message: " + e.getMessage(), context); - } - catch (AuthorizeException e) - { - processException("Could not create new top community, AuthorizeException. Message: " + e.getMessage(), context); - } - finally - { + } catch (ContextException e) { + processException("Could not create new top community, ContextException. Message: " + e.getMessage(), + context); + } catch (AuthorizeException e) { + processException("Could not create new top community, AuthorizeException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -587,178 +511,161 @@ public class CommunitiesResource extends Resource /** * Create collection in community. - * - * @param communityId - * Id of community in DSpace. - * @param collection - * Collection which will be added into community. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param communityId Id of community in DSpace. + * @param collection Collection which will be added into community. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response 200 if was everything all right. Otherwise 400 - * when id of community was incorrect or 401 if was problem with - * permission to write into collection. - * @throws WebApplicationException - * It is thrown when was problem with database reading or - * writing. Or problem with authorization to community. Or - * problem with creating context. + * when id of community was incorrect or 401 if was problem with + * permission to write into collection. + * @throws WebApplicationException It is thrown when was problem with database reading or + * writing. Or problem with authorization to community. Or + * problem with creating context. */ @POST @Path("/{community_id}/collections") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Collection addCommunityCollection(@PathParam("community_id") String communityId, Collection collection, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Adding collection into community(id=" + communityId + ")."); org.dspace.core.Context context = null; Collection retCollection = null; - try - { + try { context = createContext(); - org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, org.dspace.core.Constants.WRITE); + org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, + org.dspace.core.Constants.WRITE); writeStats(dspaceCommunity, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); org.dspace.content.Collection dspaceCollection = collectionService.create(context, dspaceCommunity); collectionService.setMetadata(context, dspaceCollection, "license", collection.getLicense()); // dspaceCollection.setLogo(collection.getLogo()); // TODO Add this option. collectionService.setMetadata(context, dspaceCollection, "name", collection.getName()); - collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.COPYRIGHT_TEXT, collection.getCopyrightText()); - collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.INTRODUCTORY_TEXT, collection.getIntroductoryText()); - collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.SHORT_DESCRIPTION, collection.getShortDescription()); - collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.SIDEBAR_TEXT, collection.getSidebarText()); + collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.COPYRIGHT_TEXT, + collection.getCopyrightText()); + collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.INTRODUCTORY_TEXT, + collection.getIntroductoryText()); + collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.SHORT_DESCRIPTION, + collection.getShortDescription()); + collectionService.setMetadata(context, dspaceCollection, org.dspace.content.Collection.SIDEBAR_TEXT, + collection.getSidebarText()); collectionService.update(context, dspaceCollection); communityService.update(context, dspaceCommunity); retCollection = new Collection(dspaceCollection, servletContext, "", context, 100, 0); context.complete(); - } - catch (SQLException e) - { - processException("Could not add collection into community(id=" + communityId + "), SQLException. Message:" + e, - context); - } - catch (AuthorizeException e) - { - processException("Could not add collection into community(id=" + communityId + "), AuthorizeException. Message:" + e, - context); - } - catch (ContextException e) - { + } catch (SQLException e) { processException( - "Could not add collection into community(id=" + communityId + "), ContextException. Message:" - + e.getMessage(), context); - } - finally - { + "Could not add collection into community(id=" + communityId + "), SQLException. Message:" + e, + context); + } catch (AuthorizeException e) { + processException( + "Could not add collection into community(id=" + communityId + "), AuthorizeException. Message:" + e, + context); + } catch (ContextException e) { + processException( + "Could not add collection into community(id=" + communityId + "), ContextException. Message:" + + e.getMessage(), context); + } finally { processFinally(context); } log.info("Collection was successfully added into community(id=" + communityId + "). Collection handle=" - + retCollection.getHandle()); + + retCollection.getHandle()); return retCollection; } /** * Create subcommunity in community. - * - * @param communityId - * Id of community in DSpace, in which will be created - * subcommunity. - * @param community - * Community which will be added into community. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param communityId Id of community in DSpace, in which will be created + * subcommunity. + * @param community Community which will be added into community. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response 200 if was everything all right. Otherwise 400 - * when id of community was incorrect or 401 if was problem with - * permission to write into collection. - * @throws WebApplicationException - * It is thrown when was problem with database reading or - * writing. Or problem with authorization to community. Or - * problem with creating context. + * when id of community was incorrect or 401 if was problem with + * permission to write into collection. + * @throws WebApplicationException It is thrown when was problem with database reading or + * writing. Or problem with authorization to community. Or + * problem with creating context. */ @POST @Path("/{community_id}/communities") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Community addCommunityCommunity(@PathParam("community_id") String communityId, Community community, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Add subcommunity into community(id=" + communityId + ")."); org.dspace.core.Context context = null; Community retCommunity = null; - try - { + try { context = createContext(); org.dspace.content.Community dspaceParentCommunity = findCommunity(context, communityId, - org.dspace.core.Constants.WRITE); + org.dspace.core.Constants.WRITE); writeStats(dspaceParentCommunity, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); - org.dspace.content.Community dspaceCommunity = communityService.createSubcommunity(context, dspaceParentCommunity); + org.dspace.content.Community dspaceCommunity = communityService + .createSubcommunity(context, dspaceParentCommunity); communityService.setMetadata(context, dspaceCommunity, "name", community.getName()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.COPYRIGHT_TEXT, community.getCopyrightText()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.INTRODUCTORY_TEXT, community.getIntroductoryText()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SHORT_DESCRIPTION, community.getShortDescription()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SIDEBAR_TEXT, community.getSidebarText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.COPYRIGHT_TEXT, + community.getCopyrightText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.INTRODUCTORY_TEXT, + community.getIntroductoryText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SHORT_DESCRIPTION, + community.getShortDescription()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SIDEBAR_TEXT, + community.getSidebarText()); communityService.update(context, dspaceCommunity); communityService.update(context, dspaceParentCommunity); retCommunity = new Community(dspaceCommunity, servletContext, "", context); context.complete(); - } - catch (SQLException e) - { - processException("Could not add subcommunity into community(id=" + communityId + "), SQLException. Message:" + e, - context); - } - catch (AuthorizeException e) - { - processException("Could not add subcommunity into community(id=" + communityId + "), AuthorizeException. Message:" + } catch (SQLException e) { + processException( + "Could not add subcommunity into community(id=" + communityId + "), SQLException. Message:" + e, + context); + } catch (AuthorizeException e) { + processException( + "Could not add subcommunity into community(id=" + communityId + "), AuthorizeException. Message:" + e, context); - } - catch (ContextException e) - { - processException("Could not add subcommunity into community(id=" + communityId + "), ContextException. Message:" + e, - context); - } - finally - { + } catch (ContextException e) { + processException( + "Could not add subcommunity into community(id=" + communityId + "), ContextException. Message:" + e, + context); + } finally { processFinally(context); } @@ -770,75 +677,69 @@ public class CommunitiesResource extends Resource /** * Update community. Replace all information about community except: id, * handle and expandle items. - * - * @param communityId - * Id of community in DSpace. - * @param community - * Instance of community which will replace actual community in - * DSpace. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param communityId Id of community in DSpace. + * @param community Instance of community which will replace actual community in + * DSpace. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Response 200 if was all ok. Otherwise 400 if id was incorrect or - * 401 if logged user has no permission to delete community. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading or writing. Or problem with writing to - * community caused by authorization. + * 401 if logged user has no permission to delete community. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading or writing. Or problem with writing to + * community caused by authorization. */ @PUT @Path("/{community_id}") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response updateCommunity(@PathParam("community_id") String communityId, Community community, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Updating community(id=" + communityId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, org.dspace.core.Constants.WRITE); + org.dspace.content.Community dspaceCommunity = findCommunity(context, communityId, + org.dspace.core.Constants.WRITE); writeStats(dspaceCommunity, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); // dspaceCommunity.setLogo(arg0); // TODO Add this option. communityService.setMetadata(context, dspaceCommunity, "name", community.getName()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.COPYRIGHT_TEXT, community.getCopyrightText()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.INTRODUCTORY_TEXT, community.getIntroductoryText()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SHORT_DESCRIPTION, community.getShortDescription()); - communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SIDEBAR_TEXT, community.getSidebarText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.COPYRIGHT_TEXT, + community.getCopyrightText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.INTRODUCTORY_TEXT, + community.getIntroductoryText()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SHORT_DESCRIPTION, + community.getShortDescription()); + communityService.setMetadata(context, dspaceCommunity, org.dspace.content.Community.SIDEBAR_TEXT, + community.getSidebarText()); communityService.update(context, dspaceCommunity); context.complete(); - } - catch (SQLException e) - { - processException("Could not update community(id=" + communityId + "), AuthorizeException. Message:" + e, context); - } - catch (ContextException e) - { - processException("Could not update community(id=" + communityId + "), ContextException Message:" + e, context); + } catch (SQLException e) { + processException("Could not update community(id=" + communityId + "), AuthorizeException. Message:" + e, + context); + } catch (ContextException e) { + processException("Could not update community(id=" + communityId + "), ContextException Message:" + e, + context); } catch (AuthorizeException e) { - processException("Could not update community(id=" + communityId + "), AuthorizeException Message:" + e, context); - } finally - { + processException("Could not update community(id=" + communityId + "), AuthorizeException Message:" + e, + context); + } finally { processFinally(context); } @@ -848,74 +749,60 @@ public class CommunitiesResource extends Resource /** * Delete community from DSpace. It delete it everything with community! - * - * @param communityId - * Id of community in DSpace. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param communityId Id of community in DSpace. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response code OK(200) if was everything all right. - * Otherwise return NOT_FOUND(404) if was id of community incorrect. - * Or (UNAUTHORIZED)401 if was problem with permission to community. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading or deleting. Or problem with deleting - * community caused by IOException or authorization. + * Otherwise return NOT_FOUND(404) if was id of community incorrect. + * Or (UNAUTHORIZED)401 if was problem with permission to community. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading or deleting. Or problem with deleting + * community caused by IOException or authorization. */ @DELETE @Path("/{community_id}") public Response deleteCommunity(@PathParam("community_id") String communityId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting community(id=" + communityId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Community community = findCommunity(context, communityId, org.dspace.core.Constants.DELETE); + org.dspace.content.Community community = findCommunity(context, communityId, + org.dspace.core.Constants.DELETE); writeStats(community, UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); communityService.delete(context, community); communityService.update(context, community); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not delete community(id=" + communityId + "), SQLException. Message:" + e, context); - } - catch (AuthorizeException e) - { - processException("Could not delete community(id=" + communityId + "), AuthorizeException. Message:" + e, context); - } - catch (IOException e) - { + } catch (AuthorizeException e) { + processException("Could not delete community(id=" + communityId + "), AuthorizeException. Message:" + e, + context); + } catch (IOException e) { processException("Could not delete community(id=" + communityId + "), IOException. Message:" + e, context); - } - catch (ContextException e) - { - processException("Could not delete community(id=" + communityId + "), ContextException. Message:" + e.getMessage(), - context); - } - finally - { + } catch (ContextException e) { + processException( + "Could not delete community(id=" + communityId + "), ContextException. Message:" + e.getMessage(), + context); + } finally { processFinally(context); } @@ -926,68 +813,58 @@ public class CommunitiesResource extends Resource /** * Delete collection in community. - * - * @param communityId - * Id of community in DSpace. - * @param collectionId - * Id of collection which will be deleted. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param communityId Id of community in DSpace. + * @param collectionId Id of collection which will be deleted. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response code OK(200) if was everything all right. - * Otherwise return NOT_FOUND(404) if was id of community or - * collection incorrect. Or (UNAUTHORIZED)401 if was problem with - * permission to community or collection. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading or deleting. Or problem with deleting - * collection caused by IOException or authorization. + * Otherwise return NOT_FOUND(404) if was id of community or + * collection incorrect. Or (UNAUTHORIZED)401 if was problem with + * permission to community or collection. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading or deleting. Or problem with deleting + * collection caused by IOException or authorization. */ @DELETE @Path("/{community_id}/collections/{collection_id}") public Response deleteCommunityCollection(@PathParam("community_id") String communityId, - @PathParam("collection_id") String collectionId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @PathParam("collection_id") String collectionId, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting collection(id=" + collectionId + ") in community(id=" + communityId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); - org.dspace.content.Community community = findCommunity(context, communityId, org.dspace.core.Constants.WRITE); + org.dspace.content.Community community = findCommunity(context, communityId, + org.dspace.core.Constants.WRITE); org.dspace.content.Collection collection = collectionService.findByIdOrLegacyId(context, collectionId); - if (collection == null) - { + if (collection == null) { context.abort(); log.warn("Collection(id=" + collectionId + ") was not found!"); throw new WebApplicationException(Response.Status.NOT_FOUND); - } - else if (!authorizeService.authorizeActionBoolean(context, collection, org.dspace.core.Constants.REMOVE)) - { + } else if (!authorizeService + .authorizeActionBoolean(context, collection, org.dspace.core.Constants.REMOVE)) { context.abort(); - if (context.getCurrentUser() != null) - { - log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to delete collection!"); - } - else - { + if (context.getCurrentUser() != null) { + log.error( + "User(" + context.getCurrentUser().getEmail() + ") has not permission to delete collection!"); + } else { log.error("User(anonymous) has not permission to delete collection!"); } throw new WebApplicationException(Response.Status.UNAUTHORIZED); @@ -998,35 +875,25 @@ public class CommunitiesResource extends Resource collectionService.update(context, collection); writeStats(community, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); writeStats(collection, UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not delete collection(id=" + collectionId + ") in community(id=" + communityId - + "), SQLException. Message:" + e, context); - } - catch (AuthorizeException e) - { + + "), SQLException. Message:" + e, context); + } catch (AuthorizeException e) { processException("Could not delete collection(id=" + collectionId + ") in community(id=" + communityId - + "), AuthorizeException. Message:" + e, context); - } - catch (IOException e) - { + + "), AuthorizeException. Message:" + e, context); + } catch (IOException e) { processException("Could not delete collection(id=" + collectionId + ") in community(id=" + communityId - + "), IOException. Message:" + e, context); - } - catch (ContextException e) - { + + "), IOException. Message:" + e, context); + } catch (ContextException e) { processException("Could not delete collection(id=" + collectionId + ") in community(id=" + communityId - + "), ContextExcpetion. Message:" + e.getMessage(), context); - } - finally - { + + "), ContextExcpetion. Message:" + e.getMessage(), context); + } finally { processFinally(context); } @@ -1037,69 +904,58 @@ public class CommunitiesResource extends Resource /** * Delete subcommunity in community. - * - * @param parentCommunityId - * Id of community in DSpace. - * @param subcommunityId - * Id of community which will be deleted. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param parentCommunityId Id of community in DSpace. + * @param subcommunityId Id of community which will be deleted. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response code OK(200) if was everything all right. - * Otherwise return NOT_FOUND(404) if was id of community or - * subcommunity incorrect. Or (UNAUTHORIZED)401 if was problem with - * permission to community or subcommunity. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading or deleting. Or problem with deleting - * subcommunity caused by IOException or authorization. + * Otherwise return NOT_FOUND(404) if was id of community or + * subcommunity incorrect. Or (UNAUTHORIZED)401 if was problem with + * permission to community or subcommunity. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading or deleting. Or problem with deleting + * subcommunity caused by IOException or authorization. */ @DELETE @Path("/{community_id}/communities/{community_id2}") public Response deleteCommunityCommunity(@PathParam("community_id") String parentCommunityId, - @PathParam("community_id2") String subcommunityId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @PathParam("community_id2") String subcommunityId, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting community(id=" + parentCommunityId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.Community parentCommunity = findCommunity(context, parentCommunityId, - org.dspace.core.Constants.WRITE); + org.dspace.core.Constants.WRITE); org.dspace.content.Community subcommunity = communityService.findByIdOrLegacyId(context, subcommunityId); - if (subcommunity == null) - { + if (subcommunity == null) { context.abort(); log.warn("Subcommunity(id=" + subcommunityId + ") in community(id=" + ") was not found!"); throw new WebApplicationException(Response.Status.NOT_FOUND); - } - else if (!authorizeService.authorizeActionBoolean(context, subcommunity, org.dspace.core.Constants.REMOVE)) - { + } else if (!authorizeService + .authorizeActionBoolean(context, subcommunity, org.dspace.core.Constants.REMOVE)) { context.abort(); - if (context.getCurrentUser() != null) - { - log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to delete community!"); - } - else - { + if (context.getCurrentUser() != null) { + log.error( + "User(" + context.getCurrentUser().getEmail() + ") has not permission to delete community!"); + } else { log.error("User(anonymous) has not permission to delete community!"); } throw new WebApplicationException(Response.Status.UNAUTHORIZED); @@ -1110,40 +966,35 @@ public class CommunitiesResource extends Resource communityService.update(context, subcommunity); writeStats(parentCommunity, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); writeStats(subcommunity, UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); context.complete(); - } - catch (SQLException e) - { - processException("Could not delete subcommunity(id=" + subcommunityId + ") in community(id=" + parentCommunityId + } catch (SQLException e) { + processException( + "Could not delete subcommunity(id=" + subcommunityId + ") in community(id=" + parentCommunityId + "), SQLException. Message:" + e, context); - } - catch (AuthorizeException e) - { - processException("Could not delete subcommunity(id=" + subcommunityId + ") in community(id=" + parentCommunityId + } catch (AuthorizeException e) { + processException( + "Could not delete subcommunity(id=" + subcommunityId + ") in community(id=" + parentCommunityId + "), AuthorizeException. Message:" + e, context); - } - catch (IOException e) - { - processException("Could not delete subcommunity(id=" + subcommunityId + ") in community(id=" + parentCommunityId + } catch (IOException e) { + processException( + "Could not delete subcommunity(id=" + subcommunityId + ") in community(id=" + parentCommunityId + "), IOException. Message:" + e, context); - } - catch (ContextException e) - { - processException("Could not delete subcommunity(id=" + subcommunityId + ") in community(id=" + parentCommunityId + } catch (ContextException e) { + processException( + "Could not delete subcommunity(id=" + subcommunityId + ") in community(id=" + parentCommunityId + "), ContextException. Message:" + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } - log.info("Subcommunity(id=" + subcommunityId + ") from community(id=" + parentCommunityId + ") was successfully deleted."); + log.info("Subcommunity(id=" + subcommunityId + ") from community(id=" + parentCommunityId + + ") was successfully deleted."); return Response.status(Response.Status.OK).build(); } @@ -1151,51 +1002,38 @@ public class CommunitiesResource extends Resource * Find community from DSpace database. It is encapsulation of method * org.dspace.content.Community.find with checking if item exist and if user * logged into context has permission to do passed action. - * - * @param context - * Context of actual logged user. - * @param id - * Id of community in DSpace. - * @param action - * Constant from org.dspace.core.Constants. + * + * @param context Context of actual logged user. + * @param id Id of community in DSpace. + * @param action Constant from org.dspace.core.Constants. * @return It returns DSpace collection. - * @throws WebApplicationException - * Is thrown when item with passed id is not exists and if user - * has no permission to do passed action. + * @throws WebApplicationException Is thrown when item with passed id is not exists and if user + * has no permission to do passed action. */ private org.dspace.content.Community findCommunity(org.dspace.core.Context context, String id, int action) - throws WebApplicationException - { + throws WebApplicationException { org.dspace.content.Community community = null; - try - { + try { community = communityService.findByIdOrLegacyId(context, id); - if (community == null) - { + if (community == null) { context.abort(); log.warn("Community(id=" + id + ") was not found!"); throw new WebApplicationException(Response.Status.NOT_FOUND); - } - else if (!authorizeService.authorizeActionBoolean(context, community, action)) - { + } else if (!authorizeService.authorizeActionBoolean(context, community, action)) { context.abort(); - if (context.getCurrentUser() != null) - { + if (context.getCurrentUser() != null) { log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to " - + getActionString(action) + " community!"); - } - else - { + + getActionString(action) + " community!"); + } else { log.error("User(anonymous) has not permission to " + getActionString(action) + " community!"); } throw new WebApplicationException(Response.Status.UNAUTHORIZED); } - } - catch (SQLException e) - { - processException("Something get wrong while finding community(id=" + id + "). SQLException, Message:" + e, context); + } catch (SQLException e) { + processException("Something get wrong while finding community(id=" + id + "). SQLException, Message:" + e, + context); } return community; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/DSpaceRestApplication.java b/dspace-rest/src/main/java/org/dspace/rest/DSpaceRestApplication.java index 3560272ceb..baa5c8555b 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/DSpaceRestApplication.java +++ b/dspace-rest/src/main/java/org/dspace/rest/DSpaceRestApplication.java @@ -9,7 +9,6 @@ package org.dspace.rest; import org.glassfish.jersey.jackson.JacksonFeature; import org.glassfish.jersey.server.ResourceConfig; -import org.springframework.web.filter.RequestContextFilter; public class DSpaceRestApplication extends ResourceConfig { diff --git a/dspace-rest/src/main/java/org/dspace/rest/FilteredCollectionsResource.java b/dspace-rest/src/main/java/org/dspace/rest/FilteredCollectionsResource.java index 5887c9ad39..7312e5c4b7 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/FilteredCollectionsResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/FilteredCollectionsResource.java @@ -7,6 +7,22 @@ */ package org.dspace.rest; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.apache.log4j.Logger; import org.dspace.authorize.factory.AuthorizeServiceFactory; @@ -19,17 +35,6 @@ import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.usage.UsageEvent; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /* * This class provides the items within a collection evaluated against a set of Item Filters. * @@ -46,188 +51,162 @@ public class FilteredCollectionsResource extends Resource { * Return array of all collections in DSpace. You can add more properties * through expand parameter. * - * @param expand - * String in which is what you want to add to returned instance - * of collection. Options are: "all", "parentCommunityList", - * "parentCommunity", "topCommunity", "items", "license" and "logo". - * If you want to use multiple options, it must be separated by commas. - * @param limit - * Limit value for items in list in collection. Default value is - * 100. - * @param offset - * Offset of start index in list of items of collection. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param filters - * Comma separated list of Item Filters to use to evaluate against - * the items in a collection - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param servletContext - * Context of the servlet container. - * @param headers - * If you want to access the collections as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * @param expand String in which is what you want to add to returned instance + * of collection. Options are: "all", "parentCommunityList", + * "parentCommunity", "topCommunity", "items", "license" and "logo". + * If you want to use multiple options, it must be separated by commas. + * @param limit Limit value for items in list in collection. Default value is + * 100. + * @param offset Offset of start index in list of items of collection. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param filters Comma separated list of Item Filters to use to evaluate against + * the items in a collection + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param servletContext Context of the servlet container. + * @param headers If you want to access the collections as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of collection, on which has logged user permission - * to view. - * @throws WebApplicationException - * It is thrown when was problem with database reading - * (SQLException) or problem with creating - * context(ContextException). + * to view. + * @throws WebApplicationException It is thrown when was problem with database reading + * (SQLException) or problem with creating + * context(ContextException). */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public org.dspace.rest.common.FilteredCollection[] getCollections(@QueryParam("expand") String expand, - @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("filters") @DefaultValue("is_item") String filters, @QueryParam("xforwardedfor") String xforwardedfor, - @Context ServletContext servletContext, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("limit") @DefaultValue("100") + Integer limit, + @QueryParam("offset") @DefaultValue("0") + Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("filters") @DefaultValue("is_item") + String filters, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context ServletContext servletContext, + @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading all filtered collections.(offset=" + offset + ",limit=" + limit + ")"); org.dspace.core.Context context = null; List collections = new ArrayList(); - try - { + try { context = createContext(); - if (!configurationService.getBooleanProperty("rest.reporting-authenticate", true)) { - context.turnOffAuthorisationSystem(); - } - if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) - { + if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) { log.warn("Paging was badly set."); limit = 100; offset = 0; } List dspaceCollections = collectionService.findAll(context, limit, offset); - for (org.dspace.content.Collection dspaceCollection : dspaceCollections) - { - if (authorizeService.authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) - { - FilteredCollection collection = new org.dspace.rest.common.FilteredCollection(dspaceCollection, servletContext, filters, expand, context, limit, - offset); + for (org.dspace.content.Collection dspaceCollection : dspaceCollections) { + if (authorizeService + .authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) { + FilteredCollection collection = new org.dspace.rest.common.FilteredCollection(dspaceCollection, + servletContext, + filters, expand, + context, limit, + offset); collections.add(collection); writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent, - xforwardedfor, headers, request, context); + xforwardedfor, headers, request, context); } } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Something went wrong while reading collections from database. Message: " + e, context); - } - catch (ContextException e) - { - processException("Something went wrong while reading collections, ContextError. Message: " + e.getMessage(), context); - } - finally - { + } catch (ContextException e) { + processException("Something went wrong while reading collections, ContextError. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } log.trace("All collections were successfully read."); return collections.toArray(new org.dspace.rest.common.FilteredCollection[0]); } + /** * Return instance of collection with passed id. You can add more properties * through expand parameter. * - * @param collection_id - * Id of collection in DSpace. - * @param expand - * String in which is what you want to add to returned instance - * of collection. Options are: "all", "parentCommunityList", - * "parentCommunity", "topCommunity", "items", "license" and "logo". - * If you want to use multiple options, it must be separated by commas. - * @param limit - * Limit value for items in list in collection. Default value is - * 100. - * @param offset - * Offset of start index in list of items of collection. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param filters - * Comma separated list of Item Filters to use to evaluate against - * the items in a collection - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. - * @param servletContext - * Context of the servlet container. + * @param collection_id Id of collection in DSpace. + * @param expand String in which is what you want to add to returned instance + * of collection. Options are: "all", "parentCommunityList", + * "parentCommunity", "topCommunity", "items", "license" and "logo". + * If you want to use multiple options, it must be separated by commas. + * @param limit Limit value for items in list in collection. Default value is + * 100. + * @param offset Offset of start index in list of items of collection. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param filters Comma separated list of Item Filters to use to evaluate against + * the items in a collection + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. + * @param servletContext Context of the servlet container. * @return Return instance of collection. It can also return status code - * NOT_FOUND(404) if id of collection is incorrect or status code - * UNATHORIZED(401) if user has no permission to read collection. - * @throws WebApplicationException - * It is thrown when was problem with database reading - * (SQLException) or problem with creating - * context(ContextException). It is thrown by NOT_FOUND and - * UNATHORIZED status codes, too. + * NOT_FOUND(404) if id of collection is incorrect or status code + * UNATHORIZED(401) if user has no permission to read collection. + * @throws WebApplicationException It is thrown when was problem with database reading + * (SQLException) or problem with creating + * context(ContextException). It is thrown by NOT_FOUND and + * UNATHORIZED status codes, too. */ @GET @Path("/{collection_id}") - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public org.dspace.rest.common.FilteredCollection getCollection(@PathParam("collection_id") String collection_id, @QueryParam("expand") String expand, - @QueryParam("limit") @DefaultValue("1000") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @QueryParam("filters") @DefaultValue("is_item") String filters, - @Context HttpHeaders headers, @Context HttpServletRequest request, @Context ServletContext servletContext) - { + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.FilteredCollection getCollection(@PathParam("collection_id") String collection_id, + @QueryParam("expand") String expand, + @QueryParam("limit") @DefaultValue("1000") Integer + limit, + @QueryParam("offset") @DefaultValue("0") Integer + offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @QueryParam("filters") @DefaultValue("is_item") + String filters, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context ServletContext servletContext) { org.dspace.core.Context context = null; FilteredCollection retColl = new org.dspace.rest.common.FilteredCollection(); - try - { + try { context = createContext(); - if (!configurationService.getBooleanProperty("rest.reporting-authenticate", true)) - { - context.turnOffAuthorisationSystem(); - } org.dspace.content.Collection collection = collectionService.findByIdOrLegacyId(context, collection_id); - if (authorizeService.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) - { + if (authorizeService.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) { writeStats(collection, UsageEvent.Action.VIEW, user_ip, - user_agent, xforwardedfor, headers, request, context); + user_agent, xforwardedfor, headers, request, context); retColl = new org.dspace.rest.common.FilteredCollection( collection, servletContext, filters, expand, context, limit, offset); - } - else - { + } else { throw new WebApplicationException(Response.Status.UNAUTHORIZED); } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException(e.getMessage(), context); - } - catch (ContextException e) - { - processException(String.format("Could not read collection %d. %s", collection_id, e.getMessage()), context); + } catch (ContextException e) { + processException(String.format("Could not read collection %s. %s", collection_id, e.getMessage()), + context); } finally { processFinally(context); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/FilteredItemsResource.java b/dspace-rest/src/main/java/org/dspace/rest/FilteredItemsResource.java index c28b3f0286..5129bce840 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/FilteredItemsResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/FilteredItemsResource.java @@ -7,6 +7,23 @@ */ package org.dspace.rest; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; @@ -18,122 +35,101 @@ import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.SiteService; -import org.dspace.rest.exceptions.ContextException; import org.dspace.rest.common.ItemFilter; import org.dspace.rest.common.ItemFilterQuery; +import org.dspace.rest.exceptions.ContextException; import org.dspace.rest.filter.ItemFilterSet; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.usage.UsageEvent; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.HttpHeaders; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; - /* * This class retrieves items by a constructed metadata query evaluated against a set of Item Filters. - * + * * @author Terry Brady, Georgetown University */ @Path("/filtered-items") public class FilteredItemsResource extends Resource { protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); - protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected SiteService siteService = ContentServiceFactory.getInstance().getSiteService(); protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - + private static Logger log = Logger.getLogger(FilteredItemsResource.class); - + /** * Return instance of collection with passed id. You can add more properties * through expand parameter. - * - * @param expand - * String in which is what you want to add to returned instance - * of collection. Options are: "all", "parentCommunityList", - * "parentCommunity", "items", "license" and "logo". If you want - * to use multiple options, it must be separated by commas. - * @param limit - * Limit value for items in list in collection. Default value is - * 100. - * @param offset - * Offset of start index in list of items of collection. Default - * value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param filters - * Comma separated list of Item Filters to use to evaluate against - * the items in a collection - * @param query_field - * List of metadata fields to evaluate in a metadata query. - * Each list value is used in conjunction with a query_op and query_field. - * @param query_op - * List of metadata operators to use in a metadata query. - * Each list value is used in conjunction with a query_field and query_field. - * @param query_val - * List of metadata values to evaluate in a metadata query. - * Each list value is used in conjunction with a query_value and query_op. - * @param collSel - * List of collections to query. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. - * @param servletContext - * Context of the servlet container. + * + * @param expand String in which is what you want to add to returned instance + * of collection. Options are: "all", "parentCommunityList", + * "parentCommunity", "items", "license" and "logo". If you want + * to use multiple options, it must be separated by commas. + * @param limit Limit value for items in list in collection. Default value is + * 100. + * @param offset Offset of start index in list of items of collection. Default + * value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param filters Comma separated list of Item Filters to use to evaluate against + * the items in a collection + * @param query_field List of metadata fields to evaluate in a metadata query. + * Each list value is used in conjunction with a query_op and query_field. + * @param query_op List of metadata operators to use in a metadata query. + * Each list value is used in conjunction with a query_field and query_field. + * @param query_val List of metadata values to evaluate in a metadata query. + * Each list value is used in conjunction with a query_value and query_op. + * @param collSel List of collections to query. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. + * @param servletContext Context of the servlet container. * @return Return instance of collection. It can also return status code - * NOT_FOUND(404) if id of collection is incorrect or status code - * UNATHORIZED(401) if user has no permission to read collection. - * @throws WebApplicationException - * It is thrown when was problem with database reading - * (SQLException) or problem with creating - * context(ContextException). It is thrown by NOT_FOUND and - * UNATHORIZED status codes, too. + * NOT_FOUND(404) if id of collection is incorrect or status code + * UNATHORIZED(401) if user has no permission to read collection. + * @throws WebApplicationException It is thrown when was problem with database reading + * (SQLException) or problem with creating + * context(ContextException). It is thrown by NOT_FOUND and + * UNATHORIZED status codes, too. */ @GET - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public org.dspace.rest.common.ItemFilter getItemQuery(@QueryParam("expand") String expand, - @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @QueryParam("filters") @DefaultValue("is_item,all_filters") String filters, - @QueryParam("query_field[]") @DefaultValue("dc.title") List query_field, - @QueryParam("query_op[]") @DefaultValue("exists") List query_op, - @QueryParam("query_val[]") @DefaultValue("") List query_val, - @QueryParam("collSel[]") @DefaultValue("") List collSel, - @Context HttpHeaders headers, @Context HttpServletRequest request, @Context ServletContext servletContext) { + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.ItemFilter getItemQuery(@QueryParam("expand") String expand, + @QueryParam("limit") @DefaultValue("100") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @QueryParam("filters") @DefaultValue("is_item,all_filters") + String filters, + @QueryParam("query_field[]") @DefaultValue("dc.title") + List query_field, + @QueryParam("query_op[]") @DefaultValue("exists") + List query_op, + @QueryParam("query_val[]") @DefaultValue("") List + query_val, + @QueryParam("collSel[]") @DefaultValue("") List + collSel, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context ServletContext servletContext) { org.dspace.core.Context context = null; ItemFilterSet itemFilterSet = new ItemFilterSet(filters, true); ItemFilter result = itemFilterSet.getAllFiltersFilter(); try { context = createContext(); - if (!configurationService.getBooleanProperty("rest.reporting-authenticate", true)) { - context.turnOffAuthorisationSystem(); - } - + int index = Math.min(query_field.size(), Math.min(query_op.size(), query_val.size())); List itemFilterQueries = new ArrayList(); - for(int i=0; i uuids = getUuidsFromStrings(collSel); - List> listFieldList = getMetadataFieldsList(context, query_field); + List> listFieldList = getMetadataFieldsList(context, query_field); + + Iterator childItems = itemService + .findByMetadataQuery(context, listFieldList, query_op, query_val, uuids, regexClause, offset, limit); - Iterator childItems = itemService.findByMetadataQuery(context, listFieldList, query_op, query_val, uuids, regexClause, offset, limit); - int count = itemFilterSet.processSaveItems(context, servletContext, childItems, true, expand); - writeStats(siteService.findSite(context), UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(siteService.findSite(context), UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, + headers, request, context); result.annotateQuery(query_field, query_op, query_val); result.setUnfilteredItemCount(count); context.complete(); @@ -165,10 +163,11 @@ public class FilteredItemsResource extends Resource { } return result; } - - private List> getMetadataFieldsList(org.dspace.core.Context context, List query_field) throws SQLException { + + private List> getMetadataFieldsList(org.dspace.core.Context context, List query_field) + throws SQLException { List> listFieldList = new ArrayList>(); - for(String s: query_field) { + for (String s : query_field) { ArrayList fields = new ArrayList(); listFieldList.add(fields); if (s.equals("*")) { @@ -178,33 +177,34 @@ public class FilteredItemsResource extends Resource { String element = ""; String qualifier = null; String[] parts = s.split("\\."); - if (parts.length>0) { + if (parts.length > 0) { schema = parts[0]; } - if (parts.length>1) { + if (parts.length > 1) { element = parts[1]; } - if (parts.length>2) { + if (parts.length > 2) { qualifier = parts[2]; } - + if (Item.ANY.equals(qualifier)) { - for(MetadataField mf: metadataFieldService.findFieldsByElementNameUnqualified(context, schema, element)){ - fields.add(mf); + for (MetadataField mf : metadataFieldService + .findFieldsByElementNameUnqualified(context, schema, element)) { + fields.add(mf); } } else { MetadataField mf = metadataFieldService.findByElement(context, schema, element, qualifier); if (mf != null) { - fields.add(mf); + fields.add(mf); } } } return listFieldList; } - + private List getUuidsFromStrings(List collSel) { List uuids = new ArrayList(); - for(String s: collSel) { + for (String s : collSel) { try { uuids.add(UUID.fromString(s)); } catch (IllegalArgumentException e) { @@ -213,5 +213,5 @@ public class FilteredItemsResource extends Resource { } return uuids; } - + } diff --git a/dspace-rest/src/main/java/org/dspace/rest/FiltersResource.java b/dspace-rest/src/main/java/org/dspace/rest/FiltersResource.java index e597d13b4c..904d62c6c8 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/FiltersResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/FiltersResource.java @@ -7,7 +7,6 @@ */ package org.dspace.rest; - import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -23,44 +22,36 @@ import org.dspace.rest.common.ItemFilter; /** * Class which provides read methods over the metadata registry. - * + * * @author Terry Brady, Georgetown University - * */ @Path("/filters") -public class FiltersResource -{ +public class FiltersResource { private static Logger log = Logger.getLogger(FiltersResource.class); /** * Return all Use Case Item Filters in DSpace. - * - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of metadata schemas. - * @throws WebApplicationException - * It can be caused by creating context or while was problem - * with reading community from database(SQLException). + * @throws WebApplicationException It can be caused by creating context or while was problem + * with reading community from database(SQLException). */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public ItemFilter[] getFilters(@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading all Item Filters."); return ItemFilter.getItemFilters(ItemFilter.ALL, false).toArray(new ItemFilter[0]); diff --git a/dspace-rest/src/main/java/org/dspace/rest/HandleResource.java b/dspace-rest/src/main/java/org/dspace/rest/HandleResource.java index c4ab1624fa..71a3b8a084 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/HandleResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/HandleResource.java @@ -7,6 +7,17 @@ */ package org.dspace.rest; +import java.sql.SQLException; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + import org.apache.log4j.Logger; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; @@ -21,12 +32,6 @@ import org.dspace.rest.common.DSpaceObject; import org.dspace.rest.common.Item; import org.dspace.rest.exceptions.ContextException; -import javax.ws.rs.*; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.sql.SQLException; - /** * Created with IntelliJ IDEA. * User: peterdietz @@ -43,8 +48,11 @@ public class HandleResource extends Resource { @GET @Path("/{prefix}/{suffix}") - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public org.dspace.rest.common.DSpaceObject getObject(@PathParam("prefix") String prefix, @PathParam("suffix") String suffix, @QueryParam("expand") String expand, @javax.ws.rs.core.Context HttpHeaders headers) { + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.DSpaceObject getObject(@PathParam("prefix") String prefix, + @PathParam("suffix") String suffix, + @QueryParam("expand") String expand, + @javax.ws.rs.core.Context HttpHeaders headers) { DSpaceObject dSpaceObject = new DSpaceObject(); org.dspace.core.Context context = null; @@ -53,19 +61,22 @@ public class HandleResource extends Resource { org.dspace.content.DSpaceObject dso = handleService.resolveToObject(context, prefix + "/" + suffix); - if(dso == null) { + if (dso == null) { throw new WebApplicationException(Response.Status.NOT_FOUND); } DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService(dso); - log.info("DSO Lookup by handle: [" + prefix + "] / [" + suffix + "] got result of: " + dSpaceObjectService.getTypeText(dso) + "_" + dso.getID()); + log.info("DSO Lookup by handle: [" + prefix + "] / [" + suffix + "] got result of: " + dSpaceObjectService + .getTypeText(dso) + "_" + dso.getID()); - if(authorizeService.authorizeActionBoolean(context, dso, org.dspace.core.Constants.READ)) { - switch(dso.getType()) { + if (authorizeService.authorizeActionBoolean(context, dso, org.dspace.core.Constants.READ)) { + switch (dso.getType()) { case Constants.COMMUNITY: - dSpaceObject = new Community((org.dspace.content.Community) dso, servletContext, expand, context); + dSpaceObject = new Community((org.dspace.content.Community) dso, servletContext, expand, + context); break; case Constants.COLLECTION: - dSpaceObject = new Collection((org.dspace.content.Collection) dso, servletContext, expand, context, null, null); + dSpaceObject = new Collection((org.dspace.content.Collection) dso, servletContext, expand, + context, null, null); break; case Constants.ITEM: dSpaceObject = new Item((org.dspace.content.Item) dso, servletContext, expand, context); @@ -83,12 +94,12 @@ public class HandleResource extends Resource { } catch (SQLException e) { log.error(e.getMessage()); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); - } catch (ContextException e) - { - processException("Could not read handle(prefix=" + prefix + "), (suffix=" + suffix + ") ContextException. Message:" + e.getMessage(), - context); - } finally - { + } catch (ContextException e) { + processException( + "Could not read handle(prefix=" + prefix + "), (suffix=" + suffix + ") ContextException. Message:" + e + .getMessage(), + context); + } finally { processFinally(context); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/HierarchyResource.java b/dspace-rest/src/main/java/org/dspace/rest/HierarchyResource.java index a2f4ccd885..716f361f76 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/HierarchyResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/HierarchyResource.java @@ -7,6 +7,19 @@ */ package org.dspace.rest; +import java.io.UnsupportedEncodingException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import org.apache.log4j.Logger; import org.dspace.authorize.factory.AuthorizeServiceFactory; @@ -23,70 +36,51 @@ import org.dspace.rest.common.HierarchySite; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.HttpHeaders; - -import java.io.UnsupportedEncodingException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /* * This class retrieves the community hierarchy in an optimized format. - * + * * @author Terry Brady, Georgetown University */ @Path("/hierarchy") -@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) +@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public class HierarchyResource extends Resource { private static Logger log = Logger.getLogger(HierarchyResource.class); protected SiteService siteService = ContentServiceFactory.getInstance().getSiteService(); protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - + /** - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the collection as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the collection as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return instance of collection. It can also return status code - * NOT_FOUND(404) if id of collection is incorrect or status code - * @throws UnsupportedEncodingException - * The Character Encoding is not supported. - * @throws WebApplicationException - * It is thrown when was problem with database reading - * (SQLException) or problem with creating - * context(ContextException). It is thrown by NOT_FOUND and - * UNATHORIZED status codes, too. + * NOT_FOUND(404) if id of collection is incorrect or status code + * @throws UnsupportedEncodingException The Character Encoding is not supported. + * @throws WebApplicationException It is thrown when was problem with database reading + * (SQLException) or problem with creating + * context(ContextException). It is thrown by NOT_FOUND and + * UNATHORIZED status codes, too. */ @GET - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public HierarchySite getHierarchy( - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws UnsupportedEncodingException, WebApplicationException { - + @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws UnsupportedEncodingException, WebApplicationException { + org.dspace.core.Context context = null; HierarchySite repo = new HierarchySite(); - + try { context = createContext(); - if (!configurationService.getBooleanProperty("rest.hierarchy-authenticate", true)) { - context.turnOffAuthorisationSystem(); - } Site site = siteService.findSite(context); repo.setId(site.getID().toString()); @@ -107,9 +101,10 @@ public class HierarchyResource extends Resource { } return repo; } - - - private void processCommunity(org.dspace.core.Context context, HierarchyCommunity parent, List communities) throws SQLException { + + + private void processCommunity(org.dspace.core.Context context, HierarchyCommunity parent, + List communities) throws SQLException { if (communities == null) { return; } @@ -118,26 +113,28 @@ public class HierarchyResource extends Resource { } List parentComms = new ArrayList(); parent.setCommunities(parentComms); - for(Community comm: communities) { + for (Community comm : communities) { if (!authorizeService.authorizeActionBoolean(context, comm, org.dspace.core.Constants.READ)) { continue; } - HierarchyCommunity mycomm = new HierarchyCommunity(comm.getID().toString(), comm.getName(), comm.getHandle()); + HierarchyCommunity mycomm = new HierarchyCommunity(comm.getID().toString(), comm.getName(), + comm.getHandle()); parentComms.add(mycomm); List colls = comm.getCollections(); if (colls.size() > 0) { List myColls = new ArrayList(); mycomm.setCollections(myColls); - for(Collection coll: colls) { + for (Collection coll : colls) { if (!authorizeService.authorizeActionBoolean(context, coll, org.dspace.core.Constants.READ)) { continue; } - HierarchyCollection mycoll = new HierarchyCollection(coll.getID().toString(), coll.getName(), coll.getHandle()); + HierarchyCollection mycoll = new HierarchyCollection(coll.getID().toString(), coll.getName(), + coll.getHandle()); myColls.add(mycoll); } } processCommunity(context, mycomm, comm.getSubcommunities()); - } - + } + } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java b/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java index 3086b0eed1..84dd35e9a9 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java @@ -7,6 +7,31 @@ */ package org.dspace.rest; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.factory.AuthorizeServiceFactory; @@ -14,7 +39,11 @@ import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.ResourcePolicyService; import org.dspace.content.Bundle; import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; +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.ItemService; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.GroupService; import org.dspace.rest.common.Bitstream; @@ -23,39 +52,24 @@ import org.dspace.rest.common.MetadataEntry; import org.dspace.rest.exceptions.ContextException; import org.dspace.usage.UsageEvent; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - /** * Class which provide all CRUD methods over items. * * @author Rostislav Novak (Computing and Information Centre, CTU in Prague) - * */ // Every DSpace class used without namespace is from package org.dspace.rest.common.*. Otherwise namespace is defined. @SuppressWarnings("deprecation") @Path("/items") -public class ItemsResource extends Resource -{ +public class ItemsResource extends Resource { protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() + .getBitstreamFormatService(); protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService(); - protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); + protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance() + .getResourcePolicyService(); protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); private static final Logger log = Logger.getLogger(ItemsResource.class); @@ -64,72 +78,59 @@ public class ItemsResource extends Resource * Return item properties without metadata and bitstreams. You can add * additional properties by parameter expand. * - * @param itemId - * Id of item in DSpace. - * @param expand - * String which define, what additional properties will be in - * returned item. Options are separeted by commas and are: "all", - * "metadata", "parentCollection", "parentCollectionList", - * "parentCommunityList" and "bitstreams". - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param itemId Id of item in DSpace. + * @param expand String which define, what additional properties will be in + * returned item. Options are separeted by commas and are: "all", + * "metadata", "parentCollection", "parentCollectionList", + * "parentCommunityList" and "bitstreams". + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return If user is allowed to read item, it returns item. Otherwise is - * thrown WebApplicationException with response status - * UNAUTHORIZED(401) or NOT_FOUND(404) if was id incorrect. - * @throws WebApplicationException - * This exception can be throw by NOT_FOUND(bad id of item), - * UNAUTHORIZED, SQLException if wasproblem with reading from - * database and ContextException, if there was problem with - * creating context of DSpace. + * thrown WebApplicationException with response status + * UNAUTHORIZED(401) or NOT_FOUND(404) if was id incorrect. + * @throws WebApplicationException This exception can be throw by NOT_FOUND(bad id of item), + * UNAUTHORIZED, SQLException if wasproblem with reading from + * database and ContextException, if there was problem with + * creating context of DSpace. */ @GET @Path("/{item_id}") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Item getItem(@PathParam("item_id") String itemId, @QueryParam("expand") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading item(id=" + itemId + ")."); org.dspace.core.Context context = null; Item item = null; - try - { + try { context = createContext(); org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.READ); - writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request, + context); item = new Item(dspaceItem, servletContext, expand, context); context.complete(); log.trace("Item(id=" + itemId + ") was successfully read."); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read item(id=" + itemId + "), SQLException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not read item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), context); - } - finally - { + } catch (ContextException e) { + processException("Could not read item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -141,89 +142,71 @@ public class ItemsResource extends Resource * list will be and from which index will start. Items in list are sorted by * handle, not by id. * - * @param expand - * String which define, what additional properties will be in - * returned item. Options are separeted by commas and are: "all", - * "metadata", "parentCollection", "parentCollectionList", - * "parentCommunityList" and "bitstreams". - * @param limit - * How many items in array will be. Default value is 100. - * @param offset - * On which index will array start. Default value is 0. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param expand String which define, what additional properties will be in + * returned item. Options are separeted by commas and are: "all", + * "metadata", "parentCollection", "parentCollectionList", + * "parentCommunityList" and "bitstreams". + * @param limit How many items in array will be. Default value is 100. + * @param offset On which index will array start. Default value is 0. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return Return array of items, on which has logged user into context - * permission. - * @throws WebApplicationException - * It can be thrown by SQLException, when was problem with - * reading items from database or ContextException, when was - * problem with creating context of DSpace. + * permission. + * @throws WebApplicationException It can be thrown by SQLException, when was problem with + * reading items from database or ContextException, when was + * problem with creating context of DSpace. */ @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Item[] getItems(@QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit, - @QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading items.(offset=" + offset + ",limit=" + limit + ")."); org.dspace.core.Context context = null; List items = null; - try - { + try { context = createContext(); Iterator dspaceItems = itemService.findAllUnfiltered(context); items = new ArrayList(); - if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) - { + if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) { log.warn("Paging was badly set, using default values."); limit = 100; offset = 0; } - for (int i = 0; (dspaceItems.hasNext()) && (i < (limit + offset)); i++) - { + for (int i = 0; (dspaceItems.hasNext()) && (i < (limit + offset)); i++) { org.dspace.content.Item dspaceItem = dspaceItems.next(); - if (i >= offset) - { - if (itemService.isItemListedForUser(context, dspaceItem)) - { + if (i >= offset) { + if (itemService.isItemListedForUser(context, dspaceItem)) { items.add(new Item(dspaceItem, servletContext, expand, context)); writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); } } } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Something went wrong while reading items from database. Message: " + e, context); - } - catch (ContextException e) - { - processException("Something went wrong while reading items, ContextException. Message: " + e.getMessage(), context); - } - finally - { + } catch (ContextException e) { + processException("Something went wrong while reading items, ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -234,65 +217,53 @@ public class ItemsResource extends Resource /** * Returns item metadata in list. * - * @param itemId - * Id of item in DSpace. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param itemId Id of item in DSpace. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return Return list of metadata fields if was everything ok. Otherwise it - * throw WebApplication exception with response code NOT_FOUND(404) - * or UNAUTHORIZED(401). - * @throws WebApplicationException - * It can be thrown by two exceptions: SQLException if was - * problem wtih reading item from database and ContextException, - * if was problem with creating context of DSpace. And can be - * thrown by NOT_FOUND and UNAUTHORIZED too. + * throw WebApplication exception with response code NOT_FOUND(404) + * or UNAUTHORIZED(401). + * @throws WebApplicationException It can be thrown by two exceptions: SQLException if was + * problem wtih reading item from database and ContextException, + * if was problem with creating context of DSpace. And can be + * thrown by NOT_FOUND and UNAUTHORIZED too. */ @GET @Path("/{item_id}/metadata") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public MetadataEntry[] getItemMetadata(@PathParam("item_id") String itemId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading item(id=" + itemId + ") metadata."); org.dspace.core.Context context = null; List metadata = null; - try - { + try { context = createContext(); org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.READ); - writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request, + context); metadata = new org.dspace.rest.common.Item(dspaceItem, servletContext, "metadata", context).getMetadata(); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read item(id=" + itemId + "), SQLException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not read item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), context); - } - finally - { + } catch (ContextException e) { + processException("Could not read item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -303,76 +274,62 @@ public class ItemsResource extends Resource /** * Return array of bitstreams in item. It can be paged. * - * @param itemId - * Id of item in DSpace. - * @param limit - * How many items will be in array. - * @param offset - * On which index will start array. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param itemId Id of item in DSpace. + * @param limit How many items will be in array. + * @param offset On which index will start array. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return Return paged array of bitstreams in item. - * @throws WebApplicationException - * It can be throw by NOT_FOUND, UNAUTHORIZED, SQLException if - * was problem with reading from database and ContextException - * if was problem with creating context of DSpace. + * @throws WebApplicationException It can be throw by NOT_FOUND, UNAUTHORIZED, SQLException if + * was problem with reading from database and ContextException + * if was problem with creating context of DSpace. */ @GET @Path("/{item_id}/bitstreams") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Bitstream[] getItemBitstreams(@PathParam("item_id") String itemId, - @QueryParam("limit") @DefaultValue("20") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("limit") @DefaultValue("20") Integer limit, + @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading item(id=" + itemId + ") bitstreams.(offset=" + offset + ",limit=" + limit + ")"); org.dspace.core.Context context = null; List bitstreams = null; - try - { + try { context = createContext(); org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.READ); - writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request, + context); - List itemBitstreams = new Item(dspaceItem, servletContext, "bitstreams", context).getBitstreams(); + List itemBitstreams = new Item(dspaceItem, servletContext, "bitstreams", context) + .getBitstreams(); - if ((offset + limit) > (itemBitstreams.size() - offset)) - { + if ((offset + limit) > (itemBitstreams.size() - offset)) { bitstreams = itemBitstreams.subList(offset, itemBitstreams.size()); - } - else - { + } else { bitstreams = itemBitstreams.subList(offset, offset + limit); } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read item(id=" + itemId + ") bitstreams, SQLExcpetion. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not read item(id=" + itemId + ") bitstreams, ContextException. Message: " + e.getMessage(), - context); - } - finally - { + } catch (ContextException e) { + processException( + "Could not read item(id=" + itemId + ") bitstreams, ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -384,77 +341,65 @@ public class ItemsResource extends Resource * Adding metadata fields to item. If metadata key is in item, it will be * added, NOT REPLACED! * - * @param itemId - * Id of item in DSpace. - * @param metadata - * List of metadata fields, which will be added into item. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param itemId Id of item in DSpace. + * @param metadata List of metadata fields, which will be added into item. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return It returns status code OK(200) if all was ok. UNAUTHORIZED(401) - * if user is not allowed to write to item. NOT_FOUND(404) if id of - * item is incorrect. - * @throws WebApplicationException - * It is throw by these exceptions: SQLException, if was problem - * with reading from database or writing to database. - * AuthorizeException, if was problem with authorization to item - * fields. ContextException, if was problem with creating - * context of DSpace. + * if user is not allowed to write to item. NOT_FOUND(404) if id of + * item is incorrect. + * @throws WebApplicationException It is throw by these exceptions: SQLException, if was problem + * with reading from database or writing to database. + * AuthorizeException, if was problem with authorization to item + * fields. ContextException, if was problem with creating + * context of DSpace. */ @POST @Path("/{item_id}/metadata") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response addItemMetadata(@PathParam("item_id") String itemId, List metadata, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response addItemMetadata(@PathParam("item_id") String itemId, + List metadata, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Adding metadata to item(id=" + itemId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE); - writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, + context); - for (MetadataEntry entry : metadata) - { + for (MetadataEntry entry : metadata) { // TODO Test with Java split String data[] = mySplit(entry.getKey()); // Done by my split, because of java split was not function. - if ((data.length >= 2) && (data.length <= 3)) - { - itemService.addMetadata(context, dspaceItem, data[0], data[1], data[2], entry.getLanguage(), entry.getValue()); + if ((data.length >= 2) && (data.length <= 3)) { + itemService.addMetadata(context, dspaceItem, data[0], data[1], data[2], entry.getLanguage(), + entry.getValue()); } } context.complete(); - } - catch (SQLException e) - { - processException("Could not write metadata to item(id=" + itemId + "), SQLException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not write metadata to item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), - context); - } - finally - { + } catch (SQLException e) { + processException("Could not write metadata to item(id=" + itemId + "), SQLException. Message: " + e, + context); + } catch (ContextException e) { + processException( + "Could not write metadata to item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -465,70 +410,58 @@ public class ItemsResource extends Resource /** * Create bitstream in item. * - * @param name - * Btstream name to set. - * @param description - * Btstream description to set. - * @param groupId - * ResourcePolicy group (allowed to READ). - * @param year - * ResourcePolicy start date year. - * @param month - * ResourcePolicy start date month. - * @param day - * ResourcePolicy start date day. - * @param itemId - * Id of item in DSpace. - * @param inputStream - * Data of bitstream in inputStream. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param name Btstream name to set. + * @param description Btstream description to set. + * @param groupId ResourcePolicy group (allowed to READ). + * @param year ResourcePolicy start date year. + * @param month ResourcePolicy start date month. + * @param day ResourcePolicy start date day. + * @param itemId Id of item in DSpace. + * @param inputStream Data of bitstream in inputStream. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return Returns bitstream with status code OK(200). If id of item is - * invalid , it returns status code NOT_FOUND(404). If user is not - * allowed to write to item, UNAUTHORIZED(401). - * @throws WebApplicationException - * It is thrown by these exceptions: SQLException, when was - * problem with reading/writing from/to database. - * AuthorizeException, when was problem with authorization to - * item and add bitstream to item. IOException, when was problem - * with creating file or reading from inpustream. - * ContextException. When was problem with creating context of - * DSpace. + * invalid , it returns status code NOT_FOUND(404). If user is not + * allowed to write to item, UNAUTHORIZED(401). + * @throws WebApplicationException It is thrown by these exceptions: SQLException, when was + * problem with reading/writing from/to database. + * AuthorizeException, when was problem with authorization to + * item and add bitstream to item. IOException, when was problem + * with creating file or reading from inpustream. + * ContextException. When was problem with creating context of + * DSpace. */ // TODO Add option to add bitstream by URI.(for very big files) @POST @Path("/{item_id}/bitstreams") public Bitstream addItemBitstream(@PathParam("item_id") String itemId, InputStream inputStream, - @QueryParam("name") String name, @QueryParam("description") String description, - @QueryParam("groupId") String groupId, @QueryParam("year") Integer year, @QueryParam("month") Integer month, - @QueryParam("day") Integer day, @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("name") String name, @QueryParam("description") String description, + @QueryParam("groupId") String groupId, @QueryParam("year") Integer year, + @QueryParam("month") Integer month, + @QueryParam("day") Integer day, @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Adding bitstream to item(id=" + itemId + ")."); org.dspace.core.Context context = null; Bitstream bitstream = null; - try - { + try { context = createContext(); org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE); - writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, + context); // Is better to add bitstream to ORIGINAL bundle or to item own? log.trace("Creating bitstream in item."); @@ -536,17 +469,13 @@ public class ItemsResource extends Resource org.dspace.content.Bitstream dspaceBitstream = null; List bundles = itemService.getBundles(dspaceItem, org.dspace.core.Constants.CONTENT_BUNDLE_NAME); - if(bundles != null && bundles.size() != 0) - { + if (bundles != null && bundles.size() != 0) { bundle = bundles.get(0); // There should be only one bundle ORIGINAL. } - if (bundle == null) - { + if (bundle == null) { log.trace("Creating bundle in item."); dspaceBitstream = itemService.createSingleBitstream(context, inputStream, dspaceItem); - } - else - { + } else { log.trace("Getting bundle from item."); dspaceBitstream = bitstreamService.create(context, bundle, inputStream); } @@ -554,42 +483,36 @@ public class ItemsResource extends Resource dspaceBitstream.setSource(context, "DSpace REST API"); // Set bitstream name and description - if (name != null) - { - if (BitstreamResource.getMimeType(name) == null) - { + if (name != null) { + if (BitstreamResource.getMimeType(name) == null) { dspaceBitstream.setFormat(context, bitstreamFormatService.findUnknown(context)); - } - else - { - bitstreamService.setFormat(context, dspaceBitstream, bitstreamFormatService.findByMIMEType(context, BitstreamResource.getMimeType(name))); + } else { + bitstreamService.setFormat(context, dspaceBitstream, bitstreamFormatService + .findByMIMEType(context, BitstreamResource.getMimeType(name))); } dspaceBitstream.setName(context, name); } - if (description != null) - { + if (description != null) { dspaceBitstream.setDescription(context, description); } // Create policy for bitstream - if (groupId != null) - { + if (groupId != null) { bundles = dspaceBitstream.getBundles(); - for (Bundle dspaceBundle : bundles) - { - List bitstreamsPolicies = bundleService.getBitstreamPolicies(context, dspaceBundle); + for (Bundle dspaceBundle : bundles) { + List bitstreamsPolicies = bundleService + .getBitstreamPolicies(context, dspaceBundle); // Remove default bitstream policies - List policiesToRemove = new ArrayList(); + List policiesToRemove = new ArrayList(); for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies) { - if (policy.getdSpaceObject().getID().equals(dspaceBitstream.getID())) - { + if (policy.getdSpaceObject().getID().equals(dspaceBitstream.getID())) { policiesToRemove.add(policy); } } - for (org.dspace.authorize.ResourcePolicy policy : policiesToRemove) - { + for (org.dspace.authorize.ResourcePolicy policy : policiesToRemove) { bitstreamsPolicies.remove(policy); } @@ -597,19 +520,15 @@ public class ItemsResource extends Resource dspacePolicy.setAction(org.dspace.core.Constants.READ); dspacePolicy.setGroup(groupService.findByIdOrLegacyId(context, groupId)); dspacePolicy.setdSpaceObject(dspaceBitstream); - if ((year != null) || (month != null) || (day != null)) - { + if ((year != null) || (month != null) || (day != null)) { Date date = new Date(); - if (year != null) - { + if (year != null) { date.setYear(year - 1900); } - if (month != null) - { + if (month != null) { date.setMonth(month - 1); } - if (day != null) - { + if (day != null) { date.setDate(day); } date.setHours(0); @@ -629,26 +548,20 @@ public class ItemsResource extends Resource context.complete(); - } - catch (SQLException e) - { - processException("Could not create bitstream in item(id=" + itemId + "), SQLException. Message: " + e, context); - } - catch (AuthorizeException e) - { - processException("Could not create bitstream in item(id=" + itemId + "), AuthorizeException. Message: " + e, context); - } - catch (IOException e) - { - processException("Could not create bitstream in item(id=" + itemId + "), IOException Message: " + e, context); - } - catch (ContextException e) - { + } catch (SQLException e) { + processException("Could not create bitstream in item(id=" + itemId + "), SQLException. Message: " + e, + context); + } catch (AuthorizeException e) { + processException("Could not create bitstream in item(id=" + itemId + "), AuthorizeException. Message: " + e, + context); + } catch (IOException e) { + processException("Could not create bitstream in item(id=" + itemId + "), IOException Message: " + e, + context); + } catch (ContextException e) { processException( - "Could not create bitstream in item(id=" + itemId + "), ContextException Message: " + e.getMessage(), context); - } - finally - { + "Could not create bitstream in item(id=" + itemId + "), ContextException Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -659,71 +572,61 @@ public class ItemsResource extends Resource /** * Replace all metadata in item with new passed metadata. * - * @param itemId - * Id of item in DSpace. - * @param metadata - * List of metadata fields, which will replace old metadata in - * item. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param itemId Id of item in DSpace. + * @param metadata List of metadata fields, which will replace old metadata in + * item. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return It returns status code: OK(200). NOT_FOUND(404) if item was not - * found, UNAUTHORIZED(401) if user is not allowed to write to item. - * @throws WebApplicationException - * It is thrown by: SQLException, when was problem with database - * reading or writting, AuthorizeException when was problem with - * authorization to item and metadata fields. And - * ContextException, when was problem with creating context of - * DSpace. + * found, UNAUTHORIZED(401) if user is not allowed to write to item. + * @throws WebApplicationException It is thrown by: SQLException, when was problem with database + * reading or writting, AuthorizeException when was problem with + * authorization to item and metadata fields. And + * ContextException, when was problem with creating context of + * DSpace. */ @PUT @Path("/{item_id}/metadata") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response updateItemMetadata(@PathParam("item_id") String itemId, MetadataEntry[] metadata, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Updating metadata in item(id=" + itemId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE); - writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, + context); log.trace("Deleting original metadata from item."); - for (MetadataEntry entry : metadata) - { + for (MetadataEntry entry : metadata) { String data[] = mySplit(entry.getKey()); - if ((data.length >= 2) && (data.length <= 3)) - { - itemService.clearMetadata(context, dspaceItem, data[0], data[1], data[2], org.dspace.content.Item.ANY); + if ((data.length >= 2) && (data.length <= 3)) { + itemService + .clearMetadata(context, dspaceItem, data[0], data[1], data[2], org.dspace.content.Item.ANY); } } log.trace("Adding new metadata to item."); - for (MetadataEntry entry : metadata) - { + for (MetadataEntry entry : metadata) { String data[] = mySplit(entry.getKey()); - if ((data.length >= 2) && (data.length <= 3)) - { - itemService.addMetadata(context, dspaceItem, data[0], data[1], data[2], entry.getLanguage(), entry.getValue()); + if ((data.length >= 2) && (data.length <= 3)) { + itemService.addMetadata(context, dspaceItem, data[0], data[1], data[2], entry.getLanguage(), + entry.getValue()); } } //Update the item to ensure that all the events get fired. @@ -731,20 +634,18 @@ public class ItemsResource extends Resource context.complete(); - } - catch (SQLException e) - { - processException("Could not update metadata in item(id=" + itemId + "), SQLException. Message: " + e, context); - } - catch (ContextException e) - { + } catch (SQLException e) { + processException("Could not update metadata in item(id=" + itemId + "), SQLException. Message: " + e, + context); + } catch (ContextException e) { processException( - "Could not update metadata in item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), context); + "Could not update metadata in item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), + context); } catch (AuthorizeException e) { processException( - "Could not update metadata in item(id=" + itemId + "), AuthorizeException. Message: " + e.getMessage(), context); - } finally - { + "Could not update metadata in item(id=" + itemId + "), AuthorizeException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -755,75 +656,59 @@ public class ItemsResource extends Resource /** * Delete item from DSpace. It delete bitstreams only from item bundle. * - * @param itemId - * Id of item which will be deleted. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param itemId Id of item which will be deleted. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return It returns status code: OK(200). NOT_FOUND(404) if item was not - * found, UNAUTHORIZED(401) if user is not allowed to delete item - * metadata. - * @throws WebApplicationException - * It can be thrown by: SQLException, when was problem with - * database reading. AuthorizeException, when was problem with - * authorization to item.(read and delete) IOException, when was - * problem with deleting bitstream file. ContextException, when - * was problem with creating context of DSpace. + * found, UNAUTHORIZED(401) if user is not allowed to delete item + * metadata. + * @throws WebApplicationException It can be thrown by: SQLException, when was problem with + * database reading. AuthorizeException, when was problem with + * authorization to item.(read and delete) IOException, when was + * problem with deleting bitstream file. ContextException, when + * was problem with creating context of DSpace. */ @DELETE @Path("/{item_id}") public Response deleteItem(@PathParam("item_id") String itemId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting item(id=" + itemId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.DELETE); - writeStats(dspaceItem, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(dspaceItem, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor, headers, request, + context); log.trace("Deleting item."); itemService.delete(context, dspaceItem); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not delete item(id=" + itemId + "), SQLException. Message: " + e, context); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { processException("Could not delete item(id=" + itemId + "), AuthorizeException. Message: " + e, context); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); - } - catch (IOException e) - { + } catch (IOException e) { processException("Could not delete item(id=" + itemId + "), IOException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not delete item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), context); - } - finally - { + } catch (ContextException e) { + processException("Could not delete item(id=" + itemId + "), ContextException. Message: " + e.getMessage(), + context); + } finally { processFinally(context); } @@ -834,61 +719,59 @@ public class ItemsResource extends Resource /** * Delete all item metadata. * - * @param itemId - * Id of item in DSpace. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param itemId Id of item in DSpace. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return It returns status code: OK(200). NOT_FOUND(404) if item was not - * found, UNAUTHORIZED(401) if user is not allowed to delete item - * metadata. - * @throws WebApplicationException - * Thrown by three exceptions. SQLException, when there was - * a problem reading item from database or editing metadata - * fields. AuthorizeException, when there was a problem with - * authorization to item. And ContextException, when there was a problem - * with creating a DSpace context. + * found, UNAUTHORIZED(401) if user is not allowed to delete item + * metadata. + * @throws WebApplicationException Thrown by three exceptions. SQLException, when there was + * a problem reading item from database or editing metadata + * fields. AuthorizeException, when there was a problem with + * authorization to item. And ContextException, when there was a problem + * with creating a DSpace context. */ @DELETE @Path("/{item_id}/metadata") public Response deleteItemMetadata(@PathParam("item_id") String itemId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting metadata in item(id=" + itemId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE); - writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, context); + writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, + context); log.trace("Deleting metadata."); // TODO Rewrite without deprecated object. Leave there only generated metadata. - String valueAccessioned = itemService.getMetadataFirstValue(dspaceItem, "dc", "date", "accessioned", org.dspace.content.Item.ANY); - String valueAvailable = itemService.getMetadataFirstValue(dspaceItem, "dc", "date", "available", org.dspace.content.Item.ANY); - String valueURI = itemService.getMetadataFirstValue(dspaceItem, "dc", "identifier", "uri", org.dspace.content.Item.ANY); - String valueProvenance = itemService.getMetadataFirstValue(dspaceItem, "dc", "description", "provenance", org.dspace.content.Item.ANY); + String valueAccessioned = itemService + .getMetadataFirstValue(dspaceItem, "dc", "date", "accessioned", org.dspace.content.Item.ANY); + String valueAvailable = itemService + .getMetadataFirstValue(dspaceItem, "dc", "date", "available", org.dspace.content.Item.ANY); + String valueURI = itemService + .getMetadataFirstValue(dspaceItem, "dc", "identifier", "uri", org.dspace.content.Item.ANY); + String valueProvenance = itemService + .getMetadataFirstValue(dspaceItem, "dc", "description", "provenance", org.dspace.content.Item.ANY); - itemService.clearMetadata(context, dspaceItem, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, - org.dspace.content.Item.ANY); + itemService.clearMetadata(context, dspaceItem, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, + org.dspace.content.Item.ANY, + org.dspace.content.Item.ANY); // Add their generated metadata itemService.addMetadata(context, dspaceItem, "dc", "date", "accessioned", null, valueAccessioned); @@ -897,17 +780,12 @@ public class ItemsResource extends Resource itemService.addMetadata(context, dspaceItem, "dc", "description", "provenance", null, valueProvenance); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not delete item(id=" + itemId + "), SQLException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not delete item(id=" + itemId + "), ContextException. Message:" + e.getMessage(), context); - } - finally - { + } catch (ContextException e) { + processException("Could not delete item(id=" + itemId + "), ContextException. Message:" + e.getMessage(), + context); + } finally { processFinally(context); } @@ -918,94 +796,79 @@ public class ItemsResource extends Resource /** * Delete bitstream from item bundle. * - * @param itemId - * Id of item in DSpace. - * @param bitstreamId - * Id of bitstream, which will be deleted from bundle. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the context. - * The value of the "rest-dspace-token" header must be set with passed - * token from login method. - * @param request - * Servlet's HTTP request object. + * @param itemId Id of item in DSpace. + * @param bitstreamId Id of bitstream, which will be deleted from bundle. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the context. + * The value of the "rest-dspace-token" header must be set with passed + * token from login method. + * @param request Servlet's HTTP request object. * @return Return status code OK(200) if is all ok. NOT_FOUND(404) if item - * or bitstream was not found. UNAUTHORIZED(401) if user is not - * allowed to delete bitstream. - * @throws WebApplicationException - * It is thrown, when: Was problem with edditting database, - * SQLException. Or problem with authorization to item, bundle - * or bitstream, AuthorizeException. When was problem with - * deleting file IOException. Or problem with creating context - * of DSpace, ContextException. + * or bitstream was not found. UNAUTHORIZED(401) if user is not + * allowed to delete bitstream. + * @throws WebApplicationException It is thrown, when: Was problem with edditting database, + * SQLException. Or problem with authorization to item, bundle + * or bitstream, AuthorizeException. When was problem with + * deleting file IOException. Or problem with creating context + * of DSpace, ContextException. */ @DELETE @Path("/{item_id}/bitstreams/{bitstream_id}") - public Response deleteItemBitstream(@PathParam("item_id") String itemId, @PathParam("bitstream_id") String bitstreamId, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + public Response deleteItemBitstream(@PathParam("item_id") String itemId, + @PathParam("bitstream_id") String bitstreamId, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting bitstream in item(id=" + itemId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.Item item = findItem(context, itemId, org.dspace.core.Constants.WRITE); org.dspace.content.Bitstream bitstream = bitstreamService.findByIdOrLegacyId(context, bitstreamId); - if (bitstream == null) - { + if (bitstream == null) { context.abort(); log.warn("Bitstream(id=" + bitstreamId + ") was not found."); return Response.status(Status.NOT_FOUND).build(); - } - else if (!authorizeService.authorizeActionBoolean(context, bitstream, org.dspace.core.Constants.DELETE)) - { + } else if (!authorizeService.authorizeActionBoolean(context, bitstream, org.dspace.core.Constants.DELETE)) { context.abort(); - log.error("User(" + context.getCurrentUser().getEmail() + ") is not allowed to delete bitstream(id=" + bitstreamId + ")."); + log.error("User(" + context.getCurrentUser() + .getEmail() + ") is not allowed to delete bitstream(id=" + bitstreamId + + ")."); return Response.status(Status.UNAUTHORIZED).build(); } writeStats(item, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, context); writeStats(bitstream, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); log.trace("Deleting bitstream..."); bitstreamService.delete(context, bitstream); context.complete(); - } - catch (SQLException e) - { - processException("Could not delete bitstream(id=" + bitstreamId + "), SQLException. Message: " + e, context); - } - catch (AuthorizeException e) - { - processException("Could not delete bitstream(id=" + bitstreamId + "), AuthorizeException. Message: " + e, context); - } - catch (IOException e) - { + } catch (SQLException e) { + processException("Could not delete bitstream(id=" + bitstreamId + "), SQLException. Message: " + e, + context); + } catch (AuthorizeException e) { + processException("Could not delete bitstream(id=" + bitstreamId + "), AuthorizeException. Message: " + e, + context); + } catch (IOException e) { processException("Could not delete bitstream(id=" + bitstreamId + "), IOException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not delete bitstream(id=" + bitstreamId + "), ContextException. Message:" + e.getMessage(), - context); - } - finally - { + } catch (ContextException e) { + processException( + "Could not delete bitstream(id=" + bitstreamId + "), ContextException. Message:" + e.getMessage(), + context); + } finally { processFinally(context); } @@ -1016,102 +879,86 @@ public class ItemsResource extends Resource /** * Find items by one metadata field. * - * @param metadataEntry - * Metadata field to search by. - * @param expand - * String which define, what additional properties will be in - * returned item. Options are separeted by commas and are: "all", - * "metadata", "parentCollection", "parentCollectionList", - * "parentCommunityList" and "bitstreams". - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into context, - * header "rest-dspace-token" must be set to token value retrieved - * from the login method. - * @param request - * Servlet's HTTP request object. + * @param metadataEntry Metadata field to search by. + * @param expand String which define, what additional properties will be in + * returned item. Options are separeted by commas and are: "all", + * "metadata", "parentCollection", "parentCollectionList", + * "parentCommunityList" and "bitstreams". + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into context, + * header "rest-dspace-token" must be set to token value retrieved + * from the login method. + * @param request Servlet's HTTP request object. * @return Return array of found items. - * @throws WebApplicationException - * Can be thrown: SQLException - problem with - * database reading. AuthorizeException - problem with - * authorization to item. IOException - problem with - * reading from metadata field. ContextException - - * problem with creating DSpace context. + * @throws WebApplicationException Can be thrown: SQLException - problem with + * database reading. AuthorizeException - problem with + * authorization to item. IOException - problem with + * reading from metadata field. ContextException - + * problem with creating DSpace context. */ @POST @Path("/find-by-metadata-field") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Item[] findItemsByMetadataField(MetadataEntry metadataEntry, @QueryParam("expand") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Looking for item with metadata(key=" + metadataEntry.getKey() + ",value=" + metadataEntry.getValue() - + ", language=" + metadataEntry.getLanguage() + ")."); + + ", language=" + metadataEntry.getLanguage() + ")."); org.dspace.core.Context context = null; List items = new ArrayList(); String[] metadata = mySplit(metadataEntry.getKey()); // Must used own style. - if ((metadata.length < 2) || (metadata.length > 3)) - { + if ((metadata.length < 2) || (metadata.length > 3)) { log.error("Finding failed, bad metadata key."); throw new WebApplicationException(Response.Status.NOT_FOUND); } - try - { + try { context = createContext(); - Iterator itemIterator = itemService.findByMetadataField(context, metadataEntry.getSchema(), - metadataEntry.getElement(), metadataEntry.getQualifier(), metadataEntry.getValue()); + Iterator itemIterator = itemService + .findByMetadataField(context, metadataEntry.getSchema(), + metadataEntry.getElement(), metadataEntry.getQualifier(), + metadataEntry.getValue()); - while (itemIterator.hasNext()) - { + while (itemIterator.hasNext()) { org.dspace.content.Item dspaceItem = itemIterator.next(); //Only return items that are available for the current user if (itemService.isItemListedForUser(context, dspaceItem)) { Item item = new Item(dspaceItem, servletContext, expand, context); writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, - request, context); + request, context); items.add(item); } } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Something went wrong while finding item. SQLException, Message: " + e, context); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Context error:" + e.getMessage(), context); } catch (AuthorizeException e) { processException("Authorize error:" + e.getMessage(), context); } catch (IOException e) { processException("IO error:" + e.getMessage(), context); - } finally - { + } finally { processFinally(context); } - if (items.size() == 0) - { + if (items.size() == 0) { log.info("Items not found."); - } - else - { + } else { log.info("Items were found."); } @@ -1123,50 +970,37 @@ public class ItemsResource extends Resource * org.dspace.content.Item.find with checking if item exist and if user * logged into context has permission to do passed action. * - * @param context - * Context of actual logged user. - * @param id - * Id of item in DSpace. - * @param action - * Constant from org.dspace.core.Constants. + * @param context Context of actual logged user. + * @param id Id of item in DSpace. + * @param action Constant from org.dspace.core.Constants. * @return It returns DSpace item. - * @throws WebApplicationException - * Is thrown when item with passed id is not exists and if user - * has no permission to do passed action. + * @throws WebApplicationException Is thrown when item with passed id is not exists and if user + * has no permission to do passed action. */ private org.dspace.content.Item findItem(org.dspace.core.Context context, String id, int action) - throws WebApplicationException - { + throws WebApplicationException { org.dspace.content.Item item = null; - try - { + try { item = itemService.findByIdOrLegacyId(context, id); - if (item == null) - { + if (item == null) { context.abort(); log.warn("Item(id=" + id + ") was not found!"); throw new WebApplicationException(Response.Status.NOT_FOUND); - } - else if (!authorizeService.authorizeActionBoolean(context, item, action)) - { + } else if (!authorizeService.authorizeActionBoolean(context, item, action)) { context.abort(); - if (context.getCurrentUser() != null) - { + if (context.getCurrentUser() != null) { log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to " - + getActionString(action) + " item!"); - } - else - { + + getActionString(action) + " item!"); + } else { log.error("User(anonymous) has not permission to " + getActionString(action) + " item!"); } throw new WebApplicationException(Response.Status.UNAUTHORIZED); } - } - catch (SQLException e) - { - processException("Something get wrong while finding item(id=" + id + "). SQLException, Message: " + e, context); + } catch (SQLException e) { + processException("Something get wrong while finding item(id=" + id + "). SQLException, Message: " + e, + context); } return item; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/MetadataRegistryResource.java b/dspace-rest/src/main/java/org/dspace/rest/MetadataRegistryResource.java index 1d1a99df61..333f611f6c 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/MetadataRegistryResource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/MetadataRegistryResource.java @@ -11,7 +11,6 @@ import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; - import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -38,100 +37,88 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.SiteService; +import org.dspace.rest.common.MetadataField; import org.dspace.rest.common.MetadataSchema; import org.dspace.rest.exceptions.ContextException; import org.dspace.usage.UsageEvent; -import org.dspace.rest.common.MetadataField; /** * Class which provides read methods over the metadata registry. - * + * * @author Terry Brady, Georgetown University - * + * * GET /registries/schema - Return the list of schemas in the registry * GET /registries/schema/{schema_prefix} - Returns the specified schema - * GET /registries/schema/{schema_prefix}/metadata-fields/{element} - Returns the metadata field within a schema with an unqualified element name - * GET /registries/schema/{schema_prefix}/metadata-fields/{element}/{qualifier} - Returns the metadata field within a schema with a qualified element name + * GET /registries/schema/{schema_prefix}/metadata-fields/{element} - Returns the metadata field within a schema + * with an unqualified element name + * GET /registries/schema/{schema_prefix}/metadata-fields/{element}/{qualifier} - Returns the metadata field + * within a schema with a qualified element name * POST /registries/schema/ - Add a schema to the schema registry * POST /registries/schema/{schema_prefix}/metadata-fields - Add a metadata field to the specified schema * GET /registries/metadata-fields/{field_id} - Return the specified metadata field * PUT /registries/metadata-fields/{field_id} - Update the specified metadata field * DELETE /registries/metadata-fields/{field_id} - Delete the specified metadata field from the metadata field registry * DELETE /registries/schema/{schema_id} - Delete the specified schema from the schema registry - * + * * Note: intentionally not providing since there is no date to update other than the namespace * PUT /registries/schema/{schema_id} */ @Path("/registries") -public class MetadataRegistryResource extends Resource -{ +public class MetadataRegistryResource extends Resource { protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); - protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance() + .getMetadataSchemaService(); protected SiteService siteService = ContentServiceFactory.getInstance().getSiteService(); private static Logger log = Logger.getLogger(MetadataRegistryResource.class); /** * Return all metadata registry items in DSpace. - * - * @param expand - * String in which is what you want to add to returned instance - * of metadata schema. Options are: "all", "fields". Default value "fields". - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the metadata schema as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param expand String in which is what you want to add to returned instance + * of metadata schema. Options are: "all", "fields". Default value "fields". + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the metadata schema as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return array of metadata schemas. - * @throws WebApplicationException - * It can be caused by creating context or while was problem - * with reading schema from database(SQLException). + * @throws WebApplicationException It can be caused by creating context or while was problem + * with reading schema from database(SQLException). */ @GET @Path("/schema") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public MetadataSchema[] getSchemas(@QueryParam("expand") @DefaultValue("fields") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public MetadataSchema[] getSchemas(@QueryParam("expand") @DefaultValue("fields") String expand, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading all metadata schemas."); org.dspace.core.Context context = null; ArrayList metadataSchemas = null; - try - { + try { context = createContext(); List schemas = metadataSchemaService.findAll(context); metadataSchemas = new ArrayList(); - for(org.dspace.content.MetadataSchema schema: schemas) { + for (org.dspace.content.MetadataSchema schema : schemas) { metadataSchemas.add(new MetadataSchema(schema, expand, context)); } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read metadata schemas, SQLException. Message:" + e, context); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Could not read metadata schemas, ContextException. Message:" + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -142,48 +129,40 @@ public class MetadataRegistryResource extends Resource /** * Returns metadata schema with basic properties. If you want more, use expand * parameter or method for metadata fields. - * - * @param schemaPrefix - * Prefix for schema in DSpace. - * @param expand - * String in which is what you want to add to returned instance - * of metadata schema. Options are: "all", "fields". Default value "fields". - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the metadata schema as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param schemaPrefix Prefix for schema in DSpace. + * @param expand String in which is what you want to add to returned instance + * of metadata schema. Options are: "all", "fields". Default value "fields". + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the metadata schema as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return instance of org.dspace.rest.common.MetadataSchema. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading. Also if id/prefix of schema is incorrect - * or logged user into context has no permission to read. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading. Also if id/prefix of schema is incorrect + * or logged user into context has no permission to read. */ @GET @Path("/schema/{schema_prefix}") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public MetadataSchema getSchema(@PathParam("schema_prefix") String schemaPrefix, @QueryParam("expand") @DefaultValue("fields") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public MetadataSchema getSchema(@PathParam("schema_prefix") String schemaPrefix, + @QueryParam("expand") @DefaultValue("fields") String expand, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading metadata schemas."); org.dspace.core.Context context = null; MetadataSchema metadataSchema = null; - try - { + try { context = createContext(); org.dspace.content.MetadataSchema schema = metadataSchemaService.find(context, schemaPrefix); @@ -193,129 +172,107 @@ public class MetadataRegistryResource extends Resource } context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read metadata schema, SQLException. Message:" + e, context); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Could not read metadata schema, ContextException. Message:" + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } log.trace("Metadata schemas successfully read."); return metadataSchema; } - + /** - * Returns metadata field with basic properties. - * - * @param schemaPrefix - * Prefix for schema in DSpace. - * @param element - * Unqualified element name for field in the metadata registry. - * @param expand - * String in which is what you want to add to returned instance - * of the metadata field. Options are: "all", "parentSchema". Default value "". - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * Returns metadata field with basic properties. + * + * @param schemaPrefix Prefix for schema in DSpace. + * @param element Unqualified element name for field in the metadata registry. + * @param expand String in which is what you want to add to returned instance + * of the metadata field. Options are: "all", "parentSchema". Default value "". + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return instance of org.dspace.rest.common.MetadataField. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading. Also if id of field is incorrect - * or logged user into context has no permission to read. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading. Also if id of field is incorrect + * or logged user into context has no permission to read. */ @GET @Path("/schema/{schema_prefix}/metadata-fields/{element}") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public MetadataField getMetadataFieldUnqualified(@PathParam("schema_prefix") String schemaPrefix, - @PathParam("element") String element, - @QueryParam("expand") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { - return getMetadataFieldQualified(schemaPrefix, element, "", expand, user_ip, user_agent, xforwardedfor, headers, request); + @PathParam("element") String element, + @QueryParam("expand") String expand, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { + return getMetadataFieldQualified(schemaPrefix, element, "", expand, user_ip, user_agent, xforwardedfor, headers, + request); } - + /** - * Returns metadata field with basic properties. - * - * @param schemaPrefix - * Prefix for schema in DSpace. - * @param element - * Element name for field in the metadata registry. - * @param qualifier - * Element name qualifier for field in the metadata registry. - * @param expand - * String in which is what you want to add to returned instance - * of the metadata field. Options are: "all", "parentSchema". Default value "". - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * Returns metadata field with basic properties. + * + * @param schemaPrefix Prefix for schema in DSpace. + * @param element Element name for field in the metadata registry. + * @param qualifier Element name qualifier for field in the metadata registry. + * @param expand String in which is what you want to add to returned instance + * of the metadata field. Options are: "all", "parentSchema". Default value "". + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return instance of org.dspace.rest.common.MetadataField. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading. Also if id of field is incorrect - * or logged user into context has no permission to read. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading. Also if id of field is incorrect + * or logged user into context has no permission to read. */ @GET @Path("/schema/{schema_prefix}/metadata-fields/{element}/{qualifier}") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public MetadataField getMetadataFieldQualified(@PathParam("schema_prefix") String schemaPrefix, - @PathParam("element") String element, - @PathParam("qualifier") @DefaultValue("") String qualifier, - @QueryParam("expand") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @PathParam("element") String element, + @PathParam("qualifier") @DefaultValue("") String qualifier, + @QueryParam("expand") String expand, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading metadata field."); org.dspace.core.Context context = null; MetadataField metadataField = null; - try - { + try { context = createContext(); org.dspace.content.MetadataSchema schema = metadataSchemaService.find(context, schemaPrefix); - + if (schema == null) { log.error(String.format("Schema not found for prefix %s", schemaPrefix)); throw new WebApplicationException(Response.Status.NOT_FOUND); } - - org.dspace.content.MetadataField field = metadataFieldService.findByElement(context, schema, element, qualifier); + + org.dspace.content.MetadataField field = metadataFieldService + .findByElement(context, schema, element, qualifier); if (field == null) { log.error(String.format("Field %s.%s.%s not found", schemaPrefix, element, qualifier)); throw new WebApplicationException(Response.Status.NOT_FOUND); @@ -323,17 +280,11 @@ public class MetadataRegistryResource extends Resource metadataField = new MetadataField(schema, field, expand, context); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read metadata field, SQLException. Message:" + e, context); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Could not read metadata field, ContextException. Message:" + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -342,50 +293,42 @@ public class MetadataRegistryResource extends Resource } /** - * Returns metadata field with basic properties. - * - * @param fieldId - * Id of metadata field in DSpace. - * @param expand - * String in which is what you want to add to returned instance - * of the metadata field. Options are: "all", "parentSchema". Default value "parentSchema". - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the community as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * Returns metadata field with basic properties. + * + * @param fieldId Id of metadata field in DSpace. + * @param expand String in which is what you want to add to returned instance + * of the metadata field. Options are: "all", "parentSchema". Default value "parentSchema". + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the community as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return instance of org.dspace.rest.common.MetadataField. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading. Also if id of field is incorrect - * or logged user into context has no permission to read. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading. Also if id of field is incorrect + * or logged user into context has no permission to read. */ @GET @Path("/metadata-fields/{field_id}") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public MetadataField getMetadataField(@PathParam("field_id") Integer fieldId, - @QueryParam("expand") @DefaultValue("parentSchema") String expand, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public MetadataField getMetadataField(@PathParam("field_id") Integer fieldId, + @QueryParam("expand") @DefaultValue("parentSchema") String expand, + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Reading metadata field."); org.dspace.core.Context context = null; MetadataField metadataField = null; - try - { + try { context = createContext(); org.dspace.content.MetadataField field = metadataFieldService.find(context, fieldId); @@ -401,17 +344,11 @@ public class MetadataRegistryResource extends Resource metadataField = new MetadataField(schema, field, expand, context); context.complete(); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not read metadata field, SQLException. Message:" + e, context); - } - catch (ContextException e) - { + } catch (ContextException e) { processException("Could not read metadata field, ContextException. Message:" + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -421,94 +358,80 @@ public class MetadataRegistryResource extends Resource /** * Create schema in the schema registry. Creating a schema is restricted to admin users. - * - * @param schema - * Schema that will be added to the metadata registry. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the schema as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param schema Schema that will be added to the metadata registry. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the schema as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response 200 if was everything all right. Otherwise 400 - * when id of community was incorrect or 401 if was problem with - * permission to write into collection. - * Returns the schema (schemaId), if was all ok. - * @throws WebApplicationException - * It can be thrown by SQLException, AuthorizeException and - * ContextException. + * when id of community was incorrect or 401 if was problem with + * permission to write into collection. + * Returns the schema (schemaId), if was all ok. + * @throws WebApplicationException It can be thrown by SQLException, AuthorizeException and + * ContextException. */ @POST @Path("/schema") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public MetadataSchema createSchema(MetadataSchema schema, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Creating a schema."); org.dspace.core.Context context = null; MetadataSchema retSchema = null; - try - { + try { context = createContext(); - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { context.abort(); String user = "anonymous"; - if (context.getCurrentUser() != null) - { + if (context.getCurrentUser() != null) { user = context.getCurrentUser().getEmail(); } log.error("User(" + user + ") does not have permission to create a metadata schema!"); throw new WebApplicationException(Response.Status.UNAUTHORIZED); } - log.debug(String.format("Admin user creating schema with namespace %s and prefix %s", schema.getNamespace(), schema.getPrefix())); + log.debug(String.format("Admin user creating schema with namespace %s and prefix %s", schema.getNamespace(), + schema.getPrefix())); - org.dspace.content.MetadataSchema dspaceSchema = metadataSchemaService.create(context, schema.getPrefix(), schema.getNamespace()); + org.dspace.content.MetadataSchema dspaceSchema = metadataSchemaService + .create(context, schema.getPrefix(), schema.getNamespace()); log.debug("Creating return object."); retSchema = new MetadataSchema(dspaceSchema, "", context); - + writeStats(siteService.findSite(context), UsageEvent.Action.CREATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); context.complete(); log.info("Schema created" + retSchema.getPrefix()); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not create new metadata schema, SQLException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not create new metadata schema, ContextException. Message: " + e.getMessage(), context); - } - catch (AuthorizeException e) - { - processException("Could not create new metadata schema, AuthorizeException. Message: " + e.getMessage(), context); - } - catch (NonUniqueMetadataException e) { - processException("Could not create new metadata schema, NonUniqueMetadataException. Message: " + e.getMessage(), context); - } - catch (Exception e) - { + } catch (ContextException e) { + processException("Could not create new metadata schema, ContextException. Message: " + e.getMessage(), + context); + } catch (AuthorizeException e) { + processException("Could not create new metadata schema, AuthorizeException. Message: " + e.getMessage(), + context); + } catch (NonUniqueMetadataException e) { + processException( + "Could not create new metadata schema, NonUniqueMetadataException. Message: " + e.getMessage(), + context); + } catch (Exception e) { processException("Could not create new metadata schema, Exception. Class: " + e.getClass(), context); - } - finally - { + } finally { processFinally(context); } @@ -517,59 +440,49 @@ public class MetadataRegistryResource extends Resource /** - * Create a new metadata field within a schema. + * Create a new metadata field within a schema. * Creating a metadata field is restricted to admin users. - * - * @param schemaPrefix - * Prefix for schema in DSpace. - * @param field - * Field that will be added to the metadata registry for a schema. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the schema as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param schemaPrefix Prefix for schema in DSpace. + * @param field Field that will be added to the metadata registry for a schema. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the schema as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response 200 if was everything all right. Otherwise 400 - * when id of community was incorrect or 401 if was problem with - * permission to write into collection. - * Returns the field (with fieldId), if was all ok. - * @throws WebApplicationException - * It can be thrown by SQLException, AuthorizeException and - * ContextException. + * when id of community was incorrect or 401 if was problem with + * permission to write into collection. + * Returns the field (with fieldId), if was all ok. + * @throws WebApplicationException It can be thrown by SQLException, AuthorizeException and + * ContextException. */ @POST @Path("/schema/{schema_prefix}/metadata-fields") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public MetadataField createMetadataField(@PathParam("schema_prefix") String schemaPrefix, - MetadataField field, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + MetadataField field, @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info(String.format("Creating metadataField within schema %s.", schemaPrefix)); org.dspace.core.Context context = null; MetadataField retField = null; - try - { + try { context = createContext(); - if (!authorizeService.isAdmin(context)) - { + if (!authorizeService.isAdmin(context)) { context.abort(); String user = "anonymous"; - if (context.getCurrentUser() != null) - { + if (context.getCurrentUser() != null) { user = context.getCurrentUser().getEmail(); } log.error("User(" + user + ") does not have permission to create a metadata field!"); @@ -581,35 +494,28 @@ public class MetadataRegistryResource extends Resource log.error(String.format("Schema not found for prefix %s", schemaPrefix)); throw new WebApplicationException(Response.Status.NOT_FOUND); } - org.dspace.content.MetadataField dspaceField = metadataFieldService.create(context, schema, field.getElement(), field.getQualifier(), field.getDescription()); + org.dspace.content.MetadataField dspaceField = metadataFieldService + .create(context, schema, field.getElement(), field.getQualifier(), field.getDescription()); writeStats(siteService.findSite(context), UsageEvent.Action.CREATE, user_ip, user_agent, xforwardedfor, - headers, request, context); - + headers, request, context); + retField = new MetadataField(schema, dspaceField, "", context); context.complete(); log.info("Metadata field created within schema" + retField.getName()); - } - catch (SQLException e) - { + } catch (SQLException e) { processException("Could not create new metadata field, SQLException. Message: " + e, context); - } - catch (ContextException e) - { - processException("Could not create new metadata field, ContextException. Message: " + e.getMessage(), context); - } - catch (AuthorizeException e) - { - processException("Could not create new metadata field, AuthorizeException. Message: " + e.getMessage(), context); - } - catch (NonUniqueMetadataException e) { - processException("Could not create new metadata field, NonUniqueMetadataException. Message: " + e.getMessage(), context); - } - catch (Exception e) - { + } catch (ContextException e) { + processException("Could not create new metadata field, ContextException. Message: " + e.getMessage(), + context); + } catch (AuthorizeException e) { + processException("Could not create new metadata field, AuthorizeException. Message: " + e.getMessage(), + context); + } catch (NonUniqueMetadataException e) { + processException( + "Could not create new metadata field, NonUniqueMetadataException. Message: " + e.getMessage(), context); + } catch (Exception e) { processException("Could not create new metadata field, Exception. Message: " + e.getMessage(), context); - } - finally - { + } finally { processFinally(context); } @@ -622,48 +528,40 @@ public class MetadataRegistryResource extends Resource /** * Update metadata field. Replace all information about community except the id and the containing schema. - * - * @param fieldId - * Id of the field in the DSpace metdata registry. - * @param field - * Instance of the metadata field which will replace actual metadata field in - * DSpace. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the metadata field as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param fieldId Id of the field in the DSpace metdata registry. + * @param field Instance of the metadata field which will replace actual metadata field in + * DSpace. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the metadata field as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Response 200 if was all ok. Otherwise 400 if was id incorrect or - * 401 if logged user has no permission to update the metadata field. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading or writing. Or problem with writing to - * community caused by authorization. + * 401 if logged user has no permission to update the metadata field. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading or writing. Or problem with writing to + * community caused by authorization. */ @PUT @Path("/metadata-fields/{field_id}") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response updateMetadataField(@PathParam("field_id") Integer fieldId, MetadataField field, - @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, - @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, @Context HttpServletRequest request) - throws WebApplicationException - { + @QueryParam("userIP") String user_ip, + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers, + @Context HttpServletRequest request) + throws WebApplicationException { log.info("Updating metadata field(id=" + fieldId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.MetadataField dspaceField = metadataFieldService.find(context, fieldId); @@ -673,36 +571,31 @@ public class MetadataRegistryResource extends Resource } writeStats(siteService.findSite(context), UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, - headers, request, context); + headers, request, context); dspaceField.setElement(field.getElement()); dspaceField.setQualifier(field.getQualifier()); dspaceField.setScopeNote(field.getDescription()); metadataFieldService.update(context, dspaceField); - + context.complete(); - } - catch (SQLException e) - { - processException("Could not update metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e, context); - } - catch (ContextException e) - { - processException("Could not update metadata field(id=" + fieldId + "), ContextException Message:" + e, context); - } - catch (AuthorizeException e) - { - processException("Could not update metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e, context); - } - catch (NonUniqueMetadataException e) { - processException("Could not update metadata field(id=" + fieldId + "), NonUniqueMetadataException. Message:" + e, context); - } - catch (IOException e) { + } catch (SQLException e) { + processException("Could not update metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e, + context); + } catch (ContextException e) { + processException("Could not update metadata field(id=" + fieldId + "), ContextException Message:" + e, + context); + } catch (AuthorizeException e) { + processException("Could not update metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e, + context); + } catch (NonUniqueMetadataException e) { + processException( + "Could not update metadata field(id=" + fieldId + "), NonUniqueMetadataException. Message:" + e, + context); + } catch (IOException e) { processException("Could not update metadata field(id=" + fieldId + "), IOException. Message:" + e, context); - } - finally - { + } finally { processFinally(context); } @@ -712,44 +605,37 @@ public class MetadataRegistryResource extends Resource /** * Delete metadata field from the DSpace metadata registry - * - * @param fieldId - * Id of the metadata field in DSpace. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the metadata field as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param fieldId Id of the metadata field in DSpace. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the metadata field as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response code OK(200) if was everything all right. - * Otherwise return NOT_FOUND(404) if was id of metadata field is incorrect. - * Or (UNAUTHORIZED)401 if was problem with permission to metadata field. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading or deleting. Or problem with deleting - * metadata field caused by IOException or authorization. + * Otherwise return NOT_FOUND(404) if was id of metadata field is incorrect. + * Or (UNAUTHORIZED)401 if was problem with permission to metadata field. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading or deleting. Or problem with deleting + * metadata field caused by IOException or authorization. */ @DELETE @Path("/metadata-fields/{field_id}") public Response deleteMetadataField(@PathParam("field_id") Integer fieldId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting metadata field(id=" + fieldId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.MetadataField dspaceField = metadataFieldService.find(context, fieldId); @@ -757,28 +643,24 @@ public class MetadataRegistryResource extends Resource log.error(String.format("Metadata Field %d not found", fieldId)); throw new WebApplicationException(Response.Status.NOT_FOUND); } - writeStats(siteService.findSite(context), UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor, headers, - request, context); + writeStats(siteService.findSite(context), UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor, + headers, + request, context); metadataFieldService.delete(context, dspaceField); context.complete(); - } - catch (SQLException e) - { - processException("Could not delete metadata field(id=" + fieldId + "), SQLException. Message:" + e, context); - } - catch (AuthorizeException e) - { - processException("Could not delete metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e, context); - } - catch (ContextException e) - { - processException("Could not delete metadata field(id=" + fieldId + "), ContextException. Message:" + e.getMessage(), - context); - } - finally - { + } catch (SQLException e) { + processException("Could not delete metadata field(id=" + fieldId + "), SQLException. Message:" + e, + context); + } catch (AuthorizeException e) { + processException("Could not delete metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e, + context); + } catch (ContextException e) { + processException( + "Could not delete metadata field(id=" + fieldId + "), ContextException. Message:" + e.getMessage(), + context); + } finally { processFinally(context); } @@ -789,44 +671,37 @@ public class MetadataRegistryResource extends Resource /** * Delete metadata schema from the DSpace metadata registry - * - * @param schemaId - * Id of the metadata schema in DSpace. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the metadata schema as the user logged into the - * context. The value of the "rest-dspace-token" header must be set - * to the token received from the login method response. - * @param request - * Servlet's HTTP request object. + * + * @param schemaId Id of the metadata schema in DSpace. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the metadata schema as the user logged into the + * context. The value of the "rest-dspace-token" header must be set + * to the token received from the login method response. + * @param request Servlet's HTTP request object. * @return Return response code OK(200) if was everything all right. - * Otherwise return NOT_FOUND(404) if was id of metadata schema is incorrect. - * Or (UNAUTHORIZED)401 if was problem with permission to metadata schema. - * @throws WebApplicationException - * Thrown if there was a problem with creating context or problem - * with database reading or deleting. Or problem with deleting - * metadata schema caused by IOException or authorization. + * Otherwise return NOT_FOUND(404) if was id of metadata schema is incorrect. + * Or (UNAUTHORIZED)401 if was problem with permission to metadata schema. + * @throws WebApplicationException Thrown if there was a problem with creating context or problem + * with database reading or deleting. Or problem with deleting + * metadata schema caused by IOException or authorization. */ @DELETE @Path("/schema/{schema_id}") public Response deleteSchema(@PathParam("schema_id") Integer schemaId, @QueryParam("userIP") String user_ip, - @QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor, - @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException - { + @QueryParam("userAgent") String user_agent, + @QueryParam("xforwardedfor") String xforwardedfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) + throws WebApplicationException { log.info("Deleting metadata schema(id=" + schemaId + ")."); org.dspace.core.Context context = null; - try - { + try { context = createContext(); org.dspace.content.MetadataSchema dspaceSchema = metadataSchemaService.find(context, schemaId); @@ -834,28 +709,24 @@ public class MetadataRegistryResource extends Resource log.error(String.format("Metadata Schema %d not found", schemaId)); throw new WebApplicationException(Response.Status.NOT_FOUND); } - writeStats(siteService.findSite(context), UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor, headers, - request, context); + writeStats(siteService.findSite(context), UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor, + headers, + request, context); metadataSchemaService.delete(context, dspaceSchema); context.complete(); - } - catch (SQLException e) - { - processException("Could not delete metadata schema(id=" + schemaId + "), SQLException. Message:" + e, context); - } - catch (AuthorizeException e) - { - processException("Could not delete metadata schema(id=" + schemaId + "), AuthorizeException. Message:" + e, context); - } - catch (ContextException e) - { - processException("Could not delete metadata schema(id=" + schemaId + "), ContextException. Message:" + e.getMessage(), - context); - } - finally - { + } catch (SQLException e) { + processException("Could not delete metadata schema(id=" + schemaId + "), SQLException. Message:" + e, + context); + } catch (AuthorizeException e) { + processException("Could not delete metadata schema(id=" + schemaId + "), AuthorizeException. Message:" + e, + context); + } catch (ContextException e) { + processException( + "Could not delete metadata schema(id=" + schemaId + "), ContextException. Message:" + e.getMessage(), + context); + } finally { processFinally(context); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/Resource.java b/dspace-rest/src/main/java/org/dspace/rest/Resource.java index 3773665ce6..65fdbd2048 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/Resource.java +++ b/dspace-rest/src/main/java/org/dspace/rest/Resource.java @@ -7,34 +7,24 @@ */ package org.dspace.rest; -import java.net.CookieHandler; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; -import java.util.List; - import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Cookie; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; -import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.DSpaceObject; import org.dspace.core.Context; -import org.dspace.eperson.EPerson; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.rest.exceptions.ContextException; import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.usage.UsageEvent; -import org.dspace.utils.DSpace; import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; /** @@ -42,21 +32,21 @@ import org.springframework.security.core.context.SecurityContextHolder; * context, write statistics, processsing exceptions, splitting a key of * metadata, string representation of action and method for getting the logged * in user from the token in request header. - * + * * @author Rostislav Novak (Computing and Information Centre, CTU in Prague) - * */ -public class Resource -{ +public class Resource { - @javax.ws.rs.core.Context public ServletContext servletContext; + @javax.ws.rs.core.Context + public ServletContext servletContext; private static Logger log = Logger.getLogger(Resource.class); private static final boolean writeStatistics; - static - { - writeStatistics = DSpaceServicesFactory.getInstance().getConfigurationService().getBooleanProperty("rest.stats", false); + + static { + writeStatistics = DSpaceServicesFactory.getInstance().getConfigurationService() + .getBooleanProperty("rest.stats", false); } /** @@ -66,29 +56,30 @@ public class Resource * with reading from database. Throws AuthorizeException if there was * a problem with authorization to read from the database. Throws Exception * if there was a problem creating context. - * + * * @return Newly created context with the logged in user unless the specified user was null. - * If user is null, create the context without a logged in user. - * @throws ContextException - * Thrown in case of a problem creating context. Can be caused by - * SQLException error in creating context or finding the user to - * log in. Can be caused by AuthorizeException if there was a - * problem authorizing the found user. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * If user is null, create the context without a logged in user. + * @throws ContextException Thrown in case of a problem creating context. Can be caused by + * SQLException error in creating context or finding the user to + * log in. Can be caused by AuthorizeException if there was a + * problem authorizing the found user. + * @throws SQLException An exception that provides information on a database access error or other errors. */ protected static org.dspace.core.Context createContext() throws ContextException, SQLException { org.dspace.core.Context context = new org.dspace.core.Context(); //context.getDBConnection().setAutoCommit(false); // Disable autocommit. Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if(authentication != null) - { - Collection specialGroups = (Collection) authentication.getAuthorities(); + if (authentication != null) { + Collection specialGroups = (Collection) authentication + .getAuthorities(); for (SimpleGrantedAuthority grantedAuthority : specialGroups) { - context.setSpecialGroup(EPersonServiceFactory.getInstance().getGroupService().findByName(context, grantedAuthority.getAuthority()).getID()); + context.setSpecialGroup(EPersonServiceFactory.getInstance().getGroupService() + .findByName(context, grantedAuthority.getAuthority()) + .getID()); } - context.setCurrentUser(EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, authentication.getName())); + context.setCurrentUser( + EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, authentication.getName())); } return context; @@ -96,44 +87,34 @@ public class Resource /** * Records a statistics event about an object used via REST API. - * @param dspaceObject - * DSpace object on which a request was performed. - * @param action - * Action that was performed. - * @param user_ip - * User's IP address. - * @param user_agent - * User agent string (specifies browser used and its version). - * @param xforwardedfor - * When accessed via a reverse proxy, the application sees the proxy's IP as the - * source of the request. The proxy may be configured to add the - * "X-Forwarded-For" HTTP header containing the original IP of the client - * so that the reverse-proxied application can get the client's IP. - * @param headers - * If you want to access the item as the user logged into the - * context. The header "rest-dspace-token" with the token passed - * from the login method must be set. - * @param request - * Servlet's HTTP request object. - * @param context - * Context which must be aborted. + * + * @param dspaceObject DSpace object on which a request was performed. + * @param action Action that was performed. + * @param user_ip User's IP address. + * @param user_agent User agent string (specifies browser used and its version). + * @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the + * source of the request. The proxy may be configured to add the + * "X-Forwarded-For" HTTP header containing the original IP of the client + * so that the reverse-proxied application can get the client's IP. + * @param headers If you want to access the item as the user logged into the + * context. The header "rest-dspace-token" with the token passed + * from the login method must be set. + * @param request Servlet's HTTP request object. + * @param context Context which must be aborted. */ protected void writeStats(DSpaceObject dspaceObject, UsageEvent.Action action, - String user_ip, String user_agent, String xforwardedfor, HttpHeaders headers, HttpServletRequest request, Context context) - { - if (!writeStatistics) - { + String user_ip, String user_agent, String xforwardedfor, HttpHeaders headers, + HttpServletRequest request, Context context) { + if (!writeStatistics) { return; } - if ((user_ip == null) || (user_ip.length() == 0)) - { - DSpaceServicesFactory.getInstance().getEventService().fireEvent(new UsageEvent(action, request, context, dspaceObject)); - } - else - { + if ((user_ip == null) || (user_ip.length() == 0)) { + DSpaceServicesFactory.getInstance().getEventService() + .fireEvent(new UsageEvent(action, request, context, dspaceObject)); + } else { DSpaceServicesFactory.getInstance().getEventService().fireEvent( - new UsageEvent(action, user_ip, user_agent, xforwardedfor, context, dspaceObject)); + new UsageEvent(action, user_ip, user_agent, xforwardedfor, context, dspaceObject)); } log.debug("fired event"); @@ -142,18 +123,14 @@ public class Resource /** * Process exception, print message to logger error stream and abort DSpace * context. - * - * @param message - * Message, which will be printed to error stream. - * @param context - * Context which must be aborted. - * @throws WebApplicationException - * This exception is throw for user of REST api. + * + * @param message Message, which will be printed to error stream. + * @param context Context which must be aborted. + * @throws WebApplicationException This exception is throw for user of REST api. */ - protected static void processException(String message, org.dspace.core.Context context) throws WebApplicationException - { - if ((context != null) && (context.isValid())) - { + protected static void processException(String message, org.dspace.core.Context context) + throws WebApplicationException { + if ((context != null) && (context.isValid())) { context.abort(); } log.error(message); @@ -164,15 +141,11 @@ public class Resource * Process finally statement. It will print message to logger error stream * and abort DSpace context, if was not properly ended. * - * @param context - * Context which must be aborted. - * @throws WebApplicationException - * This exception is thrown for user of REST API. + * @param context Context which must be aborted. + * @throws WebApplicationException This exception is thrown for user of REST API. */ - protected void processFinally(org.dspace.core.Context context) throws WebApplicationException - { - if ((context != null) && (context.isValid())) - { + protected void processFinally(org.dspace.core.Context context) throws WebApplicationException { + if ((context != null) && (context.isValid())) { context.abort(); log.error("Something get wrong. Aborting context in finally statement."); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); @@ -181,30 +154,23 @@ public class Resource /** * Split string with regex ".". - * - * @param key - * String which will be splitted. + * + * @param key String which will be splitted. * @return String array filed with separated string. */ - protected String[] mySplit(String key) - { + protected String[] mySplit(String key) { ArrayList list = new ArrayList(); int prev = 0; - for (int i = 0; i < key.length(); i++) - { - if (key.charAt(i) == '.') - { + for (int i = 0; i < key.length(); i++) { + if (key.charAt(i) == '.') { list.add(key.substring(prev, i)); prev = i + 1; - } - else if (i + 1 == key.length()) - { + } else if (i + 1 == key.length()) { list.add(key.substring(prev, i + 1)); } } - if (list.size() == 2) - { + if (list.size() == 2) { list.add(null); } @@ -214,34 +180,31 @@ public class Resource /** * Return string representation of values * org.dspace.core.Constants.{READ,WRITE,DELETE}. - * - * @param action - * Constant from org.dspace.core.Constants.* + * + * @param action Constant from org.dspace.core.Constants.* * @return String representation. read or write or delete. */ - protected String getActionString(int action) - { + protected String getActionString(int action) { String actionStr; - switch (action) - { - case org.dspace.core.Constants.READ: - actionStr = "read"; - break; - case org.dspace.core.Constants.WRITE: - actionStr = "write"; - break; - case org.dspace.core.Constants.DELETE: - actionStr = "delete"; - break; - case org.dspace.core.Constants.REMOVE: - actionStr = "remove"; - break; - case org.dspace.core.Constants.ADD: - actionStr = "add"; - break; - default: - actionStr = "(?action?)"; - break; + switch (action) { + case org.dspace.core.Constants.READ: + actionStr = "read"; + break; + case org.dspace.core.Constants.WRITE: + actionStr = "write"; + break; + case org.dspace.core.Constants.DELETE: + actionStr = "delete"; + break; + case org.dspace.core.Constants.REMOVE: + actionStr = "remove"; + break; + case org.dspace.core.Constants.ADD: + actionStr = "add"; + break; + default: + actionStr = "(?action?)"; + break; } return actionStr; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/RestIndex.java b/dspace-rest/src/main/java/org/dspace/rest/RestIndex.java index f8f68ed221..dfb5e2bb39 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/RestIndex.java +++ b/dspace-rest/src/main/java/org/dspace/rest/RestIndex.java @@ -11,15 +11,16 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.sql.SQLException; import java.util.Iterator; - import javax.servlet.ServletContext; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; -import javax.ws.rs.core.*; import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -39,7 +40,6 @@ import org.dspace.utils.DSpace; * printing every method which is provides by RESTful api. * * @author Rostislav Novak (Computing and Information Centre, CTU in Prague) - * */ @Path("/") public class RestIndex { @@ -50,105 +50,121 @@ public class RestIndex { * Return html page with information about REST api. It contains methods all * methods provide by REST api. * - * @param servletContext - * Context of the servlet container. + * @param servletContext Context of the servlet container. * @return HTML page which has information about all methods of REST API. */ @GET @Produces(MediaType.TEXT_HTML) - public String sayHtmlHello(@Context ServletContext servletContext) - { + public String sayHtmlHello(@Context ServletContext servletContext) { // TODO Better graphics, add arguments to all methods. (limit, offset, item and so on) return "DSpace REST - index" + - "" - + "

    DSpace REST API

    " + - "Server path: " + servletContext.getContextPath() + - "

    Index

    " + - "
      " + - "
    • GET / - Return this page.
    • " + - "
    • GET /test - Return the string \"REST api is running\" for testing purposes.
    • " + - "
    • POST /login - Method for logging into the DSpace RESTful API. You must post the parameters \"email\" and \"password\". Example: \"email=test@dspace&password=pass\". Returns a JSESSIONID cookie which can be used for future authenticated requests.
    • " + - "
    • POST /logout - Method for logging out of the DSpace RESTful API. The request must include the \"rest-dspace-token\" token
    • header." + - "
    " + - "

    Communities

    " + - "
      " + - "
    • GET /communities - Return an array of all communities in DSpace.
    • " + - "
    • GET /communities/top-communities - Returns an array of all top-leve communities in DSpace.
    • " + - "
    • GET /communities/{communityId} - Returns a community with the specified ID.
    • " + - "
    • GET /communities/{communityId}/collections - Returns an array of collections of the specified community.
    • " + - "
    • GET /communities/{communityId}/communities - Returns an array of subcommunities of the specified community.
    • " + - "
    • POST /communities - Create a new top-level community. You must post a community.
    • " + - "
    • POST /communities/{communityId}/collections - Create a new collection in the specified community. You must post a collection.
    • " + - "
    • POST /communities/{communityId}/communities - Create a new subcommunity in the specified community. You must post a community.
    • " + - "
    • PUT /communities/{communityId} - Update the specified community.
    • " + - "
    • DELETE /communities/{communityId} - Delete the specified community.
    • " + - "
    • DELETE /communities/{communityId}/collections/{collectionId} - Delete the specified collection in the specified community.
    • " + - "
    • DELETE /communities/{communityId}/communities/{communityId2} - Delete the specified subcommunity (communityId2) in the specified community (communityId).
    • " + - "
    " + - "

    Collections

    " + - "
      " + - "
    • GET /collections - Return all DSpace collections in array.
    • " + - "
    • GET /collections/{collectionId} - Return a collection with the specified ID.
    • " + - "
    • GET /collections/{collectionId}/items - Return all items of the specified collection.
    • " + - "
    • POST /collections/{collectionId}/items - Create an item in the specified collection. You must post an item.
    • " + - "
    • POST /collections/find-collection - Find a collection by name.
    • " + - "
    • PUT /collections/{collectionId}
    • - Update the specified collection. You must post a collection." + - "
    • DELETE /collections/{collectionId} - Delete the specified collection from DSpace.
    • " + - "
    • DELETE /collections/{collectionId}/items/{itemId} - Delete the specified item (itemId) in the specified collection (collectionId).
    • " + - "
    " + - "

    Items

    " + - "
      " + - "
    • GET /items - Return a list of items.
    • " + - "
    • GET /items/{item id} - Return the specified item.
    • " + - "
    • GET /items/{item id}/metadata - Return metadata of the specified item.
    • " + - "
    • GET /items/{item id}/bitstreams - Return bitstreams of the specified item.
    • " + - "
    • POST /items/find-by-metadata-field - Find items by the specified metadata value.
    • " + - "
    • POST /items/{item id}/metadata - Add metadata to the specified item.
    • " + - "
    • POST /items/{item id}/bitstreams - Add a bitstream to the specified item.
    • " + - "
    • PUT /items/{item id}/metadata - Update metadata in the specified item.
    • " + - "
    • DELETE /items/{item id} - Delete the specified item.
    • " + - "
    • DELETE /items/{item id}/metadata - Clear metadata of the specified item.
    • " + - "
    • DELETE /items/{item id}/bitstreams/{bitstream id} - Delete the specified bitstream of the specified item.
    • " + - "
    " + - "

    Bitstreams

    " + - "
      " + - "
    • GET /bitstreams - Return all bitstreams in DSpace.
    • " + - "
    • GET /bitstreams/{bitstream id} - Return the specified bitstream.
    • " + - "
    • GET /bitstreams/{bitstream id}/policy - Return policies of the specified bitstream.
    • " + - "
    • GET /bitstreams/{bitstream id}/retrieve - Return the contents of the specified bitstream.
    • " + - "
    • POST /bitstreams/{bitstream id}/policy - Add a policy to the specified bitstream.
    • " + - "
    • PUT /bitstreams/{bitstream id}/data - Update the contents of the specified bitstream.
    • " + - "
    • PUT /bitstreams/{bitstream id} - Update metadata of the specified bitstream.
    • " + - "
    • DELETE /bitstreams/{bitstream id} - Delete the specified bitstream from DSpace.
    • " + - "
    • DELETE /bitstreams/{bitstream id}/policy/{policy_id} - Delete the specified bitstream policy.
    • " + - "
    " + - "

    Hierarchy

    " + - "
      " + - "
    • GET /hierarchy - Return hierarchy of communities and collections in tree form. Each object is minimally populated (name, handle, id) for efficient retrieval.
    • " + - "
    " + - "

    Metadata and Schema Registry

    " + - "
      " + - "
    • GET /registries/schema - Return the list of metadata schemas in the registry
    • " + - "
    • GET /registries/schema/{schema_prefix} - Returns the specified metadata schema
    • " + - "
    • GET /registries/schema/{schema_prefix}/metadata-fields/{element} - Returns the metadata field within a schema with an unqualified element name
    • " + - "
    • GET /registries/schema/{schema_prefix}/metadata-fields/{element}/{qualifier} - Returns the metadata field within a schema with a qualified element name
    • " + - "
    • POST /registries/schema/ - Add a schema to the schema registry
    • " + - "
    • POST /registries/schema/{schema_prefix}/metadata-fields - Add a metadata field to the specified schema
    • " + - "
    • GET /registries/metadata-fields/{field_id} - Return the specified metadata field
    • " + - "
    • PUT /registries/metadata-fields/{field_id} - Update the specified metadata field
    • " + - "
    • DELETE /registries/metadata-fields/{field_id} - Delete the specified metadata field from the metadata field registry
    • " + - "
    • DELETE /registries/schema/{schema_id} - Delete the specified schema from the schema registry
    • " + - "
    " + - "

    Query/Reporting Tools

    " + - "
      " + - "
    • GET /reports - Return a list of report tools built on the rest api
    • " + - "
    • GET /reports/{nickname} - Return a redirect to a specific report
    • " + - "
    • GET /filters - Return a list of use case filters available for quality control reporting
    • " + - "
    • GET /filtered-collections - Return collections and item counts based on pre-defined filters
    • " + - "
    • GET /filtered-collections/{collection_id} - Return items and item counts for a collection based on pre-defined filters
    • " + - "
    • GET /filtered-items - Retrieve a set of items based on a metadata query and a set of filters
    • " + - "
    " + - " "; + "" + + "

    DSpace REST API

    " + + "Server path: " + servletContext.getContextPath() + + "

    Index

    " + + "
      " + + "
    • GET / - Return this page.
    • " + + "
    • GET /test - Return the string \"REST api is running\" for testing purposes.
    • " + + "
    • POST /login - Method for logging into the DSpace RESTful API. You must post the parameters \"email\"" + + " and \"password\". Example: \"email=test@dspace&password=pass\". Returns a JSESSIONID cookie which can " + + "be used for future authenticated requests.
    • " + + "
    • POST /logout - Method for logging out of the DSpace RESTful API. The request must include the " + + "\"rest-dspace-token\" token
    • header." + + "
    " + + "

    Communities

    " + + "
      " + + "
    • GET /communities - Return an array of all communities in DSpace.
    • " + + "
    • GET /communities/top-communities - Returns an array of all top-leve communities in DSpace.
    • " + + "
    • GET /communities/{communityId} - Returns a community with the specified ID.
    • " + + "
    • GET /communities/{communityId}/collections - Returns an array of collections of the specified " + + "community.
    • " + + "
    • GET /communities/{communityId}/communities - Returns an array of subcommunities of the specified " + + "community.
    • " + + "
    • POST /communities - Create a new top-level community. You must post a community.
    • " + + "
    • POST /communities/{communityId}/collections - Create a new collection in the specified community. " + + "You must post a collection.
    • " + + "
    • POST /communities/{communityId}/communities - Create a new subcommunity in the specified community. " + + "You must post a community.
    • " + + "
    • PUT /communities/{communityId} - Update the specified community.
    • " + + "
    • DELETE /communities/{communityId} - Delete the specified community.
    • " + + "
    • DELETE /communities/{communityId}/collections/{collectionId} - Delete the specified collection in " + + "the specified community.
    • " + + "
    • DELETE /communities/{communityId}/communities/{communityId2} - Delete the specified subcommunity " + + "(communityId2) in the specified community (communityId).
    • " + + "
    " + + "

    Collections

    " + + "
      " + + "
    • GET /collections - Return all DSpace collections in array.
    • " + + "
    • GET /collections/{collectionId} - Return a collection with the specified ID.
    • " + + "
    • GET /collections/{collectionId}/items - Return all items of the specified collection.
    • " + + "
    • POST /collections/{collectionId}/items - Create an item in the specified collection. You must post " + + "an item.
    • " + + "
    • POST /collections/find-collection - Find a collection by name.
    • " + + "
    • PUT /collections/{collectionId}
    • - Update the specified collection. You must post a collection." + + "
    • DELETE /collections/{collectionId} - Delete the specified collection from DSpace.
    • " + + "
    • DELETE /collections/{collectionId}/items/{itemId} - Delete the specified item (itemId) in the " + + "specified collection (collectionId).
    • " + + "
    " + + "

    Items

    " + + "
      " + + "
    • GET /items - Return a list of items.
    • " + + "
    • GET /items/{item id} - Return the specified item.
    • " + + "
    • GET /items/{item id}/metadata - Return metadata of the specified item.
    • " + + "
    • GET /items/{item id}/bitstreams - Return bitstreams of the specified item.
    • " + + "
    • POST /items/find-by-metadata-field - Find items by the specified metadata value.
    • " + + "
    • POST /items/{item id}/metadata - Add metadata to the specified item.
    • " + + "
    • POST /items/{item id}/bitstreams - Add a bitstream to the specified item.
    • " + + "
    • PUT /items/{item id}/metadata - Update metadata in the specified item.
    • " + + "
    • DELETE /items/{item id} - Delete the specified item.
    • " + + "
    • DELETE /items/{item id}/metadata - Clear metadata of the specified item.
    • " + + "
    • DELETE /items/{item id}/bitstreams/{bitstream id} - Delete the specified bitstream of the specified " + + "item.
    • " + + "
    " + + "

    Bitstreams

    " + + "
      " + + "
    • GET /bitstreams - Return all bitstreams in DSpace.
    • " + + "
    • GET /bitstreams/{bitstream id} - Return the specified bitstream.
    • " + + "
    • GET /bitstreams/{bitstream id}/policy - Return policies of the specified bitstream.
    • " + + "
    • GET /bitstreams/{bitstream id}/retrieve - Return the contents of the specified bitstream.
    • " + + "
    • POST /bitstreams/{bitstream id}/policy - Add a policy to the specified bitstream.
    • " + + "
    • PUT /bitstreams/{bitstream id}/data - Update the contents of the specified bitstream.
    • " + + "
    • PUT /bitstreams/{bitstream id} - Update metadata of the specified bitstream.
    • " + + "
    • DELETE /bitstreams/{bitstream id} - Delete the specified bitstream from DSpace.
    • " + + "
    • DELETE /bitstreams/{bitstream id}/policy/{policy_id} - Delete the specified bitstream policy.
    • " + + "
    " + + "

    Hierarchy

    " + + "
      " + + "
    • GET /hierarchy - Return hierarchy of communities and collections in tree form. Each object is " + + "minimally populated (name, handle, id) for efficient retrieval.
    • " + + "
    " + + "

    Metadata and Schema Registry

    " + + "
      " + + "
    • GET /registries/schema - Return the list of metadata schemas in the registry
    • " + + "
    • GET /registries/schema/{schema_prefix} - Returns the specified metadata schema
    • " + + "
    • GET /registries/schema/{schema_prefix}/metadata-fields/{element} - Returns the metadata field within" + + " a schema with an unqualified element name
    • " + + "
    • GET /registries/schema/{schema_prefix}/metadata-fields/{element}/{qualifier} - Returns the metadata " + + "field within a schema with a qualified element name
    • " + + "
    • POST /registries/schema/ - Add a schema to the schema registry
    • " + + "
    • POST /registries/schema/{schema_prefix}/metadata-fields - Add a metadata field to the specified " + + "schema
    • " + + "
    • GET /registries/metadata-fields/{field_id} - Return the specified metadata field
    • " + + "
    • PUT /registries/metadata-fields/{field_id} - Update the specified metadata field
    • " + + "
    • DELETE /registries/metadata-fields/{field_id} - Delete the specified metadata field from the " + + "metadata field registry
    • " + + "
    • DELETE /registries/schema/{schema_id} - Delete the specified schema from the schema registry
    • " + + "
    " + + "

    Query/Reporting Tools

    " + + "
      " + + "
    • GET /reports - Return a list of report tools built on the rest api
    • " + + "
    • GET /reports/{nickname} - Return a redirect to a specific report
    • " + + "
    • GET /filters - Return a list of use case filters available for quality control reporting
    • " + + "
    • GET /filtered-collections - Return collections and item counts based on pre-defined filters
    • " + + "
    • GET /filtered-collections/{collection_id} - Return items and item counts for a collection based on " + + "pre-defined filters
    • " + + "
    • GET /filtered-items - Retrieve a set of items based on a metadata query and a set of filters
    • " + + "
    " + + " "; } /** @@ -158,8 +174,7 @@ public class RestIndex { */ @GET @Path("/test") - public String test() - { + public String test() { return "REST api is running."; } @@ -167,61 +182,54 @@ public class RestIndex { * Method to login a user into REST API. * * @return Returns response code OK and a token. Otherwise returns response - * code FORBIDDEN(403). + * code FORBIDDEN(403). */ @POST @Path("/login") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response login() - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response login() { //If you can get here, you are authenticated, the actual login is handled by spring security return Response.ok().build(); } @GET @Path("/shibboleth-login") - @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public Response shibbolethLogin() - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response shibbolethLogin() { //If you can get here, you are authenticated, the actual login is handled by spring security return Response.ok().build(); } @GET @Path("/login-shibboleth") - @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public Response shibbolethLoginEndPoint() - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response shibbolethLoginEndPoint() { org.dspace.core.Context context = null; - try - { + try { context = Resource.createContext(); - AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance().getAuthenticationService(); - Iterator authenticationMethodIterator = authenticationService.authenticationMethodIterator(); - while (authenticationMethodIterator.hasNext()) - { + AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance() + .getAuthenticationService(); + Iterator authenticationMethodIterator = authenticationService + .authenticationMethodIterator(); + while (authenticationMethodIterator.hasNext()) { AuthenticationMethod authenticationMethod = authenticationMethodIterator.next(); - if (authenticationMethod instanceof ShibAuthentication) - { + if (authenticationMethod instanceof ShibAuthentication) { //TODO: Perhaps look for a better way of handling this ? - org.dspace.services.model.Request currentRequest = new DSpace().getRequestService().getCurrentRequest(); - String loginPageURL = authenticationMethod.loginPageURL(context, currentRequest.getHttpServletRequest(), currentRequest.getHttpServletResponse()); - if (StringUtils.isNotBlank(loginPageURL)) - { + org.dspace.services.model.Request currentRequest = new DSpace().getRequestService() + .getCurrentRequest(); + String loginPageURL = authenticationMethod + .loginPageURL(context, currentRequest.getHttpServletRequest(), + currentRequest.getHttpServletResponse()); + if (StringUtils.isNotBlank(loginPageURL)) { currentRequest.getHttpServletResponse().sendRedirect(loginPageURL); } } } context.abort(); - } - catch (ContextException | SQLException | IOException e) - { + } catch (ContextException | SQLException | IOException e) { Resource.processException("Shibboleth endpoint error: " + e.getMessage(), context); - } - finally - { - if (context != null && context.isValid()) - { + } finally { + if (context != null && context.isValid()) { context.abort(); } @@ -233,17 +241,15 @@ public class RestIndex { * Method to logout a user from DSpace REST API. Removes the token and user from * TokenHolder. * - * @param headers - * Request header which contains the header named - * "rest-dspace-token" containing the token as value. + * @param headers Request header which contains the header named + * "rest-dspace-token" containing the token as value. * @return Return response OK, otherwise BAD_REQUEST, if there was a problem with - * logout or the token is incorrect. + * logout or the token is incorrect. */ @POST @Path("/logout") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response logout(@Context HttpHeaders headers) - { + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Response logout(@Context HttpHeaders headers) { //If you can get here, you are logged out, this actual logout is handled by spring security return Response.ok().build(); } @@ -255,45 +261,35 @@ public class RestIndex { * authenticated: true | false * epersonEMAIL: user@example.com * epersonNAME: John Doe - * @param headers - * Request header which contains the header named - * "rest-dspace-token" containing the token as value. + * + * @param headers Request header which contains the header named + * "rest-dspace-token" containing the token as value. * @return status the Status object with information about REST API - * @throws UnsupportedEncodingException - * The Character Encoding is not supported. + * @throws UnsupportedEncodingException The Character Encoding is not supported. */ @GET @Path("/status") - @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Status status(@Context HttpHeaders headers) - throws UnsupportedEncodingException - { + throws UnsupportedEncodingException { org.dspace.core.Context context = null; - try - { + try { context = Resource.createContext(); EPerson ePerson = context.getCurrentUser(); - if (ePerson != null) - { + if (ePerson != null) { //DB EPerson needed since token won't have full info, need context EPerson dbEPerson = epersonService.findByEmail(context, ePerson.getEmail()); Status status = new Status(dbEPerson.getEmail(), dbEPerson.getFullName()); return status; } - } - catch (ContextException e) - { + } catch (ContextException e) { Resource.processException("Status context error: " + e.getMessage(), context); - } - catch (SQLException e) - { + } catch (SQLException e) { Resource.processException("Status eperson db lookup error: " + e.getMessage(), context); - } - finally - { + } finally { context.abort(); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/RestReports.java b/dspace-rest/src/main/java/org/dspace/rest/RestReports.java index 96612e9d16..dda44b5868 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/RestReports.java +++ b/dspace-rest/src/main/java/org/dspace/rest/RestReports.java @@ -10,7 +10,6 @@ package org.dspace.rest; import java.net.URI; import java.util.ArrayList; import java.util.List; - import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; @@ -32,7 +31,6 @@ import org.dspace.services.factory.DSpaceServicesFactory; * printing every method which is provides by RESTful api. * * @author Terry Brady, Georgetown University - * */ @Path("/reports") public class RestReports { @@ -50,14 +48,11 @@ public class RestReports { @GET @Produces(MediaType.APPLICATION_XML) public Report[] reportIndex() - throws WebApplicationException - { + throws WebApplicationException { ArrayList reports = new ArrayList(); List propNames = configurationService.getPropertyKeys("rest"); - for (String propName: propNames) - { - if (propName.startsWith(REST_RPT_URL)) - { + for (String propName : propNames) { + if (propName.startsWith(REST_RPT_URL)) { String nickname = propName.substring(REST_RPT_URL.length()); String url = configurationService.getProperty(propName); reports.add(new Report(nickname, url)); @@ -69,24 +64,20 @@ public class RestReports { @Path("/{report_nickname}") @GET public Response customReport(@PathParam("report_nickname") String report_nickname, @Context UriInfo uriInfo) - throws WebApplicationException - { - URI uri = null; - if (!report_nickname.isEmpty()) - { + throws WebApplicationException { + URI uri = null; + if (!report_nickname.isEmpty()) { log.info(String.format("Seeking report %s", report_nickname)); String url = configurationService.getProperty(REST_RPT_URL + report_nickname); log.info(String.format("URL for report %s found: [%s]", report_nickname, url)); - if (!url.isEmpty()) - { + if (!url.isEmpty()) { uri = uriInfo.getBaseUriBuilder().path(url).build(""); log.info(String.format("URI for report %s", uri)); } } - if (uri != null) - { + if (uri != null) { return Response.temporaryRedirect(uri).build(); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/authentication/DSpaceAuthenticationProvider.java b/dspace-rest/src/main/java/org/dspace/rest/authentication/DSpaceAuthenticationProvider.java index 8a114ef224..65bedce85b 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/authentication/DSpaceAuthenticationProvider.java +++ b/dspace-rest/src/main/java/org/dspace/rest/authentication/DSpaceAuthenticationProvider.java @@ -7,12 +7,19 @@ */ package org.dspace.rest.authentication; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.authenticate.AuthenticationMethod; import org.dspace.authenticate.factory.AuthenticateServiceFactory; import org.dspace.authenticate.service.AuthenticationService; import org.dspace.core.Context; import org.dspace.core.LogManager; +import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.utils.DSpace; import org.springframework.security.authentication.AuthenticationProvider; @@ -22,26 +29,21 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import javax.servlet.http.HttpServletRequest; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - /** - * The core authentication and authorization provider. This provider is called when logging in. + * The core authentication & authorization provider, this provider is called when logging in & will process * * @author Roeland Dillen (roeland at atmire dot com) * @author kevinvandevelde at atmire.com * - * @deprecated This provider handles both the authorization as well as the authentication, + * FIXME This provider handles both the authorization as well as the authentication, * due to the way that the DSpace authentication is implemented there is currently no other way to do this. */ -@Deprecated public class DSpaceAuthenticationProvider implements AuthenticationProvider { private static Logger log = Logger.getLogger(DSpaceAuthenticationProvider.class); - protected AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance().getAuthenticationService(); + protected AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance() + .getAuthenticationService(); @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { @@ -51,34 +53,38 @@ public class DSpaceAuthenticationProvider implements AuthenticationProvider { context = new Context(); String name = authentication.getName(); String password = authentication.getCredentials().toString(); - HttpServletRequest httpServletRequest = new DSpace().getRequestService().getCurrentRequest().getHttpServletRequest(); + HttpServletRequest httpServletRequest = new DSpace().getRequestService().getCurrentRequest() + .getHttpServletRequest(); List grantedAuthorities = new ArrayList<>(); - int implicitStatus = authenticationService.authenticateImplicit(context, null, null, null, httpServletRequest); + int implicitStatus = authenticationService + .authenticateImplicit(context, null, null, null, httpServletRequest); if (implicitStatus == AuthenticationMethod.SUCCESS) { log.info(LogManager.getHeader(context, "login", "type=implicit")); addSpecialGroupsToGrantedAuthorityList(context, httpServletRequest, grantedAuthorities); - return new UsernamePasswordAuthenticationToken(name, password, grantedAuthorities); + return createAuthenticationToken(password, context, grantedAuthorities); + } else { - int authenticateResult = authenticationService.authenticate(context, name, password, null, httpServletRequest); + int authenticateResult = authenticationService + .authenticate(context, name, password, null, httpServletRequest); if (AuthenticationMethod.SUCCESS == authenticateResult) { addSpecialGroupsToGrantedAuthorityList(context, httpServletRequest, grantedAuthorities); log.info(LogManager - .getHeader(context, "login", "type=explicit")); + .getHeader(context, "login", "type=explicit")); + + return createAuthenticationToken(password, context, grantedAuthorities); - return new UsernamePasswordAuthenticationToken(name, password, grantedAuthorities); } else { log.info(LogManager.getHeader(context, "failed_login", "email=" - + name + ", result=" - + authenticateResult)); + + name + ", result=" + + authenticateResult)); throw new BadCredentialsException("Login failed"); } } - } catch (BadCredentialsException e) - { + } catch (BadCredentialsException e) { throw e; } catch (Exception e) { log.error("Error while authenticating in the rest api", e); @@ -95,15 +101,30 @@ public class DSpaceAuthenticationProvider implements AuthenticationProvider { return null; } - protected void addSpecialGroupsToGrantedAuthorityList(Context context, HttpServletRequest httpServletRequest, List grantedAuthorities) throws SQLException { + protected void addSpecialGroupsToGrantedAuthorityList(Context context, HttpServletRequest httpServletRequest, + List grantedAuthorities) + throws SQLException { List groups = authenticationService.getSpecialGroups(context, httpServletRequest); for (Group group : groups) { grantedAuthorities.add(new SimpleGrantedAuthority(group.getName())); } } + private Authentication createAuthenticationToken(final String password, final Context context, + final List grantedAuthorities) { + EPerson ePerson = context.getCurrentUser(); + if (ePerson != null && StringUtils.isNotBlank(ePerson.getEmail())) { + return new UsernamePasswordAuthenticationToken(ePerson.getEmail(), password, grantedAuthorities); + + } else { + log.info( + LogManager.getHeader(context, "failed_login", "No eperson with an non-blank e-mail address found")); + throw new BadCredentialsException("Login failed"); + } + } + @Override public boolean supports(Class authentication) { return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); } -} +} \ No newline at end of file diff --git a/dspace-rest/src/main/java/org/dspace/rest/authentication/NoRedirectAuthenticationLoginSuccessHandler.java b/dspace-rest/src/main/java/org/dspace/rest/authentication/NoRedirectAuthenticationLoginSuccessHandler.java index e81d064813..af146f27b7 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/authentication/NoRedirectAuthenticationLoginSuccessHandler.java +++ b/dspace-rest/src/main/java/org/dspace/rest/authentication/NoRedirectAuthenticationLoginSuccessHandler.java @@ -7,13 +7,13 @@ */ package org.dspace.rest.authentication; -import org.springframework.security.web.RedirectStrategy; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; - +import java.io.IOException; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; + +import org.springframework.security.web.RedirectStrategy; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; /** * @author kevinvandevelde at atmire.com @@ -27,15 +27,15 @@ public class NoRedirectAuthenticationLoginSuccessHandler extends SimpleUrlAuthen setRedirectStrategy(new NoRedirectStrategy()); } - protected class NoRedirectStrategy implements RedirectStrategy { + protected class NoRedirectStrategy implements RedirectStrategy { - @Override - public void sendRedirect(HttpServletRequest request, - HttpServletResponse response, String url) throws IOException { - // no redirect + @Override + public void sendRedirect(HttpServletRequest request, + HttpServletResponse response, String url) throws IOException { + // no redirect - } + } - } + } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/authentication/NoRedirectAuthenticationLogoutSuccessHandler.java b/dspace-rest/src/main/java/org/dspace/rest/authentication/NoRedirectAuthenticationLogoutSuccessHandler.java index cf27232df9..db28f2e388 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/authentication/NoRedirectAuthenticationLogoutSuccessHandler.java +++ b/dspace-rest/src/main/java/org/dspace/rest/authentication/NoRedirectAuthenticationLogoutSuccessHandler.java @@ -7,13 +7,13 @@ */ package org.dspace.rest.authentication; -import org.springframework.security.web.RedirectStrategy; -import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; - +import java.io.IOException; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; + +import org.springframework.security.web.RedirectStrategy; +import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; /** * @author kevinvandevelde at atmire.com @@ -26,14 +26,14 @@ public class NoRedirectAuthenticationLogoutSuccessHandler extends SimpleUrlLogou setRedirectStrategy(new NoRedirectStrategy()); } - protected class NoRedirectStrategy implements RedirectStrategy { + protected class NoRedirectStrategy implements RedirectStrategy { - @Override - public void sendRedirect(HttpServletRequest request, - HttpServletResponse response, String url) throws IOException { - // no redirect + @Override + public void sendRedirect(HttpServletRequest request, + HttpServletResponse response, String url) throws IOException { + // no redirect - } + } - } + } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Bitstream.java b/dspace-rest/src/main/java/org/dspace/rest/common/Bitstream.java index aee814569b..ecfc31ef26 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/Bitstream.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Bitstream.java @@ -11,7 +11,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - import javax.servlet.ServletContext; import javax.xml.bind.annotation.XmlRootElement; @@ -54,34 +53,31 @@ public class Bitstream extends DSpaceObject { } - public Bitstream(org.dspace.content.Bitstream bitstream, ServletContext servletContext, String expand, Context context) - throws SQLException - { + public Bitstream(org.dspace.content.Bitstream bitstream, ServletContext servletContext, String expand, + Context context) + throws SQLException { super(bitstream, servletContext); setup(bitstream, servletContext, expand, context); } - public void setup(org.dspace.content.Bitstream bitstream, ServletContext servletContext, String expand, Context context) - throws SQLException - { + public void setup(org.dspace.content.Bitstream bitstream, ServletContext servletContext, String expand, + Context context) + throws SQLException { List expandFields = new ArrayList(); - if (expand != null) - { + if (expand != null) { expandFields = Arrays.asList(expand.split(",")); } //A logo bitstream might not have a bundle... - if (bitstream.getBundles() != null & bitstream.getBundles().size() >= 0) - { - if (bitstreamService.getParentObject(context, bitstream).getType() == Constants.ITEM) - { + if (bitstream.getBundles() != null && !bitstream.getBundles().isEmpty()) { + if (bitstreamService.getParentObject(context, bitstream).getType() == Constants.ITEM) { bundleName = bitstream.getBundles().get(0).getName(); } } description = bitstream.getDescription(); format = bitstreamService.getFormatDescription(context, bitstream); - sizeBytes = bitstream.getSize(); + sizeBytes = bitstream.getSizeBytes(); String path = new DSpace().getRequestService().getCurrentRequest().getHttpServletRequest().getContextPath(); retrieveLink = path + "/bitstreams/" + bitstream.getID() + "/retrieve"; mimeType = bitstreamService.getFormat(context, bitstream).getMIMEType(); @@ -91,41 +87,32 @@ public class Bitstream extends DSpaceObject { checkSum.setValue(bitstream.getChecksum()); this.setCheckSum(checkSum); - if (expandFields.contains("parent") || expandFields.contains("all")) - { + if (expandFields.contains("parent") || expandFields.contains("all")) { parentObject = new DSpaceObject(bitstreamService.getParentObject(context, bitstream), servletContext); - } - else - { + } else { this.addExpand("parent"); } - if (expandFields.contains("policies") || expandFields.contains("all")) - { + if (expandFields.contains("policies") || expandFields.contains("all")) { // Find policies without context. List tempPolicies = new ArrayList(); List bundles = bitstream.getBundles(); - for (Bundle bundle : bundles) - { - List bitstreamsPolicies = bundleService.getBitstreamPolicies(context, bundle); - for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies) - { - if (policy.getdSpaceObject().equals(bitstream)) - { + for (Bundle bundle : bundles) { + List bitstreamsPolicies = bundleService + .getBitstreamPolicies(context, bundle); + for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies) { + if (policy.getdSpaceObject().equals(bitstream)) { tempPolicies.add(new ResourcePolicy(policy)); } } } policies = tempPolicies.toArray(new ResourcePolicy[0]); - } - else - { + } else { this.addExpand("policies"); } - if (!expandFields.contains("all")) - { + if (!expandFields.contains("all")) { this.addExpand("all"); } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/CheckSum.java b/dspace-rest/src/main/java/org/dspace/rest/common/CheckSum.java index 829275c8ea..2db36ae9a0 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/CheckSum.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/CheckSum.java @@ -13,13 +13,14 @@ import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlValue; @XmlType -public class CheckSum{ +public class CheckSum { String checkSumAlgorithm; String value; - public CheckSum(){} + public CheckSum() { + } - @XmlAttribute(name="checkSumAlgorithm") + @XmlAttribute(name = "checkSumAlgorithm") public String getCheckSumAlgorith() { return checkSumAlgorithm; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Collection.java b/dspace-rest/src/main/java/org/dspace/rest/common/Collection.java index 3e80d598b7..9bb66dba20 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/Collection.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Collection.java @@ -7,6 +7,15 @@ */ package org.dspace.rest.common; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import javax.servlet.ServletContext; +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlRootElement; + import org.apache.log4j.Logger; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; @@ -14,15 +23,6 @@ import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; import org.dspace.core.Context; -import javax.servlet.ServletContext; -import javax.ws.rs.WebApplicationException; -import javax.xml.bind.annotation.XmlRootElement; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - /** * Created with IntelliJ IDEA. * User: peterdietz @@ -47,105 +47,90 @@ public class Collection extends DSpaceObject { //Collection-Metadata private String license; - private String copyrightText, introductoryText, shortDescription, sidebarText; + private String copyrightText; + private String introductoryText; + private String shortDescription; + private String sidebarText; //Calculated private Integer numberItems; - public Collection(){} + public Collection() { + } - public Collection(org.dspace.content.Collection collection, ServletContext servletContext, String expand, Context context, Integer limit, Integer offset) - throws SQLException, WebApplicationException - { + public Collection(org.dspace.content.Collection collection, ServletContext servletContext, String expand, + Context context, Integer limit, Integer offset) + throws SQLException, WebApplicationException { super(collection, servletContext); setup(collection, servletContext, expand, context, limit, offset); } - private void setup(org.dspace.content.Collection collection, ServletContext servletContext, String expand, Context context, Integer limit, Integer offset) - throws SQLException - { + private void setup(org.dspace.content.Collection collection, ServletContext servletContext, String expand, + Context context, Integer limit, Integer offset) + throws SQLException { List expandFields = new ArrayList(); - if (expand != null) - { + if (expand != null) { expandFields = Arrays.asList(expand.split(",")); } this.setCopyrightText(collectionService.getMetadata(collection, org.dspace.content.Collection.COPYRIGHT_TEXT)); - this.setIntroductoryText(collectionService.getMetadata(collection, org.dspace.content.Collection.INTRODUCTORY_TEXT)); - this.setShortDescription(collectionService.getMetadata(collection, org.dspace.content.Collection.SHORT_DESCRIPTION)); + this.setIntroductoryText( + collectionService.getMetadata(collection, org.dspace.content.Collection.INTRODUCTORY_TEXT)); + this.setShortDescription( + collectionService.getMetadata(collection, org.dspace.content.Collection.SHORT_DESCRIPTION)); this.setSidebarText(collectionService.getMetadata(collection, org.dspace.content.Collection.SIDEBAR_TEXT)); - if (expandFields.contains("parentCommunityList") || expandFields.contains("all")) - { + if (expandFields.contains("parentCommunityList") || expandFields.contains("all")) { List parentCommunities = communityService.getAllParents(context, collection); - for (org.dspace.content.Community parentCommunity : parentCommunities) - { + for (org.dspace.content.Community parentCommunity : parentCommunities) { this.addParentCommunityList(new Community(parentCommunity, servletContext, null, context)); } - } - else - { + } else { this.addExpand("parentCommunityList"); } - if (expandFields.contains("parentCommunity") | expandFields.contains("all")) - { + if (expandFields.contains("parentCommunity") | expandFields.contains("all")) { org.dspace.content.Community parentCommunity = (org.dspace.content.Community) collectionService .getParentObject(context, collection); this.setParentCommunity(new Community( parentCommunity, servletContext, null, context)); - } - else - { + } else { this.addExpand("parentCommunity"); } //TODO: Item paging. limit, offset/page - if (expandFields.contains("items") || expandFields.contains("all")) - { + if (expandFields.contains("items") || expandFields.contains("all")) { Iterator childItems = itemService.findByCollection(context, collection, limit, offset); items = new ArrayList(); - while (childItems.hasNext()) - { + while (childItems.hasNext()) { org.dspace.content.Item item = childItems.next(); - if (itemService.isItemListedForUser(context, item)) - { + if (itemService.isItemListedForUser(context, item)) { items.add(new Item(item, servletContext, null, context)); } } - } - else - { + } else { this.addExpand("items"); } - if (expandFields.contains("license") || expandFields.contains("all")) - { + if (expandFields.contains("license") || expandFields.contains("all")) { setLicense(collectionService.getLicense(collection)); - } - else - { + } else { this.addExpand("license"); } - if (expandFields.contains("logo") || expandFields.contains("all")) - { - if (collection.getLogo() != null) - { + if (expandFields.contains("logo") || expandFields.contains("all")) { + if (collection.getLogo() != null) { this.logo = new Bitstream(collection.getLogo(), servletContext, null, context); } - } - else - { + } else { this.addExpand("logo"); } - if (!expandFields.contains("all")) - { + if (!expandFields.contains("all")) { this.addExpand("all"); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Community.java b/dspace-rest/src/main/java/org/dspace/rest/common/Community.java index 42372735eb..45d62ffe96 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/Community.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Community.java @@ -7,6 +7,15 @@ */ package org.dspace.rest.common; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.servlet.ServletContext; +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + import org.apache.log4j.Logger; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; @@ -15,15 +24,6 @@ import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; import org.dspace.core.Context; -import javax.servlet.ServletContext; -import javax.ws.rs.WebApplicationException; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - /** * Created with IntelliJ IDEA. * User: peterdietz @@ -32,7 +32,7 @@ import java.util.List; * To change this template use File | Settings | File Templates. */ @XmlRootElement(name = "community") -public class Community extends DSpaceObject{ +public class Community extends DSpaceObject { protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); @@ -44,107 +44,92 @@ public class Community extends DSpaceObject{ private Community parentCommunity; - private String copyrightText, introductoryText, shortDescription, sidebarText; + private String copyrightText; + private String introductoryText; + private String shortDescription; + private String sidebarText; private Integer countItems; private List subcommunities = new ArrayList(); private List collections = new ArrayList(); - public Community(){} - - public Community(org.dspace.content.Community community, ServletContext servletContext, String expand, Context context) - throws SQLException, WebApplicationException - { - super(community, servletContext); - setup(community,servletContext, expand, context); + public Community() { } - private void setup(org.dspace.content.Community community, ServletContext servletContext, String expand, Context context) - throws SQLException - { + public Community(org.dspace.content.Community community, ServletContext servletContext, String expand, + Context context) + throws SQLException, WebApplicationException { + super(community, servletContext); + setup(community, servletContext, expand, context); + } + + private void setup(org.dspace.content.Community community, ServletContext servletContext, String expand, + Context context) + throws SQLException { List expandFields = new ArrayList(); if (expand != null) { expandFields = Arrays.asList(expand.split(",")); } this.setCopyrightText(communityService.getMetadata(community, org.dspace.content.Community.COPYRIGHT_TEXT)); - this.setIntroductoryText(communityService.getMetadata(community, org.dspace.content.Community.INTRODUCTORY_TEXT)); - this.setShortDescription(communityService.getMetadata(community, org.dspace.content.Community.SHORT_DESCRIPTION)); + this.setIntroductoryText( + communityService.getMetadata(community, org.dspace.content.Community.INTRODUCTORY_TEXT)); + this.setShortDescription( + communityService.getMetadata(community, org.dspace.content.Community.SHORT_DESCRIPTION)); this.setSidebarText(communityService.getMetadata(community, org.dspace.content.Community.SIDEBAR_TEXT)); this.setCountItems(itemService.countItems(context, community)); - if (expandFields.contains("parentCommunity") || expandFields.contains("all")) - { - org.dspace.content.Community parentCommunity = (org.dspace.content.Community) communityService.getParentObject(context, community); - if (parentCommunity != null) - { - setParentCommunity(new Community(parentCommunity,servletContext, null, context)); + if (expandFields.contains("parentCommunity") || expandFields.contains("all")) { + org.dspace.content.Community parentCommunity = (org.dspace.content.Community) communityService + .getParentObject(context, community); + if (parentCommunity != null) { + setParentCommunity(new Community(parentCommunity, servletContext, null, context)); } - } - else - { + } else { this.addExpand("parentCommunity"); } - if (expandFields.contains("collections") || expandFields.contains("all")) - { + if (expandFields.contains("collections") || expandFields.contains("all")) { List collections = community.getCollections(); List restCollections = new ArrayList<>(); - for (org.dspace.content.Collection collection : collections) - { - if (authorizeService.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) - { - restCollections.add(new Collection(collection,servletContext, null, context, null, null)); - } - else - { + for (org.dspace.content.Collection collection : collections) { + if (authorizeService.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) { + restCollections.add(new Collection(collection, servletContext, null, context, null, null)); + } else { log.info("Omitted restricted collection: " + collection.getID() + " _ " + collection.getName()); } } setCollections(restCollections); - } - else - { + } else { this.addExpand("collections"); } - if (expandFields.contains("subCommunities") || expandFields.contains("all")) - { + if (expandFields.contains("subCommunities") || expandFields.contains("all")) { List communities = community.getSubcommunities(); subcommunities = new ArrayList(); - for (org.dspace.content.Community subCommunity : communities) - { - if (authorizeService.authorizeActionBoolean(context, subCommunity, org.dspace.core.Constants.READ)) - { + for (org.dspace.content.Community subCommunity : communities) { + if (authorizeService.authorizeActionBoolean(context, subCommunity, org.dspace.core.Constants.READ)) { subcommunities.add(new Community(subCommunity, servletContext, null, context)); - } - else - { - log.info("Omitted restricted subCommunity: " + subCommunity.getID() + " _ " + subCommunity.getName()); + } else { + log.info( + "Omitted restricted subCommunity: " + subCommunity.getID() + " _ " + subCommunity.getName()); } } - } - else - { + } else { this.addExpand("subCommunities"); } - if (expandFields.contains("logo") || expandFields.contains("all")) - { - if (community.getLogo() != null) - { - logo = new Bitstream(community.getLogo(),servletContext, null, context); + if (expandFields.contains("logo") || expandFields.contains("all")) { + if (community.getLogo() != null) { + logo = new Bitstream(community.getLogo(), servletContext, null, context); } - } - else - { + } else { this.addExpand("logo"); } - if (!expandFields.contains("all")) - { + if (!expandFields.contains("all")) { this.addExpand("all"); } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/DSpaceObject.java b/dspace-rest/src/main/java/org/dspace/rest/common/DSpaceObject.java index 55554a60a3..08df254336 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/DSpaceObject.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/DSpaceObject.java @@ -7,18 +7,15 @@ */ package org.dspace.rest.common; -import org.atteo.evo.inflector.English; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.DSpaceObjectService; -import org.dspace.rest.Resource; - +import java.util.ArrayList; +import java.util.List; import javax.servlet.ServletContext; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import org.atteo.evo.inflector.English; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.DSpaceObjectService; /** * Created with IntelliJ IDEA. @@ -55,7 +52,7 @@ public class DSpaceObject { link = createLink(servletContext); } - public String getName(){ + public String getName() { return this.name; } @@ -104,7 +101,7 @@ public class DSpaceObject { this.uuid = uuid; } - private String createLink(ServletContext context){ + private String createLink(ServletContext context) { return context.getContextPath() + "/" + English.plural(getType()) + "/" + getUUID(); } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/FilteredCollection.java b/dspace-rest/src/main/java/org/dspace/rest/common/FilteredCollection.java index e8d22ec5a2..525b823301 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/FilteredCollection.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/FilteredCollection.java @@ -7,8 +7,16 @@ */ package org.dspace.rest.common; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import javax.servlet.ServletContext; +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlRootElement; + import org.apache.log4j.Logger; -import org.dspace.content.*; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; @@ -16,18 +24,9 @@ import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.rest.filter.ItemFilterSet; -import javax.servlet.ServletContext; -import javax.ws.rs.WebApplicationException; -import javax.xml.bind.annotation.XmlRootElement; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - /** * Retrieve items within a collection that match a specific set of Item Filters of interest - * + * * @author Terry Brady, Georgetown University */ @XmlRootElement(name = "filtered-collection") @@ -43,46 +42,43 @@ public class FilteredCollection extends DSpaceObject { private List parentCommunityList = new ArrayList(); private List items = new ArrayList(); - + private List itemFilters = new ArrayList(); - + //Calculated private Integer numberItems; private Integer numberItemsProcessed; - public FilteredCollection(){} + public FilteredCollection() { + } /** * Evaluate a collection against of set of Item Filters - * @param collection - * DSpace Collection to evaluate - * @param servletContext - * Context of the servlet container. - * @param filters - * String representing a list of filters - * @param expand - * String in which is what you want to add to returned instance - * of collection. Options are: "all", "parentCommunityList", - * "parentCommunity", "items", "license" and "logo". If you want - * to use multiple options, it must be separated by commas. - * @param context - * The relevant DSpace Context. - * @param limit - * Limit value for items in list in collection. Default value is 100. - * @param offset - * Offset of start index in list of items of collection. Default - * value is 0. - * @throws SQLException - * An exception that provides information on a database access error or other errors. - * @throws WebApplicationException - * Runtime exception for applications. + * + * @param collection DSpace Collection to evaluate + * @param servletContext Context of the servlet container. + * @param filters String representing a list of filters + * @param expand String in which is what you want to add to returned instance + * of collection. Options are: "all", "parentCommunityList", + * "parentCommunity", "items", "license" and "logo". If you want + * to use multiple options, it must be separated by commas. + * @param context The relevant DSpace Context. + * @param limit Limit value for items in list in collection. Default value is 100. + * @param offset Offset of start index in list of items of collection. Default + * value is 0. + * @throws SQLException An exception that provides information on a database access error or other + * errors. + * @throws WebApplicationException Runtime exception for applications. */ - public FilteredCollection(org.dspace.content.Collection collection, ServletContext servletContext, String filters, String expand, Context context, Integer limit, Integer offset) throws SQLException, WebApplicationException{ + public FilteredCollection(org.dspace.content.Collection collection, ServletContext servletContext, String filters, + String expand, Context context, Integer limit, Integer offset) + throws SQLException, WebApplicationException { super(collection, servletContext); setup(collection, servletContext, expand, context, limit, offset, filters); } - private void setup(org.dspace.content.Collection collection, ServletContext servletContext, String expand, Context context, Integer limit, Integer offset, String filters) throws SQLException{ + private void setup(org.dspace.content.Collection collection, ServletContext servletContext, String expand, + Context context, Integer limit, Integer offset, String filters) throws SQLException { List expandFields = new ArrayList(); if (expand != null) { expandFields = Arrays.asList(expand.split(",")); @@ -91,7 +87,7 @@ public class FilteredCollection extends DSpaceObject { if (expandFields.contains("parentCommunityList") || expandFields.contains("all")) { List parentCommunities = communityService.getAllParents(context, collection); List parentCommunityList = new ArrayList(); - for(org.dspace.content.Community parentCommunity : parentCommunities) { + for (org.dspace.content.Community parentCommunity : parentCommunities) { parentCommunityList.add(new Community(parentCommunity, servletContext, null, context)); } this.setParentCommunityList(parentCommunityList); @@ -109,29 +105,31 @@ public class FilteredCollection extends DSpaceObject { if (expandFields.contains("topCommunity") | expandFields.contains("all")) { List parentCommunities = communityService.getAllParents(context, collection); if (parentCommunities.size() > 0) { - org.dspace.content.Community topCommunity = parentCommunities.get(parentCommunities.size()-1); + org.dspace.content.Community topCommunity = parentCommunities.get(parentCommunities.size() - 1); this.setTopCommunity(new Community(topCommunity, servletContext, null, context)); } } else { this.addExpand("topCommunity"); } - + boolean reportItems = expandFields.contains("items") || expandFields.contains("all"); ItemFilterSet itemFilterSet = new ItemFilterSet(filters, reportItems); this.setItemFilters(itemFilterSet.getItemFilters()); - + this.setNumberItemsProcessed(0); if (itemFilters.size() > 0) { - Iterator childItems = itemService.findByCollection(context, collection, limit, offset); - int numProc = itemFilterSet.processSaveItems(context, servletContext, childItems, items, reportItems, expand); + Iterator childItems = itemService + .findAllByCollection(context, collection, limit, offset); + int numProc = itemFilterSet + .processSaveItems(context, servletContext, childItems, items, reportItems, expand); this.setNumberItemsProcessed(numProc); - } - + } + if (!expandFields.contains("all")) { this.addExpand("all"); } - this.setNumberItems(itemService.countItems(context, collection)); + this.setNumberItems(itemService.countAllItems(context, collection)); } public Integer getNumberItems() { @@ -141,6 +139,7 @@ public class FilteredCollection extends DSpaceObject { public void setNumberItems(Integer numberItems) { this.numberItems = numberItems; } + public Integer getNumberItemsProcessed() { return numberItemsProcessed; } @@ -165,15 +164,15 @@ public class FilteredCollection extends DSpaceObject { this.topCommunity = topCommunity; } - + public List getItems() { return items; } - + public void setItems(List items) { this.items = items; } - + public void setParentCommunityList(List parentCommunityList) { this.parentCommunityList = parentCommunityList; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyCollection.java b/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyCollection.java index 2d02a33e6c..6c40faf62b 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyCollection.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyCollection.java @@ -12,15 +12,13 @@ import javax.xml.bind.annotation.XmlRootElement; /** * Used to handle/determine status of REST API. * Mainly to know your authentication status - * */ @XmlRootElement(name = "collection") -public class HierarchyCollection extends HierarchyObject -{ - public HierarchyCollection(){ +public class HierarchyCollection extends HierarchyObject { + public HierarchyCollection() { } - - public HierarchyCollection(String id, String name, String handle){ - super(id, name, handle); + + public HierarchyCollection(String id, String name, String handle) { + super(id, name, handle); } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyCommunity.java b/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyCommunity.java index 32de1cf578..3618608e3e 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyCommunity.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyCommunity.java @@ -9,20 +9,18 @@ package org.dspace.rest.common; import java.util.ArrayList; import java.util.List; - import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "community") -public class HierarchyCommunity extends HierarchyObject -{ +public class HierarchyCommunity extends HierarchyObject { private List communities = new ArrayList(); private List collections = new ArrayList(); - public HierarchyCommunity(){ + public HierarchyCommunity() { } - public HierarchyCommunity(String id, String name, String handle){ + public HierarchyCommunity(String id, String name, String handle) { super(id, name, handle); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyObject.java b/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyObject.java index 49e52779b3..0074eeea6a 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyObject.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/HierarchyObject.java @@ -10,22 +10,21 @@ package org.dspace.rest.common; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "object") -public class HierarchyObject -{ - //id may be a numeric id or a uuid depending on the version of DSpace +public class HierarchyObject { + //id may be a numeric id or a uuid depending on the version of DSpace private String id; private String name; private String handle; - public HierarchyObject(){ + public HierarchyObject() { } - - public HierarchyObject(String id, String name, String handle){ - setId(id); - setName(name); - setHandle(handle); + + public HierarchyObject(String id, String name, String handle) { + setId(id); + setName(name); + setHandle(handle); } - + public String getId() { return id; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/HierarchySite.java b/dspace-rest/src/main/java/org/dspace/rest/common/HierarchySite.java index ac1f439b61..5eb2cc523c 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/HierarchySite.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/HierarchySite.java @@ -12,15 +12,13 @@ import javax.xml.bind.annotation.XmlRootElement; /** * Used to handle/determine status of REST API. * Mainly to know your authentication status - * */ @XmlRootElement(name = "site") -public class HierarchySite extends HierarchyCommunity -{ - public HierarchySite(){ +public class HierarchySite extends HierarchyCommunity { + public HierarchySite() { } - - public HierarchySite(String id, String name, String handle){ - super(id, name, handle); + + public HierarchySite(String id, String name, String handle) { + super(id, name, handle); } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Item.java b/dspace-rest/src/main/java/org/dspace/rest/common/Item.java index e794b1ec0b..e336247736 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/Item.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Item.java @@ -7,6 +7,15 @@ */ package org.dspace.rest.common; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.servlet.ServletContext; +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + import org.apache.log4j.Logger; import org.dspace.app.util.factory.UtilServiceFactory; import org.dspace.app.util.service.MetadataExposureService; @@ -19,16 +28,6 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.Context; -import javax.servlet.ServletContext; -import javax.ws.rs.WebApplicationException; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - /** * Created with IntelliJ IDEA. * User: peterdietz @@ -40,7 +39,8 @@ import java.util.List; @XmlRootElement(name = "item") public class Item extends DSpaceObject { protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - protected MetadataExposureService metadataExposureService = UtilServiceFactory.getInstance().getMetadataExposureService(); + protected MetadataExposureService metadataExposureService = UtilServiceFactory.getInstance() + .getMetadataExposureService(); protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); Logger log = Logger.getLogger(Item.class); @@ -55,46 +55,39 @@ public class Item extends DSpaceObject { List metadata; List bitstreams; - public Item(){} + public Item() { + } public Item(org.dspace.content.Item item, ServletContext servletContext, String expand, Context context) - throws SQLException, WebApplicationException - { + throws SQLException, WebApplicationException { super(item, servletContext); setup(item, servletContext, expand, context); } private void setup(org.dspace.content.Item item, ServletContext servletContext, String expand, Context context) - throws SQLException - { + throws SQLException { List expandFields = new ArrayList(); - if (expand != null) - { + if (expand != null) { expandFields = Arrays.asList(expand.split(",")); } - if (expandFields.contains("metadata") || expandFields.contains("all")) - { + if (expandFields.contains("metadata") || expandFields.contains("all")) { metadata = new ArrayList(); List metadataValues = itemService.getMetadata( item, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY); - for (MetadataValue metadataValue : metadataValues) - { + for (MetadataValue metadataValue : metadataValues) { MetadataField metadataField = metadataValue.getMetadataField(); if (!metadataExposureService.isHidden(context, - metadataField.getMetadataSchema().getName(), - metadataField.getElement(), - metadataField.getQualifier())) - { + metadataField.getMetadataSchema().getName(), + metadataField.getElement(), + metadataField.getQualifier())) { metadata.add(new MetadataEntry(metadataField.toString('.'), - metadataValue.getValue(), metadataValue.getLanguage())); + metadataValue.getValue(), metadataValue.getLanguage())); } } - } - else - { + } else { this.addExpand("metadata"); } @@ -102,79 +95,59 @@ public class Item extends DSpaceObject { this.setWithdrawn(Boolean.toString(item.isWithdrawn())); this.setLastModified(item.getLastModified().toString()); - if (expandFields.contains("parentCollection") || expandFields.contains("all")) - { - if (item.getOwningCollection() != null) - { + if (expandFields.contains("parentCollection") || expandFields.contains("all")) { + if (item.getOwningCollection() != null) { this.parentCollection = new Collection(item.getOwningCollection(), - servletContext, null, context, null, null); - } - else - { + servletContext, null, context, null, null); + } else { this.addExpand("parentCollection"); } - } - else - { + } else { this.addExpand("parentCollection"); } - if (expandFields.contains("parentCollectionList") || expandFields.contains("all")) - { + if (expandFields.contains("parentCollectionList") || expandFields.contains("all")) { this.parentCollectionList = new ArrayList(); List collections = item.getCollections(); - for (org.dspace.content.Collection collection : collections) - { + for (org.dspace.content.Collection collection : collections) { this.parentCollectionList.add(new Collection(collection, - servletContext, null, context, null, null)); + servletContext, null, context, null, null)); } - } - else - { + } else { this.addExpand("parentCollectionList"); } - if (expandFields.contains("parentCommunityList") || expandFields.contains("all")) - { + if (expandFields.contains("parentCommunityList") || expandFields.contains("all")) { this.parentCommunityList = new ArrayList(); List communities = itemService.getCommunities(context, item); - for (org.dspace.content.Community community : communities) - { + for (org.dspace.content.Community community : communities) { this.parentCommunityList.add(new Community(community, servletContext, null, context)); } - } - else - { + } else { this.addExpand("parentCommunityList"); } //TODO: paging - offset, limit - if (expandFields.contains("bitstreams") || expandFields.contains("all")) - { + if (expandFields.contains("bitstreams") || expandFields.contains("all")) { bitstreams = new ArrayList(); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { List itemBitstreams = bundle.getBitstreams(); - for (org.dspace.content.Bitstream itemBitstream : itemBitstreams) - { - if (authorizeService.authorizeActionBoolean(context, itemBitstream, org.dspace.core.Constants.READ)) - { + for (org.dspace.content.Bitstream itemBitstream : itemBitstreams) { + if (authorizeService + .authorizeActionBoolean(context, itemBitstream, org.dspace.core.Constants.READ)) { bitstreams.add(new Bitstream(itemBitstream, servletContext, null, context)); } } } - } - else - { + } else { this.addExpand("bitstreams"); } - if (!expandFields.contains("all")) - { + if (!expandFields.contains("all")) { this.addExpand("all"); } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/ItemFilter.java b/dspace-rest/src/main/java/org/dspace/rest/common/ItemFilter.java index baaded9c20..6a1466eb35 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/ItemFilter.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/ItemFilter.java @@ -7,6 +7,16 @@ */ package org.dspace.rest.common; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + import org.apache.log4j.Logger; import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; @@ -14,20 +24,10 @@ import org.dspace.rest.filter.ItemFilterDefs; import org.dspace.rest.filter.ItemFilterList; import org.dspace.rest.filter.ItemFilterTest; -import javax.ws.rs.WebApplicationException; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; - /** * Use Case Item Filters that match a specific set of criteria. + * * @author Terry Brady, Georgetown University */ @XmlRootElement(name = "item-filter") @@ -47,49 +47,40 @@ public class ItemFilter { private Integer unfilteredItemCount; private boolean saveItems = false; - public ItemFilter(){} + public ItemFilter() { + } public static final String ALL_FILTERS = "all_filters"; public static final String ALL = "all"; - public static List getItemFilters(String filters, boolean saveItems) - { - LinkedHashMap availableTests = new LinkedHashMap(); - for (ItemFilterList plugobj: - (ItemFilterList[]) CoreServiceFactory.getInstance() - .getPluginService().getPluginSequence(ItemFilterList.class)) - { - for (ItemFilterTest defFilter: plugobj.getFilters()) - { + public static List getItemFilters(String filters, boolean saveItems) { + LinkedHashMap availableTests = new LinkedHashMap(); + for (ItemFilterList plugobj : + (ItemFilterList[]) CoreServiceFactory.getInstance() + .getPluginService().getPluginSequence(ItemFilterList.class)) { + for (ItemFilterTest defFilter : plugobj.getFilters()) { availableTests.put(defFilter.getName(), defFilter); } } List itemFilters = new ArrayList(); ItemFilter allFilters = new ItemFilter(ItemFilter.ALL_FILTERS, "Matches all specified filters", - "This filter includes all items that matched ALL specified filters", - ItemFilterDefs.CAT_ITEM, saveItems); + "This filter includes all items that matched ALL specified filters", + ItemFilterDefs.CAT_ITEM, saveItems); - if (filters.equals(ALL)) - { - for (ItemFilterTest itemFilterDef: availableTests.values()) - { + if (filters.equals(ALL)) { + for (ItemFilterTest itemFilterDef : availableTests.values()) { itemFilters.add(new ItemFilter(itemFilterDef, saveItems)); } itemFilters.add(allFilters); - } - else - { - for (String filter: Arrays.asList(filters.split(","))) - { - if (filter.equals(ItemFilter.ALL_FILTERS)) - { + } else { + for (String filter : Arrays.asList(filters.split(","))) { + if (filter.equals(ItemFilter.ALL_FILTERS)) { continue; } ItemFilterTest itemFilterDef; itemFilterDef = availableTests.get(filter); - if (itemFilterDef == null) - { + if (itemFilterDef == null) { continue; } itemFilters.add(new ItemFilter(itemFilterDef, saveItems)); @@ -99,12 +90,9 @@ public class ItemFilter { return itemFilters; } - public static ItemFilter getAllFiltersFilter(List itemFilters) - { - for (ItemFilter itemFilter: itemFilters) - { - if (itemFilter.getFilterName().equals(ALL_FILTERS)) - { + public static ItemFilter getAllFiltersFilter(List itemFilters) { + for (ItemFilter itemFilter : itemFilters) { + if (itemFilter.getFilterName().equals(ALL_FILTERS)) { itemFilter.initCount(); return itemFilter; } @@ -113,16 +101,15 @@ public class ItemFilter { } public ItemFilter(ItemFilterTest itemFilterTest, boolean saveItems) - throws WebApplicationException - { + throws WebApplicationException { this.itemFilterTest = itemFilterTest; this.saveItems = saveItems; setup(itemFilterTest.getName(), itemFilterTest.getTitle(), - itemFilterTest.getDescription(), itemFilterTest.getCategory()); + itemFilterTest.getDescription(), itemFilterTest.getCategory()); } public ItemFilter(String name, String title, String description, String category, boolean saveItems) - throws WebApplicationException{ + throws WebApplicationException { this.saveItems = saveItems; setup(name, title, description, category); } @@ -134,14 +121,11 @@ public class ItemFilter { this.setCategory(category); } - private void initCount() - { - if (itemCount == null) - { + private void initCount() { + if (itemCount == null) { itemCount = 0; } - if (unfilteredItemCount == null) - { + if (unfilteredItemCount == null) { unfilteredItemCount = 0; } } @@ -150,32 +134,27 @@ public class ItemFilter { return itemFilterTest != null; } - public void addItem(org.dspace.rest.common.Item restItem) - { + public void addItem(org.dspace.rest.common.Item restItem) { initCount(); - if (saveItems) - { + if (saveItems) { items.add(restItem); } itemCount++; } - public boolean testItem(Context context, org.dspace.content.Item item, org.dspace.rest.common.Item restItem) - { + public boolean testItem(Context context, org.dspace.content.Item item, org.dspace.rest.common.Item restItem) { initCount(); - if (itemFilterTest == null) - { + if (itemFilterTest == null) { return false; } - if (itemFilterTest.testItem(context, item)) - { + if (itemFilterTest.testItem(context, item)) { addItem(restItem); return true; } return false; } - @XmlAttribute(name="filter-name") + @XmlAttribute(name = "filter-name") public String getFilterName() { return filterName; } @@ -184,7 +163,7 @@ public class ItemFilter { this.filterName = name; } - @XmlAttribute(name="title") + @XmlAttribute(name = "title") public String getTitle() { return title; } @@ -193,7 +172,7 @@ public class ItemFilter { this.title = title; } - @XmlAttribute(name="category") + @XmlAttribute(name = "category") public String getCategory() { return category; } @@ -202,7 +181,7 @@ public class ItemFilter { this.category = category; } - @XmlAttribute(name="description") + @XmlAttribute(name = "description") public String getDescription() { return description; } @@ -211,21 +190,18 @@ public class ItemFilter { this.description = description; } - @XmlAttribute(name="query-annotation") + @XmlAttribute(name = "query-annotation") public String getQueryAnnotation() { return queryAnnotation; } public void annotateQuery(List query_field, List query_op, List query_val) - throws SQLException - { + throws SQLException { int index = Math.min(query_field.size(), Math.min(query_op.size(), query_val.size())); StringBuilder sb = new StringBuilder(); - for (int i=0; i show_fields) - { - if (show_fields != null) - { + public void initMetadataList(List show_fields) { + if (show_fields != null) { List returnFields = new ArrayList(); - for (String field: show_fields) - { + for (String field : show_fields) { returnFields.add(new MetadataEntry(field, null, null)); } setMetadata(returnFields); diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/ItemFilterQuery.java b/dspace-rest/src/main/java/org/dspace/rest/common/ItemFilterQuery.java index a576645a30..448d3a8cfc 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/ItemFilterQuery.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/ItemFilterQuery.java @@ -7,14 +7,15 @@ */ package org.dspace.rest.common; -import org.apache.log4j.Logger; - import javax.ws.rs.WebApplicationException; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; +import org.apache.log4j.Logger; + /** * Metadata Query for DSpace Items using the REST API + * * @author Terry Brady, Georgetown University */ @XmlRootElement(name = "item-filter-query") @@ -25,18 +26,16 @@ public class ItemFilterQuery { private String operation = ""; private String value = ""; - public ItemFilterQuery(){} + public ItemFilterQuery() { + } /** * Construct a metadata query for DSpace items - * @param field - * Name of the metadata field to query - * @param operation - * Operation to perform on a metadata field - * @param value - Query value. - * @throws WebApplicationException - Runtime exception for applications. + * + * @param field Name of the metadata field to query + * @param operation Operation to perform on a metadata field + * @param value Query value. + * @throws WebApplicationException Runtime exception for applications. */ public ItemFilterQuery(String field, String operation, String value) throws WebApplicationException { setup(field, operation, value); @@ -48,7 +47,7 @@ public class ItemFilterQuery { this.setValue(value); } - @XmlAttribute(name="field") + @XmlAttribute(name = "field") public String getField() { return field; } @@ -56,8 +55,8 @@ public class ItemFilterQuery { public void setField(String field) { this.field = field; } - - @XmlAttribute(name="operation") + + @XmlAttribute(name = "operation") public String getOperation() { return operation; } @@ -65,7 +64,8 @@ public class ItemFilterQuery { public void setOperation(String operation) { this.operation = operation; } - @XmlAttribute(name="value") + + @XmlAttribute(name = "value") public String getValue() { return value; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/MetadataEntry.java b/dspace-rest/src/main/java/org/dspace/rest/common/MetadataEntry.java index ab0ddafda9..27f31cec9c 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/MetadataEntry.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/MetadataEntry.java @@ -7,61 +7,51 @@ */ package org.dspace.rest.common; -import javax.xml.bind.annotation.XmlRootElement; import java.util.regex.Pattern; +import javax.xml.bind.annotation.XmlRootElement; /** * @author peterdietz, Rostislav Novak (Computing and Information Centre, CTU in - * Prague) - * + * Prague) */ @XmlRootElement(name = "metadataentry") -public class MetadataEntry -{ +public class MetadataEntry { String key; String value; String language; - public MetadataEntry() - { + public MetadataEntry() { } - public MetadataEntry(String key, String value, String language) - { + public MetadataEntry(String key, String value, String language) { this.key = key; this.value = value; this.language = language; } - public String getValue() - { + public String getValue() { return value; } - public void setValue(String value) - { + public void setValue(String value) { this.value = value; } - public String getKey() - { + public String getKey() { return key; } - public void setKey(String key) - { + public void setKey(String key) { this.key = key; } - public String getLanguage() - { + public String getLanguage() { return language; } - public void setLanguage(String language) - { + public void setLanguage(String language) { this.language = language; } @@ -77,7 +67,7 @@ public class MetadataEntry public String getQualifier() { String[] fieldPieces = key.split(Pattern.quote(".")); - if(fieldPieces.length == 3) { + if (fieldPieces.length == 3) { return fieldPieces[2]; } else { return null; diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/MetadataField.java b/dspace-rest/src/main/java/org/dspace/rest/common/MetadataField.java index 2b204ccb63..3688b5b8ca 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/MetadataField.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/MetadataField.java @@ -7,105 +7,117 @@ */ package org.dspace.rest.common; -import org.dspace.core.Context; - -import javax.ws.rs.WebApplicationException; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.dspace.core.Context; /** * Metadata field representation + * * @author Terry Brady, Georgetown University. */ @XmlRootElement(name = "field") public class MetadataField { - private int fieldId; + private int fieldId; private String name; private String element; private String qualifier; private String description; - + private MetadataSchema parentSchema; @XmlElement(required = true) private ArrayList expand = new ArrayList(); - public MetadataField(){} + public MetadataField() { + } - public MetadataField(org.dspace.content.MetadataSchema schema, org.dspace.content.MetadataField field, String expand, Context context) throws SQLException, WebApplicationException{ + public MetadataField(org.dspace.content.MetadataSchema schema, org.dspace.content.MetadataField field, + String expand, Context context) throws SQLException, WebApplicationException { setup(schema, field, expand, context); } - private void setup(org.dspace.content.MetadataSchema schema, org.dspace.content.MetadataField field, String expand, Context context) throws SQLException{ + private void setup(org.dspace.content.MetadataSchema schema, org.dspace.content.MetadataField field, String expand, + Context context) throws SQLException { List expandFields = new ArrayList(); - if(expand != null) { + if (expand != null) { expandFields = Arrays.asList(expand.split(",")); } StringBuilder sb = new StringBuilder(); sb.append(schema.getName()); sb.append("."); sb.append(field.getElement()); - if (field.getQualifier()!=null) { + if (field.getQualifier() != null) { sb.append("."); - sb.append(field.getQualifier()); + sb.append(field.getQualifier()); } - + this.setName(sb.toString()); this.setFieldId(field.getID()); this.setElement(field.getElement()); this.setQualifier(field.getQualifier()); this.setDescription(field.getScopeNote()); - + if (expandFields.contains("parentSchema") || expandFields.contains("all")) { - this.addExpand("parentSchema"); - parentSchema = new MetadataSchema(schema, "", context); + this.addExpand("parentSchema"); + parentSchema = new MetadataSchema(schema, "", context); } } public void setParentSchema(MetadataSchema schema) { - this.parentSchema = schema; + this.parentSchema = schema; } - + public MetadataSchema getParentSchema() { - return this.parentSchema; + return this.parentSchema; } - + public void setFieldId(int fieldId) { this.fieldId = fieldId; } + public void setName(String name) { this.name = name; } + public void setElement(String element) { this.element = element; } + public void setQualifier(String qualifier) { this.qualifier = qualifier; } + public void setDescription(String description) { this.description = description; } - + public int getFieldId() { return fieldId; } + public String getName() { return name; } - + public String getQualifier() { return qualifier; } + public String getElement() { return element; } + public String getDescription() { return description; } + public List getExpand() { return expand; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/MetadataSchema.java b/dspace-rest/src/main/java/org/dspace/rest/common/MetadataSchema.java index 7557bb87d1..4b1e29fea2 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/MetadataSchema.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/MetadataSchema.java @@ -7,45 +7,48 @@ */ package org.dspace.rest.common; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.MetadataFieldService; -import org.dspace.core.Context; - -import javax.ws.rs.WebApplicationException; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.core.Context; /** * Metadata schema representation + * * @author Terry Brady, Georgetown University. */ @XmlRootElement(name = "schema") public class MetadataSchema { protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); - private int schemaID; + private int schemaID; private String prefix; private String namespace; - + @XmlElement(required = true) private ArrayList expand = new ArrayList(); @XmlElement(name = "fields", required = true) private List fields = new ArrayList(); - public MetadataSchema(){} + public MetadataSchema() { + } - public MetadataSchema(org.dspace.content.MetadataSchema schema, String expand, Context context) throws SQLException, WebApplicationException{ + public MetadataSchema(org.dspace.content.MetadataSchema schema, String expand, Context context) + throws SQLException, WebApplicationException { setup(schema, expand, context); } - private void setup(org.dspace.content.MetadataSchema schema, String expand, Context context) throws SQLException{ + private void setup(org.dspace.content.MetadataSchema schema, String expand, Context context) throws SQLException { List expandFields = new ArrayList(); - if(expand != null) { + if (expand != null) { expandFields = Arrays.asList(expand.split(",")); } this.setSchemaID(schema.getID()); @@ -54,37 +57,40 @@ public class MetadataSchema { if (expandFields.contains("fields") || expandFields.contains("all")) { List fields = metadataFieldService.findAllInSchema(context, schema); this.addExpand("fields"); - for(org.dspace.content.MetadataField field: fields) { + for (org.dspace.content.MetadataField field : fields) { this.fields.add(new MetadataField(schema, field, "", context)); - } + } } } public void setPrefix(String prefix) { this.prefix = prefix; } + public void setNamespace(String namespace) { this.namespace = namespace; } - + public String getPrefix() { return prefix; - } + } + public String getNamespace() { return namespace; } - public int getSchemaID() - { + + public int getSchemaID() { return this.schemaID; } - public void setSchemaID(int schemaID) - { + public void setSchemaID(int schemaID) { this.schemaID = schemaID; } + public List getMetadataFields() { return fields; } + public List getExpand() { return expand; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Report.java b/dspace-rest/src/main/java/org/dspace/rest/common/Report.java index 73670874c0..dcaf7d269e 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/Report.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Report.java @@ -12,40 +12,36 @@ import javax.xml.bind.annotation.XmlRootElement; /** * Used to handle/determine status of REST API. * Mainly to know your authentication status - * */ @XmlRootElement(name = "report") -public class Report -{ +public class Report { private String nickname; private String url; public Report() { - setNickname("na"); - setUrl(""); + setNickname("na"); + setUrl(""); } - + public Report(String nickname, String url) { setNickname(nickname); setUrl(url); } - public String getUrl() - { + + public String getUrl() { return this.url; } - public String getNickname() - { + + public String getNickname() { return this.nickname; } - public void setUrl(String url) - { + public void setUrl(String url) { this.url = url; } - public void setNickname(String nickname) - { + public void setNickname(String nickname) { this.nickname = nickname; } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/ResourcePolicy.java b/dspace-rest/src/main/java/org/dspace/rest/common/ResourcePolicy.java index 2a4fb9b397..366bd5fc3a 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/ResourcePolicy.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/ResourcePolicy.java @@ -7,21 +7,20 @@ */ package org.dspace.rest.common; +import java.util.Date; +import javax.xml.bind.annotation.XmlRootElement; + import com.fasterxml.jackson.annotation.JsonIgnore; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import java.util.Date; - -import javax.xml.bind.annotation.XmlRootElement; - @XmlRootElement(name = "resourcepolicy") -public class ResourcePolicy{ - +public class ResourcePolicy { + public enum Action { READ, WRITE, DELETE; } - + private Integer id; private Action action; private String epersonId; //UUID @@ -33,12 +32,13 @@ public class ResourcePolicy{ private String rpType; private Date startDate; private Date endDate; - - public ResourcePolicy() {} - + + public ResourcePolicy() { + } + public ResourcePolicy(org.dspace.authorize.ResourcePolicy dspacePolicy) { this.id = dspacePolicy.getID(); - + switch (dspacePolicy.getAction()) { case org.dspace.core.Constants.READ: this.action = Action.READ; @@ -49,15 +49,17 @@ public class ResourcePolicy{ case org.dspace.core.Constants.DELETE: this.action = Action.DELETE; break; + default: + break; } EPerson ePerson = dspacePolicy.getEPerson(); - if(ePerson != null) { + if (ePerson != null) { this.epersonId = ePerson.getID().toString(); } Group group = dspacePolicy.getGroup(); - if(group != null) { + if (group != null) { this.groupId = group.getID().toString(); } @@ -67,8 +69,7 @@ public class ResourcePolicy{ this.rpType = dspacePolicy.getRpType(); this.startDate = dspacePolicy.getStartDate(); this.endDate = dspacePolicy.getEndDate(); - switch (dspacePolicy.getdSpaceObject().getType()) - { + switch (dspacePolicy.getdSpaceObject().getType()) { case org.dspace.core.Constants.BITSTREAM: this.resourceType = "bitstream"; break; @@ -101,10 +102,9 @@ public class ResourcePolicy{ public Action getAction() { return action; } - + @JsonIgnore - public int getActionInt() - { + public int getActionInt() { switch (action) { case READ: return org.dspace.core.Constants.READ; @@ -112,8 +112,9 @@ public class ResourcePolicy{ return org.dspace.core.Constants.WRITE; case DELETE: return org.dspace.core.Constants.DELETE; + default: + return org.dspace.core.Constants.READ; } - return org.dspace.core.Constants.READ; } public void setAction(Action action) { diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Status.java b/dspace-rest/src/main/java/org/dspace/rest/common/Status.java index 1512ce5cb5..cdbb8210b9 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/common/Status.java +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Status.java @@ -7,21 +7,19 @@ */ package org.dspace.rest.common; -import com.fasterxml.jackson.annotation.JsonProperty; -import org.dspace.eperson.EPerson; -import org.dspace.app.util.Util; - import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.dspace.app.util.Util; +import org.dspace.eperson.EPerson; + /** * Determine status of REST API - is it running, accessible and without errors?. * Find out API version (DSpace major version) and DSpace source version. * Find out your authentication status. - * */ @XmlRootElement(name = "status") -public class Status -{ +public class Status { private boolean okay; private boolean authenticated; private String email; @@ -48,7 +46,7 @@ public class Status public Status(EPerson eperson) { setOkay(true); - if(eperson != null) { + if (eperson != null) { setAuthenticated(true); setEmail(eperson.getEmail()); setFullname(eperson.getFullName()); @@ -58,13 +56,11 @@ public class Status } @JsonProperty("okay") - public boolean isOkay() - { + public boolean isOkay() { return this.okay; } - public void setOkay(boolean okay) - { + public void setOkay(boolean okay) { this.okay = okay; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/exceptions/ContextException.java b/dspace-rest/src/main/java/org/dspace/rest/exceptions/ContextException.java index 7dec5caeb2..817b662f73 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/exceptions/ContextException.java +++ b/dspace-rest/src/main/java/org/dspace/rest/exceptions/ContextException.java @@ -10,25 +10,21 @@ package org.dspace.rest.exceptions; /** * Simple exception which only encapsulate classic exception. This exception is * only for exceptions caused by creating context. - * + * * @author Rostislav Novak (Computing and Information Centre, CTU in Prague) - * */ -public class ContextException extends Exception -{ +public class ContextException extends Exception { private static final long serialVersionUID = 1L; Exception causedBy; - public ContextException(String message, Exception causedBy) - { + public ContextException(String message, Exception causedBy) { super(message); this.causedBy = causedBy; } - public Exception getCausedBy() - { + public Exception getCausedBy() { return causedBy; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefs.java b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefs.java index 70350695f6..0712ec546d 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefs.java +++ b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefs.java @@ -12,69 +12,70 @@ import org.dspace.core.Context; /** * Define the set of use cases for filtering items of interest through the REST API. - * @author Terry Brady, Georgetown University * + * @author Terry Brady, Georgetown University */ public class ItemFilterDefs implements ItemFilterList { public static final String CAT_ITEM = "Item Property Filters"; public static final String CAT_BASIC = "Basic Bitstream Filters"; public static final String CAT_MIME = "Bitstream Filters by MIME Type"; - + public static final String[] MIMES_PDF = {"application/pdf"}; public static final String[] MIMES_JPG = {"image/jpeg"}; - - + + private enum EnumItemFilterDefs implements ItemFilterTest { is_item("Is Item - always true", null, CAT_ITEM) { public boolean testItem(Context context, Item item) { return true; - } + } }, is_withdrawn("Withdrawn Items", null, CAT_ITEM) { public boolean testItem(Context context, Item item) { return item.isWithdrawn(); - } + } }, is_not_withdrawn("Available Items - Not Withdrawn", null, CAT_ITEM) { public boolean testItem(Context context, Item item) { return !item.isWithdrawn(); - } + } }, is_discoverable("Discoverable Items - Not Private", null, CAT_ITEM) { public boolean testItem(Context context, Item item) { return item.isDiscoverable(); - } + } }, is_not_discoverable("Not Discoverable - Private Item", null, CAT_ITEM) { public boolean testItem(Context context, Item item) { return !item.isDiscoverable(); - } + } }, has_multiple_originals("Item has Multiple Original Bitstreams", null, CAT_BASIC) { public boolean testItem(Context context, Item item) { return ItemFilterUtil.countOriginalBitstream(item) > 1; - } + } }, has_no_originals("Item has No Original Bitstreams", null, CAT_BASIC) { public boolean testItem(Context context, Item item) { return ItemFilterUtil.countOriginalBitstream(item) == 0; - } + } }, has_one_original("Item has One Original Bitstream", null, CAT_BASIC) { public boolean testItem(Context context, Item item) { return ItemFilterUtil.countOriginalBitstream(item) == 1; - } + } }, has_doc_original("Item has a Doc Original Bitstream (PDF, Office, Text, HTML, XML, etc)", null, CAT_MIME) { public boolean testItem(Context context, Item item) { - return ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()) > 0; + return ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()) > 0; } }, has_image_original("Item has an Image Original Bitstream", null, CAT_MIME) { public boolean testItem(Context context, Item item) { return ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image") > 0; - } + } }, has_unsupp_type("Has Other Bitstream Types (not Doc or Image)", null, ItemFilterDefs.CAT_MIME) { public boolean testItem(Context context, Item item) { @@ -82,16 +83,20 @@ public class ItemFilterDefs implements ItemFilterList { if (bitCount == 0) { return false; } - int docCount = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); + int docCount = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); int imgCount = ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image"); return (bitCount - docCount - imgCount) > 0; - } + } }, has_mixed_original("Item has multiple types of Original Bitstreams (Doc, Image, Other)", null, CAT_MIME) { public boolean testItem(Context context, Item item) { int countBit = ItemFilterUtil.countOriginalBitstream(item); - if (countBit <= 1) return false; - int countDoc = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); + if (countBit <= 1) { + return false; + } + int countDoc = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); if (countDoc > 0) { return countDoc != countBit; } @@ -100,42 +105,46 @@ public class ItemFilterDefs implements ItemFilterList { return countImg != countBit; } return false; - } + } }, has_pdf_original("Item has a PDF Original Bitstream", null, CAT_MIME) { public boolean testItem(Context context, Item item) { return ItemFilterUtil.countOriginalBitstreamMime(context, item, MIMES_PDF) > 0; - } + } }, has_jpg_original("Item has JPG Original Bitstream", null, CAT_MIME) { public boolean testItem(Context context, Item item) { return ItemFilterUtil.countOriginalBitstreamMime(context, item, MIMES_JPG) > 0; - } - }, - ; - + } + },; + private String title = null; private String description = null; + private EnumItemFilterDefs(String title, String description, String category) { this.title = title; this.description = description; this.category = category; } - + private EnumItemFilterDefs() { this(null, null, null); } - + public String getName() { return name(); } + public String getTitle() { return title; } + public String getDescription() { return description; } + private String category = null; + public String getCategory() { return category; } @@ -143,7 +152,8 @@ public class ItemFilterDefs implements ItemFilterList { public ItemFilterDefs() { } + public ItemFilterTest[] getFilters() { return EnumItemFilterDefs.values(); - } + } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsMeta.java b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsMeta.java index d1da2148eb..278c0c8a1e 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsMeta.java +++ b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsMeta.java @@ -18,8 +18,8 @@ import org.dspace.services.factory.DSpaceServicesFactory; /** * Define the set of use cases for filtering items of interest through the REST API. - * @author Terry Brady, Georgetown University * + * @author Terry Brady, Georgetown University */ public class ItemFilterDefsMeta implements ItemFilterList { @@ -29,6 +29,7 @@ public class ItemFilterDefsMeta implements ItemFilterList { public static final String CAT_META_GEN = "General Metadata Filters"; public static final String CAT_META_SPEC = "Specific Metadata Filters"; public static final String CAT_MOD = "Recently Modified"; + private enum EnumItemFilterDefs implements ItemFilterTest { has_no_title("Has no dc.title", null, CAT_META_SPEC) { public boolean testItem(Context context, Item item) { @@ -47,14 +48,17 @@ public class ItemFilterDefsMeta implements ItemFilterList { }, has_compound_subject("Has compound subject", null, CAT_META_SPEC) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-compound-subject"); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-compound-subject"); return ItemFilterUtil.hasMetadataMatch(item, "dc.subject.*", Pattern.compile(regex)); } }, has_compound_author("Has compound author", null, CAT_META_SPEC) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-compound-author"); - return ItemFilterUtil.hasMetadataMatch(item, "dc.creator,dc.contributor.author", Pattern.compile(regex)); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-compound-author"); + return ItemFilterUtil + .hasMetadataMatch(item, "dc.creator,dc.contributor.author", Pattern.compile(regex)); } }, has_empty_metadata("Has empty metadata", null, CAT_META_GEN) { @@ -64,43 +68,50 @@ public class ItemFilterDefsMeta implements ItemFilterList { }, has_unbreaking_metadata("Has unbreaking metadata", null, CAT_META_GEN) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-unbreaking"); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-unbreaking"); return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile(regex)); } }, has_long_metadata("Has long metadata field", null, CAT_META_GEN) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-long"); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-long"); return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile(regex)); } }, has_xml_entity("Has XML entity in metadata", null, CAT_META_GEN) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-xml-entity"); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-xml-entity"); return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile(regex)); } }, has_non_ascii("Has non-ascii in metadata", null, CAT_META_GEN) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-non-ascii"); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-non-ascii"); return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile(regex)); } }, has_desc_url("Has url in description", null, CAT_META_SPEC) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-url"); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-url"); return ItemFilterUtil.hasMetadataMatch(item, "dc.description.*", Pattern.compile(regex)); } }, has_fulltext_provenance("Has fulltext in provenance", null, CAT_META_SPEC) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-fulltext"); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-fulltext"); return ItemFilterUtil.hasMetadataMatch(item, "dc.description.provenance", Pattern.compile(regex)); } }, no_fulltext_provenance("Doesn't have fulltext in provenance", null, CAT_META_SPEC) { public boolean testItem(Context context, Item item) { - String regex = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("rest.report-regex-fulltext"); + String regex = DSpaceServicesFactory.getInstance().getConfigurationService() + .getProperty("rest.report-regex-fulltext"); return !ItemFilterUtil.hasMetadataMatch(item, "dc.description.provenance", Pattern.compile(regex)); } }, @@ -123,11 +134,11 @@ public class ItemFilterDefsMeta implements ItemFilterList { public boolean testItem(Context context, Item item) { return ItemFilterUtil.recentlyModified(item, 60); } - }, - ; + },; private String title = null; private String description = null; + private EnumItemFilterDefs(String title, String description, String category) { this.title = title; this.description = description; @@ -141,14 +152,17 @@ public class ItemFilterDefsMeta implements ItemFilterList { public String getName() { return name(); } + public String getTitle() { return title; } + public String getDescription() { return description; } private String category = null; + public String getCategory() { return category; } @@ -156,6 +170,7 @@ public class ItemFilterDefsMeta implements ItemFilterList { public ItemFilterDefsMeta() { } + public ItemFilterTest[] getFilters() { return EnumItemFilterDefs.values(); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsMisc.java b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsMisc.java index e154708694..5b5cc4b12d 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsMisc.java +++ b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsMisc.java @@ -16,204 +16,180 @@ import org.dspace.services.factory.DSpaceServicesFactory; /** * Define the set of use cases for filtering items of interest through the REST API. - * @author Terry Brady, Georgetown University * + * @author Terry Brady, Georgetown University */ public class ItemFilterDefsMisc implements ItemFilterList { public static final String CAT_MISC = "Bitstream Bundle Filters"; public static final String CAT_MIME_SUPP = "Supported MIME Type Filters"; - private enum EnumItemFilterDefs implements ItemFilterTest - { - has_only_supp_image_type("Item Image Bitstreams are Supported", null, CAT_MIME_SUPP) - { - public boolean testItem(Context context, Item item) - { + + private enum EnumItemFilterDefs implements ItemFilterTest { + has_only_supp_image_type("Item Image Bitstreams are Supported", null, CAT_MIME_SUPP) { + public boolean testItem(Context context, Item item) { int imageCount = ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image/"); - if (imageCount == 0) - { + if (imageCount == 0) { return false; } - int suppImageCount = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedImageMimeTypes()); + int suppImageCount = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedImageMimeTypes()); return (imageCount == suppImageCount); - } + } }, - has_unsupp_image_type("Item has Image Bitstream that is Unsupported", null, CAT_MIME_SUPP) - { - public boolean testItem(Context context, Item item) - { + has_unsupp_image_type("Item has Image Bitstream that is Unsupported", null, CAT_MIME_SUPP) { + public boolean testItem(Context context, Item item) { int imageCount = ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image/"); - if (imageCount == 0) - { + if (imageCount == 0) { return false; } - int suppImageCount = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedImageMimeTypes()); + int suppImageCount = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedImageMimeTypes()); return (imageCount - suppImageCount) > 0; - } + } }, - has_only_supp_doc_type("Item Document Bitstreams are Supported", null, CAT_MIME_SUPP) - { - public boolean testItem(Context context, Item item) - { - int docCount = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); - if (docCount == 0) - { + has_only_supp_doc_type("Item Document Bitstreams are Supported", null, CAT_MIME_SUPP) { + public boolean testItem(Context context, Item item) { + int docCount = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); + if (docCount == 0) { return false; } - int suppDocCount = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedDocumentMimeTypes()); + int suppDocCount = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedDocumentMimeTypes()); return docCount == suppDocCount; - } + } }, - has_unsupp_doc_type("Item has Document Bitstream that is Unsupported", null, CAT_MIME_SUPP) - { - public boolean testItem(Context context, Item item) - { - int docCount = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); - if (docCount == 0) - { + has_unsupp_doc_type("Item has Document Bitstream that is Unsupported", null, CAT_MIME_SUPP) { + public boolean testItem(Context context, Item item) { + int docCount = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); + if (docCount == 0) { return false; } - int suppDocCount = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedDocumentMimeTypes()); + int suppDocCount = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedDocumentMimeTypes()); return (docCount - suppDocCount) > 0; - } + } }, - has_small_pdf("Has unusually small PDF", null, ItemFilterDefs.CAT_MIME) - { - public boolean testItem(Context context, Item item) - { - return ItemFilterUtil.countBitstreamSmallerThanMinSize(context, BundleName.ORIGINAL, item, ItemFilterDefs.MIMES_PDF, "rest.report-pdf-min-size") > 0; - } + has_small_pdf("Has unusually small PDF", null, ItemFilterDefs.CAT_MIME) { + public boolean testItem(Context context, Item item) { + return ItemFilterUtil + .countBitstreamSmallerThanMinSize(context, BundleName.ORIGINAL, item, ItemFilterDefs.MIMES_PDF, + "rest.report-pdf-min-size") > 0; + } }, - has_large_pdf("Has unusually large PDF", null, ItemFilterDefs.CAT_MIME) - { - public boolean testItem(Context context, Item item) - { - return ItemFilterUtil.countBitstreamLargerThanMaxSize(context, BundleName.ORIGINAL, item, ItemFilterDefs.MIMES_PDF, "rest.report-pdf-max-size") > 0; - } + has_large_pdf("Has unusually large PDF", null, ItemFilterDefs.CAT_MIME) { + public boolean testItem(Context context, Item item) { + return ItemFilterUtil + .countBitstreamLargerThanMaxSize(context, BundleName.ORIGINAL, item, ItemFilterDefs.MIMES_PDF, + "rest.report-pdf-max-size") > 0; + } }, - has_unsupported_bundle("Has bitstream in an unsuppored bundle", null, CAT_MISC) - { - public boolean testItem(Context context, Item item) - { - String[] bundleList = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("rest.report-supp-bundles"); + has_unsupported_bundle("Has bitstream in an unsuppored bundle", null, CAT_MISC) { + public boolean testItem(Context context, Item item) { + String[] bundleList = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("rest.report-supp-bundles"); return ItemFilterUtil.hasUnsupportedBundle(item, bundleList); - } + } }, - has_small_thumbnail("Has unusually small thumbnail", null, CAT_MISC) - { - public boolean testItem(Context context, Item item) - { - return ItemFilterUtil.countBitstreamSmallerThanMinSize(context, BundleName.THUMBNAIL, item, ItemFilterDefs.MIMES_JPG, "rest.report-thumbnail-min-size") > 0; - } + has_small_thumbnail("Has unusually small thumbnail", null, CAT_MISC) { + public boolean testItem(Context context, Item item) { + return ItemFilterUtil + .countBitstreamSmallerThanMinSize(context, BundleName.THUMBNAIL, item, ItemFilterDefs.MIMES_JPG, + "rest.report-thumbnail-min-size") > 0; + } }, - has_doc_without_text("Has document bitstream without TEXT item", null, ItemFilterDefs.CAT_MIME) - { - public boolean testItem(Context context, Item item) - { - int countDoc = ItemFilterUtil.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); - if (countDoc == 0) - { + has_doc_without_text("Has document bitstream without TEXT item", null, ItemFilterDefs.CAT_MIME) { + public boolean testItem(Context context, Item item) { + int countDoc = ItemFilterUtil + .countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()); + if (countDoc == 0) { return false; } int countText = ItemFilterUtil.countBitstream(BundleName.TEXT, item); return countDoc > countText; - } + } }, - has_original_without_thumbnail("Has original bitstream without thumbnail", null, CAT_MISC) - { - public boolean testItem(Context context, Item item) - { + has_original_without_thumbnail("Has original bitstream without thumbnail", null, CAT_MISC) { + public boolean testItem(Context context, Item item) { int countBit = ItemFilterUtil.countOriginalBitstream(item); - if (countBit == 0) - { + if (countBit == 0) { return false; } int countThumb = ItemFilterUtil.countBitstream(BundleName.THUMBNAIL, item); return countBit > countThumb; - } + } }, - has_invalid_thumbnail_name("Has invalid thumbnail name (assumes one thumbnail for each original)", null, CAT_MISC) - { - public boolean testItem(Context context, Item item) - { + has_invalid_thumbnail_name("Has invalid thumbnail name (assumes one thumbnail for each original)", null, + CAT_MISC) { + public boolean testItem(Context context, Item item) { List originalNames = ItemFilterUtil.getBitstreamNames(BundleName.ORIGINAL, item); List thumbNames = ItemFilterUtil.getBitstreamNames(BundleName.THUMBNAIL, item); - if (thumbNames.size() != originalNames.size()) - { + if (thumbNames.size() != originalNames.size()) { return false; } - for (String name: originalNames) - { - if (!thumbNames.contains(name+".jpg")) - { + for (String name : originalNames) { + if (!thumbNames.contains(name + ".jpg")) { return true; } } return false; - } + } }, - has_non_generated_thumb("Has non generated thumbnail", null, CAT_MISC) - { - public boolean testItem(Context context, Item item) - { - String[] generatedThumbDesc = DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("rest.report-gen-thumbnail-desc"); + has_non_generated_thumb("Has non generated thumbnail", null, CAT_MISC) { + public boolean testItem(Context context, Item item) { + String[] generatedThumbDesc = DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("rest.report-gen-thumbnail-desc"); int countThumb = ItemFilterUtil.countBitstream(BundleName.THUMBNAIL, item); - if (countThumb == 0) - { + if (countThumb == 0) { return false; } int countGen = ItemFilterUtil.countBitstreamByDesc(BundleName.THUMBNAIL, item, generatedThumbDesc); return (countThumb > countGen); - } + } }, - no_license("Doesn't have a license", null, CAT_MISC) - { - public boolean testItem(Context context, Item item) - { + no_license("Doesn't have a license", null, CAT_MISC) { + public boolean testItem(Context context, Item item) { return ItemFilterUtil.countBitstream(BundleName.LICENSE, item) == 0; - } + } }, - has_license_documentation("Has documentation in the license bundle", null, CAT_MISC) - { - public boolean testItem(Context context, Item item) - { + has_license_documentation("Has documentation in the license bundle", null, CAT_MISC) { + public boolean testItem(Context context, Item item) { List names = ItemFilterUtil.getBitstreamNames(BundleName.LICENSE, item); - for (String name: names) - { - if (!name.equals("license.txt")) - { + for (String name : names) { + if (!name.equals("license.txt")) { return true; } } return false; - } - }, - ; - + } + },; + private String title = null; private String description = null; - private EnumItemFilterDefs(String title, String description, String category) - { + private EnumItemFilterDefs(String title, String description, String category) { this.title = title; this.description = description; this.category = category; } - + private EnumItemFilterDefs() { this(null, null, null); } - + public String getName() { return name(); } + public String getTitle() { return title; } + public String getDescription() { return description; } - + private String category = null; public String getCategory() { @@ -226,5 +202,5 @@ public class ItemFilterDefsMisc implements ItemFilterList { public ItemFilterTest[] getFilters() { return EnumItemFilterDefs.values(); - } + } } diff --git a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsPerm.java b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsPerm.java index c2ded2a9f8..daa5d022b2 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsPerm.java +++ b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterDefsPerm.java @@ -20,8 +20,8 @@ import org.dspace.rest.filter.ItemFilterUtil.BundleName; /** * Define the set of use cases for filtering items of interest through the REST API. - * @author Terry Brady, Georgetown University * + * @author Terry Brady, Georgetown University */ public class ItemFilterDefsPerm implements ItemFilterList { protected static AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); @@ -31,87 +31,67 @@ public class ItemFilterDefsPerm implements ItemFilterList { public ItemFilterDefsPerm() { } - public enum EnumItemFilterPermissionDefs implements ItemFilterTest - { + public enum EnumItemFilterPermissionDefs implements ItemFilterTest { has_restricted_original("Item has Restricted Original Bitstream", - "Item has at least one original bitstream that is not accessible to Anonymous user", CAT_PERM) - { - public boolean testItem(Context context, Item item) - { - try - { - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(BundleName.ORIGINAL)) - { + "Item has at least one original bitstream that is not accessible to Anonymous user", + CAT_PERM) { + public boolean testItem(Context context, Item item) { + try { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(BundleName.ORIGINAL.name())) { continue; } - for (Bitstream bit: bundle.getBitstreams()) - { - if (!authorizeService.authorizeActionBoolean(getAnonContext(), bit, org.dspace.core.Constants.READ)) - { + for (Bitstream bit : bundle.getBitstreams()) { + if (!authorizeService + .authorizeActionBoolean(getAnonContext(), bit, org.dspace.core.Constants.READ)) { return true; } } } - } - catch (SQLException e) - { + } catch (SQLException e) { ItemFilterDefsPerm.log.warn("SQL Exception testing original bitstream access " + e.getMessage(), e); } return false; } }, has_restricted_thumbnail("Item has Restricted Thumbnail", - "Item has at least one thumbnail that is not accessible to Anonymous user", CAT_PERM) - { - public boolean testItem(Context context, Item item) - { - try - { - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(BundleName.THUMBNAIL)) - { + "Item has at least one thumbnail that is not accessible to Anonymous user", CAT_PERM) { + public boolean testItem(Context context, Item item) { + try { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(BundleName.THUMBNAIL.name())) { continue; } - for (Bitstream bit: bundle.getBitstreams()) - { - if (!authorizeService.authorizeActionBoolean(getAnonContext(), bit, org.dspace.core.Constants.READ)) - { + for (Bitstream bit : bundle.getBitstreams()) { + if (!authorizeService + .authorizeActionBoolean(getAnonContext(), bit, org.dspace.core.Constants.READ)) { return true; } } } - } - catch (SQLException e) - { - ItemFilterDefsPerm.log.warn("SQL Exception testing thumbnail bitstream access " + e.getMessage(), e); + } catch (SQLException e) { + ItemFilterDefsPerm.log + .warn("SQL Exception testing thumbnail bitstream access " + e.getMessage(), e); } return false; } }, has_restricted_metadata("Item has Restricted Metadata", - "Item has metadata that is not accessible to Anonymous user", CAT_PERM) - { - public boolean testItem(Context context, Item item) - { - try - { - return !authorizeService.authorizeActionBoolean(getAnonContext(), item, org.dspace.core.Constants.READ); - } - catch (SQLException e) - { + "Item has metadata that is not accessible to Anonymous user", CAT_PERM) { + public boolean testItem(Context context, Item item) { + try { + return !authorizeService + .authorizeActionBoolean(getAnonContext(), item, org.dspace.core.Constants.READ); + } catch (SQLException e) { ItemFilterDefsPerm.log.warn("SQL Exception testing item metadata access " + e.getMessage(), e); return false; } } - }, - ; + },; private static Context anonContext; - private static Context getAnonContext() - { + + private static Context getAnonContext() { if (anonContext == null) { anonContext = new Context(); } @@ -121,8 +101,8 @@ public class ItemFilterDefsPerm implements ItemFilterList { private String title = null; private String description = null; - private EnumItemFilterPermissionDefs(String title, String description, String category) - { + + private EnumItemFilterPermissionDefs(String title, String description, String category) { this.title = title; this.description = description; this.category = category; @@ -135,14 +115,17 @@ public class ItemFilterDefsPerm implements ItemFilterList { public String getName() { return name(); } + public String getTitle() { return title; } + public String getDescription() { return description; } private String category = null; + public String getCategory() { return category; } diff --git a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterList.java b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterList.java index 61a830c6ab..f6590e36f8 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterList.java +++ b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterList.java @@ -5,7 +5,7 @@ * * http://www.dspace.org/license/ */ - package org.dspace.rest.filter; +package org.dspace.rest.filter; public interface ItemFilterList { public ItemFilterTest[] getFilters(); diff --git a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterSet.java b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterSet.java index edd667f572..837ed4ee4b 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterSet.java +++ b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterSet.java @@ -11,7 +11,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; - import javax.servlet.ServletContext; import javax.ws.rs.WebApplicationException; @@ -24,34 +23,32 @@ import org.dspace.rest.common.ItemFilter; /** * The set of Item Filter Use Cases to apply to a collection of items. - * + * * @author Terry Brady, Georgetown University - * */ public class ItemFilterSet { protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); static Logger log = Logger.getLogger(ItemFilterSet.class); private List itemFilters; - private ItemFilter allFiltersFilter; + private ItemFilter allFiltersFilter; /** * Construct a set of Item Filters identified by a list string. - * - * @param filterList - * Comma separated list of filter names to include. - * Use {@link org.dspace.rest.common.ItemFilter#ALL} to retrieve all filters. - * @param reportItems - * If true, return item details. If false, return only counts of items. + * + * @param filterList Comma separated list of filter names to include. + * Use {@link org.dspace.rest.common.ItemFilter#ALL} to retrieve all filters. + * @param reportItems If true, return item details. If false, return only counts of items. */ public ItemFilterSet(String filterList, boolean reportItems) { - log.debug(String.format("Create ItemFilterSet: %s", filterList)); + log.debug(String.format("Create ItemFilterSet: %s", filterList)); itemFilters = ItemFilter.getItemFilters(filterList, reportItems); allFiltersFilter = ItemFilter.getAllFiltersFilter(itemFilters); } - + /** * Get the special filter that represents the intersection of all items in the Item Filter Set. + * * @return the special Item Filter that contains items that satisfied every other Item Filter in the Item Filter Set */ public ItemFilter getAllFiltersFilter() { @@ -60,28 +57,25 @@ public class ItemFilterSet { /** * Evaluate an item against the use cases in the Item Filter Set. - * + * * If an item satisfies all items in the Item Filter Set, it should also ve added to the special all items filter. - * - * @param context - * Active DSpace Context - * @param item - * DSpace Object to evaluate - * @param restItem - * REST representation of the DSpace Object being evaluated + * + * @param context Active DSpace Context + * @param item DSpace Object to evaluate + * @param restItem REST representation of the DSpace Object being evaluated */ public void testItem(Context context, org.dspace.content.Item item, Item restItem) { boolean bAllTrue = true; - for(ItemFilter itemFilter: itemFilters) { + for (ItemFilter itemFilter : itemFilters) { if (itemFilter.hasItemTest()) { - bAllTrue &= itemFilter.testItem(context, item, restItem); + bAllTrue &= itemFilter.testItem(context, item, restItem); } } if (bAllTrue && allFiltersFilter != null) { allFiltersFilter.addItem(restItem); } } - + /** * Get all of the Item Filters initialized into the Item Filter Set * @@ -90,63 +84,52 @@ public class ItemFilterSet { public List getItemFilters() { return itemFilters; } - + /** * Evaluate a set of Items against the Item Filters in the Item Filter Set - * Current DSpace Context + * Current DSpace Context * - * @param context - * Current DSpace Context - * @param servletContext - * Context of the servlet container. - * @param childItems - * Collection of Items to Evaluate - * @param save - * If true, save the details of each item that is evaluated - * @param expand - * List of item details to include in the results - * @return - * The number of items evaluated - * @throws WebApplicationException - * Runtime exception for applications. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param context Current DSpace Context + * @param servletContext Context of the servlet container. + * @param childItems Collection of Items to Evaluate + * @param save If true, save the details of each item that is evaluated + * @param expand List of item details to include in the results + * @return The number of items evaluated + * @throws WebApplicationException Runtime exception for applications. + * @throws SQLException An exception that provides information on a database access error or other + * errors. */ - public int processSaveItems(Context context, ServletContext servletContext, Iterator childItems, boolean save, String expand) throws WebApplicationException, SQLException { - return processSaveItems(context, servletContext, childItems, new ArrayList(), save, expand); + public int processSaveItems(Context context, ServletContext servletContext, + Iterator childItems, boolean save, String expand) + throws WebApplicationException, SQLException { + return processSaveItems(context, servletContext, childItems, new ArrayList(), save, expand); } /** * Evaluate a set of Items against the Item Filters in the Item Filter Set * - * @param context - * Current DSpace Context - * @param servletContext - * Context of the servlet container. - * @param childItems - * Collection of Items to Evaluate - * @param items - * List of items to contain saved results - * @param save - * If true, save the details of each item that is evaluated - * @param expand - * List of item details to include in the results - * @return - * The number of items evaluated - * @throws WebApplicationException - * Runtime exception for applications. - * @throws SQLException - * An exception that provides information on a database access error or other errors. + * @param context Current DSpace Context + * @param servletContext Context of the servlet container. + * @param childItems Collection of Items to Evaluate + * @param items List of items to contain saved results + * @param save If true, save the details of each item that is evaluated + * @param expand List of item details to include in the results + * @return The number of items evaluated + * @throws WebApplicationException Runtime exception for applications. + * @throws SQLException An exception that provides information on a database access error or other + * errors. */ - public int processSaveItems(Context context, ServletContext servletContext, Iterator childItems, List items, boolean save, String expand) throws WebApplicationException, SQLException { - int count = 0; - while(childItems.hasNext()) { - count++; + public int processSaveItems(Context context, ServletContext servletContext, + Iterator childItems, List items, boolean save, + String expand) throws WebApplicationException, SQLException { + int count = 0; + while (childItems.hasNext()) { + count++; org.dspace.content.Item item = childItems.next(); log.debug(item.getHandle() + " evaluate."); - if(authorizeService.authorizeActionBoolean(context, item, org.dspace.core.Constants.READ)) { + if (authorizeService.authorizeActionBoolean(context, item, org.dspace.core.Constants.READ)) { Item restItem = new Item(item, servletContext, expand, context); - if(save) { + if (save) { items.add(restItem); } testItem(context, item, restItem); @@ -156,5 +139,5 @@ public class ItemFilterSet { } return count; } - + } diff --git a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterTest.java b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterTest.java index 3649785881..4ef2998e16 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterTest.java +++ b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterTest.java @@ -13,14 +13,17 @@ import org.dspace.core.Context; /** * Item Filter Use Case Interface. * Items will be evaluated against a set of filters. - * + * * @author Terry Brady, Georgetown University - * */ public interface ItemFilterTest { public String getName(); + public String getTitle(); + public String getDescription(); + public String getCategory(); + public boolean testItem(Context context, Item i); } diff --git a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterUtil.java b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterUtil.java index 2a71be5db0..d6d68ba6a7 100644 --- a/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterUtil.java +++ b/dspace-rest/src/main/java/org/dspace/rest/filter/ItemFilterUtil.java @@ -5,13 +5,14 @@ * * http://www.dspace.org/license/ */ - package org.dspace.rest.filter; +package org.dspace.rest.filter; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; +import com.ibm.icu.util.Calendar; import org.apache.log4j.Logger; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; @@ -22,36 +23,40 @@ import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.services.factory.DSpaceServicesFactory; -import com.ibm.icu.util.Calendar; - public class ItemFilterUtil { protected static ItemService itemService = ContentServiceFactory.getInstance().getItemService(); static Logger log = Logger.getLogger(ItemFilterUtil.class); - public enum BundleName{ORIGINAL,TEXT,LICENSE,THUMBNAIL;} + + public enum BundleName { ORIGINAL, TEXT, LICENSE, THUMBNAIL } + + /** + * Default constructor + */ + private ItemFilterUtil() { } static String[] getDocumentMimeTypes() { - return DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("rest.report-mime-document"); + return DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("rest.report-mime-document"); } static String[] getSupportedDocumentMimeTypes() { - return DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("rest.report-mime-document-supported"); + return DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("rest.report-mime-document-supported"); } static String[] getSupportedImageMimeTypes() { - return DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty("rest.report-mime-document-image"); + return DSpaceServicesFactory.getInstance().getConfigurationService() + .getArrayProperty("rest.report-mime-document-image"); } static int countOriginalBitstream(Item item) { return countBitstream(BundleName.ORIGINAL, item); } - static int countBitstream(BundleName bundleName, Item item) - { + static int countBitstream(BundleName bundleName, Item item) { int count = 0; - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(bundleName.name())) - { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(bundleName.name())) { continue; } count += bundle.getBitstreams().size(); @@ -60,17 +65,13 @@ public class ItemFilterUtil { return count; } - static List getBitstreamNames(BundleName bundleName, Item item) - { + static List getBitstreamNames(BundleName bundleName, Item item) { ArrayList names = new ArrayList(); - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(bundleName.name())) - { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(bundleName.name())) { continue; } - for (Bitstream bit: bundle.getBitstreams()) - { + for (Bitstream bit : bundle.getBitstreams()) { names.add(bit.getName()); } } @@ -82,28 +83,19 @@ public class ItemFilterUtil { return countBitstreamMime(context, BundleName.ORIGINAL, item, mimeList); } - static int countBitstreamMime(Context context, BundleName bundleName, Item item, String[] mimeList) - { + static int countBitstreamMime(Context context, BundleName bundleName, Item item, String[] mimeList) { int count = 0; - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(bundleName.name())) - { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(bundleName.name())) { continue; } - for (Bitstream bit: bundle.getBitstreams()) - { - for (String mime: mimeList) - { - try - { - if (bit.getFormat(context).getMIMEType().equals(mime.trim())) - { + for (Bitstream bit : bundle.getBitstreams()) { + for (String mime : mimeList) { + try { + if (bit.getFormat(context).getMIMEType().equals(mime.trim())) { count++; } - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Get format error for bitstream " + bit.getName()); } } @@ -112,26 +104,19 @@ public class ItemFilterUtil { return count; } - static int countBitstreamByDesc(BundleName bundleName, Item item, String[] descList) - { + static int countBitstreamByDesc(BundleName bundleName, Item item, String[] descList) { int count = 0; - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(bundleName.name())) - { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(bundleName.name())) { continue; } - for (Bitstream bit: bundle.getBitstreams()) - { - for (String desc: descList) - { + for (Bitstream bit : bundle.getBitstreams()) { + for (String desc : descList) { String bitDesc = bit.getDescription(); - if (bitDesc == null) - { + if (bitDesc == null) { continue; } - if (bitDesc.equals(desc.trim())) - { + if (bitDesc.equals(desc.trim())) { count++; } } @@ -140,26 +125,19 @@ public class ItemFilterUtil { return count; } - static int countBitstreamSmallerThanMinSize(Context context, BundleName bundleName, Item item, String[] mimeList, String prop) - { + static int countBitstreamSmallerThanMinSize(Context context, BundleName bundleName, Item item, String[] mimeList, + String prop) { long size = DSpaceServicesFactory.getInstance().getConfigurationService().getLongProperty(prop); int count = 0; - try - { - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(bundleName.name())) - { + try { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(bundleName.name())) { continue; } - for (Bitstream bit: bundle.getBitstreams()) - { - for (String mime: mimeList) - { - if (bit.getFormat(context).getMIMEType().equals(mime.trim())) - { - if (bit.getSize() < size) - { + for (Bitstream bit : bundle.getBitstreams()) { + for (String mime : mimeList) { + if (bit.getFormat(context).getMIMEType().equals(mime.trim())) { + if (bit.getSizeBytes() < size) { count++; } } @@ -167,39 +145,32 @@ public class ItemFilterUtil { } } } catch (SQLException e) { + // ignore } return count; } - static int countBitstreamLargerThanMaxSize(Context context, BundleName bundleName, Item item, String[] mimeList, String prop) - { + static int countBitstreamLargerThanMaxSize(Context context, BundleName bundleName, Item item, String[] mimeList, + String prop) { long size = DSpaceServicesFactory.getInstance().getConfigurationService().getLongProperty(prop); int count = 0; - try - { - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(bundleName.name())) - { + try { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(bundleName.name())) { continue; } - for (Bitstream bit: bundle.getBitstreams()) - { - for (String mime: mimeList) - { - if (bit.getFormat(context).getMIMEType().equals(mime.trim())) - { - if (bit.getSize() > size) - { + for (Bitstream bit : bundle.getBitstreams()) { + for (String mime : mimeList) { + if (bit.getFormat(context).getMIMEType().equals(mime.trim())) { + if (bit.getSizeBytes() > size) { count++; } } } } } - } - catch (SQLException e) - { + } catch (SQLException e) { + // ignore } return count; } @@ -208,47 +179,35 @@ public class ItemFilterUtil { return countBitstreamMimeStartsWith(context, BundleName.ORIGINAL, item, prefix); } - static int countBitstreamMimeStartsWith(Context context, BundleName bundleName, Item item, String prefix) - { + static int countBitstreamMimeStartsWith(Context context, BundleName bundleName, Item item, String prefix) { int count = 0; - try - { - for (Bundle bundle: item.getBundles()) - { - if (!bundle.getName().equals(bundleName.name())) - { + try { + for (Bundle bundle : item.getBundles()) { + if (!bundle.getName().equals(bundleName.name())) { continue; } - for (Bitstream bit: bundle.getBitstreams()) - { - if (bit.getFormat(context).getMIMEType().startsWith(prefix)) - { + for (Bitstream bit : bundle.getBitstreams()) { + if (bit.getFormat(context).getMIMEType().startsWith(prefix)) { count++; } } } - } - catch (SQLException e) - { + } catch (SQLException e) { + // ignore } return count; } - static boolean hasUnsupportedBundle(Item item, String[] bundleList) - { - if (bundleList == null) - { + static boolean hasUnsupportedBundle(Item item, String[] bundleList) { + if (bundleList == null) { return false; } ArrayList bundles = new ArrayList(); - for (String bundleName: bundleList) - { + for (String bundleName : bundleList) { bundles.add(bundleName.trim()); } - for (Bundle bundle: item.getBundles()) - { - if (!bundles.contains(bundle.getName())) - { + for (Bundle bundle : item.getBundles()) { + if (!bundles.contains(bundle.getName())) { return true; } } @@ -263,26 +222,19 @@ public class ItemFilterUtil { return countBitstreamMime(context, bundleName, item, mimeList) > 0; } - static boolean hasMetadataMatch(Item item, String fieldList, Pattern regex) - { - if (fieldList.equals("*")) - { - for (MetadataValue md: itemService.getMetadata(item, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY)) - { - if (regex.matcher(md.getValue()).matches()) - { + static boolean hasMetadataMatch(Item item, String fieldList, Pattern regex) { + if (fieldList.equals("*")) { + for (MetadataValue md : itemService + .getMetadata(item, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, + org.dspace.content.Item.ANY, org.dspace.content.Item.ANY)) { + if (regex.matcher(md.getValue()).matches()) { return true; } } - } - else - { - for (String field: fieldList.split(",")) - { - for (MetadataValue md: itemService.getMetadataByMetadataString(item, field.trim())) - { - if (regex.matcher(md.getValue()).matches()) - { + } else { + for (String field : fieldList.split(",")) { + for (MetadataValue md : itemService.getMetadataByMetadataString(item, field.trim())) { + if (regex.matcher(md.getValue()).matches()) { return true; } } @@ -292,35 +244,24 @@ public class ItemFilterUtil { return false; } - static boolean hasOnlyMetadataMatch(Item item, String fieldList, Pattern regex) - { + static boolean hasOnlyMetadataMatch(Item item, String fieldList, Pattern regex) { boolean matches = false; - if (fieldList.equals("*")) - { - for (MetadataValue md: itemService.getMetadata(item, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY)) - { - if (regex.matcher(md.getValue()).matches()) - { + if (fieldList.equals("*")) { + for (MetadataValue md : itemService + .getMetadata(item, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, + org.dspace.content.Item.ANY, org.dspace.content.Item.ANY)) { + if (regex.matcher(md.getValue()).matches()) { matches = true; - } - else - { + } else { return false; } } - } - else - { - for (String field: fieldList.split(",")) - { - for (MetadataValue md: itemService.getMetadataByMetadataString(item, field.trim())) - { - if (regex.matcher(md.getValue()).matches()) - { + } else { + for (String field : fieldList.split(",")) { + for (MetadataValue md : itemService.getMetadataByMetadataString(item, field.trim())) { + if (regex.matcher(md.getValue()).matches()) { matches = true; - } - else - { + } else { return false; } } diff --git a/dspace-rest/src/main/java/org/dspace/utils/DSpaceWebapp.java b/dspace-rest/src/main/java/org/dspace/utils/DSpaceWebapp.java index 6faa68ded4..5d3ce8bfa8 100644 --- a/dspace-rest/src/main/java/org/dspace/utils/DSpaceWebapp.java +++ b/dspace-rest/src/main/java/org/dspace/utils/DSpaceWebapp.java @@ -16,17 +16,13 @@ import org.dspace.app.util.AbstractDSpaceWebapp; * @author Bram Luyten (bram at atmire dot com) */ public class DSpaceWebapp - extends AbstractDSpaceWebapp -{ - public DSpaceWebapp() - { + extends AbstractDSpaceWebapp { + public DSpaceWebapp() { super("REST"); } @Override - public boolean isUI() - { + public boolean isUI() { return false; } } - diff --git a/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml b/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml index ef5d9d31b6..48dcabcfdf 100644 --- a/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml +++ b/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml @@ -10,38 +10,33 @@ --> + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> - - + + - + + - + --> - - + diff --git a/dspace-rest/src/main/webapp/WEB-INF/security-applicationContext.xml b/dspace-rest/src/main/webapp/WEB-INF/security-applicationContext.xml index a0f1a075db..0a70a1b399 100644 --- a/dspace-rest/src/main/webapp/WEB-INF/security-applicationContext.xml +++ b/dspace-rest/src/main/webapp/WEB-INF/security-applicationContext.xml @@ -24,25 +24,28 @@ - + - + - + - + - + @@ -50,12 +53,13 @@ - + - + @@ -66,8 +70,11 @@ - + - - + + \ No newline at end of file diff --git a/dspace-rest/src/main/webapp/WEB-INF/web.xml b/dspace-rest/src/main/webapp/WEB-INF/web.xml index 839bd3c824..df639b9b08 100644 --- a/dspace-rest/src/main/webapp/WEB-INF/web.xml +++ b/dspace-rest/src/main/webapp/WEB-INF/web.xml @@ -8,11 +8,9 @@ http://www.dspace.org/license/ --> - + dspace.request @@ -68,7 +66,7 @@ CONFIDENTIAL - + @@ -98,7 +96,7 @@ org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener - + org.springframework.web.context.ContextLoaderListener @@ -110,4 +108,4 @@ - \ No newline at end of file + diff --git a/dspace-rest/src/main/webapp/static/reports/index.html b/dspace-rest/src/main/webapp/static/reports/index.html index d6634187e9..bc71b0417c 100644 --- a/dspace-rest/src/main/webapp/static/reports/index.html +++ b/dspace-rest/src/main/webapp/static/reports/index.html @@ -52,11 +52,21 @@
    +

    Bitstream data to return

    +
    +
    + +

    Results

    -
    +
    + + + + Export will export one page of results +
    diff --git a/dspace-rest/src/main/webapp/static/reports/query.html b/dspace-rest/src/main/webapp/static/reports/query.html index 3f24956402..5a7a79cb20 100644 --- a/dspace-rest/src/main/webapp/static/reports/query.html +++ b/dspace-rest/src/main/webapp/static/reports/query.html @@ -81,11 +81,21 @@
    +

    Bitstream data to return

    +
    +
    + +

    Item Results

    -
    +
    + + + + Export will export one page of results, increase result limits as needed +
    diff --git a/dspace-rest/src/main/webapp/static/reports/restClient.css b/dspace-rest/src/main/webapp/static/reports/restClient.css index 7e22e01331..d81724ae67 100644 --- a/dspace-rest/src/main/webapp/static/reports/restClient.css +++ b/dspace-rest/src/main/webapp/static/reports/restClient.css @@ -88,4 +88,11 @@ fieldset.catdiv div { .toobig::before { content: "*"; +} +#exlimit { + font-style: italic; +} + +.red { + color: red; } \ No newline at end of file diff --git a/dspace-rest/src/main/webapp/static/reports/restCollReport.js b/dspace-rest/src/main/webapp/static/reports/restCollReport.js index 27fb644361..1d1c04ae07 100644 --- a/dspace-rest/src/main/webapp/static/reports/restCollReport.js +++ b/dspace-rest/src/main/webapp/static/reports/restCollReport.js @@ -9,7 +9,15 @@ var CollReport = function() { Report.call(this); //If sortable.js is included, uncomment the following //this.hasSorttable = function(){return true;} + this.getLangSuffix = function(){ + return "[en]"; + } + //Indicate if Password Authentication is supported + //this.makeAuthLink = function(){return true;}; + //Indicate if Shibboleth Authentication is supported + //this.makeShibLink = function(){return true;}; + this.COLL_LIMIT = 20; this.TOOBIG = 10000; this.loadId = 0; @@ -17,9 +25,13 @@ var CollReport = function() { this.THREADSP = 11; this.ACCIDX_COLL = 1; this.ACCIDX_ITEM = 2; + this.IACCIDX_META = 0; + this.IACCIDX_BIT = 1; + this.IACCIDX_ITEM = 2; this.getDefaultParameters = function(){ return { - "show_fields[]" : [], + "show_fields[]" : [], + "show_fields_bits[]" : [], filters : "", limit : this.COUNT_LIMIT, offset : 0, @@ -30,6 +42,7 @@ var CollReport = function() { this.getCurrentParameters = function(){ return { "show_fields[]" : this.myMetadataFields.getShowFields(), + "show_fields_bits[]" : this.myBitstreamFields.getShowFieldsBits(), filters : this.myFilters.getFilterList(), limit : this.myReportParameters.getLimit(), offset : this.myReportParameters.getOffset(), @@ -46,17 +59,16 @@ var CollReport = function() { $("#itemResults").accordion({ heightStyle: "content", collapsible: true, - active: 1 + active: 2 }); } this.myAuth.callback = function(data) { self.createCollectionTable(); - $("#table tbody tr").remove(); $(".showCollections").bind("click", function(){ self.loadData(); }); - $("#refresh-fields").bind("click", function(){ + $("#refresh-fields,#refresh-fields-bits").bind("click", function(){ self.drawItemTable($("#icollection").val(), $("#ifilter").val(), 0); }); } @@ -399,13 +411,28 @@ var CollReport = function() { self.myHtmlUtil.addTh(tr, field + self.getLangSuffix()); }); } + var bitfields = $("#show-fields-bits select").val(); + if (bitfields != null) { + $.each(bitfields, function(index, bitf){ + self.myHtmlUtil.addTh(tr, bitf); + }); + } + + var expand = "items"; + if (fields != null) { + expand += ",metadata"; + } + if (bitfields != null) { + expand += ",bitstreams"; + } var params = { - expand: fields == null ? "items" : "items,metadata", + expand: expand, limit: self.ITEM_LIMIT, filters: filter, offset: offset, "show_fields[]" : fields, + "show_fields_bits[]" : bitfields, } $.ajax({ @@ -426,16 +453,22 @@ var CollReport = function() { if (fields != null) { $.each(fields, function(index, field){ var text = ""; + var td = self.myHtmlUtil.addTd(tr, ""); $.each(item.metadata, function(mindex,mv){ if (mv.key == field) { - if (text != "") { - text += "
    "; - } - text += mv.value; + td.append($("
    "+mv.value+"
    ")); } }); - self.myHtmlUtil.addTd(tr, text); - }); + }); + } + if (bitfields != null) { + $.each(bitfields, function(index, bitfield){ + var td = self.myHtmlUtil.addTd(tr, ""); + var fieldtext = self.myBitstreamFields.getKeyText(bitfield, item, bitfields); + for(var j=0; j"+fieldtext[j]+"")); + } + }); } }); self.displayItems(filter + " Items in " + data.name, @@ -456,7 +489,8 @@ var CollReport = function() { }, complete: function(xhr, status) { self.spinner.stop(); - $(".showCollections").attr("disabled", false); + $(".showCollections").attr("disabled", false); + $("#itemResults").accordion("option", "active", self.IACCIDX_ITEM); } }); } @@ -476,4 +510,4 @@ CollReport.prototype = Object.create(Report.prototype); $(document).ready(function(){ var myReport=new CollReport(); myReport.init(); -}); +}); \ No newline at end of file diff --git a/dspace-rest/src/main/webapp/static/reports/restQueryReport.js b/dspace-rest/src/main/webapp/static/reports/restQueryReport.js index a237125149..9a8297fb69 100644 --- a/dspace-rest/src/main/webapp/static/reports/restQueryReport.js +++ b/dspace-rest/src/main/webapp/static/reports/restQueryReport.js @@ -10,7 +10,15 @@ var QueryReport = function() { //If sortable.js is included, uncomment the following //this.hasSorttable = function(){return true;} + this.getLangSuffix = function(){ + return "[en]"; + } + //Indicate if Password Authentication is supported + //this.makeAuthLink = function(){return true;}; + //Indicate if Shibboleth Authentication is supported + //this.makeShibLink = function(){return true;}; + this.getDefaultParameters = function(){ return { "collSel[]" : [], @@ -18,12 +26,17 @@ var QueryReport = function() { "query_op[]" : [], "query_val[]" : [], "show_fields[]" : [], + "show_fields_bits[]" : [], "filters" : "", "limit" : this.ITEM_LIMIT, "offset" : 0, }; } this.getCurrentParameters = function(){ + var expand = "parentCollection,metadata"; + if (this.myBitstreamFields.hasBitstreamFields()) { + expand += ",bitstreams"; + } var params = { "query_field[]" : [], "query_op[]" : [], @@ -31,9 +44,10 @@ var QueryReport = function() { "collSel[]" : ($("#collSel").val() == null) ? [""] : $("#collSel").val(), limit : this.myReportParameters.getLimit(), offset : this.myReportParameters.getOffset(), - "expand" : "parentCollection,metadata", + "expand" : expand, filters : this.myFilters.getFilterList(), "show_fields[]" : this.myMetadataFields.getShowFields(), + "show_fields_bits[]" : this.myBitstreamFields.getShowFieldsBits(), }; $("select.query-tool,input.query-tool").each(function() { var paramArr = params[$(this).attr("name")]; @@ -45,6 +59,7 @@ var QueryReport = function() { this.init = function() { this.baseInit(); + var communitySelector = new CommunitySelector(this, $("#collSelector"), this.myReportParameters.params["collSel[]"]); } this.initMetadataFields = function() { @@ -52,7 +67,6 @@ var QueryReport = function() { this.myMetadataFields.load(); } this.myAuth.callback = function(data) { - var communitySelector = new CommunitySelector(self, $("#collSelector"), self.myReportParameters.params["collSel[]"]); $(".query-button").click(function(){self.runQuery();}) } @@ -66,16 +80,17 @@ var QueryReport = function() { headers: self.myAuth.getHeaders(), success: function(data){ data.metadata = $("#show-fields select").val(); + data.bitfields = $("#show-fields-bits select").val(); self.drawItemFilterTable(data); self.spinner.stop(); - $("button").not("#next,#prev").attr("disabled", false); + $("button").not("#next,#prev").attr("disabled", false); }, error: function(xhr, status, errorThrown) { alert("Error in /rest/filtered-items "+ status+ " " + errorThrown); }, complete: function(xhr, status, errorThrown) { self.spinner.stop(); - $("button").not("#next,#prev").attr("disabled", false); + $("button").not("#next,#prev").attr("disabled", false); } }); } @@ -100,6 +115,15 @@ var QueryReport = function() { }); } + if (data.bitfields) { + $.each(data.bitfields, function(index, bitfield) { + if (bitfield != "") { + self.myHtmlUtil.addTh(tr,bitfield).addClass("returnFields"); + mdCols[mdCols.length] = bitfield; + } + }); + } + $.each(data.items, function(index, item){ var tr = self.myHtmlUtil.addTr(itbl); tr.addClass(index % 2 == 0 ? "odd data" : "even data"); @@ -124,6 +148,10 @@ var QueryReport = function() { } } }); + var fieldtext = self.myBitstreamFields.getKeyText(key, item, data.bitfields); + for(var j=0; j"+fieldtext[j]+"")) + } } }); @@ -320,4 +348,4 @@ var QueryableMetadataFields = function(report) { } } } -QueryableMetadataFields.prototype = Object.create(MetadataFields.prototype); +QueryableMetadataFields.prototype = Object.create(MetadataFields.prototype); \ No newline at end of file diff --git a/dspace-rest/src/main/webapp/static/reports/restReport.js b/dspace-rest/src/main/webapp/static/reports/restReport.js index f2ba2ab0e6..3efc67e85e 100644 --- a/dspace-rest/src/main/webapp/static/reports/restReport.js +++ b/dspace-rest/src/main/webapp/static/reports/restReport.js @@ -16,9 +16,13 @@ var Report = function() { //this.ROOTPATH = "/jspui/handle/" //this.ROOTPATH = "/handle/" - //disable this setting if Password Authentication is not supported + //Indicate if Password Authentication is supported this.makeAuthLink = function(){return false;}; + //Indicate if Shibboleth Authentication is supported + this.makeShibLink = function(){return false;}; + this.shibPath = "/Shibboleth.sso/Login"; + //Override this to return obj.id for DSpace 5 versions this.getId = function(obj) { return obj.uuid; @@ -102,6 +106,7 @@ var Report = function() { itemsTitle += " (" + (offset+1) + " - " + last + suff + ")"; $("#prev,#next").attr("disabled",true); $("#itemdiv h3").text(itemsTitle); + $("#exlimit").removeClass("red"); if (offset > 0) $("#prev").attr("disabled", false); $("#prev").off("click").on("click", funcdec); //in case of filters, always allow next @@ -110,9 +115,11 @@ var Report = function() { $("#next").attr("disabled", false); } else if (offset + limit < total) { $("#next").attr("disabled", false); + $("#exlimit").addClass("red"); } else if (limit == total) { //total may only be accurate to one page $("#next").attr("disabled", false); + $("#exlimit").addClass("red"); } $("#next").off("click").on("click", funcinc); } @@ -126,6 +133,11 @@ var Report = function() { this.myMetadataFields.load(); } + this.initBitstreamFields = function() { + this.myBitstreamFields = new BitstreamFields(self); + this.myBitstreamFields.load(); + } + this.baseInit = function() { this.myReportParameters = new ReportParameters( this.getDefaultParameters(), @@ -134,10 +146,12 @@ var Report = function() { this.spinner.spin($("h1")[0]); this.myFilters = new Filters(this.myReportParameters.params["filters"]); this.initMetadataFields(); + this.initBitstreamFields(); + this.getActiveTab = function(){return 1;} $("#metadatadiv").accordion({ heightStyle: "content", collapsible: true, - active: $("#metadatadiv > h3").length - 2 + active: self.getActiveTab() }); $("#export").click(function(){ self.export($("#itemtable tr")); @@ -149,14 +163,19 @@ var Report = function() { this.myAuth.init(); } - this.export = function(rows) { - var itemdata = "data:text/csv;charset=utf-8,"; + this.makeCsv = function(rows) { + var itemdata = ""; rows.each(function(rownum, row){ itemdata += (rownum == 0) ? "" : "\r\n"; $(row).find("td,th").each(function(colnum, col){ itemdata += self.exportCol(colnum, col); }); }); + return itemdata; + } + + this.export = function(rows) { + var itemdata = "data:text/csv;charset=utf-8," + this.makeCsv(rows); var encodedUri = encodeURI(itemdata); window.open(encodedUri); } @@ -175,7 +194,7 @@ var Report = function() { if ($(node).is("hr")) { data += "||"; } else { - data += $(node).text().replace(/\n/g," ").replace(/"/g,"\"\""); + data += $(node).text().replace(/\n/g," ").replace(/"/g,"\"\"").replace(/\s/g," "); if ($(node).is("div:not(:last-child)")) { data += "||"; } @@ -225,6 +244,15 @@ var Auth = function(report) { } }); } + + this.verifyShibLogin = function() { + var self = this; + $.ajax({ + url: "/rest/shibboleth-login", + success: self.authStat + }); + } + this.authStat = function() { var self = this; $.ajax({ @@ -234,20 +262,27 @@ var Auth = function(report) { alert("Error in /rest/status "+ status+ " " + errorThrown); }, success: function(data) { - var user = ""; - if (data.email != undefined) { - user = data.email; - } else { - user = "You are not logged in. Some items may be excluded from reports."; - } - var anchor = $("").text(user); - if (self.report.makeAuthLink()) { - anchor.attr("href","javascript:window.open('authenticate.html','Authenticate (Password Auth Only)','height=200,width=500')"); - } - $("#currentUser").empty().append("Current User: ").append(anchor); - } + var user = ""; + if (data.email != undefined) { + user = data.email; + } else { + user = "You are not logged in. Some items may be excluded from reports."; + } + var anchor = $("").text(user); + if (self.report.makeShibLink()) { + anchor.attr("href", self.report.shibPath + "?target="+document.location); + } + if (self.report.makeAuthLink()) { + anchor.attr("href","javascript:window.open('authenticate.html','Authenticate (Password Auth Only)','height=200,width=500')"); + } + $("#currentUser").empty().append("Current User: ").append(anchor); + if (data.email == undefined && self.report.makeShibLink()) { + self.verifyShibLogin(); + } + } }); } + this.logout = function() { var self = this; $.ajax({ @@ -443,7 +478,6 @@ var MetadataFields = function(report) { } this.drawShowFields = function(pfields) { - if (pfields == null) return; var self = this; var sel = $(""); + sel.attr("multiple","true").attr("size","8").appendTo("#show-fields-bits"); + for(var i=0; i"); @@ -542,7 +701,6 @@ var HtmlUtil = function() { var CommunitySelector = function(report, parent, paramCollSel) { var self = this; - $("#collSel,#collSel option").remove(); var collSel = $(" + + + + + + + + + \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/AuthenticationRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/AuthenticationRestControllerIT.java new file mode 100644 index 0000000000..19107d46b4 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/AuthenticationRestControllerIT.java @@ -0,0 +1,445 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static java.lang.Thread.sleep; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertNotEquals; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Base64; + +import org.dspace.app.rest.builder.GroupBuilder; +import org.dspace.app.rest.matcher.GroupMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.eperson.Group; +import org.dspace.services.ConfigurationService; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; + +/** + * Integration test that covers various authentication scenarios + * + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + * @author Tom Desair (tom dot desair at atmire dot com) + */ +public class AuthenticationRestControllerIT extends AbstractControllerIntegrationTest { + + @Autowired + ConfigurationService configurationService; + + public static final String[] PASS_ONLY = {"org.dspace.authenticate.PasswordAuthentication"}; + public static final String[] SHIB_ONLY = {"org.dspace.authenticate.ShibAuthentication"}; + public static final String[] SHIB_AND_IP = + {"org.dspace.authenticate.IPAuthentication", + "org.dspace.authenticate.ShibAuthentication"}; + + @Before + public void setup() throws Exception { + super.setUp(); + configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", PASS_ONLY); + } + + @Test + public void testStatusAuthenticated() throws Exception { + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authn/status")) + + .andExpect(status().isOk()) + + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))) + + .andExpect(jsonPath("$._links.eperson.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._embedded.eperson.email", is(eperson.getEmail()))) + .andExpect(jsonPath("$._embedded.eperson.groups", contains( + GroupMatcher.matchGroupWithName("Anonymous")))); + } + + @Test + public void testStatusNotAuthenticated() throws Exception { + + getClient().perform(get("/api/authn/status")) + + .andExpect(status().isOk()) + + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(false))) + .andExpect(jsonPath("$.type", is("status"))); + } + + @Test + public void testTwoAuthenticationTokens() throws Exception { + String token1 = getAuthToken(eperson.getEmail(), password); + + //Sleep so tokens are different + sleep(1200); + + String token2 = getAuthToken(eperson.getEmail(), password); + + assertNotEquals(token1, token2); + + getClient(token1).perform(get("/api/authn/status")) + + .andExpect(status().isOk()) + + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))) + + .andExpect(jsonPath("$._links.eperson.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._embedded.eperson.email", is(eperson.getEmail()))); + + getClient(token2).perform(get("/api/authn/status")) + + .andExpect(status().isOk()) + + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))) + + .andExpect(jsonPath("$._links.eperson.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._embedded.eperson.email", is(eperson.getEmail()))); + + } + + @Test + public void testTamperingWithToken() throws Exception { + //Receive a valid token + String token = getAuthToken(eperson.getEmail(), password); + + //Check it is really valid + getClient(token).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))); + + //The group we try to add to our token + context.turnOffAuthorisationSystem(); + Group internalGroup = GroupBuilder.createGroup(context) + .withName("Internal Group") + .build(); + context.restoreAuthSystemState(); + + //Tamper with the token, insert id of group we don't belong to + String[] jwtSplit = token.split("\\."); + + //We try to inject a special group ID to spoof membership + String tampered = new String(Base64.getUrlEncoder().encode( + new String(Base64.getUrlDecoder().decode( + token.split("\\.")[1])) + .replaceAll("\\[]", "[\"" + internalGroup.getID() + "\"]") + .getBytes())); + + String tamperedToken = jwtSplit[0] + "." + tampered + "." + jwtSplit[2]; + + //Try to get authenticated with the tampered token + getClient(tamperedToken).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(false))) + .andExpect(jsonPath("$.type", is("status"))); + } + + @Test + public void testLogout() throws Exception { + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))); + + getClient(token).perform(get("/api/authn/logout")) + .andExpect(status().isNoContent()); + + getClient(token).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(false))) + .andExpect(jsonPath("$.type", is("status"))); + } + + @Test + public void testLogoutInvalidatesAllTokens() throws Exception { + String token1 = getAuthToken(eperson.getEmail(), password); + + //Sleep so tokens are different + sleep(1200); + + String token2 = getAuthToken(eperson.getEmail(), password); + + assertNotEquals(token1, token2); + + getClient(token1).perform(get("/api/authn/logout")); + + getClient(token1).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(false))) + .andExpect(jsonPath("$.type", is("status"))); + + + getClient(token2).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(false))) + .andExpect(jsonPath("$.type", is("status"))); + } + + @Test + public void testRefreshToken() throws Exception { + String token = getAuthToken(eperson.getEmail(), password); + + //Sleep so tokens are different + sleep(1200); + + String newToken = getClient(token).perform(post("/api/authn/login")) + .andExpect(status().isOk()) + .andReturn().getResponse().getHeader("Authorization"); + + assertNotEquals(token, newToken); + + getClient(newToken).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))); + } + + @Test + public void testReuseTokenWithDifferentIP() throws Exception { + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/authn/status")) + + .andExpect(status().isOk()) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))); + + getClient(token).perform(get("/api/authn/status") + .header("X-FORWARDED-FOR", "1.1.1.1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(false))) + .andExpect(jsonPath("$.type", is("status"))); + + + getClient(token).perform(get("/api/authn/status") + .with(ip("1.1.1.1"))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(false))) + .andExpect(jsonPath("$.type", is("status"))); + } + + @Test + public void testFailedLoginResponseCode() throws Exception { + getClient().perform(post("/api/authn/login") + .param("user", eperson.getEmail()).param("password", "fakePassword")) + + .andExpect(status().isUnauthorized()); + } + + @Test + public void testLoginLogoutStatusLink() throws Exception { + getClient().perform(get("/api/authn")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._links.login.href", endsWith("login"))) + .andExpect(jsonPath("$._links.logout.href", endsWith("logout"))) + .andExpect(jsonPath("$._links.status.href", endsWith("status"))); + } + + /** + * Check if we can just request a new token after we logged out + * + * @throws Exception + */ + @Test + public void testLoginAgainAfterLogout() throws Exception { + String token = getAuthToken(eperson.getEmail(), password); + + //Check if we have a valid token + getClient(token).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))); + + //Logout + getClient(token).perform(get("/api/authn/logout")) + .andExpect(status().isNoContent()); + + //Check if we are actually logged out + getClient(token).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(false))) + .andExpect(jsonPath("$.type", is("status"))); + + //request a new token + token = getAuthToken(eperson.getEmail(), password); + + //Check if we succesfully authenticated again + getClient(token).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))); + + + } + + @Test + public void testLoginEmptyRequest() throws Exception { + getClient().perform(post("/api/authn/login")) + .andExpect(status().isUnauthorized()) + .andExpect(status().reason(containsString("Login failed"))); + } + + @Test + public void testLoginGetRequest() throws Exception { + getClient().perform(get("/api/authn/login") + .param("user", eperson.getEmail()) + .param("password", password)) + .andExpect(status().isMethodNotAllowed()); + } + + @Test + public void testShibbolethLoginRequestAttribute() throws Exception { + context.turnOffAuthorisationSystem(); + //Enable Shibboleth login + configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", SHIB_ONLY); + + //Create a reviewers group + Group reviewersGroup = GroupBuilder.createGroup(context) + .withName("Reviewers") + .build(); + + //Faculty members are assigned to the Reviewers group + configurationService.setProperty("authentication-shibboleth.role.faculty", "Reviewers"); + context.restoreAuthSystemState(); + + getClient().perform(post("/api/authn/login").header("Referer", "http://my.uni.edu")) + .andExpect(status().isUnauthorized()) + .andExpect(header().string("WWW-Authenticate", + "shibboleth realm=\"DSpace REST API\", " + + "location=\"/Shibboleth.sso/Login?target=http%3A%2F%2Fmy.uni.edu\"")); + + //Simulate that a shibboleth authentication has happened + + String token = getClient().perform(post("/api/authn/login") + .requestAttr("SHIB-MAIL", eperson.getEmail()) + .requestAttr("SHIB-SCOPED-AFFILIATION", "faculty;staff")) + .andExpect(status().isOk()) + .andReturn().getResponse().getHeader(AUTHORIZATION_HEADER); + + getClient(token).perform(get("/api/authn/status")) + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))) + .andExpect(jsonPath("$._links.eperson.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._embedded.eperson.email", is(eperson.getEmail()))) + .andExpect(jsonPath("$._embedded.eperson.groups", containsInAnyOrder( + GroupMatcher.matchGroupWithName("Anonymous"), GroupMatcher.matchGroupWithName("Reviewers")))); + } + + @Test + public void testShibbolethLoginRequestHeaderWithIpAuthentication() throws Exception { + configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", SHIB_AND_IP); + configurationService.setProperty("authentication-ip.Administrator", "123.123.123.123"); + + + getClient().perform(post("/api/authn/login") + .header("Referer", "http://my.uni.edu") + .with(ip("123.123.123.123"))) + .andExpect(status().isUnauthorized()) + .andExpect(header().string("WWW-Authenticate", + "ip realm=\"DSpace REST API\", shibboleth realm=\"DSpace REST API\", " + + "location=\"/Shibboleth.sso/Login?target=http%3A%2F%2Fmy.uni.edu\"")); + + //Simulate that a shibboleth authentication has happened + String token = getClient().perform(post("/api/authn/login") + .with(ip("123.123.123.123")) + .header("SHIB-MAIL", eperson.getEmail())) + .andExpect(status().isOk()) + .andReturn().getResponse().getHeader(AUTHORIZATION_HEADER); + + getClient(token).perform(get("/api/authn/status") + .with(ip("123.123.123.123"))) + .andDo(MockMvcResultHandlers.print()) + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))) + .andExpect(jsonPath("$._links.eperson.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._embedded.eperson.email", is(eperson.getEmail()))) + .andExpect(jsonPath("$._embedded.eperson.groups", containsInAnyOrder( + GroupMatcher.matchGroupWithName("Administrator"), + GroupMatcher.matchGroupWithName("Anonymous")))); + + //Simulate that a new shibboleth authentication has happened from another IP + token = getClient().perform(post("/api/authn/login") + .with(ip("234.234.234.234")) + .header("SHIB-MAIL", eperson.getEmail())) + .andExpect(status().isOk()) + .andReturn().getResponse().getHeader(AUTHORIZATION_HEADER); + + getClient(token).perform(get("/api/authn/status") + .with(ip("234.234.234.234"))) + .andDo(MockMvcResultHandlers.print()) + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.okay", is(true))) + .andExpect(jsonPath("$.authenticated", is(true))) + .andExpect(jsonPath("$.type", is("status"))) + .andExpect(jsonPath("$._links.eperson.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._embedded.eperson.email", is(eperson.getEmail()))) + .andExpect(jsonPath("$._embedded.eperson.groups", contains( + GroupMatcher.matchGroupWithName("Anonymous")))); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamContentRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamContentRestControllerIT.java new file mode 100644 index 0000000000..36d838daa9 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamContentRestControllerIT.java @@ -0,0 +1,420 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.io.Writer; +import java.util.UUID; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.CharEncoding; +import org.apache.commons.lang3.StringUtils; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.text.PDFTextStripper; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.dspace.app.rest.builder.BitstreamBuilder; +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.GroupBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.disseminate.CitationDocumentServiceImpl; +import org.dspace.eperson.Group; +import org.dspace.services.ConfigurationService; +import org.dspace.solr.MockSolrServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Integration test to test the /api/core/bitstreams/[id]/content endpoint + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + */ +public class BitstreamContentRestControllerIT extends AbstractControllerIntegrationTest { + + private MockSolrServer mockSolrServer; + + @Autowired + private ConfigurationService configurationService; + + @Autowired + private CitationDocumentServiceImpl citationDocumentService; + + @Before + public void setup() throws Exception { + super.setUp(); + mockSolrServer = new MockSolrServer("statistics"); + mockSolrServer.getSolrServer().deleteByQuery("*:*"); + mockSolrServer.getSolrServer().commit(); + configurationService.setProperty("citation-page.enable_globally", false); + } + + @After + public void destroy() throws Exception { + super.destroy(); + mockSolrServer.destroy(); + } + + @Test + public void retrieveFullBitstream() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community and one collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. A public item with a bitstream + String bitstreamContent = "0123456789"; + + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .build(); + + Bitstream bitstream = BitstreamBuilder + .createBitstream(context, publicItem1, is) + .withName("Test bitstream") + .withDescription("This is a bitstream to test range requests") + .withMimeType("text/plain") + .build(); + + //** WHEN ** + //We download the bitstream + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content")) + + //** THEN ** + .andExpect(status().isOk()) + + //The Content Length must match the full length + .andExpect(header().longValue("Content-Length", bitstreamContent.getBytes().length)) + //The server should indicate we support Range requests + .andExpect(header().string("Accept-Ranges", "bytes")) + //The ETag has to be based on the checksum + .andExpect(header().string("ETag", bitstream.getChecksum())) + //We expect the content type to match the bitstream mime type + .andExpect(content().contentType("text/plain")) + //THe bytes of the content must match the original content + .andExpect(content().bytes(bitstreamContent.getBytes())); + + //A If-None-Match HEAD request on the ETag must tell is the bitstream is not modified + getClient().perform(head("/api/core/bitstreams/" + bitstream.getID() + "/content") + .header("If-None-Match", bitstream.getChecksum())) + .andExpect(status().isNotModified()); + + //The download and head request should also be logged as a statistics record + checkNumberOfStatsRecords(bitstream, 2); + } + } + + @Test + public void retrieveRangeBitstream() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community and one collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. A public item with a bitstream + String bitstreamContent = "0123456789"; + + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .build(); + + Bitstream bitstream = BitstreamBuilder + .createBitstream(context, publicItem1, is) + .withName("Test bitstream") + .withDescription("This is a bitstream to test range requests") + .withMimeType("text/plain") + .build(); + + //** WHEN ** + //We download only a specific byte range of the bitstream + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content") + .header("Range", "bytes=1-3")) + + //** THEN ** + .andExpect(status().is(206)) + + //The Content Length must match the requested range + .andExpect(header().longValue("Content-Length", 3)) + //The server should indicate we support Range requests + .andExpect(header().string("Accept-Ranges", "bytes")) + //The ETag has to be based on the checksum + .andExpect(header().string("ETag", bitstream.getChecksum())) + //The response should give us details about the range + .andExpect(header().string("Content-Range", "bytes 1-3/10")) + //We expect the content type to match the bitstream mime type + .andExpect(content().contentType("text/plain")) + //We only expect the bytes 1, 2 and 3 + .andExpect(content().bytes("123".getBytes())); + + //** WHEN ** + //We download the rest of the range + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content") + .header("Range", "bytes=4-")) + + //** THEN ** + .andExpect(status().is(206)) + + //The Content Length must match the requested range + .andExpect(header().longValue("Content-Length", 6)) + //The server should indicate we support Range requests + .andExpect(header().string("Accept-Ranges", "bytes")) + //The ETag has to be based on the checksum + .andExpect(header().string("ETag", bitstream.getChecksum())) + //The response should give us details about the range + .andExpect(header().string("Content-Range", "bytes 4-9/10")) + //We expect the content type to match the bitstream mime type + .andExpect(content().contentType("text/plain")) + //We all remaining bytes, starting at byte 4 + .andExpect(content().bytes("456789".getBytes())); + + //Check that NO statistics record was logged for the Range requests + checkNumberOfStatsRecords(bitstream, 0); + } + } + + @Test + public void testBitstreamNotFound() throws Exception { + getClient().perform(get("/api/core/bitstreams/" + UUID.randomUUID() + "/content")) + .andExpect(status().isNotFound()); + } + + @Test + public void testEmbargoedBitstream() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community and one collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. A public item with an embargoed bitstream + String bitstreamContent = "Embargoed!"; + + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .build(); + + Bitstream bitstream = BitstreamBuilder + .createBitstream(context, publicItem1, is) + .withName("Test Embargoed Bitstream") + .withDescription("This bitstream is embargoed") + .withMimeType("text/plain") + .withEmbargoPeriod("6 months") + .build(); + + //** WHEN ** + //We download the bitstream + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content")) + + //** THEN ** + .andExpect(status().isUnauthorized()); + + //An unauthorized request should not log statistics + checkNumberOfStatsRecords(bitstream, 0); + } + } + + @Test + public void testPrivateBitstream() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community and one collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. A public item with a private bitstream + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .build(); + + Group internalGroup = GroupBuilder.createGroup(context) + .withName("Internal Group") + .build(); + + String bitstreamContent = "Private!"; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + + Bitstream bitstream = BitstreamBuilder + .createBitstream(context, publicItem1, is) + .withName("Test Embargoed Bitstream") + .withDescription("This bitstream is embargoed") + .withMimeType("text/plain") + .withReaderGroup(internalGroup) + .build(); + + //** WHEN ** + //We download the bitstream + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content")) + + //** THEN ** + .andExpect(status().isUnauthorized()); + + //An unauthorized request should not log statistics + checkNumberOfStatsRecords(bitstream, 0); + + } + } + + private void checkNumberOfStatsRecords(Bitstream bitstream, int expectedNumberOfStatsRecords) + throws SolrServerException, IOException { + mockSolrServer.getSolrServer().commit(); + + SolrQuery query = new SolrQuery("id:\"" + bitstream.getID() + "\"") + .setRows(0) + .setStart(0); + QueryResponse queryResponse = mockSolrServer.getSolrServer().query(query); + assertEquals(expectedNumberOfStatsRecords, queryResponse.getResults().getNumFound()); + } + + @Test + public void retrieveCitationCoverpageOfBitstream() throws Exception { + configurationService.setProperty("citation-page.enable_globally", true); + citationDocumentService.afterPropertiesSet(); + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community and one collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. A public item with a bitstream + File originalPdf = new File(testProps.getProperty("test.bitstream")); + + + try (InputStream is = new FileInputStream(originalPdf)) { + + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item citation cover page test 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .build(); + + Bitstream bitstream = BitstreamBuilder + .createBitstream(context, publicItem1, is) + .withName("Test bitstream") + .withDescription("This is a bitstream to test the citation cover page.") + .withMimeType("application/pdf") + .build(); + + //** WHEN ** + //We download the bitstream + byte[] content = getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content")) + + //** THEN ** + .andExpect(status().isOk()) + + //The Content Length must match the full length + .andExpect(header().string("Content-Length", not(nullValue()))) + //The server should indicate we support Range requests + .andExpect(header().string("Accept-Ranges", "bytes")) + //The ETag has to be based on the checksum + .andExpect(header().string("ETag", bitstream.getChecksum())) + //We expect the content type to match the bitstream mime type + .andExpect(content().contentType("application/pdf")) + //THe bytes of the content must match the original content + .andReturn().getResponse().getContentAsByteArray(); + + // The citation cover page contains the item title. + // We will now verify that the pdf text contains this title. + String pdfText = extractPDFText(content); + System.out.println(pdfText); + assertTrue(StringUtils.contains(pdfText,"Public item citation cover page test 1")); + + // The dspace-api/src/test/data/dspaceFolder/assetstore/ConstitutionofIreland.pdf file contains 64 pages, + // manually counted + 1 citation cover page + assertEquals(65,getNumberOfPdfPages(content)); + + //A If-None-Match HEAD request on the ETag must tell is the bitstream is not modified + getClient().perform(head("/api/core/bitstreams/" + bitstream.getID() + "/content") + .header("If-None-Match", bitstream.getChecksum())) + .andExpect(status().isNotModified()); + + //The download and head request should also be logged as a statistics record + checkNumberOfStatsRecords(bitstream, 2); + } + } + + private String extractPDFText(byte[] content) throws IOException { + PDFTextStripper pts = new PDFTextStripper(); + pts.setSortByPosition(true); + + try (ByteArrayInputStream source = new ByteArrayInputStream(content); + Writer writer = new StringWriter(); + PDDocument pdfDoc = PDDocument.load(source)) { + + pts.writeText(pdfDoc, writer); + return writer.toString(); + } + } + + private int getNumberOfPdfPages(byte[] content) throws IOException { + try (ByteArrayInputStream source = new ByteArrayInputStream(content); + PDDocument pdfDoc = PDDocument.load(source)) { + return pdfDoc.getNumberOfPages(); + } + } + + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java new file mode 100644 index 0000000000..9a46c1412d --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java @@ -0,0 +1,98 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.builder.BitstreamFormatBuilder; +import org.dspace.app.rest.matcher.BitstreamFormatMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.BitstreamFormat; +import org.hamcrest.Matchers; +import org.junit.Ignore; +import org.junit.Test; + +/** + * @author Jonas Van Goolen - (jonas@atmire.com) + */ + +public class BitstreamFormatRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + public void findAllPaginationTest() throws Exception { + getClient().perform(get("/api/core/bitstreamformats")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$._links.self.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.self.href", endsWith("/api/core/bitstreamformats"))) + ; + } + + @Test + @Ignore + public void unknownFormatRequiredByDefault() throws Exception { + getClient().perform(get("/api/core/bitstreamformats")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andExpect(jsonPath("$._links.self.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.self.href", endsWith("/api/core/bitstreamformats"))) + .andExpect(jsonPath("$._embedded.bitstreamformats", Matchers.is( + BitstreamFormatMatcher.matchBitstreamFormatMimeType("Unknown") + ))); + } + + @Test + @Ignore + public void findAllMimeTypeCheck() throws Exception { + context.turnOffAuthorisationSystem(); + BitstreamFormat bitstreamFormat = BitstreamFormatBuilder.createBitstreamFormat(context) + .withMimeType("application/octet-stream") + .withDescription("Description") + .build(); + getClient().perform(get("/api/core/bitstreamformats")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$._embedded.bitstreamformats", Matchers.contains( + BitstreamFormatMatcher + .matchBitstreamFormat(bitstreamFormat.getMIMEType(), bitstreamFormat.getDescription()) + ))) + ; + + } + + @Test + @Ignore + public void findOne() throws Exception { + context.turnOffAuthorisationSystem(); + BitstreamFormat bitstreamFormat = BitstreamFormatBuilder.createBitstreamFormat(context) + .withMimeType("application/octet-stream") + .withDescription("Description") + .build(); + + getClient().perform(get("/api/core/bitstreamformats/" + bitstreamFormat.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.description", is(bitstreamFormat.getDescription()))) + .andExpect(jsonPath("$.mimetype", is(bitstreamFormat.getMIMEType()))) + .andExpect(jsonPath("$.type", is("bitstreamformat"))) + .andExpect(jsonPath("$._links.self.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.self.href", + endsWith("/api/core/bitstreamformats/" + bitstreamFormat.getID()))) + ; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java new file mode 100644 index 0000000000..49cc5f2bdd --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java @@ -0,0 +1,590 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; +import java.util.UUID; + +import org.apache.commons.codec.CharEncoding; +import org.apache.commons.io.IOUtils; +import org.dspace.app.rest.builder.BitstreamBuilder; +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.matcher.BitstreamFormatMatcher; +import org.dspace.app.rest.matcher.BitstreamMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.service.BitstreamService; +import org.hamcrest.Matchers; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class BitstreamRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Autowired + private BitstreamService bitstreamService; + + @Test + public void findAllTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public items that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("description") + .withMimeType("text/plain") + .build(); + } + + //Add a bitstream to an item + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream1") + .withDescription("description123") + .withMimeType("text/plain") + .build(); + } + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/core/bitstreams/")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.bitstreams", Matchers.containsInAnyOrder( + BitstreamMatcher.matchBitstreamEntry(bitstream), + BitstreamMatcher.matchBitstreamEntry(bitstream1) + ))); + } + + @Test + public void findAllPaginationTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public items that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("descr") + .withMimeType("text/plain") + .build(); + } + + //Add a bitstream to an item + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream1") + .withDescription("desscrip1") + .withMimeType("text/plain") + .build(); + } + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/core/bitstreams/") + .param("size", "1")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.bitstreams", Matchers.contains( + BitstreamMatcher.matchBitstreamEntry(bitstream)) + )) + .andExpect(jsonPath("$._embedded.bitstreams", Matchers.not( + Matchers.contains( + BitstreamMatcher.matchBitstreamEntry(bitstream1)) + ) + )) + + ; + + getClient(token).perform(get("/api/core/bitstreams/") + .param("size", "1") + .param("page", "1")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.bitstreams", Matchers.contains( + BitstreamMatcher.matchBitstreamEntry(bitstream1) + ))) + .andExpect(jsonPath("$._embedded.bitstreams", Matchers.not( + Matchers.contains( + BitstreamMatcher.matchBitstreamEntry(bitstream) + ) + ))); + + getClient().perform(get("/api/core/bitstreams/")) + .andExpect(status().isUnauthorized()); + } + + //TODO Re-enable test after https://jira.duraspace.org/browse/DS-3774 is fixed + @Ignore + @Test + public void findAllWithDeletedTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public items that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .build(); + + String bitstreamContent = "This is an archived bitstream"; + //Add a bitstream to an item + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withMimeType("text/plain") + .build(); + } + + //Add a bitstream to an item + bitstreamContent = "This is a deleted bitstream"; + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream1") + .withMimeType("text/plain") + .build(); + } + + //Delete the last bitstream + bitstreamService.delete(context, bitstream1); + context.commit(); + + getClient().perform(get("/api/core/bitstreams/")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.bitstreams", contains( + BitstreamMatcher.matchBitstreamEntry(bitstream) + ))) + + ; + } + + @Test + public void findOneBitstreamTest() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public items that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("Description") + .withMimeType("text/plain") + .build(); + } + + //Add a bitstream to an item + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream1") + .withDescription("Description1") + .withMimeType("text/plain") + .build(); + } + + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", BitstreamMatcher.matchBitstreamEntry(bitstream))) + .andExpect(jsonPath("$", not(BitstreamMatcher.matchBitstreamEntry(bitstream1)))) + ; + + } + + @Test + public void findOneBitstreamRelsTest() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public items that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("Description") + .withMimeType("text/plain") + .build(); + } + + //Add a bitstream to an item + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream1") + .withDescription("Description1234") + .withMimeType("text/plain") + .build(); + } + + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/format")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", BitstreamFormatMatcher.matchBitstreamFormatMimeType("text/plain"))) + ; + + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content")) + .andExpect(status().isOk()) + .andExpect(content().string("ThisIsSomeDummyText")) + ; + + } + + @Test + public void findOneLogoBitstreamTest() throws Exception { + + // We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // ** GIVEN ** + // 1. A community with a logo + parentCommunity = CommunityBuilder.createCommunity(context).withName("Community").withLogo("logo_community") + .build(); + + // 2. A collection with a logo + Collection col = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection") + .withLogo("logo_collection").build(); + + getClient().perform(get("/api/core/bitstreams/" + parentCommunity.getLogo().getID())) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + col.getLogo().getID())).andExpect(status().isOk()); + + } + + @Test + public void findOneLogoBitstreamRelsTest() throws Exception { + + // We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // ** GIVEN ** + // 1. A community with a logo + parentCommunity = CommunityBuilder.createCommunity(context).withName("Community").withLogo("logo_community") + .build(); + + // 2. A collection with a logo + Collection col = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection") + .withLogo("logo_collection").build(); + + getClient().perform(get("/api/core/bitstreams/" + parentCommunity.getLogo().getID() + "/content")) + .andExpect(status().isOk()).andExpect(content().string("logo_community")); + + getClient().perform(get("/api/core/bitstreams/" + col.getLogo().getID() + "/content")) + .andExpect(status().isOk()).andExpect(content().string("logo_collection")); + } + + @Test + public void findOneWrongUUID() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/core/bitstreams/" + UUID.randomUUID())) + .andExpect(status().isNotFound()) + ; + + } + + @Test + public void deleteOne() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public items that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("Description") + .withMimeType("text/plain") + .build(); + } + + String token = getAuthToken(admin.getEmail(), password); + + // Delete + getClient(token).perform(delete("/api/core/bitstreams/" + bitstream.getID())) + .andExpect(status().is(204)); + + // Verify 404 after delete + getClient(token).perform(get("/api/core/bitstreams/" + bitstream.getID())) + .andExpect(status().isNotFound()); + } + + @Test + public void deleteUnauthorized() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public items that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("Description") + .withMimeType("text/plain") + .build(); + } + + String token = getAuthToken(eperson.getEmail(), password); + + // Delete using an unauthorized user + getClient(token).perform(delete("/api/core/bitstreams/" + bitstream.getID())) + .andExpect(status().isForbidden()); + + // Verify the bitstream is still here + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID())) + .andExpect(status().isOk()); + } + + @Test + public void deleteForbidden() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public items that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("Description") + .withMimeType("text/plain") + .build(); + } + + // Delete as anonymous + getClient().perform(delete("/api/core/bitstreams/" + bitstream.getID())) + .andExpect(status().isUnauthorized()); + + // Verify the bitstream is still here + getClient().perform(get("/api/core/bitstreams/" + bitstream.getID())) + .andExpect(status().isOk()); + } + + @Test + public void deleteLogo() throws Exception { + // We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // ** GIVEN ** + // 1. A community with a logo + parentCommunity = CommunityBuilder.createCommunity(context).withName("Community").withLogo("logo_community") + .build(); + + // 2. A collection with a logo + Collection col = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection") + .withLogo("logo_collection").build(); + + String token = getAuthToken(admin.getEmail(), password); + + // 422 error when trying to DELETE parentCommunity logo + getClient(token).perform(delete("/api/core/bitstreams/" + parentCommunity.getLogo().getID())) + .andExpect(status().is(422)); + + // 422 error when trying to DELETE collection logo + getClient(token).perform(delete("/api/core/bitstreams/" + col.getLogo().getID())) + .andExpect(status().is(422)); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java new file mode 100644 index 0000000000..0365910570 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java @@ -0,0 +1,501 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.GroupBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.matcher.BrowseEntryResourceMatcher; +import org.dspace.app.rest.matcher.BrowseIndexMatcher; +import org.dspace.app.rest.matcher.ItemMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.eperson.Group; +import org.junit.Test; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; + +/** + * Integration test to test the /api/discover/browses endpoint + * (Class has to start or end with IT to be picked up by the failsafe plugin) + * + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + * @author Tom Desair (tom dot desair at atmire dot com) + */ +public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void findAll() throws Exception { + //When we call the root endpoint + getClient().perform(get("/api/discover/browses")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //Our default Discovery config has 4 browse indexes so we expect this to be reflected in the page + // object + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(4))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + //The array of browse index should have a size 4 + .andExpect(jsonPath("$._embedded.browses", hasSize(4))) + + //Check that all (and only) the default browse indexes are present + .andExpect(jsonPath("$._embedded.browses", containsInAnyOrder( + BrowseIndexMatcher.dateIssuedBrowseIndex("asc"), + BrowseIndexMatcher.contributorBrowseIndex("asc"), + BrowseIndexMatcher.titleBrowseIndex("asc"), + BrowseIndexMatcher.subjectBrowseIndex("asc") + ))) + ; + } + + @Test + public void findBrowseByTitle() throws Exception { + //When we call the root endpoint + getClient().perform(get("/api/discover/browses/title")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //Check that the JSON root matches the expected browse index + .andExpect(jsonPath("$", BrowseIndexMatcher.titleBrowseIndex("asc"))) + ; + } + + @Test + public void findBrowseByDateIssued() throws Exception { + //When we call the root endpoint + getClient().perform(get("/api/discover/browses/dateissued")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //Check that the JSON root matches the expected browse index + .andExpect(jsonPath("$", BrowseIndexMatcher.dateIssuedBrowseIndex("asc"))) + ; + } + + @Test + public void findBrowseByContributor() throws Exception { + //When we call the root endpoint + getClient().perform(get("/api/discover/browses/author")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //Check that the JSON root matches the expected browse index + .andExpect(jsonPath("$", BrowseIndexMatcher.contributorBrowseIndex("asc"))) + ; + } + + @Test + public void findBrowseBySubject() throws Exception { + //When we call the root endpoint + getClient().perform(get("/api/discover/browses/subject")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //Check that the JSON root matches the expected browse index + .andExpect(jsonPath("$", BrowseIndexMatcher.subjectBrowseIndex("asc"))) + ; + } + + @Test + public void findBrowseBySubjectEntries() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find which subjects are currently in the repository + getClient().perform(get("/api/discover/browses/subject/entries")) + + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.size", is(20))) + //Check that there are indeed 3 different subjects + .andExpect(jsonPath("$.page.totalElements", is(3))) + //Check the embedded resources and that they're sorted alphabetically + //Check that the subject matches as expected + //Verify that they're sorted alphabetically + .andExpect(jsonPath("$._embedded.browseEntries", + contains(BrowseEntryResourceMatcher.matchBrowseEntry("AnotherTest", 1), + BrowseEntryResourceMatcher.matchBrowseEntry("ExtraEntry", 3), + BrowseEntryResourceMatcher.matchBrowseEntry("TestingForMore", 2) + ))); + + getClient().perform(get("/api/discover/browses/subject/entries") + .param("sort", "value,desc")) + + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + .andDo(MockMvcResultHandlers.print()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.size", is(20))) + //Check that there are indeed 3 different subjects + .andExpect(jsonPath("$.page.totalElements", is(3))) + //Check the embedded resources and that they're sorted alphabetically + //Check that the subject matches as expected + //Verify that they're sorted alphabetically + .andExpect(jsonPath("$._embedded.browseEntries", + contains(BrowseEntryResourceMatcher.matchBrowseEntry("TestingForMore", 2), + BrowseEntryResourceMatcher.matchBrowseEntry("ExtraEntry", 3), + BrowseEntryResourceMatcher.matchBrowseEntry("AnotherTest", 1) + ))); + } + + @Test + public void findBrowseBySubjectItems() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Two public items with the same subject and another public item that contains that same subject, but also + // another one + // All of the items are readable by an Anonymous user + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("zPublic item more") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry").withSubject("AnotherTest") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 3") + .withIssueDate("2016-02-14") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + //** WHEN ** + //An anonymous user browses the items that correspond with the ExtraEntry subject query + getClient().perform(get("/api/discover/browses/subject/items") + .param("filterValue", "ExtraEntry")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be only one element, the one that we've added with the requested subject + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andExpect(jsonPath("$.page.size", is(20))) + //Verify that the title of the public and embargoed items are present and sorted descending + .andExpect(jsonPath("$._embedded.items", contains( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, "zPublic item more", "2017-10-17") + ))); + + //** WHEN ** + //An anonymous user browses the items that correspond with the AnotherTest subject query + getClient().perform(get("/api/discover/browses/subject/items") + .param("filterValue", "AnotherTest")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be only three elements, the ones that we've added with the requested subject + .andExpect(jsonPath("$.page.totalElements", is(3))) + .andExpect(jsonPath("$.page.size", is(20))) + //Verify that the title of the public and embargoed items are present and sorted descending + .andExpect(jsonPath("$._embedded.items", contains( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, "Public item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, "Public item 3", "2016-02-14"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, "zPublic item more", "2017-10-17") + ))); + + } + + @Test + public void findBrowseByTitleItems() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Two public items that are readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("Java").withSubject("Unit Testing") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("Angular").withSubject("Unit Testing") + .build(); + + //3. An item that has been made private + Item privateItem = ItemBuilder.createItem(context, col1) + .withTitle("This is a private item") + .withIssueDate("2015-03-12") + .withAuthor("Duck, Donald") + .withSubject("Cartoons").withSubject("Ducks") + .makeUnDiscoverable() + .build(); + + //4. An item with an item-level embargo + Item embargoedItem = ItemBuilder.createItem(context, col2) + .withTitle("An embargoed publication") + .withIssueDate("2017-08-10") + .withAuthor("Mouse, Mickey") + .withSubject("Cartoons").withSubject("Mice") + .withEmbargoPeriod("12 months") + .build(); + + //5. An item that is only readable for an internal groups + Group internalGroup = GroupBuilder.createGroup(context) + .withName("Internal Group") + .build(); + + Item internalItem = ItemBuilder.createItem(context, col2) + .withTitle("Internal publication") + .withIssueDate("2016-09-19") + .withAuthor("Doe, John") + .withSubject("Unknown") + .withReaderGroup(internalGroup) + .build(); + + context.restoreAuthSystemState(); + + //** WHEN ** + //An anonymous user browses the items in the Browse by item endpoint + //sorted descending by tile + getClient().perform(get("/api/discover/browses/title/items") + .param("sort", "title,desc")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //We expect only the two public items and the embargoed item to be present + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + //Verify that the title of the public and embargoed items are present and sorted descending + .andExpect(jsonPath("$._embedded.items", + contains(ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, + "Public item 2", + "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, + "Public item 1", + "2017-10-17"), + ItemMatcher.matchItemWithTitleAndDateIssued(embargoedItem, + "An embargoed publication", + "2017-08-10")))) + + //The private item must not be present + .andExpect(jsonPath("$._embedded.items[*].metadata[?(@.key=='dc.title')].value", + not(hasItem("This is a private item")))) + + //The internal item must not be present + .andExpect(jsonPath("$._embedded.items[*].metadata[?(@.key=='dc.title')].value", + not(hasItem("Internal publication")))) + ; + } + + @Test + public void testPaginationBrowseByDateIssuedItems() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. 7 public items that are readable by Anonymous + Item item1 = ItemBuilder.createItem(context, col1) + .withTitle("Item 1") + .withIssueDate("2017-10-17") + .build(); + + Item item2 = ItemBuilder.createItem(context, col2) + .withTitle("Item 2") + .withIssueDate("2016-02-13") + .build(); + + Item item3 = ItemBuilder.createItem(context, col1) + .withTitle("Item 3") + .withIssueDate("2016-02-12") + .build(); + + Item item4 = ItemBuilder.createItem(context, col2) + .withTitle("Item 4") + .withIssueDate("2016-02-11") + .build(); + + Item item5 = ItemBuilder.createItem(context, col1) + .withTitle("Item 5") + .withIssueDate("2016-02-10") + .build(); + + Item item6 = ItemBuilder.createItem(context, col2) + .withTitle("Item 6") + .withIssueDate("2016-01-13") + .build(); + + Item item7 = ItemBuilder.createItem(context, col1) + .withTitle("Item 7") + .withIssueDate("2016-01-12") + .build(); + + //** WHEN ** + //An anonymous user browses the items in the Browse by date issued endpoint + //sorted ascending by tile with a page size of 5 + getClient().perform(get("/api/discover/browses/dateissued/items") + .param("sort", "title,asc") + .param("size", "5")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //We expect only the first five items to be present + .andExpect(jsonPath("$.page.size", is(5))) + .andExpect(jsonPath("$.page.totalElements", is(7))) + .andExpect(jsonPath("$.page.totalPages", is(2))) + .andExpect(jsonPath("$.page.number", is(0))) + + //Verify that the title and date of the items match and that they are sorted ascending + .andExpect(jsonPath("$._embedded.items", + contains(ItemMatcher.matchItemWithTitleAndDateIssued(item1, + "Item 1", "2017-10-17"), + ItemMatcher.matchItemWithTitleAndDateIssued(item2, + "Item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(item3, + "Item 3", "2016-02-12"), + ItemMatcher.matchItemWithTitleAndDateIssued(item4, + "Item 4", "2016-02-11"), + ItemMatcher.matchItemWithTitleAndDateIssued(item5, + "Item 5", "2016-02-10") + ))); + + //The next page gives us the last two items + getClient().perform(get("/api/discover/browses/dateissued/items") + .param("sort", "title,asc") + .param("size", "5") + .param("page", "1")) + + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //We expect only the first five items to be present + .andExpect(jsonPath("$.page.size", is(5))) + .andExpect(jsonPath("$.page.totalElements", is(7))) + .andExpect(jsonPath("$.page.totalPages", is(2))) + .andExpect(jsonPath("$.page.number", is(1))) + + //Verify that the title and date of the items match and that they are sorted ascending + .andExpect(jsonPath("$._embedded.items", + contains(ItemMatcher.matchItemWithTitleAndDateIssued(item6, + "Item 6", "2016-01-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(item7, + "Item 7", "2016-01-12") + ))); + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java new file mode 100644 index 0000000000..e9de5c69d6 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java @@ -0,0 +1,279 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.UUID; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.matcher.CollectionMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTest { + + + @Test + public void findAllTest() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community Two") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child2).withName("Collection 2").build(); + + + getClient().perform(get("/api/core/collections")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.collections", Matchers.containsInAnyOrder( + CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()), + CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle()) + ))); + } + + @Test + public void findAllPaginationTest() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community Two") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child2).withName("Collection 2").build(); + + + getClient().perform(get("/api/core/collections") + .param("size", "1")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.collections", Matchers.contains( + CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()) + ))) + .andExpect(jsonPath("$._embedded.collections", Matchers.not( + Matchers.contains( + CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle()) + ) + ))); + + getClient().perform(get("/api/core/collections") + .param("size", "1") + .param("page", "1")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.collections", Matchers.contains( + CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle()) + ))) + .andExpect(jsonPath("$._embedded.collections", Matchers.not( + Matchers.contains( + CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()) + ) + ))); + } + + + @Test + public void findOneCollectionTest() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community Two") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child2).withName("Collection 2").build(); + + + getClient().perform(get("/api/core/collections/" + col1.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", is( + CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()) + ))) + .andExpect(jsonPath("$", Matchers.not( + is( + CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle()) + )))); + } + + @Test + public void findOneCollectionRelsTest() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community Two") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1") + .withLogo("TestingContentForLogo").build(); + Collection col2 = CollectionBuilder.createCollection(context, child2).withName("Collection 2").build(); + + getClient().perform(get("/api/core/collections/" + col1.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", is( + CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()) + ))) + .andExpect(jsonPath("$", Matchers.not( + is( + CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle()) + ))) + ) + ; + + getClient().perform(get("/api/core/collections/" + col1.getID() + "/logo")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.format.href", Matchers.containsString("/api/core/bitstreams"))) + .andExpect(jsonPath("$._links.format.href", Matchers.containsString("/format"))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/bitstreams"))) + .andExpect(jsonPath("$._links.content.href", Matchers.containsString("/api/core/bitstreams"))) + .andExpect(jsonPath("$._links.content.href", Matchers.containsString("/content"))) + ; + + } + + + @Test + public void findAuthorizedTest() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community Two") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child2).withName("Collection 2").build(); + + getClient().perform(get("/api/core/collections/search/findAuthorized")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()) + ; + + } + + + @Test + public void findAuthorizedByCommunityTest() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community Two") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child2).withName("Collection 2").build(); + + getClient().perform(get("/api/core/collections/search/findAuthorizedByCommunity") + .param("uuid", parentCommunity.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$._embedded").doesNotExist()); + } + + @Test + public void findAuthorizedByCommunityWithoutUUIDTest() throws Exception { + getClient().perform(get("/api/core/collections/search/findAuthorizedByCommunity")) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void findAuthorizedByCommunityWithUnexistentUUIDTest() throws Exception { + getClient().perform(get("/api/core/collections/search/findAuthorizedByCommunity") + .param("uuid", UUID.randomUUID().toString())) + .andExpect(status().isNotFound()); + } + + @Test + public void findOneCollectionTestWrongUUID() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community Two") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child2).withName("Collection 2").build(); + + + getClient().perform(get("/api/core/collections/" + UUID.randomUUID())) + .andExpect(status().isNotFound()); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java new file mode 100644 index 0000000000..d1f77fcdd1 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java @@ -0,0 +1,514 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Arrays; +import java.util.UUID; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.matcher.CommunityMatcher; +import org.dspace.app.rest.matcher.CommunityMetadataMatcher; +import org.dspace.app.rest.model.CommunityRest; +import org.dspace.app.rest.model.MetadataEntryRest; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + public void createTest() throws Exception { + context.turnOffAuthorisationSystem(); + + ObjectMapper mapper = new ObjectMapper(); + CommunityRest comm = new CommunityRest(); + // We send a name but the created community should set this to the title + comm.setName("Test Top-Level Community"); + + MetadataEntryRest description = new MetadataEntryRest(); + description.setKey("dc.description"); + description.setValue("

    Some cool HTML code here

    "); + + MetadataEntryRest abs = new MetadataEntryRest(); + abs.setKey("dc.description.abstract"); + abs.setValue("Sample top-level community created via the REST API"); + + MetadataEntryRest contents = new MetadataEntryRest(); + contents.setKey("dc.description.tableofcontents"); + contents.setValue("

    HTML News

    "); + + MetadataEntryRest copyright = new MetadataEntryRest(); + copyright.setKey("dc.rights"); + copyright.setValue("Custom Copyright Text"); + + MetadataEntryRest title = new MetadataEntryRest(); + title.setKey("dc.title"); + title.setValue("Title Text"); + + comm.setMetadata(Arrays.asList(description, + abs, + contents, + copyright, + title)); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(post("/api/core/communities") + .content(mapper.writeValueAsBytes(comm)) + .contentType(contentType)) + .andExpect(status().isCreated()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.allOf( + hasJsonPath("$.id", not(empty())), + hasJsonPath("$.uuid", not(empty())), + hasJsonPath("$.name", is("Title Text")), + hasJsonPath("$.handle", not(empty())), + hasJsonPath("$.type", is("community")), + hasJsonPath("$._links.collections.href", not(empty())), + hasJsonPath("$._links.logo.href", not(empty())), + hasJsonPath("$._links.subcommunities.href", not(empty())), + hasJsonPath("$._links.self.href", not(empty())), + hasJsonPath("$.metadata", Matchers.containsInAnyOrder( + CommunityMetadataMatcher.matchMetadata("dc.description", + "

    Some cool HTML code here

    "), + CommunityMetadataMatcher.matchMetadata("dc.description.abstract", + "Sample top-level community created via the REST API"), + CommunityMetadataMatcher.matchMetadata("dc.description.tableofcontents", + "

    HTML News

    "), + CommunityMetadataMatcher.matchMetadata("dc.rights", + "Custom Copyright Text"), + CommunityMetadataMatcher.matchMetadata("dc.title", + "Title Text") + ))))); + + } + + @Test + public void createUnauthorizedTest() throws Exception { + context.turnOffAuthorisationSystem(); + + ObjectMapper mapper = new ObjectMapper(); + CommunityRest comm = new CommunityRest(); + comm.setName("Test Top-Level Community"); + + MetadataEntryRest title = new MetadataEntryRest(); + title.setKey("dc.title"); + title.setValue("Title Text"); + + comm.setMetadata(Arrays.asList(title)); + + // Anonymous user tries to create a community. + // Should fail because user is not authenticated. Error 401. + getClient().perform(post("/api/core/communities") + .content(mapper.writeValueAsBytes(comm)) + .contentType(contentType)) + .andExpect(status().isUnauthorized()); + + // Non-admin Eperson tries to create a community. + // Should fail because user doesn't have permissions. Error 403. + String authToken = getAuthToken(eperson.getEmail(), password); + getClient(authToken).perform(post("/api/core/communities") + .content(mapper.writeValueAsBytes(comm)) + .contentType(contentType)) + .andExpect(status().isForbidden()); + } + + @Test + public void findAllTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1") + .withLogo("Test Logo") + .build(); + + getClient().perform(get("/api/core/communities")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.communities", Matchers.containsInAnyOrder( + CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(), + parentCommunity.getHandle()), + CommunityMatcher + .matchCommunityWithCollectionEntry(child1.getName(), child1.getID(), child1.getHandle(), + col1) + ))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/communities"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(2))) + ; + } + + @Test + public void findAllPaginationTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + getClient().perform(get("/api/core/communities") + .param("size", "1")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.communities", Matchers.contains( + CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(), + parentCommunity.getHandle()) + ))) + .andExpect(jsonPath("$._embedded.communities", Matchers.not( + Matchers.contains( + CommunityMatcher.matchCommunityEntry(child1.getName(), child1.getID(), child1.getHandle()) + ) + ))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/communities"))) + ; + + getClient().perform(get("/api/core/communities") + .param("size", "1") + .param("page", "1")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.communities", Matchers.contains( + CommunityMatcher.matchCommunityEntry(child1.getName(), child1.getID(), child1.getHandle()) + ))) + .andExpect(jsonPath("$._embedded.communities", Matchers.not( + Matchers.contains( + CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(), + parentCommunity.getHandle()) + ) + ))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/communities"))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(2))) + ; + } + + @Test + public void findOneTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.is( + CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(), + parentCommunity.getHandle()) + ))) + .andExpect(jsonPath("$", Matchers.not( + Matchers.is( + CommunityMatcher.matchCommunityEntry(child1.getName(), child1.getID(), child1.getHandle()) + ) + ))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/communities"))) + ; + } + + @Test + public void findOneRelsTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .withLogo("ThisIsSomeDummyText") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.is( + CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(), + parentCommunity.getHandle()) + ))) + .andExpect(jsonPath("$", Matchers.not( + Matchers.is( + CommunityMatcher.matchCommunityEntry(child1.getName(), child1.getID(), child1.getHandle()) + ) + ))) + .andExpect(jsonPath("$._links.self.href", Matchers + .containsString("/api/core/communities/" + parentCommunity.getID().toString()))) + .andExpect(jsonPath("$._links.logo.href", Matchers + .containsString("/api/core/communities/" + parentCommunity.getID().toString() + "/logo"))) + .andExpect(jsonPath("$._links.collections.href", Matchers + .containsString("/api/core/communities/" + parentCommunity.getID().toString() + "/collections"))) + .andExpect(jsonPath("$._links.subcommunities.href", Matchers + .containsString("/api/core/communities/" + parentCommunity.getID().toString() + + "/subcommunities"))) + ; + + getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString() + "/logo")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)); + + getClient().perform(get("/api/core/communities/" + child1.getID().toString() + "/logo")) + .andExpect(status().isNoContent()); + + //Main community has no collections, therefore contentType is not set + getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString() + "/collections")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + + getClient().perform(get("/api/core/communities/" + child1.getID().toString() + "/collections")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)); + + getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString() + "/subcommunities")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)); + + //child1 subcommunity has no subcommunities, therefore contentType is not set + getClient().perform(get("/api/core/communities/" + child1.getID().toString() + "/subcommunities")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + + @Test + public void findAllSearchTop() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .withLogo("ThisIsSomeDummyText") + .build(); + + Community parentCommunity2 = CommunityBuilder.createCommunity(context) + .withName("Parent Community 2") + .withLogo("SomeTest") + .build(); + + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + + Community child12 = CommunityBuilder.createSubCommunity(context, child1) + .withName("Sub Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + + getClient().perform(get("/api/core/communities/search/top")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.communities", Matchers.containsInAnyOrder( + CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(), + parentCommunity.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunity2.getName(), parentCommunity2.getID(), + parentCommunity2.getHandle()) + ))) + .andExpect(jsonPath("$._embedded.communities", Matchers.not(Matchers.containsInAnyOrder( + CommunityMatcher.matchCommunityEntry(child1.getName(), child1.getID(), child1.getHandle()), + CommunityMatcher.matchCommunityEntry(child12.getName(), child12.getID(), child12.getHandle()) + )))) + .andExpect( + jsonPath("$._links.self.href", Matchers.containsString("/api/core/communities/search/top"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(2))) + ; + } + + @Test + public void findAllSubCommunities() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .withLogo("ThisIsSomeDummyText") + .build(); + + Community parentCommunity2 = CommunityBuilder.createCommunity(context) + .withName("Parent Community 2") + .withLogo("SomeTest") + .build(); + + Community parentCommunityChild1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + + Community parentCommunityChild2 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community2") + .build(); + + Community parentCommunityChild2Child1 = CommunityBuilder.createSubCommunity(context, parentCommunityChild2) + .withName("Sub Sub Community") + .build(); + + + Community parentCommunity2Child1 = CommunityBuilder.createSubCommunity(context, parentCommunity2) + .withName("Sub2 Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunityChild1) + .withName("Collection 1") + .build(); + + getClient().perform(get("/api/core/communities/search/subCommunities") + .param("parent", parentCommunity.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + //Checking that these communities are present + .andExpect(jsonPath("$._embedded.communities", Matchers.containsInAnyOrder( + CommunityMatcher.matchCommunityEntry(parentCommunityChild1.getName(), + parentCommunityChild1.getID(), + parentCommunityChild1.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunityChild2.getName(), + parentCommunityChild2.getID(), + parentCommunityChild2.getHandle()) + ))) + //Checking that these communities are not present + .andExpect(jsonPath("$._embedded.communities", Matchers.not(Matchers.anyOf( + CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), + parentCommunity.getID(), + parentCommunity.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunity2.getName(), + parentCommunity2.getID(), + parentCommunity2.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunity2Child1.getName(), + parentCommunity2Child1.getID(), + parentCommunity2Child1.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunityChild2Child1.getName(), + parentCommunityChild2Child1.getID(), + parentCommunityChild2Child1.getHandle()) + )))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/communities/search/subCommunities"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(2))) + ; + + getClient().perform(get("/api/core/communities/search/subCommunities") + .param("parent", parentCommunityChild2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + //Checking that these communities are present + .andExpect(jsonPath("$._embedded.communities", Matchers.contains( + CommunityMatcher.matchCommunityEntry(parentCommunityChild2Child1.getName(), + parentCommunityChild2Child1.getID(), + parentCommunityChild2Child1.getHandle()) + ))) + //Checking that these communities are not present + .andExpect(jsonPath("$._embedded.communities", Matchers.not(Matchers.anyOf( + CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), + parentCommunity.getID(), + parentCommunity.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunity2.getName(), + parentCommunity2.getID(), + parentCommunity2.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunity2Child1.getName(), + parentCommunity2Child1.getID(), + parentCommunity2Child1.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunityChild2Child1.getName(), + parentCommunityChild2Child1.getID(), + parentCommunityChild2Child1.getHandle()), + CommunityMatcher.matchCommunityEntry(parentCommunityChild1.getName(), + parentCommunityChild1.getID(), + parentCommunityChild1.getHandle()) + )))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/communities/search/subCommunities"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + ; + + getClient().perform(get("/api/core/communities/search/subCommunities") + .param("parent", parentCommunityChild2Child1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/communities/search/subCommunities"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(0))) + ; + } + + @Test + public void findAllSubCommunitiesWithoutUUID() throws Exception { + getClient().perform(get("/api/core/communities/search/subCommunities")) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void findAllSubCommunitiesWithUnexistentUUID() throws Exception { + getClient().perform(get("/api/core/communities/search/subCommunities") + .param("parent", UUID.randomUUID().toString())) + .andExpect(status().isNotFound()); + } + + @Test + public void findOneTestWrongUUID() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + getClient().perform(get("/api/core/communities/" + UUID.randomUUID())).andExpect(status().isNotFound()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java new file mode 100644 index 0000000000..f09663f4be --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java @@ -0,0 +1,2959 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; +import java.util.UUID; + +import org.apache.commons.codec.CharEncoding; +import org.apache.commons.io.IOUtils; +import org.dspace.app.rest.builder.BitstreamBuilder; +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.GroupBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.matcher.AppliedFilterMatcher; +import org.dspace.app.rest.matcher.FacetEntryMatcher; +import org.dspace.app.rest.matcher.FacetValueMatcher; +import org.dspace.app.rest.matcher.PageMatcher; +import org.dspace.app.rest.matcher.SearchFilterMatcher; +import org.dspace.app.rest.matcher.SearchResultMatcher; +import org.dspace.app.rest.matcher.SortOptionMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.eperson.Group; +import org.hamcrest.Matchers; +import org.junit.Ignore; +import org.junit.Test; + +public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest { + + + @Test + public void rootDiscoverTest() throws Exception { + + //When we call this endpoint + getClient().perform(get("/api/discover")) + + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a link to the facets endpoint + .andExpect(jsonPath("$._links.facets.href", containsString("api/discover/facets"))) + //There needs to be a link to the search endpoint + .andExpect(jsonPath("$._links.search.href", containsString("api/discover/search"))) + //There needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover"))); + } + + @Test + public void discoverFacetsTestWithoutParameters() throws Exception { + + //When we call this facets endpoint + getClient().perform(get("/api/discover/facets")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.facets", containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false))) + ); + } + + @Test + public void discoverFacetsAuthorTestWithSizeParameter() throws Exception { + //Turn off the authorization system, otherwise we can't make the objects + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects and authors + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the objects in the system and enters a size of 2 + getClient().perform(get("/api/discover/facets/author") + .param("size", "2")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type needs to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet needs to be author, because that's what we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's how the author facet is configured by default + .andExpect(jsonPath("$.facetType", is("text"))) + //Because we've constructed such a structure so that we have more than 2 (size) authors, there + // needs to be a next link + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //Because there are more authors than is represented (because of the size param), hasMore has to + // be true + //The page object needs to be present and just like specified in the matcher + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //These authors need to be in the response because it's sorted on how many times the author comes + // up in different items + //These authors are the most used ones. Only two show up because of the size. + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria") + ))) + ; + } + + @Test + public void discoverFacetsAuthorTestWithPrefix() throws Exception { + //Turn off the authorization system, otherwise we can't make the objects + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects and authors + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the objects in the system and enters a size of 2 + getClient().perform(get("/api/discover/facets/author?prefix=smith") + .param("size", "10")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type needs to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet needs to be author, because that's what we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's how the author facet is configured by default + .andExpect(jsonPath("$.facetType", is("text"))) + //We only request value starting with "smith", so we expect to only receive one page + .andExpect(jsonPath("$._links.next").doesNotExist()) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author?prefix=smith"))) + //Because there are more authors than is represented (because of the size param), hasMore has to + // be true + //The page object needs to be present and just like specified in the matcher + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 10)))) + //These authors need to be in the response because it's sorted on how many times the author comes + // up in different items + //These authors are order according to count. Only two show up because of the prefix. + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) + ; + } + + @Test + public void discoverFacetsAuthorTestForHasMoreFalse() throws Exception { + //Turn of the authorization system so that we can create the structure specified below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the authors by the facets and doesn't enter a size + getClient().perform(get("/api/discover/facets/author")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author, because that's the facet that we called upon + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //There always needs to be a self link present + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The page object needs to present and exactly like how it is specified here. 20 is entered as the + // size because that's the default in the configuration if no size parameter has been given + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //The authors need to be embedded in the values, all 4 of them have to be present as the size + // allows it + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) + ; + } + + @Test + public void discoverFacetsAuthorTestForPagination() throws Exception { + + //We turn off the authorization system in order to construct the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John").withAuthor("Smith, Maria") + .withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Doe, John") + .withAuthor("Smith, Donald") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the authors by the facet + //The user enters a size of two and wants to see page 1, this is the second page. + getClient().perform(get("/api/discover/facets/author") + .param("size", "2") + .param("page", "1")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet has to be author as that's the one we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as this is the default configuration + .andExpect(jsonPath("$.facetType", is("text"))) + //There needs to be a next link because there are more authors than the current size is allowed to + // show. There are more pages after this one + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The page object has to be like this because that's what we've asked in the parameters + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(1, 2)))) + //These authors have to be present because of the current configuration + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) + ; + } + + + @Test + public void discoverFacetsTestWithSimpleQueryAndSearchFilter() throws Exception { + //Turn off the authorization system to construct the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + //** WHEN ** + //An anonymous user browses this endpoint to find the authors by the facet + //The user enters a small query, namely the title has to contain 'test' + getClient().perform(get("/api/discover/facets/author") + .param("f.title", "test,contains")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author as that's the facet that we've asked + .andExpect(jsonPath("$.name", is("author"))) + //The facetType needs to be 'text' as that's the default configuration for the given facet + .andExpect(jsonPath("$.facetType", is("text"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The self link needs to contain the query that was specified in the parameters, this is how it + // looks like + .andExpect(jsonPath("$._links.self.href", containsString("f.title=test,contains"))) + //The applied filters have to be specified like this, applied filters are the parameters given + // below starting with f. + .andExpect(jsonPath("$.appliedFilters", contains( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //This is how the page object must look like because it's the default + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //These authors need to be present in the result because these have made items that contain 'test' + // in the title + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Donald"), + FacetValueMatcher.entryAuthor("Testing, Works") + ))) + //These authors cannot be present because they've not produced an item with 'test' in the title + .andExpect(jsonPath("$._embedded.values", not(containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, Jane") + )))) + ; + } + + @Test + public void discoverFacetsDateTest() throws Exception { + //We turn off the authorization system in order to create the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2000-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + //** WHEN ** + //An anonymous user browses this endpoint to find the dateIssued results by the facet + getClient().perform(get("/api/discover/facets/dateIssued")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be 'dateIssued' as that's the facet that we've called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //The facetType has to be 'date' because that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //This is how the page object must look like because it's the default with size 20 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //The date values need to be as specified below + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + //We'll always get atleast two intervals with the items specified above, so we ask to match + // twice atleast + FacetValueMatcher.entryDateIssued(), + FacetValueMatcher.entryDateIssued() + ))) + ; + } + + + @Test + public void discoverFacetsTestWithScope() throws Exception { + //We turn off the authorization system in order to create the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the author results by the facet + //With a certain scope + getClient().perform(get("/api/discover/facets/author") + .param("scope", "testScope")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author as that's the facet that we've called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //The scope has to be the same as the one that we've given in the parameters + .andExpect(jsonPath("$.scope", is("testScope"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //These are all the authors for the items that were created and thus they have to be present in + // the embedded values section + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))); + //** WHEN ** + //An anonymous user browses this endpoint to find the author results by the facet + //With a certain scope + //And a size of 2 + getClient().perform(get("/api/discover/facets/author") + .param("scope", "testScope") + .param("size", "2")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be 'author' as that's the facet that we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //The scope has to be same as the param that we've entered + .andExpect(jsonPath("$.scope", is("testScope"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //These are the values that need to be present as it's ordered by count and these authors are the + // most common ones in the items that we've created + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria") + ))) + ; + } + + @Test + public void discoverFacetsDateTestForHasMore() throws Exception { + //We turn off the authorization system to create the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. 7 public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("1940-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + Item publicItem4 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("1950-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + Item publicItem5 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("1960-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + Item publicItem6 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("1970-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + Item publicItem7 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("1980-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the dateIssued results by the facet + //And a size of 2 + getClient().perform(get("/api/discover/facets/dateIssued") + .param("size", "2")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name needs to be dateIssued as that's the facet that we've called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //the facetType needs to be 'date' as that's the default facetType for this facet in the + // configuration + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //Seeing as we've entered a size of two and there are more dates than just two, we'll need a next + // link to go to the next page to see the rest of the dates + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/dateIssued?page"))) + //The page object needs to look like this because we've entered a size of 2 and we didn't specify + // a starting page so it defaults to 0 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //There needs to be two date results in the embedded values section because that's what we've + // specified + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryDateIssued(), + FacetValueMatcher.entryDateIssued() + ))) + ; + } + + + @Test + public void discoverFacetsDateTestWithSearchFilter() throws Exception { + + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + //** WHEN ** + //An anonymous user browses this endpoint to find the dateIssued results by the facet + //With a query stating that the title needs to contain 'test' + //And a size of 2 + getClient().perform(get("/api/discover/facets/dateIssued") + .param("f.title", "test,contains") + .param("size", "2")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be dateIssued because that's the facet that we called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //The facetType needs to be 'date' as that's the default facetType for this facet in the + // configuration + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //There needs to be an appliedFilters section that looks like this because we've specified a query + // in the parameters + .andExpect(jsonPath("$.appliedFilters", containsInAnyOrder( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //The page object needs to look like this because we entered a size of 2 and we didn't specify a + // starting page so it defaults to 0 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //There needs to be only two date intervals with a count of 1 because of the query we specified + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryDateIssuedWithCountOne(), + FacetValueMatcher.entryDateIssuedWithCountOne() + ))) + ; + } + + + @Test + public void discoverSearchTest() throws Exception { + + //When calling this root endpoint + getClient().perform(get("/api/discover/search")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a link to the objects that contains a string as specified below + .andExpect(jsonPath("$._links.objects.href", containsString("api/discover/search/objects"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/search"))) + //There needs to be a section where these filters as specified as they're the default filters + // given in the configuration + .andExpect(jsonPath("$.filters", containsInAnyOrder( + SearchFilterMatcher.titleFilter(), + SearchFilterMatcher.authorFilter(), + SearchFilterMatcher.subjectFilter(), + SearchFilterMatcher.dateIssuedFilter(), + SearchFilterMatcher.hasContentInOriginalBundleFilter(), + SearchFilterMatcher.hasFileNameInOriginalBundleFilter(), + SearchFilterMatcher.hasFileDescriptionInOriginalBundleFilter() + ))) + //These sortOptions need to be present as it's the default in the configuration + .andExpect(jsonPath("$.sortOptions", containsInAnyOrder( + SortOptionMatcher.titleSortOption(), + SortOptionMatcher.dateIssuedSortOption(), + SortOptionMatcher.dateAccessionedSortOption(), + SortOptionMatcher.scoreSortOption() + ))); + } + + @Test + public void discoverSearchObjectsTest() throws Exception { + + //We turn off the authorization system in order to create the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the objects in the system + getClient().perform(get("/api/discover/search/objects")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a page object that shows the total pages and total elements as well as the + // size and the current page (number) + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //These search results have to be shown in the embedded.objects section as these are the items + // given in the structure defined above. + //Seeing as everything fits onto one page, they have to all be present + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //This has to be like this because collections don't have anything else + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + } + + @Test + public void discoverSearchObjectsTestHasMoreAuthorFacet() throws Exception { + //We turn off the authorization system in order to create the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works").withAuthor("a1, a1") + .withAuthor("b, b").withAuthor("c, c").withAuthor("d, d").withAuthor("e, e") + .withAuthor("f, f").withAuthor("g, g") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the objects in the system + getClient().perform(get("/api/discover/search/objects")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because we've only made 7 elements, the default size is 20 + // and they all fit onto one page (20 > 7) so totalPages has to be 1. Number is 0 because + //page 0 is the default page we view if not specified otherwise + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //All elements have to be present in the embedded.objects section, these are the ones we made in + // the structure defined above + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //Match without any parameters because collections don't have anything special to check in the + // json + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + //We do however exceed the limit for the authors, so this property has to be true for the author + // facet + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(true), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + + @Test + public void discoverSearchObjectsTestHasMoreSubjectFacet() throws Exception { + //We turn off the authorization system in order to create the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry").withSubject("a") + .withSubject("b").withSubject("c") + .withSubject("d").withSubject("e") + .withSubject("f").withSubject("g") + .withSubject("h").withSubject("i") + .withSubject("j").withSubject("k") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + getClient().perform(get("/api/discover/search/objects")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because we've only made 7 items, they all fit onto 1 page + // because the default size is 20 and the default starting page is 0. + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //All the elements created in the structure above have to be present in the embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + //We do however exceed the limit for the subject, so this property has to be true for the subject + // facet + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + } + + @Test + public void discoverSearchObjectsTestWithBasicQuery() throws Exception { + //We turn off the authorization system in order to create the structure defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a query that says that the title has to contain 'test' + getClient().perform(get("/api/discover/search/objects") + .param("f.title", "test,contains")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because of the query we specified, only two elements match + // the query. + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2) + ))) + //Only the two item elements match the query, therefore those are the only ones that can be in the + // embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //We need to display the appliedFilters object that contains the query that we've ran + .andExpect(jsonPath("$.appliedFilters", contains( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + } + + + @Test + public void discoverSearchObjectsTestWithScope() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a scope 'test' + getClient().perform(get("/api/discover/search/objects") + .param("scope", "test")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page element has to look like this because it contains all the elements we've just created + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //The scope property has to be set to the value we entered in the parameters + .andExpect(jsonPath("$.scope", is("test"))) + //All the elements created in the structure above have to be present in the embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + } + + @Test + public void discoverSearchObjectsTestWithDsoType() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a dsoType 'item' + getClient().perform(get("/api/discover/search/objects") + .param("dsoType", "item")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page element needs to look like this and only have three totalElements because we only want + // the items (dsoType) and we only created three items + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) + ))) + //Only the three items can be present in the embedded.objects section as that's what we specified + // in the dsoType parameter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + } + + @Test + public void discoverSearchObjectsTestWithDsoTypeAndSort() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Testing") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a dsoType 'item' + //And a sort on the dc.title ascending + getClient().perform(get("/api/discover/search/objects") + .param("dsoType", "item") + .param("sort", "dc.title,ASC")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this and only contain three total elements because we only want + // to get the items back + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) + ))) + //Only the three items can be present in the embedded.objects section as that's what we specified + // in the dsoType parameter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //Here we want to match on the item name in a certain specified order because we want to check the + // sort properly + //We check whether the items are sorted properly as we expected + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Public"), + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Testing") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //We want to get the sort that's been used as well in the response + .andExpect(jsonPath("$.sort", is( + SortOptionMatcher.sortByAndOrder("dc.title", "ASC") + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + } + + + // This test has been disable due to its innate dependency on knowing the facetLimit + // This is currently untrue and resulted in hardcoding of expectations. + @Test + @Ignore + public void discoverFacetsDateTestWithLabels() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. 9 public items that are readable by Anonymous with different subjects + Item publicItem6 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("2017-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + Item publicItem7 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + Item publicItem8 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + Item publicItem9 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("1970-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + Item publicItem10 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("1950-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + Item publicItem11 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("1930-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + Item publicItem12 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("1910-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + Item publicItem13 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("1890-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + Item publicItem14 = ItemBuilder.createItem(context, col2) + .withTitle("Public") + .withIssueDate("1866-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find dateIssued facet values + getClient().perform(get("/api/discover/facets/dateIssued")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because the default size is 20 and the default starting + // page is 0 + .andExpect(jsonPath("$.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Then we expect these dateIssued values to be present with the labels as specified + .andExpect(jsonPath("$._embedded.values", Matchers.containsInAnyOrder( + FacetValueMatcher.entryDateIssuedWithLabel("2000 - 2017"), + FacetValueMatcher.entryDateIssuedWithLabel("1980 - 1999"), + FacetValueMatcher.entryDateIssuedWithLabel("1960 - 1979"), + FacetValueMatcher.entryDateIssuedWithLabel("1940 - 1959"), + FacetValueMatcher.entryDateIssuedWithLabel("1920 - 1939"), + FacetValueMatcher.entryDateIssuedWithLabel("1880 - 1899"), + FacetValueMatcher.entryDateIssuedWithLabel("1866 - 1879"), + FacetValueMatcher.entryDateIssuedWithLabel("1900 - 1919") + + ))) + ; + } + + @Test + public void discoverSearchObjectsTestForPaginationAndNextLinks() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a size 2 + getClient().perform(get("/api/discover/search/objects") + .param("size", "2") + .param("page", "1")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + //Size of 2 because that's what we entered + //Page number 1 because that's the param we entered + //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages + //We made 7 elements -> 7 total elements + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) + ))) + //These are the two elements that'll be shown (because page = 1, so the third and fourth element + // in the list) and they'll be the only ones because the size is 2 + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match(), + SearchResultMatcher.match() + ))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(true), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + + @Test + public void discoverSearchObjectsTestWithContentInABitstream() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + Bitstream bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withMimeType("text/plain") + .build(); + } + + //Run the filter media to make the text in the bitstream searchable through the query + runDSpaceScript("filter-media", "-f", "-i", publicItem1.getHandle()); + + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a query stating 'ThisIsSomeDummyText' + getClient().perform(get("/api/discover/search/objects") + .param("query", "ThisIsSomeDummyText")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //This is the only item that should be returned with the query given + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + ))) + + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsTestForEmbargoedItemsAndPrivateItems() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + //Make this one public to make sure that it doesn't show up in the search + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .withEmbargoPeriod("12 months") + .build(); + + //Turn on the authorization again + context.restoreAuthSystemState(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + // + getClient().perform(get("/api/discover/search/objects")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //These are the items that aren't set to private + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //This is a private item, this shouldn't show up in the result + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", + Matchers.not(SearchResultMatcher.matchOnItemName("item", "items", "Test 2")))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + //TODO Enable when solr fulltext indexing is policy-aware, see https://jira.duraspace.org/browse/DS-3758 + @Test + @Ignore + public void discoverSearchObjectsTestWithContentInAPrivateBitstream() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. one public item that is readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + + //Make the group that anon doesn't have access to + Group internalGroup = GroupBuilder.createGroup(context) + .withName("Internal Group") + .build(); + + //Add this bitstream with the internal group as the reader group + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + Bitstream bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("Test Private Bitstream") + .withMimeType("text/plain") + .withReaderGroup(internalGroup) + .build(); + } + + + //Run the filter media to be able to search on the text in the bitstream + runDSpaceScript("filter-media", "-f", "-i", publicItem1.getHandle()); + + //Turn on the authorization again to make sure that private/inaccessible items don't get show/used + context.restoreAuthSystemState(); + context.setCurrentUser(null); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a size 2 + getClient().perform(get("/api/discover/search/objects") + .param("query", "ThisIsSomeDummyText")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Make sure that the item with the private bitstream doesn't show up + .andExpect(jsonPath("$._embedded.object", Matchers.not(Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + )))) + + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + + @Test + public void discoverSearchObjectsTestForScope() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + UUID scope = col2.getID(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With the scope given + getClient().perform(get("/api/discover/search/objects") + .param("scope", String.valueOf(scope))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The scope has to be equal to the one given in the parameters + .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items belonging to the scope specified + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsTestForScopeWithPrivateItem() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Two items that are readable by Anonymous with different subjects and one private item + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + UUID scope = col2.getID(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a size 2 + getClient().perform(get("/api/discover/search/objects") + .param("scope", String.valueOf(scope))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //Make sure that the scope is set to the scope given in the param + .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Make sure that the search results contains the item with the correct scope + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2") +// SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //Make sure that the search result doesn't contain the item that's set to private but does have + // the correct scope + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( + Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + )))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsTestForHitHighlights() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("ExtraEntry") + .build(); + + + String query = "Public"; + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a query stating 'public' + getClient().perform(get("/api/discover/search/objects") + .param("query", query)) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results has to contain the item with the query in the title and the hithighlight has + // to be filled in with a string containing the query + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher + .matchOnItemNameAndHitHighlight("item", "items", + "Public item 2", query, "dc.title") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + + @Test + public void discoverSearchObjectsTestForHitHighlightsWithPrivateItem() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Two public items that are readable by Anonymous with different subjects and one private item + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + + String query = "Public"; + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a query stating 'Public' + getClient().perform(get("/api/discover/search/objects") + .param("query", query)) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results should not contain this + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( + Matchers.contains( + SearchResultMatcher + .matchOnItemNameAndHitHighlight("item", "items", + "Public item 2", query, "dc.title") + )))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsWithQueryOperatorContains() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + UUID scope = col2.getID(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With the given search filter + getClient().perform(get("/api/discover/search/objects") + .param("f.title", "test*,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Test 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsWithQueryOperatorNotContains() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + UUID scope = col2.getID(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With the given search filter + getClient().perform(get("/api/discover/search/objects") + .param("f.title", "-test*,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsTestForMinMaxValues() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a size 2 + getClient().perform(get("/api/discover/search/objects") + .param("size", "2") + .param("page", "1")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + //Size of 2 because that's what we entered + //Page number 1 because that's the param we entered + //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages + //We made 7 elements -> 7 total elements + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) + ))) + //These are the two elements that'll be shown (because page = 1, so the third and fourth element + // in the list) and they'll be the only ones because the size is 2 + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match(), + SearchResultMatcher.match() + ))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchFacetsTestForMinMaxValues() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); + + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With a size 2 + getClient().perform(get("/api/discover/search/facets")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/facets"))) + ; + + } + + @Test + public void discoverSearchObjectsWithQueryOperatorEquals() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + UUID scope = col2.getID(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With the given search filter + getClient().perform(get("/api/discover/search/objects") + .param("f.title", "Test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsWithQueryOperatorNotEquals() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + UUID scope = col2.getID(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With the given search filter + getClient().perform(get("/api/discover/search/objects") + .param("f.title", "-Test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItems( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsWithQueryOperatorNotAuthority() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + UUID scope = col2.getID(); + //** WHEN ** + //An anonymous user browses this endpoint to find the the objects in the system + //With the given search filter + getClient().perform(get("/api/discover/search/objects") + .param("f.title", "-id:test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsTestWithDateIssuedQueryTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + String bitstreamContent = "ThisIsSomeDummyText"; + //Add a bitstream to an item + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + Bitstream bitstream = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withMimeType("text/plain") + .build(); + } + + //Run the filter media to make the text in the bitstream searchable through the query + runDSpaceScript("filter-media", "-f", "-i", publicItem1.getHandle()); + + //** WHEN ** + getClient().perform(get("/api/discover/search/objects") + .param("query", "dc.date.issued:2010-02-13")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1) + ))) + //This is the only item that should be returned with the query given + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + + //** WHEN ** + getClient().perform(get("/api/discover/search/objects") + .param("query", "dc.date.issued:2013-02-13")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 0, 0) + ))) + + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsTestWithLuceneSyntaxQueryTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("TestItem2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("azeazeazeazeazeaze") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + //** WHEN ** + getClient().perform(get("/api/discover/search/objects") + .param("query", "((dc.date.issued:2010 OR dc.date.issued:1990-02-13)" + + " AND (dc.title:Test OR dc.title:TestItem2))")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2) + ))) + //This is the only item that should be returned with the query given + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "TestItem2") + ))) + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not(Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "azeazeazeazeazeaze") + )))) + + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + + @Test + public void discoverSearchObjectsTestWithEscapedLuceneCharactersTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Faithful Infidel: Exploring Conformity (2nd edition)") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("NotAProperTestTitle") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + getClient().perform(get("/api/discover/search/objects") + .param("query", "\"Faithful Infidel: Exploring Conformity (2nd edition)\"")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1) + ))) + //This is the only item that should be returned with the query given + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName + ("item", "items", "Faithful Infidel: Exploring Conformity (2nd edition)") + ))) + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", + Matchers.not(Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "NotAProperTestTitle") + )))) + + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ; + + } + @Test + public void discoverSearchObjectsTestWithUnEscapedLuceneCharactersTest() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Faithful Infidel: Exploring Conformity (2nd edition)") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Test") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("NotAProperTestTitle") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + //** WHEN ** + getClient().perform(get("/api/discover/search/objects") + .param("query", "OR")) + + .andExpect(status().isBadRequest()) + ; + + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EPersonRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EPersonRestRepositoryIT.java new file mode 100644 index 0000000000..ab84107706 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EPersonRestRepositoryIT.java @@ -0,0 +1,1044 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import javax.ws.rs.core.MediaType; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.EPersonBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.matcher.EPersonMatcher; +import org.dspace.app.rest.matcher.EPersonMetadataMatcher; +import org.dspace.app.rest.model.EPersonRest; +import org.dspace.app.rest.model.MetadataEntryRest; +import org.dspace.app.rest.model.patch.Operation; +import org.dspace.app.rest.model.patch.ReplaceOperation; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.eperson.EPerson; +import org.hamcrest.Matchers; +import org.junit.Ignore; +import org.junit.Test; + + +public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + public void createTest() throws Exception { + context.turnOffAuthorisationSystem(); + // we should check how to get it from Spring + ObjectMapper mapper = new ObjectMapper(); + EPersonRest data = new EPersonRest(); + data.setEmail("createtest@fake-email.com"); + data.setCanLogIn(true); + MetadataEntryRest surname = new MetadataEntryRest(); + surname.setKey("eperson.lastname"); + surname.setValue("Doe"); + MetadataEntryRest firstname = new MetadataEntryRest(); + firstname.setKey("eperson.firstname"); + firstname.setValue("John"); + data.setMetadata(Arrays.asList(surname, firstname)); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(post("/api/eperson/epersons") + .content(mapper.writeValueAsBytes(data)) + .contentType(contentType)) + .andExpect(status().isCreated()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.allOf( + hasJsonPath("$.uuid", not(empty())), + // is it what you expect? EPerson.getName() returns the email... + //hasJsonPath("$.name", is("Doe John")), + hasJsonPath("$.email", is("createtest@fake-email.com")), + hasJsonPath("$.type", is("eperson")), + hasJsonPath("$.canLogIn", is(true)), + hasJsonPath("$.requireCertificate", is(false)), + hasJsonPath("$._links.self.href", not(empty())), + hasJsonPath("$.metadata", Matchers.containsInAnyOrder( + EPersonMetadataMatcher.matchFirstName("John"), + EPersonMetadataMatcher.matchLastName("Doe") + ))))); + // TODO cleanup the context!!! + } + + @Test + public void findAllTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson newUser = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/eperson")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.epersons", Matchers.containsInAnyOrder( + EPersonMatcher.matchEPersonEntry(newUser), + EPersonMatcher.matchEPersonOnEmail(admin.getEmail()), + EPersonMatcher.matchEPersonOnEmail(eperson.getEmail()) + ))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + ; + + getClient().perform(get("/api/eperson/epersons")) + .andExpect(status().isUnauthorized()) + ; + } + + @Test + public void findAllUnauthorizedTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson newUser = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + getClient().perform(get("/api/eperson/eperson")) + .andExpect(status().isUnauthorized()); + } + + @Test + public void findAllForbiddenTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson newUser = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + String authToken = getAuthToken(eperson.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/eperson")) + .andExpect(status().isForbidden()); + } + + @Test + public void findAllPaginationTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson testEPerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + String authToken = getAuthToken(admin.getEmail(), password); + // using size = 2 the first page will contains our test user and admin + getClient(authToken).perform(get("/api/eperson/epersons") + .param("size", "2")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.epersons", Matchers.containsInAnyOrder( + EPersonMatcher.matchEPersonEntry(admin), + EPersonMatcher.matchEPersonEntry(testEPerson) + ))) + .andExpect(jsonPath("$._embedded.epersons", Matchers.not( + Matchers.contains( + EPersonMatcher.matchEPersonEntry(admin) + ) + ))) + .andExpect(jsonPath("$.page.size", is(2))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + ; + + // using size = 2 the first page will contains our test user and admin + getClient(authToken).perform(get("/api/eperson/epersons") + .param("size", "2") + .param("page", "1")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.epersons", Matchers.contains( + EPersonMatcher.matchEPersonEntry(eperson) + ))) + .andExpect(jsonPath("$._embedded.epersons", Matchers.hasSize(1))) + .andExpect(jsonPath("$.page.size", is(2))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + ; + + getClient().perform(get("/api/eperson/epersons")) + .andExpect(status().isUnauthorized()) + ; + } + + + @Test + public void findOneTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + EPerson ePerson2 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Jane", "Smith") + .withEmail("janesmith@fake-email.com") + .build(); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/" + ePerson2.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", is( + EPersonMatcher.matchEPersonEntry(ePerson2) + ))) + .andExpect(jsonPath("$", Matchers.not( + is( + EPersonMatcher.matchEPersonEntry(ePerson) + ) + ))); + + } + + @Test + public void readEpersonAuthorizationTest() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + EPerson ePerson2 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Jane", "Smith") + .withEmail("janesmith@fake-email.com") + .build(); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/" + ePerson2.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", is( + EPersonMatcher.matchEPersonEntry(ePerson2) + ))) + .andExpect(jsonPath("$", Matchers.not( + is( + EPersonMatcher.matchEPersonEntry(eperson) + ) + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/eperson/epersons/" + ePerson2.getID()))); + + + //EPerson can only access himself + String epersonToken = getAuthToken(eperson.getEmail(), password); + + getClient(epersonToken).perform(get("/api/eperson/epersons/" + ePerson2.getID())) + .andExpect(status().isForbidden()); + + + getClient(epersonToken).perform(get("/api/eperson/epersons/" + eperson.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", is( + EPersonMatcher.matchEPersonOnEmail(eperson.getEmail()) + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/eperson/epersons/" + eperson.getID()))); + + } + + @Test + public void findOneTestWrongUUID() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson testEPerson1 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + EPerson testEPerson2 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Jane", "Smith") + .withEmail("janesmith@fake-email.com") + .build(); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/" + UUID.randomUUID())) + .andExpect(status().isNotFound()); + + } + + @Test + public void searchMethodsExist() throws Exception { + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons")) + .andExpect(jsonPath("$._links.search.href", Matchers.notNullValue())); + + getClient(authToken).perform(get("/api/eperson/epersons/search")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.byEmail", Matchers.notNullValue())) + .andExpect(jsonPath("$._links.byName", Matchers.notNullValue())); + } + + @Test + public void findByEmail() throws Exception { + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + // create a second eperson to put the previous one in a no special position (is not the first as we have default + // epersons is not the latest created) + EPerson ePerson2 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Jane", "Smith") + .withEmail("janesmith@fake-email.com") + .build(); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/search/byEmail") + .param("email", ePerson.getEmail())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", is( + EPersonMatcher.matchEPersonEntry(ePerson) + ))); + + // it must be case-insensitive + getClient(authToken).perform(get("/api/eperson/epersons/search/byEmail") + .param("email", ePerson.getEmail().toUpperCase())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", is( + EPersonMatcher.matchEPersonEntry(ePerson) + ))); + } + + @Test + public void findByEmailUndefined() throws Exception { + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/search/byEmail") + .param("email", "undefined@undefined.com")) + .andExpect(status().isNotFound()); + } + + @Test + public void findByEmailUnprocessable() throws Exception { + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/search/byEmail")) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void findByName() throws Exception { + context.turnOffAuthorisationSystem(); + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + EPerson ePerson2 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Jane", "Smith") + .withEmail("janesmith@fake-email.com") + .build(); + + EPerson ePerson3 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Tom", "Doe") + .withEmail("tomdoe@fake-email.com") + .build(); + + EPerson ePerson4 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Dirk", "Doe-Postfix") + .withEmail("dirkdoepostfix@fake-email.com") + .build(); + + EPerson ePerson5 = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Harry", "Prefix-Doe") + .withEmail("harrydoeprefix@fake-email.com") + .build(); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/search/byName") + .param("q", ePerson.getLastName())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.epersons", Matchers.containsInAnyOrder( + EPersonMatcher.matchEPersonEntry(ePerson), + EPersonMatcher.matchEPersonEntry(ePerson3), + EPersonMatcher.matchEPersonEntry(ePerson4), + EPersonMatcher.matchEPersonEntry(ePerson5) + ))) + .andExpect(jsonPath("$.page.totalElements", is(4))); + + // it must be case insensitive + getClient(authToken).perform(get("/api/eperson/epersons/search/byName") + .param("q", ePerson.getLastName().toLowerCase())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.epersons", Matchers.containsInAnyOrder( + EPersonMatcher.matchEPersonEntry(ePerson), + EPersonMatcher.matchEPersonEntry(ePerson3), + EPersonMatcher.matchEPersonEntry(ePerson4), + EPersonMatcher.matchEPersonEntry(ePerson5) + ))) + .andExpect(jsonPath("$.page.totalElements", is(4))); + } + + @Test + public void findByNameUndefined() throws Exception { + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/search/byName") + .param("q", "Doe, John")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + @Test + public void findByNameUnprocessable() throws Exception { + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(get("/api/eperson/epersons/search/byName")) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void deleteOne() throws Exception { + context.turnOffAuthorisationSystem(); + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + // Delete + getClient(token).perform(delete("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().is(204)); + + // Verify 404 after delete + getClient().perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isNotFound()); + } + + @Test + public void deleteUnauthorized() throws Exception { + context.turnOffAuthorisationSystem(); + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + // login as a basic user + String token = getAuthToken(eperson.getEmail(), password); + + // Delete using an unauthorized user + getClient(token).perform(delete("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isForbidden()); + + // login as admin + String adminToken = getAuthToken(admin.getEmail(), password); + + // Verify the eperson is still here + getClient(adminToken).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()); + } + + @Test + public void deleteForbidden() throws Exception { + context.turnOffAuthorisationSystem(); + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + // Delete as anonymous user + getClient().perform(delete("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isUnauthorized()); + + // login as admin + String adminToken = getAuthToken(admin.getEmail(), password); + + // Verify the eperson is still here + getClient(adminToken).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()); + } + + @Ignore + @Test + public void deleteViolatingConstraints() throws Exception { + // We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("Sample", "Submitter") + .withEmail("submitter@fake-email.com") + .build(); + + // force the use of the new user for subsequent operation + context.setCurrentUser(ePerson); + + // ** GIVEN ** + // 1. A community with a logo + parentCommunity = CommunityBuilder.createCommunity(context).withName("Community").withLogo("logo_community") + .build(); + + // 2. A collection with a logo + Collection col = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection") + .withLogo("logo_collection").build(); + + + // 3. Create an item that will prevent the deletation of the eperson account (it is the submitter) + Item item = ItemBuilder.createItem(context, col).build(); + + String token = getAuthToken(admin.getEmail(), password); + + // 422 error when trying to DELETE the eperson=submitter + getClient(token).perform(delete("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().is(422)); + + // Verify the eperson is still here + getClient(token).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()); + } + + @Test + public void patchByForbiddenUser() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/netid", "newNetId"); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + String token = getAuthToken(eperson.getEmail(), password); + + // should be forbidden. + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isForbidden()); + + token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.netid", Matchers.is(nullValue()))); + + } + + @Test + public void patchByAnonymousUser() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/netid", "newNetId"); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // should be unauthorized. + getClient().perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isUnauthorized()); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.netid", Matchers.is(nullValue()))); + + } + + @Test + public void patchNetId() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .withNetId("testId") + .build(); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/netid", "newNetId"); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + String token = getAuthToken(admin.getEmail(), password); + + // update net id + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.netid", Matchers.is("newNetId"))) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.canLogIn", Matchers.is(false))); + + } + + @Test + public void patchUsingStringForBoolean() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .withNetId("testId") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + + // String should be converted to boolean. + ReplaceOperation replaceOperation = new ReplaceOperation("/canLogin", "true"); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // updatecan login + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.netid", Matchers.is("testId"))) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.canLogIn", Matchers.is(true))); + + // String should be converted to boolean. + replaceOperation = new ReplaceOperation("/canLogin", "false"); + ops.set(0, replaceOperation); + patchBody = getPatchContent(ops); + + // update can login + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.netid", Matchers.is("testId"))) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.canLogIn", Matchers.is(false))); + + } + + @Test + public void replaceOnNonExistentValue() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/netid", "newNetId"); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + String token = getAuthToken(admin.getEmail(), password); + + // update of netId should fail. + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + getClient(token).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.netid", Matchers.nullValue())); + + } + + @Test + public void patchNetIdMissingValue() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .withNetId("testId") + .build(); + + String newId = "newId"; + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/netid", newId); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // initialize to true + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.netid", Matchers.is(newId))); + + + List ops2 = new ArrayList(); + ReplaceOperation replaceOperation2 = new ReplaceOperation("/netid", null); + ops2.add(replaceOperation2); + patchBody = getPatchContent(ops2); + + // should return bad request + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // value should be unchanged. + getClient(token).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.netid", Matchers.is(newId))) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.canLogIn", Matchers.is(false))); + + + } + + @Test + public void patchCanLogin() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/canLogin", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + String token = getAuthToken(admin.getEmail(), password); + + // updates canLogIn to true + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.canLogIn", Matchers.is(true))) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.netid", Matchers.nullValue())); + + + } + + @Test + public void patchCanLoginMissingValue() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/canLogin", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // initialize to true + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.canLogIn", Matchers.is(true)));; + + + List ops2 = new ArrayList(); + ReplaceOperation replaceOperation2 = new ReplaceOperation("/canLogin", null); + ops2.add(replaceOperation2); + patchBody = getPatchContent(ops2); + + // should return bad request + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // value should still be true. + getClient(token).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.canLogIn", Matchers.is(true))) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.requireCertificate", Matchers.is(false))); + + } + + @Test + public void patchRequireCertificate() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + List ops = new ArrayList(); + // Boolean operations should accept either string or boolean as value. Try boolean. + ReplaceOperation replaceOperation = new ReplaceOperation("/certificate", false); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + String token = getAuthToken(admin.getEmail(), password); + + // updates requireCertificate to false + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.requireCertificate", Matchers.is(false))) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.netid", Matchers.nullValue())); + + } + + @Test + public void patchRequireCertificateMissingValue() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/certificate", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // initialize to true + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.requireCertificate", Matchers.is(true)));; + + List ops2 = new ArrayList(); + ReplaceOperation replaceOperation2 = new ReplaceOperation("/certificate",null); + ops2.add(replaceOperation2); + patchBody = getPatchContent(ops2); + + // should return bad request + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // value should still be true. + getClient(token).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.requireCertificate", Matchers.is(true))) + .andExpect(jsonPath("$.email", Matchers.is("johndoe@fake-email.com"))) + .andExpect(jsonPath("$.canLogIn", Matchers.is(false))); + + + } + + @Test + public void patchPassword() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .withPassword("7Testpass") + .build(); + + String newPassword = "newpassword"; + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/password", newPassword); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + String token = getAuthToken(admin.getEmail(), password); + + // updates password + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()); + + // login with new password + token = getAuthToken(ePerson.getEmail(), newPassword); + getClient(token).perform(get("/api/")) + .andExpect(status().isOk()); + + } + + @Test + public void patchPasswordMissingValue() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .withPassword("testpass79bC") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + String newPassword = "newpass"; + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/password", newPassword); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // initialize passwd + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()); + + + List ops2 = new ArrayList(); + ReplaceOperation replaceOperation2 = new ReplaceOperation("/password", null); + ops2.add(replaceOperation2); + patchBody = getPatchContent(ops2); + + // should return bad request + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // login with original password + token = getAuthToken(ePerson.getEmail(), newPassword); + getClient(token).perform(get("/api/")) + .andExpect(status().isOk()); + + } + + @Test + public void patchMultipleOperationsWithSuccess() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .withNetId("testId") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + + ReplaceOperation replaceOperation1 = new ReplaceOperation("/canLogin", true); + ops.add(replaceOperation1); + ReplaceOperation replaceOperation2 = new ReplaceOperation("/netid", "multitestId"); + ops.add(replaceOperation2); + ReplaceOperation replaceOperation3 = new ReplaceOperation("/certificate", true); + ops.add(replaceOperation3); + String patchBody = getPatchContent(ops); + + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.canLogIn", Matchers.is(true))) + .andExpect(jsonPath("$.netid", Matchers.is("multitestId"))) + .andExpect(jsonPath("$.requireCertificate", Matchers.is(true))); + + } + + @Test + public void patchMultipleOperationsWithFailure() throws Exception { + + context.turnOffAuthorisationSystem(); + + EPerson ePerson = EPersonBuilder.createEPerson(context) + .withNameInMetadata("John", "Doe") + .withEmail("Johndoe@fake-email.com") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation0 = new ReplaceOperation("/canLogin", true); + ops.add(replaceOperation0); + String patchBody = getPatchContent(ops); + + // Initialized canLogIn value is true. + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.canLogIn", Matchers.is(true))); + + // The first operation in the series sets canLogIn to be false. + ReplaceOperation replaceOperation1 = new ReplaceOperation("/canLogin", false); + ops.add(replaceOperation1); + ReplaceOperation replaceOperation2 = new ReplaceOperation("/certificate", true); + ops.add(replaceOperation2); + // This will fail. The path does not exist. + ReplaceOperation replaceOperation3 = new ReplaceOperation("/nonexistentPath", "somevalue"); + ops.add(replaceOperation3); + ReplaceOperation replaceOperation4 = new ReplaceOperation("/certificate", false); + ops.add(replaceOperation4); + patchBody = getPatchContent(ops); + + // The 3rd operation should result in bad request + getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // The value of canLogIn should equal the previously initialized value. + getClient(token).perform(get("/api/eperson/epersons/" + ePerson.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.canLogIn", Matchers.is(true))); + + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EmptyRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EmptyRestRepositoryIT.java new file mode 100644 index 0000000000..653ff072a0 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EmptyRestRepositoryIT.java @@ -0,0 +1,44 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.junit.Test; + +public class EmptyRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + public void findAllTest() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + //Test retrieval of all communities while none exist + getClient(token).perform(get("/api/core/communities")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + + //Test retrieval of all collections while none exist + getClient(token).perform(get("/api/core/collections")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + + //Test retrieval of all items while none exist + getClient(token).perform(get("/api/core/items")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + + //Test retrieval of all bitstreams while none exist + getClient(token).perform(get("/api/core/bitstreams")) + . andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java new file mode 100644 index 0000000000..b75c9cf7bb --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java @@ -0,0 +1,237 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.UUID; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.dspace.app.rest.builder.GroupBuilder; +import org.dspace.app.rest.matcher.GroupMatcher; +import org.dspace.app.rest.model.GroupRest; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.eperson.Group; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * @author Jonas Van Goolen - (jonas@atmire.com) + */ + +public class GroupRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + public void createTest() + throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + GroupRest groupRest = new GroupRest(); + String groupName = "testGroup1"; + + groupRest.setName(groupName); + + String authToken = getAuthToken(admin.getEmail(), password); + getClient(authToken).perform(post("/api/eperson/groups") + .content(mapper.writeValueAsBytes(groupRest)).contentType(contentType)) + .andExpect(status().isCreated()); + + getClient(authToken).perform(get("/api/eperson/groups")) + //The status has to be 200 OK + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.groups", Matchers.containsInAnyOrder( + GroupMatcher.matchGroupWithName(groupName), + GroupMatcher.matchGroupWithName("Administrator"), + GroupMatcher.matchGroupWithName("Anonymous")))); + + } + + @Test + public void createUnauthauthorizedTest() + throws Exception { + ObjectMapper mapper = new ObjectMapper(); + GroupRest groupRest = new GroupRest(); + String groupName = "testGroupUnauth1"; + + groupRest.setName(groupName); + + String authToken = getAuthToken(eperson.getEmail(), password); + + getClient().perform(post("/api/eperson/groups") + .content(mapper.writeValueAsBytes(groupRest)).contentType(contentType)) + .andExpect(status().isUnauthorized()); + + } + + @Test + public void createForbiddenTest() + throws Exception { + ObjectMapper mapper = new ObjectMapper(); + GroupRest groupRest = new GroupRest(); + String groupName = "testGroupForbidden1"; + + groupRest.setName(groupName); + + String authToken = getAuthToken(eperson.getEmail(), password); + + authToken = getAuthToken(eperson.getEmail(), password); + getClient(authToken).perform(post("/api/eperson/groups") + .content(mapper.writeValueAsBytes(groupRest)).contentType(contentType)) + .andExpect(status().isForbidden()); + } + + @Test + public void findAllTest() throws Exception { + + getClient().perform(get("/api/eperson/groups")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + + String token = getAuthToken(admin.getEmail(), password); + + //When we call the root endpoint + getClient(token).perform(get("/api/eperson/groups")) + //The status has to be 200 OK + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + //The array of groups should have a size 2 + .andExpect(jsonPath("$._embedded.groups", hasSize(2))) + // The default groups should consist of "Anonymous" and "Anonymous" + .andExpect(jsonPath("$._embedded.groups", Matchers.containsInAnyOrder( + GroupMatcher.matchGroupWithName("Administrator"), + GroupMatcher.matchGroupWithName("Anonymous") + ))) + ; + } + + @Test + public void findAllPaginationTest() throws Exception { + + getClient().perform(get("/api/eperson/groups")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + + String token = getAuthToken(admin.getEmail(), password); + + //When we call the root endpoint + getClient(token).perform(get("/api/eperson/groups")) + //The status has to be 200 OK + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))); + } + + + @Test + public void findOneTest() throws Exception { + context.turnOffAuthorisationSystem(); + + String testGroupName = "Test group"; + Group group = GroupBuilder.createGroup(context) + .withName(testGroupName) + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + String generatedGroupId = group.getID().toString(); + String groupIdCall = "/api/eperson/groups/" + generatedGroupId; + getClient(token).perform(get(groupIdCall)) + //The status has to be 200 OK + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.is( + GroupMatcher.matchGroupEntry(group.getID(), group.getName()) + ))) + ; + getClient(token).perform(get("/api/eperson/groups")) + //The status has to be 200 OK + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + + .andExpect(jsonPath("$.page.totalElements", is(3))); + + } + + @Test + public void readGroupAuthorizationTest() throws Exception { + context.turnOffAuthorisationSystem(); + + Group group = GroupBuilder.createGroup(context) + .withName("Group1") + .build(); + + Group group2 = GroupBuilder.createGroup(context) + .withName("Group2") + .addMember(eperson) + .build(); + + //Admin can access + String token = getAuthToken(admin.getEmail(), password); + getClient(token).perform(get("/api/eperson/groups/" + group2.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.is( + GroupMatcher.matchGroupEntry(group2.getID(), group2.getName()) + ))) + .andExpect(jsonPath("$", Matchers.not( + Matchers.is( + GroupMatcher.matchGroupEntry(group.getID(), group.getName()) + ) + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/eperson/groups/" + group2.getID()))); + + + //People in group should be able to access token + token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/eperson/groups/" + group2.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.is( + GroupMatcher.matchGroupEntry(group2.getID(), group2.getName()) + ))) + .andExpect(jsonPath("$", Matchers.not( + Matchers.is( + GroupMatcher.matchGroupEntry(group.getID(), group.getName()) + ) + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/eperson/groups/" + group2.getID()))); + } + + @Test + public void findOneTestWrongUUID() throws Exception { + context.turnOffAuthorisationSystem(); + + String testGroupName = "Test group"; + Group group = GroupBuilder.createGroup(context) + .withName(testGroupName) + .build(); + + String generatedGroupId = group.getID().toString(); + String groupIdCall = "/api/eperson/groups/" + UUID.randomUUID(); + getClient().perform(get(groupIdCall)) + //The status has to be 200 OK + .andExpect(status().isNotFound()) + ; + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/IdentifierRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/IdentifierRestControllerIT.java new file mode 100644 index 0000000000..2956e90513 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/IdentifierRestControllerIT.java @@ -0,0 +1,71 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Integration test for the identifier resolver + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + */ +public class IdentifierRestControllerIT extends AbstractControllerIntegrationTest { + + @Before + public void setup() throws Exception { + super.setUp(); + } + + @Test + public void testValidIdentifier() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // We create a top community to receive an identifier + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + context.restoreAuthSystemState(); + + String handle = parentCommunity.getHandle(); + String communityDetail = REST_SERVER_URL + "core/communities/" + parentCommunity.getID(); + + getClient().perform(get("/api/pid/find?id={handle}",handle)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the community details + .andExpect(header().string("Location", communityDetail)); + } + + @Test + public void testUnexistentIdentifier() throws Exception { + getClient().perform(get("/api/pid/find?id={id}","fakeIdentifier")) + .andExpect(status().isNotFound()); + } + + @Test + @Ignore + /** + * This test will check the return status code when no id is supplied. It currently fails as our + * RestResourceController take the precedence over the pid controller returning a 404 Repository not found + * + * @throws Exception + */ + public void testMissingIdentifierParameter() throws Exception { + getClient().perform(get("/api/pid/find")) + .andExpect(status().isUnprocessableEntity()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java new file mode 100644 index 0000000000..55de139f29 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java @@ -0,0 +1,1417 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.ws.rs.core.MediaType; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.CharEncoding; +import org.dspace.app.rest.builder.BitstreamBuilder; +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.EPersonBuilder; +import org.dspace.app.rest.builder.GroupBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.builder.WorkspaceItemBuilder; +import org.dspace.app.rest.matcher.ItemMatcher; +import org.dspace.app.rest.model.patch.Operation; +import org.dspace.app.rest.model.patch.ReplaceOperation; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.WorkspaceItem; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + public void findAllTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 3") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/core/items")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.items", Matchers.containsInAnyOrder( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, + "Public item 1", "2017-10-17"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, + "Public item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, + "Public item 3", "2016-02-13") + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + ; + } + + @Test + public void findAllWithPaginationTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 3") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/core/items") + .param("size", "2")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.items", Matchers.containsInAnyOrder( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, + "Public item 1", "2017-10-17"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, + "Public item 2", "2016-02-13") + ))) + .andExpect(jsonPath("$._embedded.items", Matchers.not( + Matchers.contains( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, + "Public item 3", "2016-02-13") + ) + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))) + ; + + getClient(token).perform(get("/api/core/items") + .param("size", "2") + .param("page", "1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.items", Matchers.contains( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, + "Public item 3", "2016-02-13") + ))) + .andExpect(jsonPath("$._embedded.items", Matchers.not( + Matchers.contains( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, + "Public item 1", "2017-10-17"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, + "Public item 2", "2016-02-13") + ) + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))) + .andExpect(jsonPath("$.page.size", is(2))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + ; + } + + @Test + public void findOneTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 3") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + getClient().perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, + "Public item 1", "2017-10-17") + ))) + .andExpect(jsonPath("$", Matchers.not( + Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, + "Public item 2", "2016-02-13") + ) + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))) + ; + } + + @Test + public void findOneRelsTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 3") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); + + //Add a bitstream to an item + String bitstreamContent = "ThisIsSomeDummyText"; + Bitstream bitstream1 = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream1 = BitstreamBuilder. + createBitstream(context, publicItem1, is) + .withName("Bitstream1") + .withMimeType("text/plain") + .build(); + } + + getClient().perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher + .matchItemWithTitleAndDateIssued(publicItem1, + "Public item 1", "2017-10-17") + ))) + .andExpect(jsonPath("$", Matchers.not( + Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, + "Public item 2", "2016-02-13") + ) + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))) + ; + + getClient().perform(get("/api/core/items/" + publicItem1.getID() + "/bitstreams")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.self.href", Matchers + .containsString("/api/core/items/" + publicItem1.getID() + "/bitstreams"))) + ; + + getClient().perform(get("/api/core/items/" + publicItem1.getID() + "/owningCollection")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/collections"))) + ; + + getClient().perform(get("/api/core/items/" + publicItem1.getID() + "/templateItemOf")) + .andExpect(status().isNoContent()); + ; + } + + @Test + public void findOneTestWrongUUID() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/core/items/" + UUID.randomUUID())) + .andExpect(status().isNotFound()) + ; + + } + + @Test + public void withdrawPatchTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1").build(); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + // A token must be provided for withdraw operation. The person + // is used in the provenance note. + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/withdrawn", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // withdraw item + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(true))) + .andExpect(jsonPath("$.inArchive", Matchers.is(false))); + + // check item status after the patch + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(true))) + .andExpect(jsonPath("$.inArchive", Matchers.is(false))); + + // item already withdrawn, no-op, 200 response + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(true))) + .andExpect(jsonPath("$.inArchive", Matchers.is(false))); + } + + @Test + public void withdrawPatchUnauthorizedTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1").build(); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/withdrawn", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // withdraw item + getClient().perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isUnauthorized()); + + // use the admin to be sure to get the item status + String tokenAdmin = getAuthToken(eperson.getEmail(), password); + + // check item status after the failed patch + getClient(tokenAdmin).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(false))) + .andExpect(jsonPath("$.inArchive", Matchers.is(true))); + } + + @Test + public void withdrawPatchForbiddenTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1").build(); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + // try to use an unauthorized user + String token = getAuthToken(eperson.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/withdrawn", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // withdraw item + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isForbidden()); + + // use the admin to be sure to get the item status + String tokenAdmin = getAuthToken(eperson.getEmail(), password); + + // check item status after the failed patch + getClient(tokenAdmin).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(false))) + .andExpect(jsonPath("$.inArchive", Matchers.is(true))); + } + + @Test + public void valueMissingForWithdrawalOperation() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1").build(); + + // we need to set a current user as the withdrawn operation use it to add provenance information + context.setCurrentUser(admin); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + //2. One withdrawn item + Item item2 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .withdrawn() + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/withdrawn", null); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // check item status after the failed patch (it must be unchanged) + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(false))) + .andExpect(jsonPath("$.inArchive", Matchers.is(true))); + + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // check item status after the failed patch (it must be unchanged) + getClient(token).perform(get("/api/core/items/" + item2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item2.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(true))) + .andExpect(jsonPath("$.inArchive", Matchers.is(false))); + } + + @Test + public void reinstatePatchTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1").build(); + + // we need to set a current user as the withdrawn operation use it to add provenance information + context.setCurrentUser(admin); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .withdrawn() + .build(); + + // A token must be provided for reinstate operation. The person + // is used in the provenance note. + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/withdrawn", false); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(false))) + .andExpect(jsonPath("$.inArchive", Matchers.is(true))); + + // check item status after the patch + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(false))) + .andExpect(jsonPath("$.inArchive", Matchers.is(true))); + + // reinstate an already installed item is a no-op + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(false))) + .andExpect(jsonPath("$.inArchive", Matchers.is(true))); + } + + @Test + public void reinstatePatchUnauthorizedTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1").build(); + + // we need to set a current user as the withdrawn operation use it to add provenance information + context.setCurrentUser(admin); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .withdrawn() + .build(); + + String tokenAdmin = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/withdrawn", false); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make an anonymous request + getClient().perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isUnauthorized()); + + // check item status after the failed patch + getClient(tokenAdmin).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(true))) + .andExpect(jsonPath("$.inArchive", Matchers.is(false))); + } + + @Test + public void reinstatePatchForbiddenTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1").build(); + + // we need to set a current user as the withdrawn operation use it to add provenance information + context.setCurrentUser(admin); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .withdrawn() + .build(); + + String token = getAuthToken(eperson.getEmail(), password); + String tokenAdmin = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/withdrawn", false); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make a request with an unauthorized user + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isForbidden()); + + // check item status after the failed patch + getClient(tokenAdmin).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.withdrawn", Matchers.is(true))) + .andExpect(jsonPath("$.inArchive", Matchers.is(false))); + } + + @Test + public void makeDiscoverablePatchTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One private item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/discoverable", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make discoverable + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(true))); + + // check item status after the patch + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(true))); + + // make discoverable an already discoverable item is a no-op + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(true))); + } + + @Test + public void makeDiscoverablePatchUnauthorizedTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One private item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/discoverable", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make discoverable with anonymous user + getClient().perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isUnauthorized()); + + // check item status after the patch + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(false))); + } + + @Test + public void makeDiscoverablePatchForbiddenTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One private item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + String token = getAuthToken(eperson.getEmail(), password); + String tokenAdmin = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/discoverable", true); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make discoverable with anonymous user + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isForbidden()); + + // check item status after the patch + getClient(tokenAdmin).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(false))); + } + + @Test + public void makeUnDiscoverablePatchTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/discoverable", false); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make private + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(false))); + + // check item status after the patch + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(false))); + + } + + + @Test + public void useStringForBooleanTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + // String value should work. + ReplaceOperation replaceOperation = new ReplaceOperation("/discoverable", "false"); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make private + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(false))); + + // check item status after the patch + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(false))); + + } + + @Test + public void makeUnDiscoverablePatchUnauthorizedTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/discoverable", false); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make private with an anonymous user + getClient().perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isUnauthorized()); + + // check item status after the failed patch + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(true))); + + } + + @Test + public void makeUnDiscoverablePatchForbiddenTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + String token = getAuthToken(eperson.getEmail(), password); + String tokenAdmin = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/discoverable", false); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + // make private + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isForbidden()); + + // check item status after the failed patch + getClient(tokenAdmin).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(true))); + + } + + @Test + public void valueMissingForDiscoverableOperation() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1) + .withName("Collection 1").build(); + + //2. One public item + Item item = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + //3. One private item + Item item2 = ItemBuilder.createItem(context, col1) + .withTitle("Not discoverable item 2") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + List ops = new ArrayList(); + ReplaceOperation replaceOperation = new ReplaceOperation("/discoverable", null); + ops.add(replaceOperation); + String patchBody = getPatchContent(ops); + + getClient(token).perform(patch("/api/core/items/" + item.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // check item status after the failed patch (it must be unchanged) + getClient(token).perform(get("/api/core/items/" + item.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(true))); + + List ops2 = new ArrayList(); + ReplaceOperation replaceOperation2 = new ReplaceOperation("/discoverable", null); + ops.add(replaceOperation); + String patchBody2 = getPatchContent(ops); + + getClient(token).perform(patch("/api/core/items/" + item2.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isBadRequest()); + + // check item status after the failed patch (it must be unchanged) + getClient(token).perform(get("/api/core/items/" + item2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.uuid", Matchers.is(item2.getID().toString()))) + .andExpect(jsonPath("$.discoverable", Matchers.is(false))); + + } + + @Test + public void deleteOneArchivedTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community with one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection col1 = CollectionBuilder + .createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. One public item, one workspace item and one template item. + Item publicItem = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + //Add a bitstream to an item + String bitstreamContent = "ThisIsSomeDummyText"; + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder. + createBitstream(context, publicItem, is) + .withName("Bitstream1") + .withMimeType("text/plain") + .build(); + } + + // Check publicItem creation + getClient().perform(get("/api/core/items/" + publicItem.getID())) + .andExpect(status().isOk()); + + // Check publicItem bitstream creatino + getClient().perform(get("/api/core/items/" + publicItem.getID() + "/bitstreams")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.self.href", Matchers + .containsString("/api/core/items/" + publicItem.getID() + "/bitstreams"))); + + String token = getAuthToken(admin.getEmail(), password); + + //Delete public item + getClient(token).perform(delete("/api/core/items/" + publicItem.getID())) + .andExpect(status().is(204)); + + //Trying to get deleted item should fail with 404 + getClient().perform(get("/api/core/items/" + publicItem.getID())) + .andExpect(status().is(404)); + + //Trying to get deleted item bitstream should fail with 404 + getClient().perform(get("/api/core/biststreams/" + bitstream.getID())) + .andExpect(status().is(404)); + } + + @Test + public void deleteOneTemplateTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + //2. A collection with one template item. + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1") + .withTemplateItem() + .build(); + + + Item templateItem = col1.getTemplateItem(); + + String token = getAuthToken(admin.getEmail(), password); + + //Trying to delete a templateItem should fail with 422 + getClient(token).perform(delete("/api/core/items/" + templateItem.getID())) + .andExpect(status().is(422)); + + //Check templateItem is available after failed deletion + getClient(token).perform(get("/api/core/items/" + templateItem.getID())) + .andExpect(status().isOk()); + } + + @Test + public void deleteOneWorkspaceTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community with one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder + .createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. One workspace item. + WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + //Trying to delete a workspaceItem should fail with 422 + getClient(token).perform(delete("/api/core/items/" + workspaceItem.getItem().getID())) + .andExpect(status().is(422)); + + //Check workspaceItem is available after failed deletion + getClient(token).perform(get("/api/core/items/" + workspaceItem.getItem().getID())) + .andExpect(status().isOk()); + } + + @Test + public void embargoAccessTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. An embargoed item + Item embargoedItem1 = ItemBuilder.createItem(context, col1) + .withTitle("embargoed item 1") + .withIssueDate("2017-12-18") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .withEmbargoPeriod("6 months") + .build(); + + //3. a public item + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + //** THEN ** + //An anonymous user can view public items + getClient().perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued( + publicItem1, "Public item 1", "2017-10-17") + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))); + + //An anonymous user is not allowed to view embargoed items + getClient().perform(get("/api/core/items/" + embargoedItem1.getID())) + .andExpect(status().isUnauthorized()); + + //An admin user is allowed to access the embargoed item + String token1 = getAuthToken(admin.getEmail(), password); + getClient(token1).perform(get("/api/core/items/" + embargoedItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued( + embargoedItem1, "embargoed item 1", "2017-12-18") + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))); + + } + + @Test + public void undiscoverableAccessTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. An undiscoverable item + Item unDiscoverableYetAccessibleItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Undiscoverable item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); + + context.restoreAuthSystemState(); + + + //Anonymous users are allowed to access undiscoverable items + getClient().perform(get("/api/core/items/" + unDiscoverableYetAccessibleItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued(unDiscoverableYetAccessibleItem1, + "Undiscoverable item 1", "2017-10-17") + ))); + + + //Admin users are allowed to acceess undiscoverable items + String token1 = getAuthToken(admin.getEmail(), password); + getClient(token1).perform(get("/api/core/items/" + unDiscoverableYetAccessibleItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued(unDiscoverableYetAccessibleItem1, + "Undiscoverable item 1", "2017-10-17") + ))); + + } + + @Test + public void privateGroupAccessTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. An item restricted to a specific internal group + Group staffGroup = GroupBuilder.createGroup(context) + .withName("Staff") + .build(); + + Item restrictedItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Restricted item 1") + .withIssueDate("2017-12-18") + .withReaderGroup(staffGroup) + .build(); + + //3. A public item + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + //4. A member of the internal group + EPerson staffEPerson = EPersonBuilder.createEPerson(context) + .withEmail("professor@myuni.edu") + .withPassword("s3cr3t") + .withNameInMetadata("Doctor", "Professor") + .withGroupMembership(staffGroup) + .build(); + + + context.restoreAuthSystemState(); + + //** THEN ** + //An anonymous user can view the public item + getClient().perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued( + publicItem1, "Public item 1", "2017-10-17") + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))); + + //An anonymous user is not allowed to the restricted item + getClient().perform(get("/api/core/items/" + restrictedItem1.getID())) + .andExpect(status().isUnauthorized()); + + //An admin user is allowed to access the restricted item + String token1 = getAuthToken(admin.getEmail(), password); + getClient(token1).perform(get("/api/core/items/" + restrictedItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued( + restrictedItem1, "Restricted item 1", "2017-12-18") + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))); + + //A member of the internal group is also allowed to access the restricted item + String token2 = getAuthToken("professor@myuni.edu", "s3cr3t"); + getClient(token2).perform(get("/api/core/items/" + restrictedItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is( + ItemMatcher.matchItemWithTitleAndDateIssued( + restrictedItem1, "Restricted item 1", "2017-12-18") + ))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("/api/core/items"))); + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadataSchemaRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadataSchemaRestRepositoryIT.java new file mode 100644 index 0000000000..1d7b60a8d0 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadataSchemaRestRepositoryIT.java @@ -0,0 +1,56 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.builder.MetadataSchemaBuilder; +import org.dspace.app.rest.matcher.MetadataschemaMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.MetadataSchema; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + public void findAll() throws Exception { + + context.turnOffAuthorisationSystem(); + MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "ATest", "ANamespace") + .build(); + + getClient().perform(get("/api/core/metadataschemas")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.metadataschemas", Matchers.hasItem( + MetadataschemaMatcher.matchEntry() + ))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/metadataschemas"))) + .andExpect(jsonPath("$.page.size", is(20))); + } + + + @Test + public void findOne() throws Exception { + + context.turnOffAuthorisationSystem(); + MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "ATest", "ANamespace") + .build(); + + getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", is( + MetadataschemaMatcher.matchEntry(metadataSchema) + ))); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java new file mode 100644 index 0000000000..7217030ab3 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java @@ -0,0 +1,127 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.builder.MetadataFieldBuilder; +import org.dspace.app.rest.builder.MetadataSchemaBuilder; +import org.dspace.app.rest.matcher.MetadataFieldMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataSchema; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegrationTest { + + + @Test + public void findAll() throws Exception { + + context.turnOffAuthorisationSystem(); + MetadataField metadataField = MetadataFieldBuilder + .createMetadataField(context, "AnElement", "AQualifier", "AScopeNote").build(); + + getClient().perform(get("/api/core/metadatafields") + .param("size", String.valueOf(100))) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItems( + MetadataFieldMatcher.matchMetadataFieldByKeys("dc","title", null), + MetadataFieldMatcher.matchMetadataFieldByKeys("dc","date", "issued")) + )) + .andExpect(jsonPath("$._links.first.href", Matchers.containsString("/api/core/metadatafields"))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/metadatafields"))) + .andExpect(jsonPath("$._links.next.href", Matchers.containsString("/api/core/metadatafields"))) + .andExpect(jsonPath("$._links.last.href", Matchers.containsString("/api/core/metadatafields"))) + + .andExpect(jsonPath("$.page.size", is(100))); + } + + @Test + public void findOne() throws Exception { + + context.turnOffAuthorisationSystem(); + MetadataField metadataField = MetadataFieldBuilder + .createMetadataField(context, "AnElement", "AQualifier", "AScopeNote").build(); + + getClient().perform(get("/api/core/metadatafields/" + metadataField.getID())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.is( + MetadataFieldMatcher.matchMetadataField(metadataField) + ))); + } + + @Test + public void searchMethodsExist() throws Exception { + getClient().perform(get("/api/core/metadatafields")) + .andExpect(jsonPath("$._links.search.href", Matchers.notNullValue())); + + getClient().perform(get("/api/core/metadatafields/search")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._links.bySchema", Matchers.notNullValue())); + } + + @Test + public void findBySchema() throws Exception { + + context.turnOffAuthorisationSystem(); + MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema", + "http://www.dspace.org/ns/aschema").build(); + + MetadataField metadataField = MetadataFieldBuilder + .createMetadataField(context, schema, "AnElement", "AQualifier", "AScopeNote").build(); + + getClient().perform(get("/api/core/metadatafields/search/bySchema") + .param("schema", "dc") + .param("size", String.valueOf(100))) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItems( + MetadataFieldMatcher.matchMetadataFieldByKeys("dc","title", null), + MetadataFieldMatcher.matchMetadataFieldByKeys("dc","date", "issued")) + )) + .andExpect(jsonPath("$.page.size", is(100))); + + getClient().perform(get("/api/core/metadatafields/search/bySchema") + .param("schema", schema.getName())) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem( + MetadataFieldMatcher.matchMetadataField(metadataField)) + )) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))); + } + + @Test + public void findByUndefinedSchema() throws Exception { + + getClient().perform(get("/api/core/metadatafields/search/bySchema") + .param("schema", "undefined")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + @Test + public void findByNullSchema() throws Exception { + + getClient().perform(get("/api/core/metadatafields/search/bySchema")) + .andExpect(status().isUnprocessableEntity()); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RestResourceControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RestResourceControllerIT.java new file mode 100644 index 0000000000..a309cc4a2d --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RestResourceControllerIT.java @@ -0,0 +1,72 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.UUID; + +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.junit.Test; + +/** + * Integration test for the {@link RestResourceController} + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + */ +public class RestResourceControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void undefinedRepository() throws Exception { + // When we call the root endpoint + getClient().perform(get("/api/undefined/undefined")) + // The status has to be 404 Not Found + .andExpect(status().isNotFound()); + } + + @Test + public void undefinedSubResource() throws Exception { + // We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // ** GIVEN ** + // 1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build(); + + // When we call the root endpoint + getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString() + "/undefined")) + // The status has to be 404 Not Found + .andExpect(status().isNotFound()); + } + + @Test + public void selfRelIsNotASubResource() throws Exception { + // We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // ** GIVEN ** + // 1. A community-collection structure with one parent community with sub-community and one collection. + parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build(); + + // When we call the root endpoint + getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString() + "/self")) + // The status has to be 404 Not Found + .andExpect(status().isNotFound()); + } + + @Test + public void notExistentResourceValidSubPath() throws Exception { + // When we call the root endpoint + getClient().perform(get("/api/core/communities/" + UUID.randomUUID().toString() + "/collections")) + // The status has to be 404 Not Found + .andExpect(status().isNotFound()); + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RootRestResourceControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RootRestResourceControllerIT.java new file mode 100644 index 0000000000..48f805bd13 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RootRestResourceControllerIT.java @@ -0,0 +1,59 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.startsWith; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.junit.Test; + +/** + * Integration test for the {@link RootRestResourceController} + * + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + * @author Tom Desair (tom dot desair at atmire dot com) + */ +public class RootRestResourceControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void listDefinedEndpoint() throws Exception { + + //When we call the root endpoint + getClient().perform(get("/api")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //Check that all required root links are present and that they are absolute + .andExpect(jsonPath("$._links.authorities.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.bitstreamformats.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.bitstreams.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.browses.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.collections.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.communities.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.epersons.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.groups.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.items.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.metadatafields.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.metadataschemas.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.resourcePolicies.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.sites.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.submissiondefinitions.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.submissionforms.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.submissionsections.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.submissionuploads.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.workspaceitems.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.authn.href", startsWith(REST_SERVER_URL))) + ; + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SiteRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SiteRestRepositoryIT.java new file mode 100644 index 0000000000..33ada54c97 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SiteRestRepositoryIT.java @@ -0,0 +1,70 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.UUID; + +import org.dspace.app.rest.builder.SiteBuilder; +import org.dspace.app.rest.matcher.SiteMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Site; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class SiteRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + public void findAll() throws Exception { + + + context.turnOffAuthorisationSystem(); + //This will always return just one site, DSpace doesn't allow for more to be created + Site site = SiteBuilder.createSite(context).build(); + + + getClient().perform(get("/api/core/sites")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.sites[0]", SiteMatcher.matchEntry(site))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/sites"))) + .andExpect(jsonPath("$.page.size", is(20))); + + } + + @Test + public void findOne() throws Exception { + + + context.turnOffAuthorisationSystem(); + //This will always return just one site, DSpace doesn't allow for more to be created + Site site = SiteBuilder.createSite(context).build(); + + + getClient().perform(get("/api/core/sites/" + site.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", SiteMatcher.matchEntry(site))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/sites"))); + + } + + + @Test + public void findOneWrongUUID() throws Exception { + + + context.turnOffAuthorisationSystem(); + + getClient().perform(get("/api/core/sites/" + UUID.randomUUID())) + .andExpect(status().isNotFound()); + + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java new file mode 100644 index 0000000000..553251633f --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java @@ -0,0 +1,167 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.matcher.SubmissionDefinitionsMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; + +/** + * Integration test to test the /api/config/submissiondefinitions endpoint + * (Class has to start or end with IT to be picked up by the failsafe plugin) + */ +public class SubmissionDefinitionsControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void findAll() throws Exception { + //When we call the root endpoint as anonymous user + getClient().perform(get("/api/config/submissiondefinitions")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + + String token = getAuthToken(admin.getEmail(), password); + + + getClient(token).perform(get("/api/config/submissiondefinitions")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //By default we expect at least 1 submission definition so this to be reflected in the page object + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", greaterThanOrEqualTo(1))) + .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) + .andExpect(jsonPath("$.page.number", is(0))) + .andExpect( + jsonPath("$._links.search.href", is(REST_SERVER_URL + "config/submissiondefinitions/search"))) + + //The array of browse index should have a size greater or equals to 1 + .andExpect(jsonPath("$._embedded.submissiondefinitions", hasSize(greaterThanOrEqualTo(1)))) + ; + } + + @Test + public void findDefault() throws Exception { + + getClient().perform(get("/api/config/submissiondefinitions/traditional")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/config/submissiondefinitions/traditional")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //Check that the JSON root matches the expected "traditional" submission definition + .andExpect(jsonPath("$", SubmissionDefinitionsMatcher + .matchSubmissionDefinition(true, "traditional", "traditional"))) + ; + } + + @Test + public void findByCollection() throws Exception { + + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + getClient().perform(get("/api/config/submissiondefinitions/search/findByCollection") + .param("uuid", col1.getID().toString())) + //** THEN ** + //The status has to be 200 + .andExpect(status().isUnauthorized()); + + String token = getAuthToken(admin.getEmail(), password); + + + + getClient(token).perform(get("/api/config/submissiondefinitions/search/findByCollection") + .param("uuid", col1.getID().toString())) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + .andDo(MockMvcResultHandlers.print()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", SubmissionDefinitionsMatcher + .matchSubmissionDefinition(true, "traditional", "traditional"))); + } + + @Test + public void findCollections() throws Exception { + + //Match only that a section exists with a submission configuration behind + getClient().perform(get("/api/config/submissiondefinitions/traditional/collections")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + String token = getAuthToken(admin.getEmail(), password); + + + //Match only that a section exists with a submission configuration behind + getClient(token).perform(get("/api/config/submissiondefinitions/traditional/collections")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + @Test + public void findSections() throws Exception { + + getClient().perform(get("/api/config/submissiondefinitions/traditional/sections")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/config/submissiondefinitions/traditional/sections")) + // The status has to be 200 OK + .andExpect(status().isOk()) + // We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + // Match only that a section exists with a submission configuration behind + .andExpect(jsonPath("$._embedded.submissionsections", hasSize(5))) + .andExpect(jsonPath("$._embedded.submissionsections", + Matchers.hasItem( + allOf( + hasJsonPath("$.id", is("traditionalpageone")), + hasJsonPath("$.sectionType", is("submission-form")), + hasJsonPath("$.type", is("submissionsection")), + hasJsonPath("$._links.config.href", + is(REST_SERVER_URL + + "config/submissionforms/traditionalpageone")), + hasJsonPath("$._links.self.href", + is(REST_SERVER_URL + + "config/submissionsections/traditionalpageone")) + )))) + ; + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java new file mode 100644 index 0000000000..1d1b0d5ac8 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java @@ -0,0 +1,98 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.matcher.SubmissionFormFieldMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Integration test to test the /api/config/submissionforms endpoint + * (Class has to start or end with IT to be picked up by the failsafe plugin) + */ +public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void findAll() throws Exception { + //When we call the root endpoint as anonymous user + getClient().perform(get("/api/config/submissionforms")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + + String token = getAuthToken(admin.getEmail(), password); + + //When we call the root endpoint + getClient(token).perform(get("/api/config/submissionforms")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //The configuration file for the test env includes 3 forms + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", equalTo(3))) + .andExpect(jsonPath("$.page.totalPages", equalTo(1))) + .andExpect(jsonPath("$.page.number", is(0))) + .andExpect( + jsonPath("$._links.self.href", Matchers.startsWith(REST_SERVER_URL + "config/submissionforms"))) + //The array of submissionforms should have a size of 3 + .andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(3)))) + ; + } + + @Test + public void findTraditionalPageOne() throws Exception { + //When we call the root endpoint as anonymous user + getClient().perform(get("/api/config/submissionforms/traditionalpageone")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/config/submissionforms/traditionalpageone")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //Check that the JSON root matches the expected "traditionalpageone" input forms + .andExpect(jsonPath("$.id", is("traditionalpageone"))) + .andExpect(jsonPath("$.name", is("traditionalpageone"))) + .andExpect(jsonPath("$.type", is("submissionform"))) + .andExpect(jsonPath("$._links.self.href", Matchers + .startsWith(REST_SERVER_URL + "config/submissionforms/traditionalpageone"))) + // check the first two rows + .andExpect(jsonPath("$.rows[0].fields", contains( + SubmissionFormFieldMatcher.matchFormFieldDefinition("name", "Authors", null, true, + "Enter the names of the authors of this item.", "dc.contributor.author")))) + .andExpect(jsonPath("$.rows[1].fields", contains( + SubmissionFormFieldMatcher.matchFormFieldDefinition("onebox", "Title", + "You must enter a main title for this item.", false, + "Enter the main title of the item.", "dc.title")))) + // check a row with multiple fields + .andExpect(jsonPath("$.rows[3].fields", + contains( + SubmissionFormFieldMatcher.matchFormFieldDefinition("date", "Date of Issue", + "You must enter at least the year.", false, + "Please give the date", "col-sm-4", + "dc.date.issued"), + SubmissionFormFieldMatcher.matchFormFieldDefinition("onebox", "Publisher", null, false, + "Enter the name of", "col-sm-8", + "dc.publisher")))) + ; + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java new file mode 100644 index 0000000000..643debcbfc --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java @@ -0,0 +1,59 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Integration test to test the /api/config/submissionforms endpoint + * (Class has to start or end with IT to be picked up by the failsafe plugin) + */ +public class SubmissionSectionsControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void findAll() throws Exception { + //When we call the root endpoint as anonymous user + getClient().perform(get("/api/config/submissionsections")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + + String token = getAuthToken(admin.getEmail(), password); + + //When we call the root endpoint + getClient(token).perform(get("/api/config/submissionsections")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //By default we expect at least 1 submission forms so this to be reflected in the page object + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", greaterThanOrEqualTo(1))) + .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) + .andExpect(jsonPath("$.page.number", is(0))) + .andExpect(jsonPath("$._links.self.href", + Matchers.startsWith(REST_SERVER_URL + "config/submissionsections"))) + + //The array of browse index should have a size greater or equals to 1 + .andExpect(jsonPath("$._embedded.submissionsections", hasSize(greaterThanOrEqualTo(1)) + )) + ; + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java new file mode 100644 index 0000000000..07e570f609 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java @@ -0,0 +1,57 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Integration test to test the /api/config/submissionforms endpoint + * (Class has to start or end with IT to be picked up by the failsafe plugin) + */ +public class SubmissionUploadsControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void findAll() throws Exception { + //When we call the root endpoint as anonymous user + getClient().perform(get("/api/config/submissionuploads")) + //The status has to be 403 Not Authorized + .andExpect(status().isUnauthorized()); + + + String token = getAuthToken(admin.getEmail(), password); + + //When we call the root endpoint + getClient(token).perform(get("/api/config/submissionuploads")) + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //By default we expect at least 1 submission forms so this to be reflected in the page object + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", greaterThanOrEqualTo(1))) + .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) + .andExpect(jsonPath("$.page.number", is(0))) + .andExpect(jsonPath("$._links.self.href", + Matchers.startsWith(REST_SERVER_URL + "config/submissionuploads"))) + + //The array of browse index should have a size greater or equals to 1 + .andExpect(jsonPath("$._embedded.submissionuploads", hasSize(greaterThanOrEqualTo(1)))) + ; + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/UUIDLookupRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/UUIDLookupRestControllerIT.java new file mode 100644 index 0000000000..8f99811fa6 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/UUIDLookupRestControllerIT.java @@ -0,0 +1,306 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; +import java.util.UUID; + +import org.apache.commons.codec.CharEncoding; +import org.apache.commons.io.IOUtils; +import org.dspace.app.rest.builder.BitstreamBuilder; +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.GroupBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.builder.SiteBuilder; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.Site; +import org.dspace.eperson.Group; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Integration test for the UUIDLookup endpoint + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + */ +public class UUIDLookupRestControllerIT extends AbstractControllerIntegrationTest { + + @Test + /** + * Test the proper redirection of a site's uuid + * + * @throws Exception + */ + public void testSiteUUID() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // We create a site to get the uuid to lookup + Site site = SiteBuilder.createSite(context).build(); + + context.restoreAuthSystemState(); + + String uuid = site.getID().toString(); + String siteDetail = REST_SERVER_URL + "core/sites/" + uuid; + + getClient().perform(get("/api/dso/find?uuid={uuid}",uuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the site details + .andExpect(header().string("Location", siteDetail)); + } + + @Test + /** + * Test the proper redirection of an community's uuid + * + * @throws Exception + */ + public void testCommunityUUID() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // We create a community to get the uuid to lookup + Community community = CommunityBuilder.createCommunity(context) + .withName("A Community") + .build(); + + context.restoreAuthSystemState(); + + String uuid = community.getID().toString(); + String communityDetail = REST_SERVER_URL + "core/communities/" + uuid; + + getClient().perform(get("/api/dso/find?uuid={uuid}",uuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the community details + .andExpect(header().string("Location", communityDetail)); + } + + @Test + /** + * Test the proper redirection of an collection's uuid + * + * @throws Exception + */ + public void testCollectionUUID() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // We create a community and a collection to get the uuid to lookup + Community community = CommunityBuilder.createCommunity(context) + .withName("A Community") + .build(); + + Collection collection = CollectionBuilder.createCollection(context, community) + .withName("A Collection") + .build(); + + context.restoreAuthSystemState(); + + String uuid = collection.getID().toString(); + String collectionDetail = REST_SERVER_URL + "core/collections/" + uuid; + + getClient().perform(get("/api/dso/find?uuid={uuid}",uuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the community details + .andExpect(header().string("Location", collectionDetail)); + } + + @Test + /** + * Test the proper redirection of an item's uuid + * + * @throws Exception + */ + public void testItemUUID() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // We create a community and a collection to get the uuid to lookup + Community community = CommunityBuilder.createCommunity(context) + .withName("A Community") + .build(); + + Collection collection = CollectionBuilder.createCollection(context, community) + .withName("A Collection") + .build(); + + Item item = ItemBuilder.createItem(context, collection) + .withTitle("An Item") + .build(); + + context.restoreAuthSystemState(); + + String uuid = item.getID().toString(); + String itemDetail = REST_SERVER_URL + "core/items/" + uuid; + + getClient().perform(get("/api/dso/find?uuid={uuid}",uuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the community details + .andExpect(header().string("Location", itemDetail)); + } + + @Test + @Ignore + /** + * Test the proper redirection of a bundle's uuid + * + * @throws Exception + */ + public void testBundleUUID() throws Exception { + // Currently, there is no bundle endpoint + } + + @Test + /** + * Test the proper redirection of uuids of different kinds of bitstreams (standard, collection and community logo) + * + * @throws Exception + */ + public void testBitstreamUUID() throws Exception { + //We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + // We create a community and a collection to get the uuid to lookup + Community community = CommunityBuilder.createCommunity(context) + .withName("A Community") + .withLogo("Community Logo") + .build(); + + Collection collection = CollectionBuilder.createCollection(context, community) + .withName("A Collection") + .withLogo("Collection Logo") + .build(); + + Item item = ItemBuilder.createItem(context, collection) + .withTitle("An Item") + .build(); + + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream("bitstreamContent", CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder.createBitstream(context, item, is) + .withName("Bitstream") + .withDescription("description") + .withMimeType("text/plain") + .build(); + } + + context.restoreAuthSystemState(); + + String uuid = bitstream.getID().toString(); + String colLogoUuid = community.getLogo().getID().toString(); + String comLogoUuid = collection.getLogo().getID().toString(); + String bitstreamDetail = REST_SERVER_URL + "core/bitstreams/" + uuid; + String colLogoDetail = REST_SERVER_URL + "core/bitstreams/" + colLogoUuid; + String comLogoDetail = REST_SERVER_URL + "core/bitstreams/" + comLogoUuid; + + // test the resolution of a standard bitstream + getClient().perform(get("/api/dso/find?uuid={uuid}",uuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the community details + .andExpect(header().string("Location", bitstreamDetail)); + + // test the resolution of a community's logo bitstream + getClient().perform(get("/api/dso/find?uuid={uuid}", comLogoUuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the community details + .andExpect(header().string("Location", comLogoDetail)); + + // test the resolution of a collection's logo bitstream + getClient().perform(get("/api/dso/find?uuid={uuid}", colLogoUuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the community details + .andExpect(header().string("Location", colLogoDetail)); + + } + + @Test + /** + * Test the proper redirection of an eperson's uuid + * + * @throws Exception + */ + public void testEPersonUUID() throws Exception { + String uuid = eperson.getID().toString(); + String epersonDetail = REST_SERVER_URL + "eperson/epersons/" + uuid; + + getClient().perform(get("/api/dso/find?uuid={uuid}",uuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the eperson details + .andExpect(header().string("Location", epersonDetail)); + } + + @Test + /** + * Test the proper redirection of an eperson's uuid + * + * @throws Exception + */ + public void testGroupUUID() throws Exception { + // We turn off the authorization system in order to create the structure as defined below + context.turnOffAuthorisationSystem(); + + Group group = GroupBuilder.createGroup(context) + .withName("Test Group") + .build(); + + context.restoreAuthSystemState(); + + String uuid = group.getID().toString(); + String groupDetail = REST_SERVER_URL + "eperson/groups/" + uuid; + + getClient().perform(get("/api/dso/find?uuid={uuid}",uuid)) + .andExpect(status().isFound()) + //We expect a Location header to redirect to the group details + .andExpect(header().string("Location", groupDetail)); + } + + @Test + /** + * Test that a request with a valid, not existent, uuid parameter return a 404 Not Found status + * + * @throws Exception + */ + public void testUnexistentUUID() throws Exception { + getClient().perform(get("/api/dso/find?uuid={uuid}",UUID.randomUUID().toString())) + .andExpect(status().isNotFound()); + } + + @Test + /** + * Test that a request with an uuid parameter that is not an actual UUID return a 422 Unprocessable Entity status + * + * @throws Exception + */ + public void testInvalidUUID() throws Exception { + getClient().perform(get("/api/dso/find?uuid={uuid}","invalidUUID")) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + @Ignore + /** + * This test will check the return status code when no uuid is supplied. It currently fails as our + * RestResourceController take the precedence over the UUIDLookupController returning a 404 Repository not found + * + * @throws Exception + */ + public void testMissingIdentifierParameter() throws Exception { + getClient().perform(get("/api/dso/find")) + .andExpect(status().isUnprocessableEntity()); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java new file mode 100644 index 0000000000..885ad2d123 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java @@ -0,0 +1,1668 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.ws.rs.core.MediaType; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.CharEncoding; +import org.dspace.app.rest.builder.BitstreamBuilder; +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.EPersonBuilder; +import org.dspace.app.rest.builder.WorkspaceItemBuilder; +import org.dspace.app.rest.matcher.CollectionMatcher; +import org.dspace.app.rest.matcher.ItemMatcher; +import org.dspace.app.rest.matcher.WorkspaceItemMatcher; +import org.dspace.app.rest.model.patch.AddOperation; +import org.dspace.app.rest.model.patch.Operation; +import org.dspace.app.rest.model.patch.RemoveOperation; +import org.dspace.app.rest.model.patch.ReplaceOperation; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.WorkspaceItem; +import org.dspace.eperson.EPerson; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.springframework.mock.web.MockMultipartFile; + +/** + * Test suite for the WorkspaceItem endpoint + * @author Andrea Bollini (andrea.bollini at 4science.it) + * + */ +public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + /** + * All the workspaceitem should be returned regardless of the collection where they were created + * + * @throws Exception + */ + public void findAllTest() throws Exception { + context.setCurrentUser(admin); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + + //2. Three workspace items in two different collections + WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 2") + .withIssueDate("2016-02-13") + .build(); + + WorkspaceItem workspaceItem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 3") + .withIssueDate("2016-02-13") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/submission/workspaceitems")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", Matchers.containsInAnyOrder( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, "Workspace Item 2", + "2016-02-13"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", + "2016-02-13")))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/submission/workspaceitems"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(3))); + } + + @Test + /** + * The workspaceitem endpoint must provide proper pagination + * + * @throws Exception + */ + public void findAllWithPaginationTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + + //2. Three workspace items in two different collections + WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 2") + .withIssueDate("2016-02-13") + .build(); + + WorkspaceItem workspaceItem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 3") + .withIssueDate("2016-02-13") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/submission/workspaceitems").param("size", "2")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.containsInAnyOrder( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, "Workspace Item 2", + "2016-02-13")))) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.not(Matchers.contains(WorkspaceItemMatcher + .matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", "2016-02-13"))))); + + getClient(token).perform(get("/api/submission/workspaceitems").param("size", "2").param("page", "1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.contains(WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem3, + "Workspace Item 3", "2016-02-13")))) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.not(Matchers.contains( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, "Workspace Item 2", + "2016-02-13"))))) + .andExpect(jsonPath("$.page.size", is(2))).andExpect(jsonPath("$.page.totalElements", is(3))); + } + + @Test + /** + * The workspaceitem resource endpoint must expose the proper structure + * + * @throws Exception + */ + public void findOneTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())).andExpect(status().isOk()) + .andExpect(jsonPath("$", + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workspace Item 1", "2017-10-17", "ExtraEntry")))); + } + + @Test + /** + * The workspaceitem resource endpoint must expose the proper structure + * + * @throws Exception + */ + public void findOneRelsTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/collection")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers + .is(CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())))); + + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/item")).andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is(ItemMatcher.matchItemWithTitleAndDateIssued(witem.getItem(), + "Workspace Item 1", "2017-10-17")))); + + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/submissionDefinition")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is(hasJsonPath("$.id", is("traditional"))))); + + } + + @Test + /** + * Check the response code for unexistent workspaceitem + * + * @throws Exception + */ + public void findOneWrongUUIDTest() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/submission/workspaceitems/" + UUID.randomUUID())) + .andExpect(status().isNotFound()); + } + + @Test + /** + * Removing a workspaceitem should result in delete of all the underline resources (item and bitstreams) + * + * @throws Exception + */ + public void deleteOneTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community with one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + Item item = witem.getItem(); + + //Add a bitstream to the item + String bitstreamContent = "ThisIsSomeDummyText"; + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder + .createBitstream(context, item, is) + .withName("Bitstream1") + .withMimeType("text/plain").build(); + } + + String token = getAuthToken(admin.getEmail(), password); + + //Delete the workspaceitem + getClient(token).perform(delete("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().is(204)); + + //Trying to get deleted item should fail with 404 + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().is(404)); + + //Trying to get deleted workspaceitem's item should fail with 404 + getClient().perform(get("/api/core/items/" + item.getID())) + .andExpect(status().is(404)); + + //Trying to get deleted workspaceitem's bitstream should fail with 404 + getClient().perform(get("/api/core/biststreams/" + bitstream.getID())) + .andExpect(status().is(404)); + } + + @Test + /** + * Create three workspaceitem with two different submitter and verify that the findBySubmitter return the proper + * list of workspaceitem for each submitter also paginating + * + * @throws Exception + */ + public void findBySubmitterTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. create two users to use as submitters + EPerson submitter1 = EPersonBuilder.createEPerson(context) + .withEmail("submitter1@example.com") + .build(); + EPerson submitter2 = EPersonBuilder.createEPerson(context) + .withEmail("submitter2@example.com") + .build(); + + // create two workspaceitems with the first submitter + context.setCurrentUser(submitter1); + + + //3. Two workspace items in two different collections + WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 2") + .withIssueDate("2016-02-13") + .build(); + + //4. A workspaceitem for the second submitter + context.setCurrentUser(submitter2); + WorkspaceItem workspaceItem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 3") + .withIssueDate("2016-02-13") + .build(); + + // use our admin to retrieve all the workspace by submitter + String token = getAuthToken(admin.getEmail(), password); + + // the first submitter has two workspace + getClient(token).perform(get("/api/submission/workspaceitems/search/findBySubmitter") + .param("size", "20") + .param("uuid", submitter1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.containsInAnyOrder( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, "Workspace Item 2", + "2016-02-13")))) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.not(Matchers.contains(WorkspaceItemMatcher + .matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", "2016-02-13"))))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(2))); + + // the first submitter has two workspace so if we paginate with a 1-size windows the page 1 will contains the + // second workspace + getClient(token).perform(get("/api/submission/workspaceitems/search/findBySubmitter") + .param("size", "1") + .param("page", "1") + .param("uuid", submitter1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.contains(WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, + "Workspace Item 2", "2016-02-13")))) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.not(Matchers.contains( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", + "2016-02-13"))))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(2))); + + // the second submitter has a single workspace + getClient(token).perform(get("/api/submission/workspaceitems/search/findBySubmitter") + .param("size", "20") + .param("uuid", submitter2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.contains( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", + "2016-02-13")))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))); + } + + @Test + /** + * Test the creation of workspaceitem POSTing to the resource collection endpoint. It should respect the collection + * param if present or use a default if it is not used + * + * @throws Exception + */ + public void createEmptyWorkspateItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + // create a workspaceitem explicitly in the col1 + getClient(authToken).perform(post("/api/submission/workspaceitems") + .param("collection", col1.getID().toString())) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$._embedded.collection.id", is(col1.getID().toString()))); + + // create a workspaceitem explicitly in the col2 + getClient(authToken).perform(post("/api/submission/workspaceitems") + .param("collection", col2.getID().toString())) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$._embedded.collection.id", is(col2.getID().toString()))); + + // create a workspaceitem without an explicit collection, this will go in the first valid collection for the + // user: the col1 + getClient(authToken).perform(post("/api/submission/workspaceitems")) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$._embedded.collection.id", is(col1.getID().toString()))); + + // TODO cleanup the context!!! + } + + @Test + /** + * Test the creation of workspaceitems POSTing to the resource collection endpoint a bibtex file + * + * @throws Exception + */ + public void createMultipleWorkspaceItemFromFileTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + String authToken = getAuthToken(admin.getEmail(), password); + + InputStream bibtex = getClass().getResourceAsStream("bibtex-test.bib"); + final MockMultipartFile bibtexFile = new MockMultipartFile("file", "bibtex-test.bib", "application/x-bibtex", + bibtex); + + // bulk create workspaceitems in the default collection (col1) + getClient(authToken).perform(fileUpload("/api/submission/workspaceitems") + .file(bibtexFile)) + // bulk create should return 200, 201 (created) is better for single resource + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", + is("My Article"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id", is(col1.getID().toString()))) + .andExpect(jsonPath("$._embedded.workspaceitems[1].sections.traditionalpageone['dc.title'][0].value", + is("My Article 2"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[1]._embedded.collection.id", is(col1.getID().toString()))) + .andExpect(jsonPath("$._embedded.workspaceitems[2].sections.traditionalpageone['dc.title'][0].value", + is("My Article 3"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[2]._embedded.collection.id", is(col1.getID().toString()))) + .andExpect( + jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist()) + ; + + // bulk create workspaceitems explicitly in the col2 + getClient(authToken).perform(fileUpload("/api/submission/workspaceitems") + .file(bibtexFile) + .param("collection", col2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", + is("My Article"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id", is(col2.getID().toString()))) + .andExpect(jsonPath("$._embedded.workspaceitems[1].sections.traditionalpageone['dc.title'][0].value", + is("My Article 2"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[1]._embedded.collection.id", is(col2.getID().toString()))) + .andExpect(jsonPath("$._embedded.workspaceitems[2].sections.traditionalpageone['dc.title'][0].value", + is("My Article 3"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[2]._embedded.collection.id", is(col2.getID().toString()))) + .andExpect( + jsonPath("$._embedded.workspaceitems[*]._embedded.upload").doesNotExist()) + ; + + bibtex.close(); + } + + @Test + /** + * Test the creation of a workspaceitem POSTing to the resource collection endpoint a PDF file. As a single item + * will be created we expect to have the pdf file stored as a bitstream + * + * @throws Exception + */ + public void createWorkspaceItemFromPDFFileTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + String authToken = getAuthToken(admin.getEmail(), password); + + InputStream pdf = getClass().getResourceAsStream("simple-article.pdf"); + final MockMultipartFile pdfFile = new MockMultipartFile("file", "/local/path/myfile.pdf", "application/pdf", + pdf); + + // bulk create a workspaceitem + getClient(authToken).perform(fileUpload("/api/submission/workspaceitems") + .file(pdfFile)) + // bulk create should return 200, 201 (created) is better for single resource + .andExpect(status().isOk()) + //FIXME it will be nice to setup a mock grobid server for end to end testing + // no metadata for now +// .andExpect(jsonPath("$._embedded.workspaceitems[0]._embedded.traditionalpageone['dc.title'][0].value", +// is("This is a simple test file"))) + // we can just check that the pdf is stored in the item + .andExpect( + jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0].metadata['dc.title'][0].value", + is("myfile.pdf"))) + .andExpect(jsonPath( + "$._embedded.workspaceitems[0].sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/myfile.pdf"))) + ; + + pdf.close(); + } + + @Test + /** + * Test the exposition of validation error for missing required metadata both at the creation time than on existent + * workspaceitems + * + * @throws Exception + */ + public void validationErrorsRequiredMetadataTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + workspaceItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + ; + + WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 2") + .build(); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + workspaceItem2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(false))) + .andExpect(jsonPath("$.errors[?(@.message=='error.validation.required')]", + Matchers.contains( + hasJsonPath("$.paths", Matchers.contains( + hasJsonPath("$", Matchers.is("/sections/traditionalpageone/dc.date.issued")) + ))))) + ; + + // create an empty workspaceitem explicitly in the col1, check validation on creation + getClient(authToken).perform(post("/api/submission/workspaceitems") + .param("collection", col1.getID().toString())) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.status", is(false))) + // title and author are required in the first panel + // the json path with a @ selector always return an array + .andExpect(jsonPath("$.errors[?(@.message=='error.validation.required')]", + Matchers.contains( + hasJsonPath("$.paths", Matchers.containsInAnyOrder( + hasJsonPath("$", Matchers.is("/sections/traditionalpageone/dc.title")), + hasJsonPath("$", Matchers.is("/sections/traditionalpageone/dc.date.issued")) + ))))) + ; + } + + @Test + /** + * Test the update of metadata + * + * @throws Exception + */ + public void patchUpdateMetadataTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withSubject("ExtraEntry") + .build(); + + // a simple patch to update an existent metadata + List updateTitle = new ArrayList(); + Map value = new HashMap(); + value.put("value", "New Title"); + updateTitle.add(new ReplaceOperation("/sections/traditionalpageone/dc.title/0", value)); + + String patchBody = getPatchContent(updateTitle); + + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$", + // check the new title and untouched values + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "New Title", "2017-10-17", "ExtraEntry")))); + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$", + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "New Title", "2017-10-17", "ExtraEntry")))) + ; + } + + @Test + /** + * Test delete of a metadata + * + * @throws Exception + */ + public void patchDeleteMetadataTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withSubject("ExtraEntry") + .build(); + + WorkspaceItem witemMultipleSubjects = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withSubject("Subject1") + .withSubject("Subject2") + .withSubject("Subject3") + .withSubject("Subject4") + .build(); + + WorkspaceItem witemWithTitleDateAndSubjects = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withSubject("Subject1") + .withSubject("Subject2") + .withSubject("Subject3") + .withSubject("Subject4") + .build(); + + // try to remove the title + List removeTitle = new ArrayList(); + removeTitle.add(new RemoveOperation("/sections/traditionalpageone/dc.title/0")); + + String patchBody = getPatchContent(removeTitle); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(false))) + .andExpect(jsonPath("$.errors[?(@.message=='error.validation.required')]", + Matchers.contains(hasJsonPath("$.paths", + Matchers.contains( + hasJsonPath("$", + Matchers.is("/sections/traditionalpageone/dc.title"))))))) + .andExpect(jsonPath("$", + // check the new title and untouched values + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + null, "2017-10-17", "ExtraEntry")))); + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(false))) + .andExpect(jsonPath("$.errors[?(@.message=='error.validation.required')]", + Matchers.contains( + hasJsonPath("$.paths", Matchers.contains( + hasJsonPath("$", Matchers.is("/sections/traditionalpageone/dc.title")) + ))))) + .andExpect(jsonPath("$", + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + null, "2017-10-17", "ExtraEntry")))) + ; + + // try to remove a metadata in a specific position + List removeMidSubject = new ArrayList(); + removeMidSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/1")); + + patchBody = getPatchContent(removeMidSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemMultipleSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject3"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Subject4"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemMultipleSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject3"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Subject4"))) + ; + + List removeFirstSubject = new ArrayList(); + removeFirstSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/0")); + + patchBody = getPatchContent(removeFirstSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemMultipleSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject3"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject4"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemMultipleSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject3"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject4"))) + ; + + List removeLastSubject = new ArrayList(); + removeLastSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/1")); + + patchBody = getPatchContent(removeLastSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemMultipleSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject3"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemMultipleSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject3"))) + ; + + List removeFinalSubject = new ArrayList(); + removeFinalSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/0")); + + patchBody = getPatchContent(removeFinalSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemMultipleSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject']").doesNotExist()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemMultipleSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject']").doesNotExist()) + ; + + // remove all the subjects with a single operation + List removeSubjectsAllAtOnce = new ArrayList(); + removeSubjectsAllAtOnce.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject")); + + patchBody = getPatchContent(removeSubjectsAllAtOnce); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemWithTitleDateAndSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject']").doesNotExist()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemWithTitleDateAndSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject']").doesNotExist()) + ; + } + + @Test + /** + * Test the addition of metadata + * + * @throws Exception + */ + public void patchAddMetadataTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withIssueDate("2017-10-17") + .withSubject("ExtraEntry") + .build(); + + + // try to add the title + List addTitle = new ArrayList(); + // create a list of values to use in add operation + List> values = new ArrayList>(); + Map value = new HashMap(); + value.put("value", "New Title"); + values.add(value); + addTitle.add(new AddOperation("/sections/traditionalpageone/dc.title", values)); + + String patchBody = getPatchContent(addTitle); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$", + // check if the new title if back and the other values untouched + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "New Title", "2017-10-17", "ExtraEntry")))); + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$", + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "New Title", "2017-10-17", "ExtraEntry")))) + ; + } + + @Test + /** + * Test the addition of metadata + * + * @throws Exception + */ + public void patchAddMultipleMetadataValuesTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .build(); + + // try to add multiple subjects at once + List addSubjects = new ArrayList(); + // create a list of values to use in add operation + List> values = new ArrayList>(); + Map value1 = new HashMap(); + value1.put("value", "Subject1"); + Map value2 = new HashMap(); + value2.put("value", "Subject2"); + values.add(value1); + values.add(value2); + + addSubjects.add(new AddOperation("/sections/traditionalpagetwo/dc.subject", values)); + + String patchBody = getPatchContent(addSubjects); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject2"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject2"))) + ; + + // add a subject in the first position + List addFirstSubject = new ArrayList(); + Map firstSubject = new HashMap(); + firstSubject.put("value", "First Subject"); + + addFirstSubject.add(new AddOperation("/sections/traditionalpagetwo/dc.subject/0", firstSubject)); + + patchBody = getPatchContent(addFirstSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", + is("Subject2"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Subject2"))) + ; + + // add a subject in a central position + List addMidSubject = new ArrayList(); + Map midSubject = new HashMap(); + midSubject.put("value", "Mid Subject"); + + addMidSubject.add(new AddOperation("/sections/traditionalpagetwo/dc.subject/2", midSubject)); + + patchBody = getPatchContent(addMidSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", + is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", + is("Subject2"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", is("Subject2"))) + ; + + // append a last subject without specifying the index + List addLastSubject = new ArrayList(); + Map lastSubject = new HashMap(); + lastSubject.put("value", "Last Subject"); + + addLastSubject.add(new AddOperation("/sections/traditionalpagetwo/dc.subject/4", lastSubject)); + + patchBody = getPatchContent(addLastSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", + is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", + is("Subject2"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][4].value", + is("Last Subject"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", is("Subject2"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][4].value", is("Last Subject"))) + ; + + // append a last subject without specifying the index + List addFinalSubject = new ArrayList(); + Map finalSubject = new HashMap(); + finalSubject.put("value", "Final Subject"); + + addFinalSubject.add(new AddOperation("/sections/traditionalpagetwo/dc.subject/-", finalSubject)); + + patchBody = getPatchContent(addFinalSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", + is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", + is("Subject2"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][4].value", + is("Last Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][5].value", + is("Final Subject"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", is("Subject2"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][4].value", is("Last Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][5].value", is("Final Subject"))) + ; + } + + @Test + /** + * Test the acceptance of the deposit license + * + * @throws Exception + */ + public void patchAcceptLicenseTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem witem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 2") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem witem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 3") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem witem4 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 4") + .withIssueDate("2017-10-17") + .build(); + + // check that our workspaceitems come without a license (all are build in the same way, just check the first) + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // try to grant the license with an add operation + List addGrant = new ArrayList(); + addGrant.add(new AddOperation("/sections/license/granted", true)); + + String patchBody = getPatchContent(addGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // try to grant the license with an add operation supplying a string instead than a boolean + List addGrantString = new ArrayList(); + addGrantString.add(new AddOperation("/sections/license/granted", "true")); + + patchBody = getPatchContent(addGrantString); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem2.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // try to grant the license with a replace operation + List replaceGrant = new ArrayList(); + replaceGrant.add(new ReplaceOperation("/sections/license/granted", true)); + + patchBody = getPatchContent(replaceGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem3.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem3.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // try to grant the license with a replace operation supplying a string + List replaceGrantString = new ArrayList(); + replaceGrant.add(new ReplaceOperation("/sections/license/granted", "true")); + + patchBody = getPatchContent(replaceGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem4.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem4.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + } + + @Test + /** + * Test the reject of the deposit license + * + * @throws Exception + */ + public void patchRejectLicenseTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .grantLicense() + .build(); + + WorkspaceItem witem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 2") + .withIssueDate("2017-10-17") + .grantLicense() + .build(); + + WorkspaceItem witem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 3") + .withIssueDate("2017-10-17") + .grantLicense() + .build(); + + WorkspaceItem witem4 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 4") + .withIssueDate("2017-10-17") + .grantLicense() + .build(); + + // check that our workspaceitems come with a license (all are build in the same way, just check the first) + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // try to reject the license with an add operation + List addGrant = new ArrayList(); + addGrant.add(new AddOperation("/sections/license/granted", false)); + + String patchBody = getPatchContent(addGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // try to reject the license with an add operation supplying a string instead than a boolean + List addGrantString = new ArrayList(); + addGrantString.add(new AddOperation("/sections/license/granted", "false")); + + patchBody = getPatchContent(addGrantString); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem2.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // try to reject the license with a replace operation + List replaceGrant = new ArrayList(); + replaceGrant.add(new ReplaceOperation("/sections/license/granted", false)); + + patchBody = getPatchContent(replaceGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem3.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem3.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // try to reject the license with a replace operation supplying a string + List replaceGrantString = new ArrayList(); + replaceGrant.add(new ReplaceOperation("/sections/license/granted", "false")); + + patchBody = getPatchContent(replaceGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem4.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem4.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + } + + @Test + /** + * Test update of bitstream metadata in the upload section + * + * @throws Exception + */ + public void patchUploadTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + String authToken = getAuthToken(admin.getEmail(), password); + + InputStream pdf = getClass().getResourceAsStream("simple-article.pdf"); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .withFulltext("simple-article.pdf", "/local/path/simple-article.pdf", pdf) + .build(); + + // check the file metadata + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/simple-article.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("simple-article.pdf"))) + ; + + // try to change the filename and add a description + List addOpts = new ArrayList(); + Map value = new HashMap(); + value.put("value", "newfilename.pdf"); + Map valueDesc = new HashMap(); + valueDesc.put("value", "Description"); + List valueDescs = new ArrayList(); + valueDescs.add(valueDesc); + addOpts.add(new AddOperation("/sections/upload/files/0/metadata/dc.title/0", value)); + addOpts.add(new AddOperation("/sections/upload/files/0/metadata/dc.description", valueDescs)); + + String patchBody = getPatchContent(addOpts); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + // is the source still here? + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/simple-article.pdf"))) + // check the new filename + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("newfilename.pdf"))) + // check the description + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.description'][0].value", + is("Description"))) + ; + + // check that changes persist + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/simple-article.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("newfilename.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.description'][0].value", + is("Description"))) + ; + + // try to remove the description and the source now + List removeOpts = new ArrayList(); + removeOpts.add(new RemoveOperation("/sections/upload/files/0/metadata/dc.source/0")); + removeOpts.add(new RemoveOperation("/sections/upload/files/0/metadata/dc.description")); + + patchBody = getPatchContent(removeOpts); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + // check the removed source + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source']").doesNotExist()) + // check the filename still here + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("newfilename.pdf"))) + // check the removed description + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.description']").doesNotExist()) + ; + + // check that changes persist + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source']").doesNotExist()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("newfilename.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.description']").doesNotExist()) ; + + // try to update the filename with an update opt + List updateOpts = new ArrayList(); + Map updateValue = new HashMap(); + updateValue.put("value", "another-filename.pdf"); + updateOpts.add(new ReplaceOperation("/sections/upload/files/0/metadata/dc.title/0", updateValue)); + + patchBody = getPatchContent(updateOpts); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + // check the filename still here + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("another-filename.pdf"))) + ; + + // check that changes persist + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("another-filename.pdf"))) + ; + } + + @Test + /** + * Test the upload of files in the upload over section + * + * @throws Exception + */ + public void uploadTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .build(); + + InputStream pdf = getClass().getResourceAsStream("simple-article.pdf"); + final MockMultipartFile pdfFile = new MockMultipartFile("file", "/local/path/simple-article.pdf", + "application/pdf", pdf); + + // upload the file in our workspaceitem + getClient(authToken).perform(fileUpload("/api/submission/workspaceitems/" + witem.getID()) + .file(pdfFile)) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("simple-article.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/simple-article.pdf"))) + ; + + // check the file metadata + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("simple-article.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/simple-article.pdf"))) + ; + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java new file mode 100644 index 0000000000..29a219810e --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java @@ -0,0 +1,200 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.log4j.Logger; +import org.dspace.authorize.factory.AuthorizeServiceFactory; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.authorize.service.ResourcePolicyService; +import org.dspace.content.Bitstream; +import org.dspace.content.factory.ContentServiceFactory; +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.InstallItemService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.SiteService; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Context; +import org.dspace.discovery.IndexingService; +import org.dspace.eperson.factory.EPersonServiceFactory; +import org.dspace.eperson.service.EPersonService; +import org.dspace.eperson.service.GroupService; +import org.dspace.eperson.service.RegistrationDataService; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.dspace.versioning.factory.VersionServiceFactory; +import org.dspace.versioning.service.VersionHistoryService; +import org.dspace.xmlworkflow.storedcomponents.service.ClaimedTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.InProgressUserService; +import org.dspace.xmlworkflow.storedcomponents.service.PoolTaskService; +import org.dspace.xmlworkflow.storedcomponents.service.WorkflowItemRoleService; + +/** + * Abstract builder class that holds references to all available services + * + * @author Jonas Van Goolen - (jonas@atmire.com) + */ +public abstract class AbstractBuilder { + + static CommunityService communityService; + static CollectionService collectionService; + static ItemService itemService; + static InstallItemService installItemService; + static WorkspaceItemService workspaceItemService; + static EPersonService ePersonService; + static GroupService groupService; + static BundleService bundleService; + static BitstreamService bitstreamService; + static BitstreamFormatService bitstreamFormatService; + static AuthorizeService authorizeService; + static ResourcePolicyService resourcePolicyService; + static IndexingService indexingService; + static RegistrationDataService registrationDataService; + static VersionHistoryService versionHistoryService; + static ClaimedTaskService claimedTaskService; + static InProgressUserService inProgressUserService; + static PoolTaskService poolTaskService; + static WorkflowItemRoleService workflowItemRoleService; + static MetadataFieldService metadataFieldService; + static MetadataSchemaService metadataSchemaService; + static SiteService siteService; + + protected Context context; + + private static List builders = new LinkedList<>(); + /** + * log4j category + */ + private static final Logger log = Logger.getLogger(AbstractDSpaceObjectBuilder.class); + + protected AbstractBuilder(Context context) { + this.context = context; + builders.add(this); + } + + public static void init() { + communityService = ContentServiceFactory.getInstance().getCommunityService(); + collectionService = ContentServiceFactory.getInstance().getCollectionService(); + itemService = ContentServiceFactory.getInstance().getItemService(); + installItemService = ContentServiceFactory.getInstance().getInstallItemService(); + workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); + ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); + groupService = EPersonServiceFactory.getInstance().getGroupService(); + bundleService = ContentServiceFactory.getInstance().getBundleService(); + bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); + bitstreamFormatService = ContentServiceFactory.getInstance().getBitstreamFormatService(); + authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); + resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService(); + indexingService = DSpaceServicesFactory.getInstance().getServiceManager() + .getServiceByName(IndexingService.class.getName(), + IndexingService.class); + registrationDataService = EPersonServiceFactory.getInstance().getRegistrationDataService(); + versionHistoryService = VersionServiceFactory.getInstance().getVersionHistoryService(); + metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); + metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); + siteService = ContentServiceFactory.getInstance().getSiteService(); + + // Temporarily disabled + // TODO find a way to be able to test the XML and "default" workflow at the same time + //claimedTaskService = XmlWorkflowServiceFactoryImpl.getInstance().getClaimedTaskService(); + //inProgressUserService = XmlWorkflowServiceFactoryImpl.getInstance().getInProgressUserService(); + //poolTaskService = XmlWorkflowServiceFactoryImpl.getInstance().getPoolTaskService(); + //workflowItemRoleService = XmlWorkflowServiceFactoryImpl.getInstance().getWorkflowItemRoleService(); + } + + + public static void destroy() { + communityService = null; + collectionService = null; + itemService = null; + installItemService = null; + workspaceItemService = null; + ePersonService = null; + groupService = null; + bundleService = null; + bitstreamService = null; + authorizeService = null; + resourcePolicyService = null; + indexingService = null; + bitstreamFormatService = null; + registrationDataService = null; + versionHistoryService = null; + claimedTaskService = null; + inProgressUserService = null; + poolTaskService = null; + workflowItemRoleService = null; + metadataFieldService = null; + metadataSchemaService = null; + siteService = null; + } + + public static void cleanupObjects() throws Exception { + builders.sort(new Comparator() { + @Override + public int compare(AbstractBuilder o1, AbstractBuilder o2) { + return o1.getPriority() - o2.getPriority(); + } + }); + for (AbstractBuilder builder : builders) { + builder.cleanup(); + } + + // Bitstreams still leave a trace when deleted, so we need to fully "expunge" them + try (Context c = new Context()) { + List bitstreams = bitstreamService.findAll(c); + for (Bitstream bitstream : CollectionUtils.emptyIfNull(bitstreams)) { + + // We expect tests to clean up all the objects they create. This means, all bitstreams we find here + // should have already been deleted. If that is not the case (e.g. when added functionality unexpectedly + // creates a new bitstream which was not deleted), this method will throw an exception and the developer + // should look into the unexpected creation of the bitstream. + expungeBitstream(c, bitstream); + } + c.complete(); + } + } + + protected int getPriority() { + return 0; + } + + protected abstract void cleanup() throws Exception; + + public abstract T build(); + + public abstract void delete(T dso) throws Exception; + + protected abstract S getService(); + + protected B handleException(final Exception e) { + log.error(e.getMessage(), e); + return null; + } + + /** + * Method to completely delete a bitstream from the database and asset store. + * + * @param bit The deleted bitstream to remove completely + */ + static void expungeBitstream(Context c, Bitstream bit) throws Exception { + bit = c.reloadEntity(bit); + c.turnOffAuthorisationSystem(); + if (bit != null) { + bitstreamService.expunge(c, bit); + } + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractCRUDBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractCRUDBuilder.java new file mode 100644 index 0000000000..884bcc9e3c --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractCRUDBuilder.java @@ -0,0 +1,40 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import org.dspace.core.Context; +import org.dspace.core.ReloadableEntity; +import org.dspace.service.DSpaceCRUDService; + +/** + * @author Jonas Van Goolen - (jonas@atmire.com) + */ +public abstract class AbstractCRUDBuilder extends AbstractBuilder { + + protected AbstractCRUDBuilder(Context context) { + super(context); + } + + protected abstract DSpaceCRUDService getService(); + + public abstract T build(); + + public void delete(T dso) throws Exception { + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + T attachedDso = c.reloadEntity(dso); + if (attachedDso != null) { + getService().delete(c, attachedDso); + } + c.complete(); + } + + indexingService.commit(); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractDSpaceObjectBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractDSpaceObjectBuilder.java new file mode 100644 index 0000000000..9d1322bcb4 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractDSpaceObjectBuilder.java @@ -0,0 +1,234 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.util.Date; + +import org.apache.log4j.Logger; +import org.dspace.authorize.ResourcePolicy; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.MutablePeriod; +import org.joda.time.format.PeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * Abstract builder to construct DSpace Objects + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Raf Ponsaerts (raf dot ponsaerts at atmire dot com) + */ +public abstract class AbstractDSpaceObjectBuilder + extends AbstractBuilder { + + /* Log4j logger*/ + private static final Logger log = Logger.getLogger(AbstractDSpaceObjectBuilder.class); + + protected AbstractDSpaceObjectBuilder(Context context) { + super(context); + this.context = context; + } + + protected abstract void cleanup() throws Exception; + + + protected abstract DSpaceObjectService getService(); + + + protected B handleException(final Exception e) { + log.error(e.getMessage(), e); + return null; + } + + + protected > B addMetadataValue(final T dso, final String schema, + final String element, + final String qualifier, + final String value) { + try { + getService().addMetadata(context, dso, schema, element, qualifier, Item.ANY, value); + } catch (Exception e) { + return handleException(e); + } + return (B) this; + } + + protected > B setMetadataSingleValue(final T dso, final String schema, + final String element, + final String qualifier, + final String value) { + try { + getService().setMetadataSingleValue(context, dso, schema, element, qualifier, Item.ANY, value); + } catch (Exception e) { + return handleException(e); + } + + return (B) this; + } + + /** + * Support method to grant the {@link Constants#READ} permission over an object only to the {@link Group#ANONYMOUS} + * after the specified embargoPeriod. Any other READ permissions will be removed + * + * @param embargoPeriod + * the embargo period after which the READ permission will be active. It is parsed using the + * {@link PeriodFormatter#parseMutablePeriod(String)} method of the joda library + * @param dso + * the DSpaceObject on which grant the permission + * @return the builder properly configured to retain read permission on the object only for the specified group + */ + protected > B setEmbargo(String embargoPeriod, DSpaceObject dso) { + // add policy just for anonymous + try { + MutablePeriod period = PeriodFormat.getDefault().parseMutablePeriod(embargoPeriod); + Date embargoDate = DateTime.now(DateTimeZone.UTC).plus(period).toDate(); + + return setOnlyReadPermission(dso, groupService.findByName(context, Group.ANONYMOUS), embargoDate); + } catch (Exception e) { + return handleException(e); + } + } + + /** + * Support method to grant the {@link Constants#READ} permission over an object only to a specific group. Any other + * READ permissions will be removed + * + * @param dso + * the DSpaceObject on which grant the permission + * @param group + * the EPersonGroup that will be granted of the permission + * @return the builder properly configured to retain read permission on the object only for the specified group + */ + protected > B setOnlyReadPermission(DSpaceObject dso, Group group, + Date startDate) { + // add policy just for anonymous + try { + authorizeService.removeAllPolicies(context, dso); + + ResourcePolicy rp = authorizeService.createOrModifyPolicy(null, context, null, group, + null, startDate, Constants.READ, + "Integration Test", dso); + if (rp != null) { + resourcePolicyService.update(context, rp); + } + } catch (Exception e) { + return handleException(e); + } + return (B) this; + } + + /** + * Support method to grant {@link Constants#REMOVE} permission to a specific eperson + * + * @param dso + * the DSpaceObject on which grant the permission + * @param eperson + * the eperson that will be granted of the permission + * @param startDate + * the optional start date from which the permission will be grant, can be null + * @return the builder properly configured to build the object with the additional remove permission + */ + protected > B setRemovePermissionForEperson(DSpaceObject dso, + EPerson eperson, + Date startDate) { + try { + + ResourcePolicy rp = authorizeService.createOrModifyPolicy(null, context, null, null, + eperson, startDate, Constants.REMOVE, + "Integration Test", dso); + if (rp != null) { + log.info("Updating resource policy with REMOVE for eperson: " + eperson.getEmail()); + resourcePolicyService.update(context, rp); + } + } catch (Exception e) { + return handleException(e); + } + return (B) this; + } + + /** + * Support method to grant {@link Constants#ADD} permission to a specific eperson + * + * @param dso + * the DSpaceObject on which grant the permission + * @param eperson + * the eperson that will be granted of the permission + * @param startDate + * the optional start date from which the permission will be grant, can be null + * @return the builder properly configured to build the object with the additional add permission + */ + protected > B setAddPermissionForEperson(DSpaceObject dso, + EPerson eperson, + Date startDate) { + try { + + ResourcePolicy rp = authorizeService.createOrModifyPolicy(null, context, null, null, + eperson, startDate, Constants.ADD, + "Integration Test", dso); + if (rp != null) { + log.info("Updating resource policy with ADD for eperson: " + eperson.getEmail()); + resourcePolicyService.update(context, rp); + } + } catch (Exception e) { + return handleException(e); + } + return (B) this; + } + + /** + * Support method to grant {@link Constants#WRITE} permission to a specific eperson + * + * @param dso + * the DSpaceObject on which grant the permission + * @param eperson + * the eperson that will be granted of the permission + * @param startDate + * the optional start date from which the permission will be grant, can be null + * @return the builder properly configured to build the object with the additional write permission + */ + protected > B setWritePermissionForEperson(DSpaceObject dso, + EPerson eperson, + Date startDate) { + try { + + ResourcePolicy rp = authorizeService.createOrModifyPolicy(null, context, null, null, + eperson, startDate, Constants.WRITE, + "Integration Test", dso); + if (rp != null) { + log.info("Updating resource policy with WRITE for eperson: " + eperson.getEmail()); + resourcePolicyService.update(context, rp); + } + } catch (Exception e) { + return handleException(e); + } + return (B) this; + } + + public abstract T build(); + + public void delete(T dso) throws Exception { + + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + T attachedDso = c.reloadEntity(dso); + if (attachedDso != null) { + getService().delete(c, attachedDso); + } + c.complete(); + } + + indexingService.commit(); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamBuilder.java new file mode 100644 index 0000000000..080a6d68c3 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamBuilder.java @@ -0,0 +1,130 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.List; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.Item; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.core.Context; +import org.dspace.eperson.Group; + +/** + * Builder class to build bitstreams in test cases + */ +public class BitstreamBuilder extends AbstractDSpaceObjectBuilder { + + public static final String ORIGINAL = "ORIGINAL"; + + private Bitstream bitstream; + private Item item; + private Group readerGroup; + + protected BitstreamBuilder(Context context) { + super(context); + + } + + public static BitstreamBuilder createBitstream(Context context, Item item, InputStream is) + throws SQLException, AuthorizeException, IOException { + BitstreamBuilder builder = new BitstreamBuilder(context); + return builder.create(context, item, is); + } + + private BitstreamBuilder create(Context context, Item item, InputStream is) + throws SQLException, AuthorizeException, IOException { + this.context = context; + this.item = item; + + Bundle originalBundle = getOriginalBundle(item); + + bitstream = bitstreamService.create(context, originalBundle, is); + + return this; + } + + public BitstreamBuilder withName(String name) throws SQLException { + bitstream.setName(context, name); + return this; + } + + public BitstreamBuilder withDescription(String description) throws SQLException { + bitstream.setDescription(context, description); + return this; + } + + public BitstreamBuilder withMimeType(String mimeType) throws SQLException { + BitstreamFormat bf = bitstreamFormatService.findByMIMEType(context, mimeType); + + if (bf != null) { + bitstream.setFormat(context, bf); + } + + return this; + } + + private Bundle getOriginalBundle(Item item) throws SQLException, AuthorizeException { + List bundles = itemService.getBundles(item, ORIGINAL); + Bundle targetBundle = null; + + if (bundles.size() < 1) { + // not found, create a new one + targetBundle = bundleService.create(context, item, ORIGINAL); + } else { + // put bitstreams into first bundle + targetBundle = bundles.iterator().next(); + } + + return targetBundle; + } + + public BitstreamBuilder withEmbargoPeriod(String embargoPeriod) { + return setEmbargo(embargoPeriod, bitstream); + } + + public BitstreamBuilder withReaderGroup(Group group) { + readerGroup = group; + return this; + } + + public Bitstream build() { + try { + bitstreamService.update(context, bitstream); + itemService.update(context, item); + + //Check if we need to make this bitstream private. + if (readerGroup != null) { + setOnlyReadPermission(bitstream, readerGroup, null); + } + + context.dispatchEvents(); + + indexingService.commit(); + + } catch (Exception e) { + return null; + } + + return bitstream; + } + + protected void cleanup() throws Exception { + delete(bitstream); + } + + protected DSpaceObjectService getService() { + return bitstreamService; + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamFormatBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamFormatBuilder.java new file mode 100644 index 0000000000..ddca4e622a --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamFormatBuilder.java @@ -0,0 +1,87 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.BitstreamFormat; +import org.dspace.core.Context; +import org.dspace.discovery.SearchServiceException; +import org.dspace.service.DSpaceCRUDService; + +/** + * Created by jonas - jonas@atmire.com on 04/12/17. + */ +public class BitstreamFormatBuilder extends AbstractCRUDBuilder { + + /* Log4j logger*/ + private static final Logger log = Logger.getLogger(BitstreamFormatBuilder.class); + + private BitstreamFormat bitstreamFormat; + + protected BitstreamFormatBuilder(Context context) { + super(context); + } + + @Override + protected void cleanup() throws Exception { + delete(bitstreamFormat); + } + + @Override + protected DSpaceCRUDService getService() { + return bitstreamFormatService; + } + + @Override + public BitstreamFormat build() { + try { + + bitstreamFormatService.update(context, bitstreamFormat); + context.dispatchEvents(); + + indexingService.commit(); + } catch (SearchServiceException e) { + log.error(e); + } catch (SQLException e) { + log.error(e); + } catch (AuthorizeException e) { + log.error(e); + ; + } + return bitstreamFormat; + } + + + public static BitstreamFormatBuilder createBitstreamFormat(Context context) + throws SQLException, AuthorizeException { + BitstreamFormatBuilder bitstreamFormatBuilder = new BitstreamFormatBuilder(context); + return bitstreamFormatBuilder.create(context); + } + + private BitstreamFormatBuilder create(Context context) throws SQLException, AuthorizeException { + this.context = context; + + bitstreamFormat = bitstreamFormatService.create(context); + + return this; + } + + public BitstreamFormatBuilder withMimeType(String mimeType) { + bitstreamFormat.setMIMEType(mimeType); + return this; + } + + public BitstreamFormatBuilder withDescription(String description) { + bitstreamFormat.setDescription(description); + return this; + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CollectionBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CollectionBuilder.java new file mode 100644 index 0000000000..d14630b90b --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CollectionBuilder.java @@ -0,0 +1,94 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.CharEncoding; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.MetadataSchema; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.core.Context; + +/** + * Builder to construct Collection objects + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Raf Ponsaerts (raf dot ponsaerts at atmire dot com) + */ +public class CollectionBuilder extends AbstractDSpaceObjectBuilder { + + private Collection collection; + + protected CollectionBuilder(Context context) { + super(context); + + } + + public static CollectionBuilder createCollection(final Context context, final Community parent) { + CollectionBuilder builder = new CollectionBuilder(context); + return builder.create(parent); + } + + private CollectionBuilder create(final Community parent) { + try { + this.collection = collectionService.create(context, parent); + } catch (Exception e) { + return handleException(e); + } + return this; + } + + public CollectionBuilder withName(final String name) { + return setMetadataSingleValue(collection, MetadataSchema.DC_SCHEMA, "title", null, name); + } + + public CollectionBuilder withLogo(final String content) throws AuthorizeException, IOException, SQLException { + + InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8); + try { + collectionService.setLogo(context, collection, is); + return this; + + } finally { + is.close(); + } + } + + public CollectionBuilder withTemplateItem() throws SQLException, AuthorizeException { + collectionService.createTemplateItem(context, collection); + return this; + } + + @Override + public Collection build() { + try { + collectionService.update(context, collection); + context.dispatchEvents(); + indexingService.commit(); + + } catch (Exception e) { + return handleException(e); + } + return collection; + } + + protected void cleanup() throws Exception { + delete(collection); + } + + @Override + protected DSpaceObjectService getService() { + return collectionService; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java new file mode 100644 index 0000000000..1cf9ba74cb --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java @@ -0,0 +1,94 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.CharEncoding; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Community; +import org.dspace.content.MetadataSchema; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.core.Context; + +/** + * Builder to construct Community objects + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Raf Ponsaerts (raf dot ponsaerts at atmire dot com) + */ +public class CommunityBuilder extends AbstractDSpaceObjectBuilder { + + private Community community; + + protected CommunityBuilder(Context context) { + super(context); + } + + public static CommunityBuilder createCommunity(final Context context) { + CommunityBuilder builder = new CommunityBuilder(context); + return builder.create(); + } + + private CommunityBuilder create() { + return createSubCommunity(context, null); + } + + public static CommunityBuilder createSubCommunity(final Context context, final Community parent) { + CommunityBuilder builder = new CommunityBuilder(context); + return builder.createSub(parent); + } + + private CommunityBuilder createSub(final Community parent) { + try { + community = communityService.create(parent, context); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + return this; + } + + public CommunityBuilder withName(final String communityName) { + return setMetadataSingleValue(community, MetadataSchema.DC_SCHEMA, "title", null, communityName); + } + + public CommunityBuilder withLogo(String content) throws AuthorizeException, IOException, SQLException { + try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) { + communityService.setLogo(context, community, is); + } + return this; + } + + @Override + public Community build() { + try { + communityService.update(context, community); + context.dispatchEvents(); + + indexingService.commit(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + return community; + } + + protected void cleanup() throws Exception { + delete(community); + } + + @Override + protected DSpaceObjectService getService() { + return communityService; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EPersonBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EPersonBuilder.java new file mode 100644 index 0000000000..10c04479e9 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EPersonBuilder.java @@ -0,0 +1,91 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.sql.SQLException; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.core.Context; +import org.dspace.discovery.SearchServiceException; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; + +public class EPersonBuilder extends AbstractDSpaceObjectBuilder { + + private EPerson ePerson; + + protected EPersonBuilder(Context context) { + super(context); + } + + protected void cleanup() throws Exception { + delete(ePerson); + } + + protected DSpaceObjectService getService() { + return ePersonService; + } + + public EPerson build() { + try { + ePersonService.update(context, ePerson); + indexingService.commit(); + } catch (SearchServiceException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } catch (AuthorizeException e) { + e.printStackTrace(); + } + return ePerson; + } + + public static EPersonBuilder createEPerson(Context context) { + EPersonBuilder ePersonBuilder = new EPersonBuilder(context); + return ePersonBuilder.create(); + } + + private EPersonBuilder create() { + try { + ePerson = ePersonService.create(context); + } catch (SQLException e) { + e.printStackTrace(); + } catch (AuthorizeException e) { + e.printStackTrace(); + } + return this; + } + + public EPersonBuilder withNameInMetadata(String firstName, String lastName) throws SQLException { + ePerson.setFirstName(context, firstName); + ePerson.setLastName(context, lastName); + return this; + } + + public EPersonBuilder withEmail(String name) { + ePerson.setEmail(name); + return this; + } + + public EPersonBuilder withGroupMembership(Group group) { + groupService.addMember(context, group, ePerson); + return this; + } + + public EPersonBuilder withNetId(final String netId) { + ePerson.setNetid(netId); + return this; + } + + public EPersonBuilder withPassword(final String password) { + ePerson.setCanLogIn(true); + ePersonService.setPassword(ePerson, password); + return this; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/GroupBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/GroupBuilder.java new file mode 100644 index 0000000000..e35ad5ad3a --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/GroupBuilder.java @@ -0,0 +1,86 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; + +/** + * Builder to construct Group objects + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Raf Ponsaerts (raf dot ponsaerts at atmire dot com) + */ +public class GroupBuilder extends AbstractDSpaceObjectBuilder { + + private Group group; + + protected GroupBuilder(Context context) { + super(context); + + } + + protected void cleanup() throws Exception { + delete(group); + } + + public static GroupBuilder createGroup(final Context context) { + GroupBuilder builder = new GroupBuilder(context); + return builder.create(context); + } + + private GroupBuilder create(final Context context) { + this.context = context; + try { + group = groupService.create(context); + } catch (Exception e) { + return handleException(e); + } + return this; + } + + @Override + protected DSpaceObjectService getService() { + return groupService; + } + + @Override + public Group build() { + return group; + } + + public GroupBuilder withName(String groupName) { + try { + groupService.setName(group, groupName); + } catch (Exception e) { + return handleException(e); + } + return this; + } + + public GroupBuilder withParent(Group parent) { + try { + groupService.addMember(context, parent, group); + } catch (Exception e) { + return handleException(e); + } + return this; + } + + public GroupBuilder addMember(EPerson eperson) { + try { + groupService.addMember(context, group, eperson); + } catch (Exception e) { + return handleException(e); + } + return this; + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java new file mode 100644 index 0000000000..f21ba728ca --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java @@ -0,0 +1,128 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.Item; +import org.dspace.content.MetadataSchema; +import org.dspace.content.WorkspaceItem; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.core.Context; +import org.dspace.eperson.Group; + +/** + * Builder to construct Item objects + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Raf Ponsaerts (raf dot ponsaerts at atmire dot com) + */ +public class ItemBuilder extends AbstractDSpaceObjectBuilder { + + private boolean withdrawn = false; + private WorkspaceItem workspaceItem; + private Item item; + private Group readerGroup = null; + + protected ItemBuilder(Context context) { + super(context); + } + + public static ItemBuilder createItem(final Context context, final Collection col) { + ItemBuilder builder = new ItemBuilder(context); + return builder.create(context, col); + } + + private ItemBuilder create(final Context context, final Collection col) { + this.context = context; + + try { + workspaceItem = workspaceItemService.create(context, col, false); + item = workspaceItem.getItem(); + } catch (Exception e) { + return handleException(e); + } + + return this; + } + + public ItemBuilder withTitle(final String title) { + return setMetadataSingleValue(item, MetadataSchema.DC_SCHEMA, "title", null, title); + } + + public ItemBuilder withIssueDate(final String issueDate) { + return addMetadataValue(item, MetadataSchema.DC_SCHEMA, "date", "issued", new DCDate(issueDate).toString()); + } + + public ItemBuilder withAuthor(final String authorName) { + return addMetadataValue(item, MetadataSchema.DC_SCHEMA, "contributor", "author", authorName); + } + + public ItemBuilder withSubject(final String subject) { + return addMetadataValue(item, MetadataSchema.DC_SCHEMA, "subject", null, subject); + } + + public ItemBuilder makeUnDiscoverable() { + item.setDiscoverable(false); + return this; + } + + /** + * Withdrawn the item under build. Please note that an user need to be loggedin the context to avoid NPE during the + * creation of the provenance metadata + * + * @return the ItemBuilder + */ + public ItemBuilder withdrawn() { + withdrawn = true; + return this; + } + + public ItemBuilder withEmbargoPeriod(String embargoPeriod) { + return setEmbargo(embargoPeriod, item); + } + + public ItemBuilder withReaderGroup(Group group) { + readerGroup = group; + return this; + } + + @Override + public Item build() { + try { + installItemService.installItem(context, workspaceItem); + itemService.update(context, item); + + //Check if we need to make this item private. This has to be done after item install. + if (readerGroup != null) { + setOnlyReadPermission(workspaceItem.getItem(), readerGroup, null); + } + + if (withdrawn) { + itemService.withdraw(context, item); + } + + context.dispatchEvents(); + + indexingService.commit(); + return item; + } catch (Exception e) { + return handleException(e); + } + } + + protected void cleanup() throws Exception { + delete(item); + } + + @Override + protected DSpaceObjectService getService() { + return itemService; + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java new file mode 100644 index 0000000000..42f9c10752 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java @@ -0,0 +1,118 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.io.IOException; +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataSchema; +import org.dspace.content.NonUniqueMetadataException; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.core.Context; +import org.dspace.discovery.SearchServiceException; + +public class MetadataFieldBuilder extends AbstractBuilder { + + /* Log4j logger*/ + private static final Logger log = Logger.getLogger(MetadataFieldBuilder.class); + + private MetadataField metadataField; + + @Override + protected int getPriority() { + return Integer.MAX_VALUE - 1; + } + + protected MetadataFieldBuilder(Context context) { + super(context); + } + + @Override + protected MetadataFieldService getService() { + return metadataFieldService; + } + + @Override + protected void cleanup() throws Exception { + delete(metadataField); + } + + @Override + public MetadataField build() { + try { + + metadataFieldService.update(context, metadataField); + context.dispatchEvents(); + + indexingService.commit(); + } catch (SearchServiceException e) { + log.error(e); + } catch (SQLException e) { + log.error(e); + } catch (AuthorizeException e) { + log.error(e); + ; + } catch (NonUniqueMetadataException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return metadataField; + } + + public void delete(MetadataField dso) throws Exception { + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + MetadataField attachedDso = c.reloadEntity(dso); + if (attachedDso != null) { + getService().delete(c, attachedDso); + } + c.complete(); + } + + indexingService.commit(); + } + + + public static MetadataFieldBuilder createMetadataField(Context context, String element, String qualifier, + String scopeNote) throws SQLException, AuthorizeException { + MetadataFieldBuilder metadataFieldBuilder = new MetadataFieldBuilder(context); + return metadataFieldBuilder.create(context, element, qualifier, scopeNote); + } + + public static MetadataFieldBuilder createMetadataField(Context context, MetadataSchema schema, String element, + String qualifier, String scopeNote) throws SQLException, AuthorizeException { + MetadataFieldBuilder metadataFieldBuilder = new MetadataFieldBuilder(context); + return metadataFieldBuilder.create(context, schema, element, qualifier, scopeNote); + } + + private MetadataFieldBuilder create(Context context, String element, String qualifier, String scopeNote) + throws SQLException, AuthorizeException { + + create(context, metadataSchemaService.find(context, "dc"), element, qualifier, scopeNote); + return this; + } + + private MetadataFieldBuilder create(Context context, MetadataSchema schema, String element, String qualifier, + String scopeNote) throws SQLException, AuthorizeException { + + this.context = context; + + try { + metadataField = metadataFieldService + .create(context, schema, element, qualifier, scopeNote); + } catch (NonUniqueMetadataException e) { + e.printStackTrace(); + } + + return this; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataSchemaBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataSchemaBuilder.java new file mode 100644 index 0000000000..5b42f0b24a --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataSchemaBuilder.java @@ -0,0 +1,99 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.MetadataSchema; +import org.dspace.content.NonUniqueMetadataException; +import org.dspace.content.service.MetadataSchemaService; +import org.dspace.core.Context; +import org.dspace.discovery.SearchServiceException; + +public class MetadataSchemaBuilder extends AbstractBuilder { + + /* Log4j logger*/ + private static final Logger log = Logger.getLogger(MetadataSchemaBuilder.class); + + private MetadataSchema metadataSchema; + + @Override + protected int getPriority() { + return Integer.MAX_VALUE; + } + + protected MetadataSchemaBuilder(Context context) { + super(context); + } + + @Override + protected MetadataSchemaService getService() { + return metadataSchemaService; + } + + @Override + protected void cleanup() throws Exception { + delete(metadataSchema); + } + + @Override + public MetadataSchema build() { + try { + + metadataSchemaService.update(context, metadataSchema); + context.dispatchEvents(); + + indexingService.commit(); + } catch (SearchServiceException e) { + log.error(e); + } catch (SQLException e) { + log.error(e); + } catch (AuthorizeException e) { + log.error(e); + ; + } catch (NonUniqueMetadataException e) { + e.printStackTrace(); + } + return metadataSchema; + } + + public void delete(MetadataSchema dso) throws Exception { + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + MetadataSchema attachedDso = c.reloadEntity(dso); + if (attachedDso != null) { + getService().delete(c, attachedDso); + } + c.complete(); + } + + indexingService.commit(); + } + + + public static MetadataSchemaBuilder createMetadataSchema(Context context, String name, String namespace) + throws SQLException, AuthorizeException { + MetadataSchemaBuilder metadataSchemaBuilder = new MetadataSchemaBuilder(context); + return metadataSchemaBuilder.create(context, name, namespace); + } + + private MetadataSchemaBuilder create(Context context, String name, String namespace) + throws SQLException, AuthorizeException { + this.context = context; + + try { + metadataSchema = metadataSchemaService.create(context, name, namespace); + } catch (NonUniqueMetadataException e) { + e.printStackTrace(); + } + + return this; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/SiteBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/SiteBuilder.java new file mode 100644 index 0000000000..3747675253 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/SiteBuilder.java @@ -0,0 +1,62 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import org.dspace.content.Site; +import org.dspace.content.service.DSpaceObjectService; +import org.dspace.core.Context; + +public class SiteBuilder extends AbstractDSpaceObjectBuilder { + + private Site site; + + protected SiteBuilder(Context context) { + super(context); + } + + @Override + protected void cleanup() throws Exception { + //Do nothing + } + + @Override + protected DSpaceObjectService getService() { + return siteService; + } + + @Override + public Site build() { + try { + siteService.update(context, site); + + context.dispatchEvents(); + + indexingService.commit(); + return site; + } catch (Exception e) { + return handleException(e); + } + } + + public static SiteBuilder createSite(final Context context) { + SiteBuilder builder = new SiteBuilder(context); + return builder.create(context); + } + + private SiteBuilder create(final Context context) { + this.context = context; + + try { + site = siteService.createSite(context); + } catch (Exception e) { + return handleException(e); + } + + return this; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java new file mode 100644 index 0000000000..4d73d23b19 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java @@ -0,0 +1,145 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.builder; + +import java.io.InputStream; + +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.Item; +import org.dspace.content.LicenseUtils; +import org.dspace.content.MetadataSchema; +import org.dspace.content.WorkspaceItem; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; + +/** + * Builder to construct WorkspaceItem objects + * + **/ +public class WorkspaceItemBuilder extends AbstractBuilder { + + private WorkspaceItem workspaceItem; + + protected WorkspaceItemBuilder(Context context) { + super(context); + } + + public static WorkspaceItemBuilder createWorkspaceItem(final Context context, final Collection col) { + WorkspaceItemBuilder builder = new WorkspaceItemBuilder(context); + return builder.create(context, col); + } + + private WorkspaceItemBuilder create(final Context context, final Collection col) { + this.context = context; + + try { + workspaceItem = workspaceItemService.create(context, col, false); + } catch (Exception e) { + return handleException(e); + } + + return this; + } + + @Override + public WorkspaceItem build() { + return workspaceItem; + } + + @Override + public void delete(WorkspaceItem dso) throws Exception { + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + WorkspaceItem attachedDso = c.reloadEntity(dso); + if (attachedDso != null) { + getService().deleteAll(c, attachedDso); + } + c.complete(); + } + + indexingService.commit(); + } + + @Override + protected void cleanup() throws Exception { + delete(workspaceItem); + } + + @Override + protected WorkspaceItemService getService() { + return workspaceItemService; + } + + protected WorkspaceItemBuilder addMetadataValue(final String schema, + final String element, final String qualifier, final String value) { + try { + itemService.addMetadata(context, workspaceItem.getItem(), schema, element, qualifier, Item.ANY, value); + } catch (Exception e) { + return handleException(e); + } + return this; + } + + protected WorkspaceItemBuilder setMetadataSingleValue(final String schema, + final String element, final String qualifier, final String value) { + try { + itemService.setMetadataSingleValue(context, workspaceItem.getItem(), schema, element, qualifier, Item.ANY, + value); + } catch (Exception e) { + return handleException(e); + } + + return this; + } + + public WorkspaceItemBuilder withTitle(final String title) { + return setMetadataSingleValue(MetadataSchema.DC_SCHEMA, "title", null, title); + } + + public WorkspaceItemBuilder withIssueDate(final String issueDate) { + return addMetadataValue(MetadataSchema.DC_SCHEMA, "date", "issued", new DCDate(issueDate).toString()); + } + + public WorkspaceItemBuilder withAuthor(final String authorName) { + return addMetadataValue(MetadataSchema.DC_SCHEMA, "contributor", "author", authorName); + } + + public WorkspaceItemBuilder withSubject(final String subject) { + return addMetadataValue(MetadataSchema.DC_SCHEMA, "subject", null, subject); + } + + public WorkspaceItemBuilder grantLicense() { + Item item = workspaceItem.getItem(); + String license; + try { + EPerson submitter = workspaceItem.getSubmitter(); + submitter = context.reloadEntity(submitter); + license = LicenseUtils.getLicenseText(context.getCurrentLocale(), workspaceItem.getCollection(), item, + submitter); + LicenseUtils.grantLicense(context, item, license, null); + } catch (Exception e) { + handleException(e); + } + return this; + } + + public WorkspaceItemBuilder withFulltext(String name, String source, InputStream is) { + try { + Item item = workspaceItem.getItem(); + Bitstream b = itemService.createSingleBitstream(context, is, item); + b.setName(context, name); + b.setSource(context, source); + } catch (Exception e) { + handleException(e); + } + return this; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverConfigurationConverterTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverConfigurationConverterTest.java new file mode 100644 index 0000000000..5cd2b72107 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverConfigurationConverterTest.java @@ -0,0 +1,185 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter; + +import static junit.framework.TestCase.assertFalse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.util.LinkedList; + +import org.dspace.app.rest.model.SearchConfigurationRest; +import org.dspace.discovery.configuration.DiscoveryConfiguration; +import org.dspace.discovery.configuration.DiscoverySearchFilter; +import org.dspace.discovery.configuration.DiscoverySortConfiguration; +import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * This class' purpose is to test the DiscoverConfigurationConverter + */ +@RunWith(MockitoJUnitRunner.class) +public class DiscoverConfigurationConverterTest { + + SearchConfigurationRest searchConfigurationRest; + + @InjectMocks + private DiscoverConfigurationConverter discoverConfigurationConverter; + + @Mock + private DiscoverySortConfiguration discoverySortConfiguration; + + @Mock + private DiscoveryConfiguration discoveryConfiguration; + + @Before + public void setUp() throws Exception { + } + + public void populateDiscoveryConfigurationWithEmptyList() { + discoveryConfiguration.setSearchFilters(new LinkedList()); + discoveryConfiguration.setSearchSortConfiguration(new DiscoverySortConfiguration()); + } + + @Test + public void testReturnType() throws Exception { + populateDiscoveryConfigurationWithEmptyList(); + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + assertTrue(searchConfigurationRest.getFilters().isEmpty()); + assertEquals(SearchConfigurationRest.class, searchConfigurationRest.getClass()); + } + + @Test + public void testConvertWithNullParamter() throws Exception { + assertNotNull(discoverConfigurationConverter.convert(null)); + } + + @Test + public void testNoSearchSortConfigurationReturnObjectNotNull() throws Exception { + discoveryConfiguration.setSearchFilters(new LinkedList<>()); + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + assertTrue(discoveryConfiguration.getSearchFilters().isEmpty()); + assertTrue(searchConfigurationRest.getFilters().isEmpty()); + assertNotNull(searchConfigurationRest); + } + + @Test + public void testNoSearchFilterReturnObjectNotNull() throws Exception { + discoveryConfiguration.setSearchSortConfiguration(new DiscoverySortConfiguration()); + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + assertTrue(searchConfigurationRest.getFilters().isEmpty()); + assertNotNull(searchConfigurationRest); + } + + //Checks that the convert is still done properly without error even if the discoveryConfiguration's attributes + // are null + @Test + public void testNoSearchSortConfigurationAndNoSearchFilterReturnObjectNotNull() throws Exception { + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + assertNotNull(searchConfigurationRest); + } + + @Test + public void testCorrectSortOptionsAfterConvert() throws Exception { + populateDiscoveryConfigurationWithEmptyList(); + + DiscoverySortFieldConfiguration discoverySortFieldConfiguration = new DiscoverySortFieldConfiguration(); + discoverySortFieldConfiguration.setMetadataField("title"); + discoverySortFieldConfiguration.setType("text"); + DiscoverySortFieldConfiguration discoverySortFieldConfiguration1 = new DiscoverySortFieldConfiguration(); + discoverySortFieldConfiguration1.setMetadataField("author"); + discoverySortFieldConfiguration1.setType("text"); + LinkedList mockedList = new LinkedList<>(); + mockedList.add(discoverySortFieldConfiguration); + mockedList.add(discoverySortFieldConfiguration1); + + when(discoveryConfiguration.getSearchSortConfiguration()).thenReturn(discoverySortConfiguration); + when(discoverySortConfiguration.getSortFields()).thenReturn(mockedList); + + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + + int counter = 0; + for (SearchConfigurationRest.SortOption sortOption : searchConfigurationRest.getSortOptions()) { + assertEquals(mockedList.get(counter).getMetadataField(), sortOption.getName()); + assertEquals(mockedList.get(counter).getType(), sortOption.getActualName()); + counter++; + } + + assertFalse(searchConfigurationRest.getSortOptions().isEmpty()); + } + + @Test + public void testEmptySortOptionsAfterConvertWithConfigurationWithEmptySortFields() throws Exception { + populateDiscoveryConfigurationWithEmptyList(); + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + assertEquals(0, searchConfigurationRest.getSortOptions().size()); + + } + + @Test + public void testEmptySortOptionsAfterConvertWithConfigurationWithNullSortFields() throws Exception { + populateDiscoveryConfigurationWithEmptyList(); + when(discoveryConfiguration.getSearchSortConfiguration()).thenReturn(null); + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + + assertEquals(0, searchConfigurationRest.getSortOptions().size()); + } + + @Test + public void testCorrectSearchFiltersAfterConvert() throws Exception { + populateDiscoveryConfigurationWithEmptyList(); + + LinkedList mockedList = new LinkedList(); + DiscoverySearchFilter discoverySearchFilter = new DiscoverySearchFilter(); + discoverySearchFilter.setIndexFieldName("title"); + DiscoverySearchFilter discoverySearchFilter1 = new DiscoverySearchFilter(); + discoverySearchFilter1.setIndexFieldName("title2"); + + mockedList.add(discoverySearchFilter); + mockedList.add(discoverySearchFilter1); + when(discoveryConfiguration.getSearchFilters()).thenReturn(mockedList); + + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + + int counter = 0; + for (SearchConfigurationRest.Filter filter : searchConfigurationRest.getFilters()) { + DiscoverySearchFilter searchFilter = mockedList.get(counter); + assertEquals(searchFilter.getIndexFieldName(), filter.getFilter()); + //TODO checkoperators + SearchConfigurationRest.Filter.Operator operator = new SearchConfigurationRest.Filter.Operator("testing"); + filter.addOperator(operator); + assertEquals(filter.getOperators().get(filter.getOperators().size() - 1), operator); + counter++; + } + assertTrue(!(searchConfigurationRest.getFilters().isEmpty())); + } + + @Test + public void testEmptySearchFilterAfterConvertWithConfigurationWithEmptySearchFilters() throws Exception { + populateDiscoveryConfigurationWithEmptyList(); + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + assertEquals(0, searchConfigurationRest.getFilters().size()); + } + + @Test + public void testEmptySearchFiltersAfterConvertWithConfigurationWithNullSearchFilters() throws Exception { + populateDiscoveryConfigurationWithEmptyList(); + + when(discoveryConfiguration.getSearchFilters()).thenReturn(null); + searchConfigurationRest = discoverConfigurationConverter.convert(discoveryConfiguration); + + assertEquals(0, searchConfigurationRest.getFilters().size()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverFacetConfigurationConverterTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverFacetConfigurationConverterTest.java new file mode 100644 index 0000000000..bdfdc9ef8b --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverFacetConfigurationConverterTest.java @@ -0,0 +1,110 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.util.LinkedList; + +import org.dspace.app.rest.model.FacetConfigurationRest; +import org.dspace.discovery.configuration.DiscoveryConfiguration; +import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * This class has the purpose to test the DiscoverFacetConfigurationConverter + */ +@RunWith(MockitoJUnitRunner.class) +public class DiscoverFacetConfigurationConverterTest { + + FacetConfigurationRest facetConfigurationRest; + + @InjectMocks + private DiscoverFacetConfigurationConverter discoverFacetConfigurationConverter; + + @Mock + private DiscoveryConfiguration discoveryConfiguration; + + private String configurationName = "default"; + private String scopeObject = "ba9e1c83-8144-4e9c-9d58-bb97be573b46"; + + public void populateDiscoveryConfigurationWithEmptyList() { + discoveryConfiguration.setSidebarFacets(new LinkedList()); + } + + @Test + public void testReturnType() throws Exception { + populateDiscoveryConfigurationWithEmptyList(); + facetConfigurationRest = discoverFacetConfigurationConverter + .convert(configurationName, scopeObject, discoveryConfiguration); + assertTrue(facetConfigurationRest.getSidebarFacets().isEmpty()); + assertEquals(FacetConfigurationRest.class, facetConfigurationRest.getClass()); + } + + @Test + public void testConvertWithNullParamter() throws Exception { + facetConfigurationRest = discoverFacetConfigurationConverter.convert(configurationName, scopeObject, null); + assertNotNull(facetConfigurationRest); + assertTrue(facetConfigurationRest.getSidebarFacets().isEmpty()); + } + + @Test + public void testConvertWithConfigurationContainingSidebarFacetsFacetConfigurationRestContainsCorrectSidebarFacet() + throws Exception { + LinkedList discoverySearchFilterFacets = new LinkedList<>(); + DiscoverySearchFilterFacet discoverySearchFilterFacet = new DiscoverySearchFilterFacet(); + discoverySearchFilterFacet.setIndexFieldName("Testing"); + discoverySearchFilterFacet.setType("test"); + discoverySearchFilterFacets.add(discoverySearchFilterFacet); + + when(discoveryConfiguration.getSidebarFacets()).thenReturn(discoverySearchFilterFacets); + + facetConfigurationRest = discoverFacetConfigurationConverter + .convert(configurationName, scopeObject, discoveryConfiguration); + + assertNotNull(facetConfigurationRest); + assertTrue(!facetConfigurationRest.getSidebarFacets().isEmpty()); + assertEquals(discoverySearchFilterFacet.getIndexFieldName(), + facetConfigurationRest.getSidebarFacets().get(0).getName()); + assertEquals(discoverySearchFilterFacet.getType(), + facetConfigurationRest.getSidebarFacets().get(0).getFacetType()); + } + + @Test + public void testConvertWithConfigurationContainingEmptySidebarFacetListFacetConfigurationRestSidebarFacetsIsEmpty() + throws Exception { + + when(discoveryConfiguration.getSidebarFacets()).thenReturn(new LinkedList()); + + facetConfigurationRest = discoverFacetConfigurationConverter + .convert(configurationName, scopeObject, discoveryConfiguration); + + assertNotNull(facetConfigurationRest); + assertTrue(facetConfigurationRest.getSidebarFacets().isEmpty()); + } + + @Test + public void testConvertWithConfigurationContainingNullSidebarFacetListFacetConfigurationRestSidebarFacetsIsEmpty() + throws Exception { + + when(discoveryConfiguration.getSidebarFacets()).thenReturn(null); + + facetConfigurationRest = discoverFacetConfigurationConverter + .convert(configurationName, scopeObject, discoveryConfiguration); + + assertNotNull(facetConfigurationRest); + assertTrue(facetConfigurationRest.getSidebarFacets().isEmpty()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverSearchSupportConverterTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverSearchSupportConverterTest.java new file mode 100644 index 0000000000..f7680b6ffd --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/DiscoverSearchSupportConverterTest.java @@ -0,0 +1,39 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.dspace.app.rest.model.SearchSupportRest; +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the DiscoverSearchSupportConverter + */ +public class DiscoverSearchSupportConverterTest { + + + DiscoverSearchSupportConverter discoverSearchSupportConverter; + + @Before + public void setUp() throws Exception { + discoverSearchSupportConverter = new DiscoverSearchSupportConverter(); + } + + @Test + public void testReturnIsCorrectClass() throws Exception { + assertEquals(discoverSearchSupportConverter.convert().getClass(), SearchSupportRest.class); + } + + @Test + public void testReturnIsNotNull() throws Exception { + assertNotNull(discoverSearchSupportConverter.convert()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/RootConverterTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/RootConverterTest.java new file mode 100644 index 0000000000..5ec396ec81 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/RootConverterTest.java @@ -0,0 +1,59 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + +import org.dspace.app.rest.model.RootRest; +import org.dspace.services.ConfigurationService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * This class' purpose is to test the RootConvertor class. + */ +@RunWith(MockitoJUnitRunner.class) +public class RootConverterTest { + + @InjectMocks + private RootConverter rootConverter; + + @Mock + private ConfigurationService configurationService; + + @Before + public void setUp() throws Exception { + when(configurationService.getProperty("dspace.url")).thenReturn("dspaceurl"); + when(configurationService.getProperty("dspace.name")).thenReturn("dspacename"); + } + + @Test + public void testReturnCorrectClass() throws Exception { + assertEquals(rootConverter.convert("").getClass(), RootRest.class); + } + + @Test + public void testCorrectPropertiesSetFromConfigurationService() throws Exception { + String restUrl = "rest"; + RootRest rootRest = rootConverter.convert(restUrl); + assertEquals("dspaceurl", rootRest.getDspaceURL()); + assertEquals("dspacename", rootRest.getDspaceName()); + assertEquals(restUrl, rootRest.getDspaceRest()); + } + + @Test + public void testReturnNotNull() throws Exception { + assertNotNull(rootConverter.convert("")); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/query/SearchQueryConverterTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/query/SearchQueryConverterTest.java new file mode 100644 index 0000000000..e177edb5ef --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/query/SearchQueryConverterTest.java @@ -0,0 +1,118 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter.query; + +import static org.junit.Assert.assertEquals; + +import java.util.LinkedList; +import java.util.List; + +import org.dspace.app.rest.parameter.SearchFilter; +import org.junit.Before; +import org.junit.Test; + +public class SearchQueryConverterTest { + + SearchQueryConverter searchQueryConverter; + + + @Before + public void setUp() throws Exception { + searchQueryConverter = new SearchQueryConverter(); + } + + @Test + public void convertAuthorContainsSearchFilterTest() { + SearchFilter searchFilter = new SearchFilter("author", "query", "test*"); + List list = new LinkedList<>(); + list.add(searchFilter); + List transformedList = searchQueryConverter.convert(list); + + assertEquals(transformedList.get(0).getOperator(), "contains"); + assertEquals(list.get(0).getOperator(), "query"); + assertEquals(transformedList.get(0).getName(), "author"); + assertEquals(list.get(0).getName(), "author"); + assertEquals(transformedList.get(0).getValue(), "test"); + assertEquals(list.get(0).getValue(), "test*"); + } + + @Test + public void convertAuthorNotContainsSearchFilterTest() { + SearchFilter searchFilter = new SearchFilter("author", "query", "-test*"); + List list = new LinkedList<>(); + list.add(searchFilter); + List transformedList = searchQueryConverter.convert(list); + + assertEquals(transformedList.get(0).getOperator(), "notcontains"); + assertEquals(list.get(0).getOperator(), "query"); + assertEquals(transformedList.get(0).getName(), "author"); + assertEquals(list.get(0).getName(), "author"); + assertEquals(transformedList.get(0).getValue(), "test"); + assertEquals(list.get(0).getValue(), "-test*"); + } + + @Test + public void convertAuthorEqualsSearchFilterTest() { + SearchFilter searchFilter = new SearchFilter("author", "query", "test"); + List list = new LinkedList<>(); + list.add(searchFilter); + List transformedList = searchQueryConverter.convert(list); + + assertEquals(transformedList.get(0).getOperator(), "equals"); + assertEquals(list.get(0).getOperator(), "query"); + assertEquals(transformedList.get(0).getName(), "author"); + assertEquals(list.get(0).getName(), "author"); + assertEquals(transformedList.get(0).getValue(), "test"); + assertEquals(list.get(0).getValue(), "test"); + } + + @Test + public void convertAuthorNotEqualsSearchFilterTest() { + SearchFilter searchFilter = new SearchFilter("author", "query", "-test"); + List list = new LinkedList<>(); + list.add(searchFilter); + List transformedList = searchQueryConverter.convert(list); + + assertEquals(transformedList.get(0).getOperator(), "notequals"); + assertEquals(list.get(0).getOperator(), "query"); + assertEquals(transformedList.get(0).getName(), "author"); + assertEquals(list.get(0).getName(), "author"); + assertEquals(transformedList.get(0).getValue(), "test"); + assertEquals(list.get(0).getValue(), "-test"); + } + + @Test + public void convertAuthorAuthoritySearchFilterTest() { + SearchFilter searchFilter = new SearchFilter("author", "query", "id:test"); + List list = new LinkedList<>(); + list.add(searchFilter); + List transformedList = searchQueryConverter.convert(list); + + assertEquals(transformedList.get(0).getOperator(), "authority"); + assertEquals(list.get(0).getOperator(), "query"); + assertEquals(transformedList.get(0).getName(), "author"); + assertEquals(list.get(0).getName(), "author"); + assertEquals(transformedList.get(0).getValue(), "test"); + assertEquals(list.get(0).getValue(), "id:test"); + } + + @Test + public void convertAuthorNotAuthoritySearchFilterTest() { + SearchFilter searchFilter = new SearchFilter("author", "query", "-id:test"); + List list = new LinkedList<>(); + list.add(searchFilter); + List transformedList = searchQueryConverter.convert(list); + + assertEquals(transformedList.get(0).getOperator(), "notauthority"); + assertEquals(list.get(0).getOperator(), "query"); + assertEquals(transformedList.get(0).getName(), "author"); + assertEquals(list.get(0).getName(), "author"); + assertEquals(transformedList.get(0).getValue(), "test"); + assertEquals(list.get(0).getValue(), "-id:test"); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/FacetConfigurationResourceHalLinkFactoryTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/FacetConfigurationResourceHalLinkFactoryTest.java new file mode 100644 index 0000000000..504543119f --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/FacetConfigurationResourceHalLinkFactoryTest.java @@ -0,0 +1,51 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.link.search; + +import static org.junit.Assert.assertEquals; + +import org.dspace.app.rest.DiscoveryRestController; +import org.dspace.app.rest.link.HalLinkFactory; +import org.dspace.app.rest.model.hateoas.FacetConfigurationResource; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.hateoas.mvc.ControllerLinkBuilder; + +/** + * This class' purpose is to test the FacetConfigurationResourceHalLinkFactory + */ +public class FacetConfigurationResourceHalLinkFactoryTest { + + + @Mock + ControllerLinkBuilder controllerLinkBuilder; + + @Mock + HalLinkFactory halLinkFactory; + + @InjectMocks + private FacetConfigurationResourceHalLinkFactory facetConfigurationResourceHalLinkFactory; + + @Before + public void setUp() throws Exception { + facetConfigurationResourceHalLinkFactory = new FacetConfigurationResourceHalLinkFactory(); + } + + @Test + public void testControllerClassIsSetCorrectlyAfterConstructor() throws Exception { + assertEquals(DiscoveryRestController.class, facetConfigurationResourceHalLinkFactory.getControllerClass()); + } + + @Test + public void testResourceClassIsSetCorrectlyAfterConstructor() throws Exception { + assertEquals(FacetConfigurationResource.class, facetConfigurationResourceHalLinkFactory.getResourceClass()); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchConfigurationResourceHalLinkFactoryTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchConfigurationResourceHalLinkFactoryTest.java new file mode 100644 index 0000000000..dd1b16127e --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchConfigurationResourceHalLinkFactoryTest.java @@ -0,0 +1,51 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.link.search; + +import static org.junit.Assert.assertEquals; + +import org.dspace.app.rest.DiscoveryRestController; +import org.dspace.app.rest.link.HalLinkFactory; +import org.dspace.app.rest.model.hateoas.SearchConfigurationResource; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.hateoas.mvc.ControllerLinkBuilder; + +/** + * This class' purpose is to test the SearchConfigurationResourceHalLinkFactory + */ +public class SearchConfigurationResourceHalLinkFactoryTest { + + + @Mock + ControllerLinkBuilder controllerLinkBuilder; + + @Mock + HalLinkFactory halLinkFactory; + + @InjectMocks + private SearchConfigurationResourceHalLinkFactory searchConfigurationResourceHalLinkFactory; + + @Before + public void setUp() throws Exception { + searchConfigurationResourceHalLinkFactory = new SearchConfigurationResourceHalLinkFactory(); + } + + @Test + public void testControllerClassIsSetCorrectlyAfterConstructor() throws Exception { + assertEquals(DiscoveryRestController.class, searchConfigurationResourceHalLinkFactory.getControllerClass()); + } + + @Test + public void testResourceClassIsSetCorrectlyAfterConstructor() throws Exception { + assertEquals(SearchConfigurationResource.class, searchConfigurationResourceHalLinkFactory.getResourceClass()); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchResultsResourceHalLinkFactoryTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchResultsResourceHalLinkFactoryTest.java new file mode 100644 index 0000000000..1520bb47e7 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchResultsResourceHalLinkFactoryTest.java @@ -0,0 +1,37 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.link.search; + +import static org.junit.Assert.assertEquals; + +import org.dspace.app.rest.DiscoveryRestController; +import org.dspace.app.rest.model.hateoas.SearchResultsResource; +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the SearchResultsResourceHalLinkFactory + */ +public class SearchResultsResourceHalLinkFactoryTest { + SearchResultsResourceHalLinkFactory searchResultsResourceHalLinkFactory; + + @Before + public void setUp() throws Exception { + searchResultsResourceHalLinkFactory = new SearchResultsResourceHalLinkFactory(); + } + + @Test + public void testControllerClassIsSetCorrectlyAfterConstructor() throws Exception { + assertEquals(DiscoveryRestController.class, searchResultsResourceHalLinkFactory.getControllerClass()); + } + + @Test + public void testResourceClassIsSetCorrectlyAfterConstructor() throws Exception { + assertEquals(SearchResultsResource.class, searchResultsResourceHalLinkFactory.getResourceClass()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchSupportHalLinkFactoryTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchSupportHalLinkFactoryTest.java new file mode 100644 index 0000000000..0b3bbee733 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/link/search/SearchSupportHalLinkFactoryTest.java @@ -0,0 +1,38 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.link.search; + +import static org.junit.Assert.assertEquals; + +import org.dspace.app.rest.DiscoveryRestController; +import org.dspace.app.rest.model.hateoas.SearchSupportResource; +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the SearchSupportHalLinkFactory class + */ +public class SearchSupportHalLinkFactoryTest { + SearchSupportHalLinkFactory searchSupportHalLinkFactory; + + @Before + public void setUp() throws Exception { + searchSupportHalLinkFactory = new SearchSupportHalLinkFactory(); + } + + @Test + public void testControllerClassIsSetCorrectlyAfterConstructor() throws Exception { + assertEquals(DiscoveryRestController.class, searchSupportHalLinkFactory.getControllerClass()); + } + + @Test + public void testResourceClassIsSetCorrectlyAfterConstructor() throws Exception { + assertEquals(SearchSupportResource.class, searchSupportHalLinkFactory.getResourceClass()); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/AppliedFilterMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/AppliedFilterMatcher.java new file mode 100644 index 0000000000..7cd973a444 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/AppliedFilterMatcher.java @@ -0,0 +1,30 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +public class AppliedFilterMatcher { + + private AppliedFilterMatcher() { } + + public static Matcher appliedFilterEntry(String filter, String operator, String value, + String label) { + return allOf( + hasJsonPath("$.filter", is(filter)), + hasJsonPath("$.operator", is(operator)), + hasJsonPath("$.value", is(value)), + hasJsonPath("$.label", is(label)) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamFormatMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamFormatMatcher.java new file mode 100644 index 0000000000..ec5dc9f368 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamFormatMatcher.java @@ -0,0 +1,38 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +/** + * @author Jonas Van Goolen - (jonas@atmire.com) + */ +public class BitstreamFormatMatcher { + + private BitstreamFormatMatcher() { } + + public static Matcher matchBitstreamFormat(String mimetype, String description) { + return allOf( + hasJsonPath("$.mimetype", is(mimetype)), + hasJsonPath("$.description", is(description)), + hasJsonPath("$.type", is("bitstreamformat")) + ); + } + + public static Matcher matchBitstreamFormatMimeType(String mimetype) { + return allOf( + hasJsonPath("$.mimetype", is(mimetype)), + hasJsonPath("$.type", is("bitstreamformat")) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMatcher.java new file mode 100644 index 0000000000..db9caa857c --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMatcher.java @@ -0,0 +1,82 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +import java.util.UUID; + +import org.dspace.content.Bitstream; +import org.hamcrest.Matcher; + +public class BitstreamMatcher { + + private BitstreamMatcher() { } + + public static Matcher matchBitstreamEntry(Bitstream bitstream) { + return allOf( + //Check core metadata (the JSON Path expression evaluates to a collection so we have to use contains) + hasJsonPath("$.uuid", is(bitstream.getID().toString())), + hasJsonPath("$.name", is(bitstream.getName())), + hasJsonPath("$.bundleName", is("ORIGINAL")), + hasJsonPath("$.metadata", containsInAnyOrder( + BitstreamMetadataMatcher.matchTitle(bitstream.getName()), + BitstreamMetadataMatcher.matchDescription(bitstream.getDescription()) + )), + hasJsonPath("$.sizeBytes", is((int) bitstream.getSizeBytes())), + hasJsonPath("$.checkSum", matchChecksum()), + hasJsonPath("$._embedded.format", matchFormat()), + //Check links + matchBitstreamLinks(bitstream.getID()) + ); + } + + public static Matcher matchBitstreamEntry(UUID uuid, long size) { + return allOf( + //Check ID and size + hasJsonPath("$.uuid", is(uuid.toString())), + hasJsonPath("$.sizeBytes", is((int) size)), + //Make sure we have a checksum + hasJsonPath("$.checkSum", matchChecksum()), + //Make sure we have a valid format + hasJsonPath("$._embedded.format", matchFormat()), + //Check links + matchBitstreamLinks(uuid) + ); + } + + private static Matcher matchBitstreamLinks(UUID uuid) { + return allOf( + hasJsonPath("$._links.format.href", containsString("/api/core/bitstreams/" + uuid + "/format")), + hasJsonPath("$._links.self.href", containsString("/api/core/bitstreams/" + uuid)), + hasJsonPath("$._links.content.href", containsString("/api/core/bitstreams/" + uuid + "/content")) + ); + } + + private static Matcher matchChecksum() { + return allOf( + hasJsonPath("$.checkSumAlgorithm", not(empty())), + hasJsonPath("$.value", not(empty())) + ); + } + + private static Matcher matchFormat() { + return allOf( + hasJsonPath("$.mimetype", not(empty())), + hasJsonPath("$.type", is("bitstreamformat")), + hasJsonPath("$._links.self.href", not(empty())) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMetadataMatcher.java new file mode 100644 index 0000000000..1fba985560 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMetadataMatcher.java @@ -0,0 +1,33 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +public class BitstreamMetadataMatcher { + + private BitstreamMetadataMatcher() { } + + public static Matcher matchTitle(String title) { + return allOf( + hasJsonPath("$.key", is("dc.title")), + hasJsonPath("$.value", is(title)) + ); + } + + public static Matcher matchDescription(String description) { + return allOf( + hasJsonPath("$.key", is("dc.description")), + hasJsonPath("$.value", is(description)) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseEntryResourceMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseEntryResourceMatcher.java new file mode 100644 index 0000000000..e21f9ba8ae --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseEntryResourceMatcher.java @@ -0,0 +1,43 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.dspace.app.rest.test.AbstractControllerIntegrationTest.REST_SERVER_URL; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; + +import org.hamcrest.Matcher; + +/** + * Class to match JSON browse entries in ITs + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Raf Ponsaerts (raf dot ponsaerts at atmire dot com) + */ +public class BrowseEntryResourceMatcher { + + private BrowseEntryResourceMatcher() { } + + public static Matcher matchBrowseEntry(String value, int expectedCount) { + return allOf( + //Check core metadata (the JSON Path expression evaluates to a collection so we have to use contains) + hasJsonPath("$.value", is(value)), + hasJsonPath("$.count", is(expectedCount)), + //Check links + matchItemLinks() + ); + } + + public static Matcher matchItemLinks() { + return allOf( + hasJsonPath("$._links.items.href", startsWith(REST_SERVER_URL)) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseIndexMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseIndexMatcher.java new file mode 100644 index 0000000000..1ad8586574 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseIndexMatcher.java @@ -0,0 +1,76 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.dspace.app.rest.test.AbstractControllerIntegrationTest.REST_SERVER_URL; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase; + +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +/** + * Utility class to construct a Matcher for a browse index + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Raf Ponsaerts (raf dot ponsaerts at atmire dot com) + */ +public class BrowseIndexMatcher { + + private BrowseIndexMatcher() { } + + public static Matcher subjectBrowseIndex(final String order) { + return allOf( + hasJsonPath("$.metadata", contains("dc.subject.*")), + hasJsonPath("$.metadataBrowse", Matchers.is(true)), + hasJsonPath("$.order", equalToIgnoringCase(order)), + hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")), + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/subject")), + hasJsonPath("$._links.entries.href", is(REST_SERVER_URL + "discover/browses/subject/entries")), + hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/subject/items")) + ); + } + + public static Matcher titleBrowseIndex(final String order) { + return allOf( + hasJsonPath("$.metadata", contains("dc.title")), + hasJsonPath("$.metadataBrowse", Matchers.is(false)), + hasJsonPath("$.order", equalToIgnoringCase(order)), + hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")), + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/title")), + hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/title/items")) + ); + } + + public static Matcher contributorBrowseIndex(final String order) { + return allOf( + hasJsonPath("$.metadata", contains("dc.contributor.*", "dc.creator")), + hasJsonPath("$.metadataBrowse", Matchers.is(true)), + hasJsonPath("$.order", equalToIgnoringCase(order)), + hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")), + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/author")), + hasJsonPath("$._links.entries.href", is(REST_SERVER_URL + "discover/browses/author/entries")), + hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/author/items")) + ); + } + + public static Matcher dateIssuedBrowseIndex(final String order) { + return allOf( + hasJsonPath("$.metadata", contains("dc.date.issued")), + hasJsonPath("$.metadataBrowse", Matchers.is(false)), + hasJsonPath("$.order", equalToIgnoringCase(order)), + hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")), + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/dateissued")), + hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/dateissued/items")) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java new file mode 100644 index 0000000000..9986a1072a --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java @@ -0,0 +1,61 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import java.util.UUID; + +import org.dspace.content.Bitstream; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +public class CollectionMatcher { + + private CollectionMatcher() { } + + public static Matcher matchCollectionEntry(String name, UUID uuid, String handle) { + return matchCollectionEntry(name, uuid, handle, null); + } + + public static Matcher matchCollectionEntry(String name, UUID uuid, String handle, Bitstream logo) { + return allOf( + hasJsonPath("$.uuid", is(uuid.toString())), + hasJsonPath("$.name", is(name)), + hasJsonPath("$.handle", is(handle)), + hasJsonPath("$.type", is("collection")), + hasJsonPath("$.metadata", Matchers.contains( + CollectionMetadataMatcher.matchTitle(name) + )), + matchLinks(uuid), + matchLogo(logo) + ); + } + + private static Matcher matchLinks(UUID uuid) { + return allOf( + hasJsonPath("$._links.logo.href", containsString("api/core/collections/" + uuid.toString() + "/logo")), + hasJsonPath("$._links.self.href", containsString("api/core/collections/" + uuid.toString())) + ); + } + + private static Matcher matchLogo(Bitstream logo) { + return logo == null ? + allOf( + hasJsonPath("$._embedded.logo", Matchers.not(Matchers.empty())) + ) : + allOf( + hasJsonPath("$._embedded.logo", + BitstreamMatcher.matchBitstreamEntry(logo.getID(), logo.getSizeBytes())) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMetadataMatcher.java new file mode 100644 index 0000000000..3f5bbefe59 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMetadataMatcher.java @@ -0,0 +1,26 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.allOf; + +import org.hamcrest.Matcher; + +public class CollectionMetadataMatcher { + + private CollectionMetadataMatcher() { } + + public static Matcher matchTitle(String title) { + return allOf( + hasJsonPath("$.key", is("dc.title")), + hasJsonPath("$.value", is(title)) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java new file mode 100644 index 0000000000..585d955c2f --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java @@ -0,0 +1,67 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import java.util.UUID; + +import org.dspace.content.Collection; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +public class CommunityMatcher { + + private CommunityMatcher() { } + + public static Matcher matchCommunityEntry(String name, UUID uuid, String handle) { + return allOf( + matchProperties(name, uuid, handle), + hasJsonPath("$._embedded.collections", Matchers.not(Matchers.empty())), + hasJsonPath("$._embedded.logo", Matchers.not(Matchers.empty())), + matchLinks(uuid) + ); + } + + public static Matcher matchProperties(String name, UUID uuid, String handle) { + return allOf( + hasJsonPath("$.uuid", is(uuid.toString())), + hasJsonPath("$.name", is(name)), + hasJsonPath("$.handle", is(handle)), + hasJsonPath("$.type", is("community")), + hasJsonPath("$.metadata", Matchers.contains( + CommunityMetadataMatcher.matchMetadata("dc.title", name) + )) + ); + } + + public static Matcher matchLinks(UUID uuid) { + return allOf( + hasJsonPath("$._links.collections.href", + Matchers.containsString("/api/core/communities/" + uuid.toString() + "/collections")), + hasJsonPath("$._links.logo.href", + Matchers.containsString("/api/core/communities/" + uuid.toString() + "/logo")), + hasJsonPath("$._links.self.href", Matchers.containsString("/api/core/communities/" + uuid.toString())) + ); + } + + public static Matcher matchCommunityWithCollectionEntry(String name, UUID uuid, String handle, + Collection col) { + return allOf( + matchProperties(name, uuid, handle), + hasJsonPath("$._embedded.collections._embedded.collections[0]", + CollectionMatcher + .matchCollectionEntry(col.getName(), col.getID(), col.getHandle(), col.getLogo())), + hasJsonPath("$._embedded.logo", Matchers.not(Matchers.empty())), + matchLinks(uuid) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMetadataMatcher.java new file mode 100644 index 0000000000..ec251e86ea --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMetadataMatcher.java @@ -0,0 +1,26 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +public class CommunityMetadataMatcher { + + private CommunityMetadataMatcher() { } + + public static Matcher matchMetadata(String key, String value) { + return allOf( + hasJsonPath("$.key", is(key)), + hasJsonPath("$.value", is(value)) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/DSpaceObjectMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/DSpaceObjectMatcher.java new file mode 100644 index 0000000000..acb95ea010 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/DSpaceObjectMatcher.java @@ -0,0 +1,26 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.notNullValue; + +import org.hamcrest.Matcher; + +public class DSpaceObjectMatcher { + + private DSpaceObjectMatcher() { } + + public static Matcher match() { + return allOf( + hasJsonPath("$.uuid", notNullValue()) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMatcher.java new file mode 100644 index 0000000000..421af32dbe --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMatcher.java @@ -0,0 +1,52 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +import org.dspace.eperson.EPerson; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +public class EPersonMatcher { + + private EPersonMatcher() { } + + public static Matcher matchEPersonEntry(EPerson ePerson) { + return allOf( + hasJsonPath("$.uuid", is(ePerson.getID().toString())), + hasJsonPath("$.name", is(ePerson.getName())), + hasJsonPath("$.type", is("eperson")), + hasJsonPath("$.canLogIn", not(empty())), + hasJsonPath("$._links.self.href", containsString("/api/eperson/epersons/" + ePerson.getID().toString())), + hasJsonPath("$.metadata", Matchers.hasItems( + EPersonMetadataMatcher.matchFirstName(ePerson.getFirstName()), + EPersonMetadataMatcher.matchLastName(ePerson.getLastName()) + )) + ); + } + + + public static Matcher matchEPersonOnEmail(String email) { + return allOf( + hasJsonPath("$.type", is("eperson")), + hasJsonPath("$.email", is(email)) + ); + } + + public static Matcher matchDefaultTestEPerson() { + return allOf( + hasJsonPath("$.type", is("eperson")) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMetadataMatcher.java new file mode 100644 index 0000000000..74ff800632 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMetadataMatcher.java @@ -0,0 +1,40 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +public class EPersonMetadataMatcher { + + private EPersonMetadataMatcher() { } + + public static Matcher matchFirstName(String firstName) { + return allOf( + hasJsonPath("$.key", is("eperson.firstname")), + hasJsonPath("$.value", is(firstName)) + ); + } + + public static Matcher matchLastName(String lastName) { + return allOf( + hasJsonPath("$.key", is("eperson.lastname")), + hasJsonPath("$.value", is(lastName)) + ); + } + + public static Matcher matchLanguage(String language) { + return allOf( + hasJsonPath("$.key", is("eperson.language")), + hasJsonPath("$.value", is(language)) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetEntryMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetEntryMatcher.java new file mode 100644 index 0000000000..ebea0336b5 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetEntryMatcher.java @@ -0,0 +1,97 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.any; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +import org.hamcrest.Matcher; +import org.hamcrest.core.AnyOf; + +public class FacetEntryMatcher { + + private FacetEntryMatcher() { + } + + public static Matcher authorFacet(boolean hasNext) { + return allOf( + hasJsonPath("$.name", is("author")), + hasJsonPath("$.facetType", is("text")), + hasJsonPath("$.facetLimit", any(Integer.class)), + hasJsonPath("$._links.self.href", containsString("api/discover/facets/author")), + hasJsonPath("$._links", matchNextLink(hasNext, "api/discover/facets/author")) + ); + } + + public static Matcher authorFacetWithMinMax(boolean hasNext, String min, String max) { + return allOf( + hasJsonPath("$.name", is("author")), + hasJsonPath("$.facetType", is("text")), + hasJsonPath("$.facetLimit", any(Integer.class)), + hasJsonPath("$.minValue", is(min)), + hasJsonPath("$.maxValue", is(max)), + hasJsonPath("$._links.self.href", containsString("api/discover/facets/author")), + hasJsonPath("$._links", matchNextLink(hasNext, "api/discover/facets/author")) + ); + } + + public static Matcher subjectFacet(boolean hasNext) { + return allOf( + hasJsonPath("$.name", is("subject")), + hasJsonPath("$.facetType", is("hierarchical")), + hasJsonPath("$.facetLimit", any(Integer.class)), + hasJsonPath("$._links.self.href", containsString("api/discover/facets/subject")), + hasJsonPath("$._links", matchNextLink(hasNext, "api/discover/facets/subject")) + + ); + } + + public static Matcher dateIssuedFacet(boolean hasNext) { + return allOf( + hasJsonPath("$.name", is("dateIssued")), + hasJsonPath("$.facetType", is("date")), + hasJsonPath("$.facetLimit", any(Integer.class)), + hasJsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued")), + hasJsonPath("$._links", matchNextLink(hasNext, "api/discover/facets/dateIssued")) + ); + } + + public static Matcher dateIssuedFacetWithMinMax(boolean hasNext, String min, String max) { + return allOf( + hasJsonPath("$.name", is("dateIssued")), + hasJsonPath("$.facetType", is("date")), + hasJsonPath("$.facetLimit", any(Integer.class)), + hasJsonPath("$.minValue", is(min)), + hasJsonPath("$.maxValue", is(max)), + hasJsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued")), + hasJsonPath("$._links", matchNextLink(hasNext, "api/discover/facets/dateIssued")) + ); + } + + public static Matcher hasContentInOriginalBundleFacet(boolean hasNext) { + return allOf( + hasJsonPath("$.name", is("has_content_in_original_bundle")), + hasJsonPath("$.facetType", is("standard")), + hasJsonPath("$.facetLimit", any(Integer.class)), + hasJsonPath("$._links.self.href", containsString("api/discover/facets/has_content_in_original_bundle")), + hasJsonPath("$._links", matchNextLink(hasNext, "api/discover/facets/has_content_in_original_bundle")) + ); + } + + private static AnyOf matchNextLink(boolean hasNext, String path) { + + return anyOf(hasJsonPath("$.next.href", containsString(path)), + not(hasJsonPath("$.next.href", containsString(path)))); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetValueMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetValueMatcher.java new file mode 100644 index 0000000000..213d93de09 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetValueMatcher.java @@ -0,0 +1,61 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +public class FacetValueMatcher { + + private FacetValueMatcher() { } + + public static Matcher entryAuthor(String label) { + return allOf( + hasJsonPath("$.label", is(label)), + hasJsonPath("$.type", is("discover")), + hasJsonPath("$._links.search.href", containsString("api/discover/search/objects")), + hasJsonPath("$._links.search.href", containsString("f.author=" + label + ",equals")) + ); + } + + public static Matcher entryDateIssued() { + return allOf( + hasJsonPath("$.label", Matchers.notNullValue()), + hasJsonPath("$.type", is("discover")), + hasJsonPath("$._links.search.href", containsString("api/discover/search/objects")), + hasJsonPath("$._links.search.href", containsString("f.dateIssued=")), + hasJsonPath("$._links.search.href", containsString(",equals")) + ); + } + + public static Matcher entryDateIssuedWithCountOne() { + return allOf( + hasJsonPath("$.label", Matchers.notNullValue()), + hasJsonPath("$.type", is("discover")), + hasJsonPath("$.count", is(1)), + hasJsonPath("$._links.search.href", containsString("api/discover/search/objects")), + hasJsonPath("$._links.search.href", containsString("f.dateIssued=")), + hasJsonPath("$._links.search.href", containsString(",equals")) + ); + } + + public static Matcher entryDateIssuedWithLabel(String label) { + return allOf( + hasJsonPath("$.label", is(label)), + hasJsonPath("$.type", is("discover")), + hasJsonPath("$._links.search.href", containsString("api/discover/search/objects")), + hasJsonPath("$._links.search.href", containsString("f.dateIssued=")), + hasJsonPath("$._links.search.href", containsString(",equals")) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/GroupMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/GroupMatcher.java new file mode 100644 index 0000000000..c51e1097fd --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/GroupMatcher.java @@ -0,0 +1,40 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import java.util.UUID; + +import org.hamcrest.Matcher; + +public class GroupMatcher { + + private GroupMatcher() { } + + public static Matcher matchGroupEntry(UUID uuid, String name) { + return allOf( + hasJsonPath("$.uuid", is(uuid.toString())), + hasJsonPath("$.name", is(name)), + hasJsonPath("$.type", is("group")), + hasJsonPath("$._links.self.href", containsString("/api/eperson/groups/" + uuid.toString())) + ); + } + + public static Matcher matchGroupWithName(String name) { + return allOf( + hasJsonPath("$.name", is(name)), + hasJsonPath("$.type", is("group")) + ); + } + + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/HitHighlightMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/HitHighlightMatcher.java new file mode 100644 index 0000000000..ca23ab3c64 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/HitHighlightMatcher.java @@ -0,0 +1,28 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsString; + +import org.hamcrest.Matcher; + +public class HitHighlightMatcher { + + private HitHighlightMatcher() { } + + public static Matcher entry(String value, String expectedField) { + return allOf( + hasJsonPath("$.['" + expectedField + "']", contains(containsString("Public"))) + ); + } + + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java new file mode 100644 index 0000000000..e5176eea26 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java @@ -0,0 +1,67 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.dspace.app.rest.test.AbstractControllerIntegrationTest.REST_SERVER_URL; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.startsWith; + +import org.dspace.content.Item; +import org.hamcrest.Matcher; + +/** + * Utility class to construct a Matcher for an item + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Raf Ponsaerts (raf dot ponsaerts at atmire dot com) + */ +public class ItemMatcher { + + private ItemMatcher() { } + + public static Matcher matchItemWithTitleAndDateIssued(Item item, String title, String dateIssued) { + return allOf( + //Check item properties + matchItemProperties(item), + + //Check core metadata (the JSON Path expression evaluates to a collection so we have to use contains) + hasJsonPath("$.metadata[?(@.key=='dc.title')].value", contains(title)), + hasJsonPath("$.metadata[?(@.key=='dc.date.issued')].value", contains(dateIssued)), + + //Check links + matchItemLinks(item) + ); + } + + public static Matcher matchItemLinks(Item item) { + return allOf( + hasJsonPath("$._links.self.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.bitstreams.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.owningCollection.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.templateItemOf.href", startsWith(REST_SERVER_URL)) + ); + } + + public static Matcher matchItemProperties(Item item) { + return allOf( + hasJsonPath("$.uuid", is(item.getID().toString())), + hasJsonPath("$.name", is(item.getName())), + hasJsonPath("$.handle", is(item.getHandle())), + hasJsonPath("$.inArchive", is(item.isArchived())), + hasJsonPath("$.discoverable", is(item.isDiscoverable())), + hasJsonPath("$.withdrawn", is(item.isWithdrawn())), + hasJsonPath("$.lastModified", is(notNullValue())), + hasJsonPath("$.type", is("item")) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataFieldMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataFieldMatcher.java new file mode 100644 index 0000000000..59f609cdfa --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataFieldMatcher.java @@ -0,0 +1,55 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.dspace.content.MetadataField; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +public class MetadataFieldMatcher { + + private MetadataFieldMatcher() { } + + public static Matcher matchMetadataField() { + return allOf( + hasJsonPath("$.element", Matchers.not(Matchers.empty())), + hasJsonPath("$.qualifier", Matchers.not(Matchers.empty())), + hasJsonPath("$.type", is("metadatafield")), + hasJsonPath("$._embedded.schema", Matchers.not(Matchers.empty())), + hasJsonPath("$._links.schema.href", Matchers.containsString("/api/core/metadatafields")), + hasJsonPath("$._links.self.href", Matchers.containsString("/api/core/metadatafields")) + ); + } + + public static Matcher matchMetadataField(MetadataField metadataField) { + return allOf( + hasJsonPath("$.element", is(metadataField.getElement())), + hasJsonPath("$.qualifier", is(metadataField.getQualifier())), + hasJsonPath("$.type", is("metadatafield")), + hasJsonPath("$._embedded.schema", Matchers.not(Matchers.empty())), + hasJsonPath("$._links.schema.href", Matchers.containsString("/api/core/metadatafields")), + hasJsonPath("$._links.self.href", Matchers.containsString("/api/core/metadatafields")) + ); + } + + public static Matcher matchMetadataFieldByKeys(String schema, String element, String qualifier) { + return allOf( + hasJsonPath("$.element", is(element)), + hasJsonPath("$.qualifier", is(qualifier)), + hasJsonPath("$.type", is("metadatafield")), + hasJsonPath("$._embedded.schema.prefix", is(schema)), + hasJsonPath("$._links.schema.href", Matchers.containsString("/api/core/metadatafields")), + hasJsonPath("$._links.self.href", Matchers.containsString("/api/core/metadatafields")) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataschemaMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataschemaMatcher.java new file mode 100644 index 0000000000..18e8a5ad8d --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataschemaMatcher.java @@ -0,0 +1,39 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.dspace.content.MetadataSchema; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +public class MetadataschemaMatcher { + + private MetadataschemaMatcher() { } + + public static Matcher matchEntry() { + return allOf( + hasJsonPath("$.prefix", Matchers.not(Matchers.empty())), + hasJsonPath("$.namespace", Matchers.not(Matchers.empty())), + hasJsonPath("$.type", is("metadataschema")), + hasJsonPath("$._links.self.href", Matchers.containsString("/api/core/metadataschemas")) + ); + } + + public static Matcher matchEntry(MetadataSchema metadataSchema) { + return allOf( + hasJsonPath("$.prefix", is(metadataSchema.getName())), + hasJsonPath("$.namespace", is(metadataSchema.getNamespace())), + hasJsonPath("$.type", is("metadataschema")), + hasJsonPath("$._links.self.href", Matchers.containsString("/api/core/metadataschemas")) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/PageMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/PageMatcher.java new file mode 100644 index 0000000000..9f040b5f9f --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/PageMatcher.java @@ -0,0 +1,37 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +public class PageMatcher { + + private PageMatcher() { } + + public static Matcher pageEntry(int number, int size) { + return allOf( + hasJsonPath("$.number", is(number)), + hasJsonPath("$.size", is(size)) + ); + } + + public static Matcher pageEntryWithTotalPagesAndElements(int number, int size, int totalPages, + int totalElements) { + return allOf( + hasJsonPath("$.number", is(number)), + hasJsonPath("$.size", is(size)), + hasJsonPath("$.totalPages", is(totalPages)), + hasJsonPath("$.totalElements", is(totalElements)) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java new file mode 100644 index 0000000000..da344e47b4 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java @@ -0,0 +1,105 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +public class SearchFilterMatcher { + + private SearchFilterMatcher() { } + + public static Matcher titleFilter() { + return allOf( + hasJsonPath("$.filter", is("title")), + hasJsonPath("$.hasFacets", is(false)), + hasJsonPath("$.type", is("text")), + hasJsonPath("$.openByDefault", is(true)), + checkOperators() + + ); + } + + public static Matcher authorFilter() { + return allOf( + hasJsonPath("$.filter", is("author")), + hasJsonPath("$.hasFacets", is(true)), + hasJsonPath("$.type", is("text")), + hasJsonPath("$.openByDefault", is(true)), + checkOperators() + + ); + } + + public static Matcher subjectFilter() { + return allOf( + hasJsonPath("$.filter", is("subject")), + hasJsonPath("$.hasFacets", is(true)), + hasJsonPath("$.type", is("hierarchical")), + hasJsonPath("$.openByDefault", is(false)), + checkOperators() + + ); + } + + public static Matcher dateIssuedFilter() { + return allOf( + hasJsonPath("$.filter", is("dateIssued")), + hasJsonPath("$.hasFacets", is(true)), + hasJsonPath("$.type", is("date")), + hasJsonPath("$.openByDefault", is(false)), + checkOperators() + + ); + } + + public static Matcher hasContentInOriginalBundleFilter() { + return allOf( + hasJsonPath("$.filter", is("has_content_in_original_bundle")), + hasJsonPath("$.hasFacets", is(true)), + hasJsonPath("$.type", is("standard")), + hasJsonPath("$.openByDefault", is(false)), + checkOperators() + + ); + } + + public static Matcher hasFileNameInOriginalBundleFilter() { + return allOf( + hasJsonPath("$.filter", is("original_bundle_filenames")), + checkOperators() + + ); + } + + public static Matcher hasFileDescriptionInOriginalBundleFilter() { + return allOf( + hasJsonPath("$.filter", is("original_bundle_descriptions")), + checkOperators() + + ); + } + + public static Matcher checkOperators() { + return allOf( + hasJsonPath("$.operators", containsInAnyOrder( + hasJsonPath("$.operator", is("equals")), + hasJsonPath("$.operator", is("notequals")), + hasJsonPath("$.operator", is("authority")), + hasJsonPath("$.operator", is("notauthority")), + hasJsonPath("$.operator", is("contains")), + hasJsonPath("$.operator", is("notcontains")), + hasJsonPath("$.operator", is("query")) + )) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchResultMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchResultMatcher.java new file mode 100644 index 0000000000..40da1be48c --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchResultMatcher.java @@ -0,0 +1,80 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import org.hamcrest.Matcher; + +public class SearchResultMatcher { + + private SearchResultMatcher() { } + + public static Matcher match(String type, String typePlural) { + return allOf( + hasJsonPath("$.type", is("discover")), + hasJsonPath("$._links.dspaceObject.href", containsString("/api/core/" + typePlural)), + hasJsonPath("$._embedded", notNullValue()), + hasJsonPath("$._embedded.dspaceObject", is( + matchEmbeddedObject(type) + )) + ); + } + + public static Matcher match() { + return allOf( + hasJsonPath("$.type", is("discover")) + ); + } + + private static Matcher matchEmbeddedObject(String type) { + return allOf( + hasJsonPath("$.uuid", notNullValue()), + hasJsonPath("$.name", notNullValue()), + hasJsonPath("$.type", is(type)) + ); + } + + public static Matcher matchOnItemName(String type, String typePlural, String itemName) { + return allOf( + hasJsonPath("$.type", is("discover")), + hasJsonPath("$._links.dspaceObject.href", containsString("/api/core/" + typePlural)), + hasJsonPath("$._embedded", notNullValue()), + hasJsonPath("$._embedded.dspaceObject", is( + matchEmbeddedObjectOnItemName(type, itemName) + )) + ); + } + + private static Matcher matchEmbeddedObjectOnItemName(String type, String itemName) { + return allOf( + hasJsonPath("$.uuid", notNullValue()), + hasJsonPath("$.name", is(itemName)), + hasJsonPath("$.type", is(type)) + ); + } + + public static Matcher matchOnItemNameAndHitHighlight(String type, String typePlural, + String itemName, String hitHighlightQuery, + String expectedFieldInHitHighlightning) { + return allOf( + hasJsonPath("$.type", is("discover")), + hasJsonPath("$.hitHighlights", is( + HitHighlightMatcher.entry(hitHighlightQuery, expectedFieldInHitHighlightning))), + hasJsonPath("$._links.dspaceObject.href", containsString("/api/core/" + typePlural)), + hasJsonPath("$._embedded", notNullValue()), + hasJsonPath("$._embedded.dspaceObject", is( + matchEmbeddedObjectOnItemName(type, itemName) + )) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SiteMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SiteMatcher.java new file mode 100644 index 0000000000..8e92fe161e --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SiteMatcher.java @@ -0,0 +1,31 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.dspace.content.Site; +import org.hamcrest.Matcher; + +public class SiteMatcher { + + private SiteMatcher() { } + + public static Matcher matchEntry(Site site) { + return allOf( + hasJsonPath("$.uuid", is(site.getID().toString())), + hasJsonPath("$.name", is(site.getName())), + hasJsonPath("$.type", is("site")), + hasJsonPath("$._links.self.href", containsString("/api/core/sites/" + site.getID())) + + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SortOptionMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SortOptionMatcher.java new file mode 100644 index 0000000000..caef5ecb58 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SortOptionMatcher.java @@ -0,0 +1,51 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +public class SortOptionMatcher { + + private SortOptionMatcher() { } + + public static Matcher titleSortOption() { + return allOf( + hasJsonPath("$.name", is("dc.title")) + ); + } + + public static Matcher dateIssuedSortOption() { + return allOf( + hasJsonPath("$.name", is("dc.date.issued")) + ); + } + + public static Matcher dateAccessionedSortOption() { + return allOf( + hasJsonPath("$.name", is("dc.date.accessioned")) + ); + } + + public static Matcher scoreSortOption() { + return allOf( + hasJsonPath("$.name", is("score")) + ); + } + + public static Matcher sortByAndOrder(String by, String order) { + return allOf( + hasJsonPath("$.by", is(by)), + hasJsonPath("$.order", is(order)) + ); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java new file mode 100644 index 0000000000..d8e85f3495 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java @@ -0,0 +1,35 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.dspace.app.rest.test.AbstractControllerIntegrationTest.REST_SERVER_URL; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +/** + * Utility class to construct a Matcher for a submission definition + */ +public class SubmissionDefinitionsMatcher { + + private SubmissionDefinitionsMatcher() { } + + public static Matcher matchSubmissionDefinition(boolean isDefault, String name, String id) { + return allOf( + hasJsonPath("$.isDefault", is(isDefault)), + hasJsonPath("$.name", is(name)), + hasJsonPath("$.id", is(id)), + hasJsonPath("$.type", is("submissiondefinition")), + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "config/submissiondefinitions/" + id)), + hasJsonPath("$._links.sections.href", + is(REST_SERVER_URL + "config/submissiondefinitions/" + id + "/sections")) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionFormFieldMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionFormFieldMatcher.java new file mode 100644 index 0000000000..fdefed59cf --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionFormFieldMatcher.java @@ -0,0 +1,90 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasNoJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.hamcrest.Matcher; + +/** + * Helper class to simplify testing of the submission form configuration + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + * + */ +public class SubmissionFormFieldMatcher { + + private SubmissionFormFieldMatcher() { } + + /** + * Shortcut for the + * {@link SubmissionFormFieldMatcher#matchFormFieldDefinition(String, String, String, boolean, String, String, String)} + * with a null style + * + * @param type + * the expected input type + * @param label + * the expected label + * @param mandatoryMessage + * the expected mandatoryMessage, can be null. If not empty the fiedl is expected to be flagged as + * mandatory + * @param repeatable + * the expected repeatable flag + * @param hints + * the expected hints message + * @param metadata + * the expected metadata + * @return a Matcher for all the condition above + */ + public static Matcher matchFormFieldDefinition(String type, String label, String mandatoryMessage, + boolean repeatable, String hints, String metadata) { + return matchFormFieldDefinition(type, label, mandatoryMessage, repeatable, hints, null, metadata); + } + + /** + * Check the json representation of a submission form + * + * @param type + * the expected input type + * @param label + * the expected label + * @param mandatoryMessage + * the expected mandatoryMessage, can be null. If not empty the field is expected to be flagged as + * mandatory + * @param repeatable + * the expected repeatable flag + * @param hints + * the expected hints message + * @param style + * the expected style for the field, can be null. If null the corresponding json path is expected to be + * missing + * @param metadata + * the expected metadata + * @return a Matcher for all the condition above + */ + public static Matcher matchFormFieldDefinition(String type, String label, String mandatoryMessage, + boolean repeatable, String hints, String style, String metadata) { + return allOf( + // check each field definition + hasJsonPath("$.input.type", is(type)), + hasJsonPath("$.label", containsString(label)), + hasJsonPath("$.selectableMetadata[0].metadata", is(metadata)), + mandatoryMessage != null ? hasJsonPath("$.mandatoryMessage", containsString(mandatoryMessage)) : + hasNoJsonPath("$.mandatoryMessage"), + hasJsonPath("$.mandatory", is(mandatoryMessage != null)), + hasJsonPath("$.repeatable", is(repeatable)), + style != null ? hasJsonPath("$.style", is(style)) : + hasNoJsonPath("$.style"), + hasJsonPath("$.hints", containsString(hints)) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/WorkspaceItemMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/WorkspaceItemMatcher.java new file mode 100644 index 0000000000..4117e1892a --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/WorkspaceItemMatcher.java @@ -0,0 +1,113 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasNoJsonPath; +import static org.dspace.app.rest.test.AbstractControllerIntegrationTest.REST_SERVER_URL; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; + +import org.dspace.content.WorkspaceItem; +import org.hamcrest.Matcher; + +/** + * Utility class to construct a Matcher for a Workspace item + * + * @author Andrea Bollini (andrea.bollini at 4science.it) + */ +public class WorkspaceItemMatcher { + + private WorkspaceItemMatcher() { } + + /** + * Check if the returned json expose all the required links and properties and the title and dateIssued are present + * in the traditionalpageone section as by the default configuration (form-submission.xml) + * + * @param witem + * the workspaceitem + * @param title + * the dc.title + * @param dateIssued + * the dc.date.issued + * @return + */ + public static Matcher matchItemWithTitleAndDateIssued(WorkspaceItem witem, String title, + String dateIssued) { + return allOf( + // Check workspaceitem properties + matchProperties(witem), + // Check core metadata all appear in the first describe panel "traditionalpageone" + hasJsonPath("$.sections.traditionalpageone['dc.title'][0].value", is(title)), + hasJsonPath("$.sections.traditionalpageone['dc.date.issued'][0].value", is(dateIssued)), + // Check links + matchLinks(witem)); + } + + /** + * Check if the returned json expose all the required links and properties and the title and dateIssued are present + * in the traditionalpageone section and the subject in the traditionalpagetwo section as by the default + * configuration (form-submission.xml) + * + * @param witem + * the workspaceitem + * @param title + * the dc.title + * @param dateIssued + * the dc.date.issued * @param subject the dc.subject + * + * @return + */ + public static Matcher matchItemWithTitleAndDateIssuedAndSubject(WorkspaceItem witem, String title, + String dateIssued, + String subject) { + return allOf( + // Check workspaceitem properties + matchProperties(witem), + // Check core metadata all appear in the first describe panel "traditionalpageone" + title != null ? + hasJsonPath("$.sections.traditionalpageone['dc.title'][0].value", is(title)) : + hasNoJsonPath("$.sections.traditionalpageone['dc.title']"), + hasJsonPath("$.sections.traditionalpageone['dc.date.issued'][0].value", is(dateIssued)), + // Check keywords they appear in the second describe panel "traditionalpagetwo" + hasJsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is(subject)), + // Check links + matchLinks(witem)); + } + + /** + * Check that the id and type are exposed + * + * @param witem + * the workspaceitem + * @return + */ + public static Matcher matchProperties(WorkspaceItem witem) { + return allOf( + hasJsonPath("$.id", is(witem.getID())), + hasJsonPath("$.type", is("workspaceitem")) + ); + } + + /** + * Check that the required links are present + * + * @param witem + * the workspaceitem + * @return + */ + public static Matcher matchLinks(WorkspaceItem witem) { + return allOf( + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "submission/workspaceitems/" + witem.getID())), + hasJsonPath("$._links.item.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.collection.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.submitter.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.submissionDefinition.href", startsWith(REST_SERVER_URL))); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/FacetConfigurationRestTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/FacetConfigurationRestTest.java new file mode 100644 index 0000000000..468ad2f740 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/FacetConfigurationRestTest.java @@ -0,0 +1,40 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; + +import org.junit.Before; +import org.junit.Test; + +public class FacetConfigurationRestTest { + + FacetConfigurationRest facetConfigurationRest; + + @Before + public void setUp() throws Exception { + facetConfigurationRest = new FacetConfigurationRest(); + } + + @Test + public void testSidebarFacetsNotNullAfterConstructor() { + assertNotNull(facetConfigurationRest.getSidebarFacets()); + } + + @Test + public void testAddSidebarFacetsContainsCorrectSidebarFacet() { + SearchFacetEntryRest sidebarFacet = new SearchFacetEntryRest("dateName"); + sidebarFacet.setFacetType("date"); + + facetConfigurationRest.addSidebarFacet(sidebarFacet); + + assertEquals(sidebarFacet, facetConfigurationRest.getSidebarFacets().get(0)); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/FacetResultsRestTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/FacetResultsRestTest.java new file mode 100644 index 0000000000..3966b4a503 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/FacetResultsRestTest.java @@ -0,0 +1,42 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model; + +import static junit.framework.TestCase.assertNotNull; +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the FacetResultsRest class + */ +public class FacetResultsRestTest { + + FacetResultsRest facetResultsRest; + + @Before + public void setUp() throws Exception { + facetResultsRest = new FacetResultsRest(); + } + + @Test + public void testFacetResultListNotNullAfterEntrySet() throws Exception { + facetResultsRest.setFacetEntry(new SearchFacetEntryRest("test")); + assertNotNull(facetResultsRest.getFacetResultList()); + } + + @Test + public void testAddToFacetResultListContainsCorrectValue() throws Exception { + SearchFacetValueRest searchFacetValueRest = new SearchFacetValueRest(); + facetResultsRest.setFacetEntry(new SearchFacetEntryRest("test")); + facetResultsRest.addToFacetResultList(searchFacetValueRest); + assertEquals(searchFacetValueRest, facetResultsRest.getFacetResultList().get(0)); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/SearchConfigurationRestTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/SearchConfigurationRestTest.java new file mode 100644 index 0000000000..8422574609 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/SearchConfigurationRestTest.java @@ -0,0 +1,126 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the SearchConfigurationRest + */ +public class SearchConfigurationRestTest { + + SearchConfigurationRest searchConfigurationRest; + + @Before + public void setUp() throws Exception { + searchConfigurationRest = new SearchConfigurationRest(); + } + + + @Test + public void testFiltersNotNullAfterConstructor() throws Exception { + assertNotNull(searchConfigurationRest.getFilters()); + } + + @Test + public void testSortOptionsNotNullAfterConstructor() throws Exception { + assertNotNull(searchConfigurationRest.getSortOptions()); + } + + @Test + public void testAddFilterToEmptyListAndListContainsThatFilter() throws Exception { + SearchConfigurationRest.Filter filter = new SearchConfigurationRest.Filter(); + filter.setFilter("filter"); + searchConfigurationRest.addFilter(filter); + assertEquals(filter, searchConfigurationRest.getFilters().get(0)); + } + + @Test + public void testAddSortOptionToEmptyListAndListContainsThatSortOption() throws Exception { + SearchConfigurationRest.SortOption sortOption = new SearchConfigurationRest.SortOption(); + sortOption.setActualName("sort option"); + searchConfigurationRest.addSortOption(sortOption); + assertEquals(sortOption, searchConfigurationRest.getSortOptions().get(0)); + } + + @Test + public void testAddMultipleFiltersToListAndListIsConstructedProperly() throws Exception { + SearchConfigurationRest.Filter filter = new SearchConfigurationRest.Filter(); + filter.setFilter("filter"); + searchConfigurationRest.addFilter(filter); + SearchConfigurationRest.Filter filter2 = new SearchConfigurationRest.Filter(); + filter.setFilter("filter2"); + searchConfigurationRest.addFilter(filter2); + + assertEquals(2, searchConfigurationRest.getFilters().size()); + + assertTrue(searchConfigurationRest.getFilters().get(0) == filter || searchConfigurationRest.getFilters() + .get(0) == filter2); + assertTrue(searchConfigurationRest.getFilters().get(1) == filter || searchConfigurationRest.getFilters() + .get(1) == filter2); + + } + + @Test + public void testAddMultipleSortOptionsToListAndListIsConstructedProperly() throws Exception { + SearchConfigurationRest.SortOption sortOption = new SearchConfigurationRest.SortOption(); + sortOption.setActualName("sort option"); + searchConfigurationRest.addSortOption(sortOption); + SearchConfigurationRest.SortOption sortOption2 = new SearchConfigurationRest.SortOption(); + sortOption2.setActualName("sort option2"); + searchConfigurationRest.addSortOption(sortOption2); + + assertEquals(2, searchConfigurationRest.getSortOptions().size()); + + assertTrue( + searchConfigurationRest.getSortOptions().get(0) == sortOption || searchConfigurationRest.getSortOptions() + .get( + 0) == + sortOption2); + assertTrue( + searchConfigurationRest.getSortOptions().get(1) == sortOption || searchConfigurationRest.getSortOptions() + .get( + 1) == + sortOption2); + + } + + + @Test + public void testOperatorConstructorWithProperValueReturnsCorrectValue() throws Exception { + SearchConfigurationRest.Filter.Operator operator = new SearchConfigurationRest.Filter.Operator("operator"); + assertEquals("operator", operator.getOperator()); + } + + + @Test + public void testFilterGetOperatorsAfterConstructorReturnsEmptyList() throws Exception { + SearchConfigurationRest.Filter filter = new SearchConfigurationRest.Filter(); + assertTrue(filter.getOperators().isEmpty()); + } + + @Test + public void testFilterAddOperatorAddsProperlyAndIsIncludedInGetOperators() throws Exception { + SearchConfigurationRest.Filter filter = new SearchConfigurationRest.Filter(); + SearchConfigurationRest.Filter.Operator operator = new SearchConfigurationRest.Filter.Operator("operator"); + filter.addOperator(operator); + assertEquals(operator, filter.getOperators().get(0)); + } + + @Test + public void testFilterAddDefaultOperatorsToListPopulatesList() throws Exception { + SearchConfigurationRest.Filter filter = new SearchConfigurationRest.Filter(); + filter.addDefaultOperatorsToList(); + assertTrue(!filter.getOperators().isEmpty()); + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/SearchSupportRestTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/SearchSupportRestTest.java new file mode 100644 index 0000000000..09f1d494d2 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/SearchSupportRestTest.java @@ -0,0 +1,47 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.dspace.app.rest.DiscoveryRestController; +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the SearchSupportRest class + */ +public class SearchSupportRestTest { + SearchSupportRest searchSupportRest; + + @Before + public void setUp() throws Exception { + searchSupportRest = new SearchSupportRest(); + } + + @Test + public void testConstructorDoesNotReturnNull() throws Exception { + assertNotNull(searchSupportRest); + } + + @Test + public void testGetTypeReturnsCorrectValue() throws Exception { + assertEquals(SearchSupportRest.NAME, searchSupportRest.getType()); + } + + @Test + public void testGetCategoryReturnsCorrectValue() throws Exception { + assertEquals(SearchSupportRest.CATEGORY, searchSupportRest.getCategory()); + } + + @Test + public void testGetControllerReturnsCorrectValue() throws Exception { + assertEquals(DiscoveryRestController.class, searchSupportRest.getController()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/FacetConfigurationResourceTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/FacetConfigurationResourceTest.java new file mode 100644 index 0000000000..b30130762b --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/FacetConfigurationResourceTest.java @@ -0,0 +1,46 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model.hateoas; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.dspace.app.rest.model.FacetConfigurationRest; +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the FacetConfigurationRest class + */ +public class FacetConfigurationResourceTest { + private FacetConfigurationRest facetConfigurationRest; + + @Before + public void setUp() throws Exception { + facetConfigurationRest = new FacetConfigurationRest(); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructorWithNullThrowsException() throws Exception { + FacetConfigurationResource facetConfigurationResource = new FacetConfigurationResource(null); + } + + @Test + public void testConstructorAndGetterWithProperDataAndObjectNotNull() throws Exception { + FacetConfigurationResource facetConfigurationResource = new FacetConfigurationResource(facetConfigurationRest); + assertNotNull(facetConfigurationResource); + assertNotNull(facetConfigurationResource.getContent()); + } + + @Test + public void testConstructorAndGetterWithProperDataAndProperDataReturned() throws Exception { + FacetConfigurationResource facetConfigurationResource = new FacetConfigurationResource(facetConfigurationRest); + assertEquals(facetConfigurationRest, facetConfigurationResource.getContent()); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/RootResourceTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/RootResourceTest.java new file mode 100644 index 0000000000..bd25060605 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/RootResourceTest.java @@ -0,0 +1,47 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model.hateoas; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.dspace.app.rest.model.RootRest; +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the RootResource class + */ +public class RootResourceTest { + + private RootRest rootRest; + + @Before + public void setUp() throws Exception { + rootRest = new RootRest(); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructorWithNullThrowsException() throws Exception { + RootResource rootResource = new RootResource(null); + } + + + @Test + public void testConstructorAndGetterWithProperDataAndObjectNotNull() throws Exception { + RootResource rootResource = new RootResource(rootRest); + assertNotNull(rootResource); + assertNotNull(rootResource.getContent()); + } + + @Test + public void testConstructorAndGetterWithProperDataAndProperDataReturned() throws Exception { + RootResource rootResource = new RootResource(rootRest); + assertEquals(rootRest, rootResource.getContent()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/SearchConfigurationResourceTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/SearchConfigurationResourceTest.java new file mode 100644 index 0000000000..abea57299c --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/SearchConfigurationResourceTest.java @@ -0,0 +1,47 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model.hateoas; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.dspace.app.rest.model.SearchConfigurationRest; +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the SearchConfigurationResource + */ +public class SearchConfigurationResourceTest { + private SearchConfigurationRest searchConfigurationRest; + + @Before + public void setUp() throws Exception { + searchConfigurationRest = new SearchConfigurationRest(); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructorWithNullThrowsException() throws Exception { + SearchConfigurationResource searchConfigurationResource = new SearchConfigurationResource(null); + } + + @Test + public void testConstructorAndGetterWithProperDataAndObjectNotNull() throws Exception { + SearchConfigurationResource searchConfigurationResource = new SearchConfigurationResource( + searchConfigurationRest); + assertNotNull(searchConfigurationResource); + assertNotNull(searchConfigurationResource.getContent()); + } + + @Test + public void testConstructorAndGetterWithProperDataAndProperDataReturned() throws Exception { + SearchConfigurationResource searchConfigurationResource = new SearchConfigurationResource( + searchConfigurationRest); + assertEquals(searchConfigurationRest, searchConfigurationResource.getContent()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/SearchSupportResourceTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/SearchSupportResourceTest.java new file mode 100644 index 0000000000..b7c48075aa --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/model/hateoas/SearchSupportResourceTest.java @@ -0,0 +1,45 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model.hateoas; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.dspace.app.rest.model.SearchSupportRest; +import org.junit.Before; +import org.junit.Test; + +/** + * This class' purpose is to test the SearchSupportResource class + */ +public class SearchSupportResourceTest { + private SearchSupportRest searchSupportRest; + + @Before + public void setUp() throws Exception { + searchSupportRest = new SearchSupportRest(); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructorWithNullThrowsException() throws Exception { + SearchSupportResource searchSupportResource = new SearchSupportResource(null); + } + + @Test + public void testConstructorAndGetterWithProperDataAndObjectNotNull() throws Exception { + SearchSupportResource searchSupportResource = new SearchSupportResource(searchSupportRest); + assertNotNull(searchSupportResource); + assertNotNull(searchSupportResource.getContent()); + } + + @Test + public void testConstructorAndGetterWithProperDataAndProperDataReturned() throws Exception { + SearchSupportResource searchSupportResource = new SearchSupportResource(searchSupportRest); + assertEquals(searchSupportRest, searchSupportResource.getContent()); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/EPersonRestAuthenticationProviderTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/EPersonRestAuthenticationProviderTest.java new file mode 100644 index 0000000000..74c2adde4b --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/EPersonRestAuthenticationProviderTest.java @@ -0,0 +1,68 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.security; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.stream.Collectors; + +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.security.core.GrantedAuthority; + +/** + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + * @author Tom Desair (tom dot desair at atmire dot com) + */ +@RunWith(MockitoJUnitRunner.class) +public class EPersonRestAuthenticationProviderTest { + + @InjectMocks + private EPersonRestAuthenticationProvider ePersonRestAuthenticationProvider; + + @Mock + private EPerson ePerson; + + @Mock + private Context context; + + @Mock + private AuthorizeService authorizeService; + + @Test + public void testGetGrantedAuthoritiesAdmin() throws Exception { + when(authorizeService.isAdmin(context, ePerson)).thenReturn(true); + + List authorities = ePersonRestAuthenticationProvider.getGrantedAuthorities(context, ePerson); + + assertThat(authorities.stream().map(a -> a.getAuthority()).collect(Collectors.toList()), containsInAnyOrder( + WebSecurityConfiguration.ADMIN_GRANT, WebSecurityConfiguration.AUTHENTICATED_GRANT)); + + } + + @Test + public void testGetGrantedAuthoritiesEPerson() throws Exception { + when(authorizeService.isAdmin(context, ePerson)).thenReturn(false); + + List authorities = ePersonRestAuthenticationProvider.getGrantedAuthorities(context, ePerson); + + assertThat(authorities.stream().map(a -> a.getAuthority()).collect(Collectors.toList()), containsInAnyOrder( + WebSecurityConfiguration.AUTHENTICATED_GRANT)); + + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/EPersonClaimProviderTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/EPersonClaimProviderTest.java new file mode 100644 index 0000000000..954126b4d7 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/EPersonClaimProviderTest.java @@ -0,0 +1,84 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.security.jwt; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; + +import com.nimbusds.jwt.JWTClaimsSet; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.service.EPersonService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + * @author Tom Desair (tom dot desair at atmire dot com) + */ +@RunWith(MockitoJUnitRunner.class) +public class EPersonClaimProviderTest { + + @InjectMocks + private EPersonClaimProvider ePersonClaimProvider; + + @Mock + private EPerson ePerson; + + private Context context; + + @Mock + private HttpServletRequest httpServletRequest; + + @Mock + private EPersonService ePersonService; + + private JWTClaimsSet jwtClaimsSet; + + + @Before + public void setUp() throws Exception { + context = Mockito.mock(Context.class); + Mockito.doCallRealMethod().when(context).setCurrentUser(any(EPerson.class)); + Mockito.doCallRealMethod().when(context).getCurrentUser(); + when(ePerson.getID()).thenReturn(UUID.fromString("c3bae216-a481-496b-a524-7df5aabdb609")); + jwtClaimsSet = new JWTClaimsSet.Builder() + .claim(EPersonClaimProvider.EPERSON_ID, "c3bae216-a481-496b-a524-7df5aabdb609") + .build(); + when(ePersonService.find(any(), any(UUID.class))).thenReturn(ePerson); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testParseClaim() throws Exception { + ePersonClaimProvider.parseClaim(context, httpServletRequest, jwtClaimsSet); + + verify(context).setCurrentUser(ePerson); + } + + @Test + public void testGetEPerson() throws Exception { + EPerson parsed = ePersonClaimProvider.getEPerson(context, jwtClaimsSet); + assertEquals(parsed.getID(), UUID.fromString("c3bae216-a481-496b-a524-7df5aabdb609")); + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/JWTTokenHandlerTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/JWTTokenHandlerTest.java new file mode 100644 index 0000000000..75a930aa61 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/JWTTokenHandlerTest.java @@ -0,0 +1,134 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.security.jwt; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Date; +import java.util.List; +import javax.servlet.http.HttpServletRequest; + +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.service.EPersonService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.crypto.keygen.KeyGenerators; +import org.springframework.security.crypto.keygen.StringKeyGenerator; + +/** + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + * @author Tom Desair (tom dot desair at atmire dot com) + */ +@RunWith(MockitoJUnitRunner.class) +public class JWTTokenHandlerTest { + + @InjectMocks + @Spy + JWTTokenHandler jwtTokenHandler; + + @Mock + private Context context; + + @Mock + private EPerson ePerson; + + @Mock + private HttpServletRequest httpServletRequest; + + @Mock + private EPersonService ePersonService; + + @Mock + private EPersonClaimProvider ePersonClaimProvider; + + @Spy + private List jwtClaimProviders = new ArrayList<>(); + + @Before + public void setUp() throws Exception { + when(ePerson.getEmail()).thenReturn("test@dspace.org"); + when(ePerson.getSessionSalt()).thenReturn("01234567890123456789012345678901"); + when(ePerson.getLastActive()).thenReturn(new Date()); + when(context.getCurrentUser()).thenReturn(ePerson); + when(ePersonClaimProvider.getKey()).thenReturn("eid"); + when(ePersonClaimProvider.getValue(any(), Mockito.any(HttpServletRequest.class))).thenReturn("epersonID"); + jwtClaimProviders.add(ePersonClaimProvider); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testJWTNoEncryption() throws Exception { + Date previous = new Date(System.currentTimeMillis() - 10000000000L); + String token = jwtTokenHandler + .createTokenForEPerson(context, new MockHttpServletRequest(), previous, new ArrayList<>()); + SignedJWT signedJWT = SignedJWT.parse(token); + String personId = (String) signedJWT.getJWTClaimsSet().getClaim(EPersonClaimProvider.EPERSON_ID); + assertEquals("epersonID", personId); + } + + @Test(expected = ParseException.class) + public void testJWTEncrypted() throws Exception { + when(jwtTokenHandler.isEncryptionEnabled()).thenReturn(true); + Date previous = new Date(System.currentTimeMillis() - 10000000000L); + StringKeyGenerator keyGenerator = KeyGenerators.string(); + when(jwtTokenHandler.getEncryptionKey()).thenReturn(keyGenerator.generateKey().getBytes()); + String token = jwtTokenHandler + .createTokenForEPerson(context, new MockHttpServletRequest(), previous, new ArrayList<>()); + SignedJWT signedJWT = SignedJWT.parse(token); + } + + //temporary set a negative expiration time so the token is invalid immediately + @Test + public void testExpiredToken() throws Exception { + when(jwtTokenHandler.getExpirationPeriod()).thenReturn(-99999999L); + when(ePersonClaimProvider.getEPerson(any(Context.class), any(JWTClaimsSet.class))).thenReturn(ePerson); + Date previous = new Date(new Date().getTime() - 10000000000L); + String token = jwtTokenHandler + .createTokenForEPerson(context, new MockHttpServletRequest(), previous, new ArrayList<>()); + EPerson parsed = jwtTokenHandler.parseEPersonFromToken(token, httpServletRequest, context); + assertEquals(null, parsed); + + } + + //Try if we can change the expiration date + @Test + public void testTokenTampering() throws Exception { + when(jwtTokenHandler.getExpirationPeriod()).thenReturn(-99999999L); + when(ePersonClaimProvider.getEPerson(any(Context.class), any(JWTClaimsSet.class))).thenReturn(ePerson); + Date previous = new Date(new Date().getTime() - 10000000000L); + String token = jwtTokenHandler + .createTokenForEPerson(context, new MockHttpServletRequest(), previous, new ArrayList<>()); + JWTClaimsSet jwtClaimsSet = new JWTClaimsSet.Builder().claim("eid", "epersonID").expirationTime( + new Date(System.currentTimeMillis() + 99999999)).build(); + String tamperedPayload = new String(Base64.getUrlEncoder().encode(jwtClaimsSet.toString().getBytes())); + String[] splitToken = token.split("\\."); + String tamperedToken = splitToken[0] + "." + tamperedPayload + "." + splitToken[2]; + EPerson parsed = jwtTokenHandler.parseEPersonFromToken(tamperedToken, httpServletRequest, context); + assertEquals(null, parsed); + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/SpecialGroupClaimProviderTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/SpecialGroupClaimProviderTest.java new file mode 100644 index 0000000000..ff3382cb6e --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/security/jwt/SpecialGroupClaimProviderTest.java @@ -0,0 +1,87 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.security.jwt; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; + +import com.nimbusds.jwt.JWTClaimsSet; +import org.dspace.core.Context; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + * @author Tom Desair (tom dot desair at atmire dot com) + */ +@RunWith(MockitoJUnitRunner.class) +public class SpecialGroupClaimProviderTest { + + @InjectMocks + private SpecialGroupClaimProvider specialGroupClaimProvider; + + private List specialGroups = new ArrayList<>(); + + private Context context; + + private String id1 = "02af436f-a531-4934-9b36-a21cd8fdcc57"; + private String id2 = "f39d3947-c75d-4d09-86ef-f732cfae7d88"; + private String id3 = "2262d8ad-8bb6-4330-9cee-06da30f3feae"; + + @Mock + private HttpServletRequest httpServletRequest; + + private JWTClaimsSet jwtClaimsSet; + + @Before + public void setUp() throws Exception { + context = Mockito.mock(Context.class); + //Stub the specialgroups list that is normally kept in the context class + Mockito.doAnswer(invocation -> { + UUID uuid = invocation.getArgumentAt(0, UUID.class); + specialGroups.add(uuid); + return "done"; + }).when(context).setSpecialGroup(any(UUID.class)); + + List groupIds = new ArrayList<>(); + groupIds.add(id1); + groupIds.add(id2); + groupIds.add(id3); + + jwtClaimsSet = new JWTClaimsSet.Builder() + .claim(SpecialGroupClaimProvider.SPECIAL_GROUPS, groupIds) + .build(); + } + + @After + public void tearDown() throws Exception { + specialGroups.clear(); + } + + @Test + public void parseClaim() throws Exception { + specialGroupClaimProvider.parseClaim(context, httpServletRequest, jwtClaimsSet); + + assertThat(specialGroups, containsInAnyOrder( + UUID.fromString(id1), UUID.fromString(id2), UUID.fromString(id3))); + + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java new file mode 100644 index 0000000000..f790aa230a --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java @@ -0,0 +1,151 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.test; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; +import javax.servlet.Filter; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.io.Charsets; +import org.apache.commons.lang.StringUtils; +import org.dspace.app.rest.Application; +import org.dspace.app.rest.model.patch.Operation; +import org.dspace.app.rest.security.MethodSecurityConfig; +import org.dspace.app.rest.security.WebSecurityConfiguration; +import org.dspace.app.rest.utils.ApplicationConfig; +import org.junit.Assert; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.support.ErrorPageFilter; +import org.springframework.hateoas.MediaTypes; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; +import org.springframework.test.context.support.DirtiesContextTestExecutionListener; +import org.springframework.test.context.transaction.TransactionalTestExecutionListener; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.RequestPostProcessor; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; +import org.springframework.web.context.WebApplicationContext; + +/** + * Abstract controller integration test class that will take care of setting up the + * environment to run the integration test + * + * @author Tom Desair (tom dot desair at atmire dot com) + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = {Application.class, ApplicationConfig.class, WebSecurityConfiguration.class, + MethodSecurityConfig.class}) +@TestExecutionListeners( {DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, + TransactionalTestExecutionListener.class}) +@DirtiesContext +@WebAppConfiguration +public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWithDatabase { + + protected static final String AUTHORIZATION_HEADER = "Authorization"; + + //The Authorization header contains a value like "Bearer TOKENVALUE". This constant string represents the part that + //sits before the actual authentication token and can be used to easily compose or parse the Authorization header. + protected static final String AUTHORIZATION_TYPE = "Bearer "; + + public static final String REST_SERVER_URL = "http://localhost/api/"; + + protected MediaType contentType = new MediaType(MediaTypes.HAL_JSON.getType(), + MediaTypes.HAL_JSON.getSubtype(), Charsets.UTF_8); + + + protected HttpMessageConverter mappingJackson2HttpMessageConverter; + + @Autowired + private WebApplicationContext webApplicationContext; + + @Autowired + private List requestFilters; + + @Autowired + void setConverters(HttpMessageConverter[] converters) { + + this.mappingJackson2HttpMessageConverter = Arrays.asList(converters).stream().filter( + hmc -> hmc instanceof MappingJackson2HttpMessageConverter).findAny().get(); + + Assert.assertNotNull("the JSON message converter must not be null", + this.mappingJackson2HttpMessageConverter); + } + + public MockMvc getClient() throws SQLException { + return getClient(null); + } + + public MockMvc getClient(String authToken) throws SQLException { + if (context != null && context.isValid()) { + context.commit(); + } + + DefaultMockMvcBuilder mockMvcBuilder = webAppContextSetup(webApplicationContext) + //Always log the response to debug + .alwaysDo(MockMvcResultHandlers.print()) + //Add all filter implementations + .addFilters(new ErrorPageFilter()) + .addFilters(requestFilters.toArray(new Filter[requestFilters.size()])); + + if (StringUtils.isNotBlank(authToken)) { + mockMvcBuilder.defaultRequest( + get("").header(AUTHORIZATION_HEADER, AUTHORIZATION_TYPE + authToken)); + } + + return mockMvcBuilder + .build(); + } + + public MockHttpServletResponse getAuthResponse(String user, String password) throws Exception { + return getClient().perform(post("/api/authn/login") + .param("user", user) + .param("password", password)) + .andReturn().getResponse(); + } + + public String getAuthToken(String user, String password) throws Exception { + return StringUtils.substringAfter( + getAuthResponse(user, password).getHeader(AUTHORIZATION_HEADER), + AUTHORIZATION_TYPE); + } + + public String getPatchContent(List ops) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.writeValueAsString(ops); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return null; + } + + public static RequestPostProcessor ip(final String ipAddress) { + return request -> { + request.setRemoteAddr(ipAddress); + return request; + }; + } +} + diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractDSpaceIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractDSpaceIntegrationTest.java new file mode 100644 index 0000000000..3f129b5528 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractDSpaceIntegrationTest.java @@ -0,0 +1,112 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.test; + +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.net.URL; +import java.sql.SQLException; +import java.util.Properties; +import java.util.TimeZone; + +import org.apache.log4j.Logger; +import org.dspace.app.rest.builder.AbstractBuilder; +import org.dspace.servicemanager.DSpaceKernelImpl; +import org.dspace.servicemanager.DSpaceKernelInit; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * Abstract Test class copied from DSpace API + */ +public class AbstractDSpaceIntegrationTest { + + /** + * log4j category + */ + private static final Logger log = Logger.getLogger(AbstractDSpaceIntegrationTest.class); + + /** + * Test properties. These configure our general test environment + */ + protected static Properties testProps; + + /** + * DSpace Kernel. Must be started to initialize ConfigurationService and + * any other services. + */ + protected static DSpaceKernelImpl kernelImpl; + + /** + * Default constructor + */ + protected AbstractDSpaceIntegrationTest() { } + + /** + * This method will be run before the first test as per @BeforeClass. It will + * initialize shared resources required for all tests of this class. + * + * This method loads our test properties to initialize our test environment, + * and then starts the DSpace Kernel (which allows access to services). + */ + @BeforeClass + public static void initKernel() { + try { + //Stops System.exit(0) throws exception instead of exitting + System.setSecurityManager(new NoExitSecurityManager()); + + //set a standard time zone for the tests + TimeZone.setDefault(TimeZone.getTimeZone("Europe/Dublin")); + + //load the properties of the tests + testProps = new Properties(); + URL properties = AbstractDSpaceIntegrationTest.class.getClassLoader() + .getResource("test-config.properties"); + testProps.load(properties.openStream()); + + // Initialise the service manager kernel + kernelImpl = DSpaceKernelInit.getKernel(null); + if (!kernelImpl.isRunning()) { + // NOTE: the "dspace.dir" system property MUST be specified via Maven + kernelImpl.start(getDspaceDir()); // init the kernel + } + AbstractBuilder.init(); + } catch (IOException ex) { + log.error("Error initializing tests", ex); + fail("Error initializing tests: " + ex.getMessage()); + } + } + + /** + * This method will be run after all tests finish as per @AfterClass. It + * will clean resources initialized by the @BeforeClass methods. + */ + @AfterClass + public static void destroyKernel() throws SQLException { + System.setSecurityManager(null); + + //we clear the properties + testProps.clear(); + testProps = null; + + AbstractBuilder.destroy(); + + //Also clear out the kernel & nullify (so JUnit will clean it up) + if (kernelImpl != null) { + kernelImpl.destroy(); + } + kernelImpl = null; + } + + public static String getDspaceDir() { + return System.getProperty("dspace.dir"); + + } +} + diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractIntegrationTestWithDatabase.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractIntegrationTestWithDatabase.java new file mode 100644 index 0000000000..7c38a89f4d --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractIntegrationTestWithDatabase.java @@ -0,0 +1,234 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.test; + +import static org.junit.Assert.fail; + +import java.sql.SQLException; +import java.util.Arrays; + +import org.apache.log4j.Logger; +import org.dspace.app.launcher.ScriptLauncher; +import org.dspace.app.rest.builder.AbstractBuilder; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Community; +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; +import org.dspace.storage.rdbms.DatabaseUtils; +import org.jdom.Document; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; + +/** + * Abstract Test class that will initialize the in-memory database + */ +public class AbstractIntegrationTestWithDatabase extends AbstractDSpaceIntegrationTest { + /** + * log4j category + */ + private static final Logger log = Logger.getLogger(AbstractIntegrationTestWithDatabase.class); + + /** + * Context mock object to use in the tests. + */ + protected Context context; + + /** + * EPerson mock object to use in the tests. + */ + protected EPerson eperson; + + /** + * EPerson mock object in the Administrators group to use in the tests. + */ + protected EPerson admin; + + /** + * The password of our test eperson + */ + protected String password = "mySuperS3cretP4ssW0rd"; + + /** + * The test Parent Community + */ + protected Community parentCommunity = null; + + /** + * This method will be run before the first test as per @BeforeClass. It will + * initialize shared resources required for all tests of this class. + *

    + * NOTE: Per JUnit, "The @BeforeClass methods of superclasses will be run before those the current class." + * http://junit.org/apidocs/org/junit/BeforeClass.html + *

    + * This method builds on the initialization in AbstractDSpaceIntegrationTest, and + * initializes the in-memory database for tests that need it. + */ + @BeforeClass + public static void initDatabase() { + // Clear our old flyway object. Because this DB is in-memory, its + // data is lost when the last connection is closed. So, we need + // to (re)start Flyway from scratch for each Unit Test class. + DatabaseUtils.clearFlywayDBCache(); + + try { + // Update/Initialize the database to latest version (via Flyway) + DatabaseUtils.updateDatabase(); + } catch (SQLException se) { + log.error("Error initializing database", se); + fail("Error initializing database: " + se.getMessage() + + (se.getCause() == null ? "" : ": " + se.getCause().getMessage())); + } + } + + /** + * This method will be run before every test as per @Before. It will + * initialize resources required for each individual unit test. + * + * Other methods can be annotated with @Before here or in subclasses + * but no execution order is guaranteed + */ + @Before + public void setUp() throws Exception { + try { + //Start a new context + context = new Context(Context.Mode.BATCH_EDIT); + context.turnOffAuthorisationSystem(); + + //Find our global test EPerson account. If it doesn't exist, create it. + EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); + eperson = ePersonService.findByEmail(context, "test@email.com"); + if (eperson == null) { + // This EPerson creation should only happen once (i.e. for first test run) + log.info("Creating initial EPerson (email=test@email.com) for Unit Tests"); + eperson = ePersonService.create(context); + eperson.setFirstName(context, "first"); + eperson.setLastName(context, "last"); + eperson.setEmail("test@email.com"); + eperson.setCanLogIn(true); + eperson.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(eperson, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, eperson); + } + + // Set our global test EPerson as the current user in DSpace + context.setCurrentUser(eperson); + + // If our Anonymous/Administrator groups aren't initialized, initialize them as well + EPersonServiceFactory.getInstance().getGroupService().initDefaultGroupNames(context); + + admin = ePersonService.findByEmail(context, "admin@email.com"); + if (admin == null) { + // This EPerson creation should only happen once (i.e. for first test run) + log.info("Creating initial EPerson (email=admin@email.com) for Unit Tests"); + admin = ePersonService.create(context); + admin.setFirstName(context, "first (admin)"); + admin.setLastName(context, "last (admin)"); + admin.setEmail("admin@email.com"); + admin.setCanLogIn(true); + admin.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(admin, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, admin); + GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); + Group adminGroup = groupService.findByName(context, Group.ADMIN); + groupService.addMember(context, adminGroup, admin); + } + + context.restoreAuthSystemState(); + } catch (AuthorizeException ex) { + log.error("Error creating initial eperson or default groups", ex); + fail("Error creating initial eperson or default groups in AbstractUnitTest init()"); + } catch (SQLException ex) { + log.error(ex.getMessage(), ex); + fail("SQL Error on AbstractUnitTest init()"); + } + } + + /** + * This method will be run after every test as per @After. It will + * clean resources initialized by the @Before methods. + * + * Other methods can be annotated with @After here or in subclasses + * but no execution order is guaranteed + */ + @After + public void destroy() throws Exception { + // Cleanup our global context object + try { + AbstractBuilder.cleanupObjects(); + if (context == null || !context.isValid()) { + context = new Context(); + } + eperson = context.reloadEntity(eperson); + admin = context.reloadEntity(admin); + + context.turnOffAuthorisationSystem(); + if (eperson != null) { + EPersonServiceFactory.getInstance().getEPersonService().delete(context, eperson); + } + if (admin != null) { + EPersonServiceFactory.getInstance().getEPersonService().delete(context, admin); + } + parentCommunity = null; + cleanupContext(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Utility method to cleanup a created Context object (to save memory). + * This can also be used by individual tests to cleanup context objects they create. + */ + protected void cleanupContext() throws SQLException { + // If context still valid, flush all database changes and close it + if (context != null && context.isValid()) { + context.complete(); + } + + // Cleanup Context object by setting it to null + if (context != null) { + context = null; + } + } + + public void runDSpaceScript(String... args) throws Exception { + int status = 0; + try { + // Load up the ScriptLauncher's configuration + Document commandConfigs = ScriptLauncher.getConfig(kernelImpl); + + // Check that there is at least one argument (if not display command options) + if (args.length < 1) { + log.error("You must provide at least one command argument"); + } + + // Look up command in the configuration, and execute. + ScriptLauncher.runOneCommand(commandConfigs, args, kernelImpl); + + + } catch (ExitException e) { + status = e.getStatus(); + } + + if (status != 0) { + log.error("Failed to run script " + Arrays.toString(args)); + } + + if (!context.isValid()) { + setUp(); + } + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/DSpaceKernelContextCustomizerFactory.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/DSpaceKernelContextCustomizerFactory.java new file mode 100644 index 0000000000..798070915a --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/DSpaceKernelContextCustomizerFactory.java @@ -0,0 +1,32 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.test; + +import java.util.List; + +import org.dspace.kernel.DSpaceKernelManager; +import org.springframework.test.context.ContextConfigurationAttributes; +import org.springframework.test.context.ContextCustomizer; +import org.springframework.test.context.ContextCustomizerFactory; + +/** + * Context customizer factory to set the parent context of our Spring Boot application in TEST mode + * + * @author Tom Desair (tom dot desair at atmire dot com) + */ +public class DSpaceKernelContextCustomizerFactory implements ContextCustomizerFactory { + + @Override + public ContextCustomizer createContextCustomizer(Class testClass, + List configAttributes) { + return (context, mergedConfig) -> { + context.setParent(DSpaceKernelManager.getDefaultKernel().getServiceManager().getApplicationContext()); + }; + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/ExitException.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/ExitException.java new file mode 100644 index 0000000000..a377d42238 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/ExitException.java @@ -0,0 +1,21 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.test; + +public class ExitException extends SecurityException { + private final int status; + + public ExitException(int status) { + super("Process exited with code: " + status + ", you can ignore this exception"); + this.status = status; + } + + public int getStatus() { + return status; + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/NoExitSecurityManager.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/NoExitSecurityManager.java new file mode 100644 index 0000000000..79d75dcaf1 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/NoExitSecurityManager.java @@ -0,0 +1,30 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.test; + +import java.security.Permission; + +public class NoExitSecurityManager extends SecurityManager { + @Override + public void checkPermission(Permission perm) { + // allow anything. + } + + @Override + public void checkPermission(Permission perm, Object context) { + // allow anything. + } + + @Override + public void checkExit(int status) { + super.checkExit(status); + if (status >= 0) { + throw new ExitException(status); + } + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/utils/DiscoverQueryBuilderTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/utils/DiscoverQueryBuilderTest.java new file mode 100644 index 0000000000..75a22bf141 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/utils/DiscoverQueryBuilderTest.java @@ -0,0 +1,316 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.utils; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.dspace.app.rest.exception.InvalidDSpaceObjectTypeException; +import org.dspace.app.rest.exception.InvalidSearchFacetException; +import org.dspace.app.rest.exception.InvalidSearchFilterException; +import org.dspace.app.rest.exception.InvalidSortingException; +import org.dspace.app.rest.parameter.SearchFilter; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.discovery.DiscoverFacetField; +import org.dspace.discovery.DiscoverFilterQuery; +import org.dspace.discovery.DiscoverHitHighlightingField; +import org.dspace.discovery.DiscoverQuery; +import org.dspace.discovery.FacetYearRange; +import org.dspace.discovery.SolrServiceImpl; +import org.dspace.discovery.configuration.DiscoveryConfiguration; +import org.dspace.discovery.configuration.DiscoveryConfigurationParameters; +import org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration; +import org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration; +import org.dspace.discovery.configuration.DiscoverySearchFilterFacet; +import org.dspace.discovery.configuration.DiscoverySortConfiguration; +import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration; +import org.dspace.discovery.configuration.HierarchicalSidebarFacetConfiguration; +import org.dspace.services.ConfigurationService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.internal.matchers.apachecommons.ReflectionEquals; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; + +/** + * Unit tests for {@link DiscoverQueryBuilder} + */ +@RunWith(MockitoJUnitRunner.class) +public class DiscoverQueryBuilderTest { + + @InjectMocks + private DiscoverQueryBuilder queryBuilder; + + @Mock + private ConfigurationService configurationService; + + @Mock + private SolrServiceImpl searchService; + + @Mock + private Context context; + + @Mock + private DSpaceObject scope; + + private DiscoveryConfiguration discoveryConfiguration; + private String query; + private SearchFilter searchFilter; + private PageRequest page; + + @Before + public void setUp() throws Exception { + when(configurationService.getIntProperty(eq("rest.search.max.results"), anyInt())).thenReturn(100); + + when(searchService.escapeQueryChars(any(String.class))).then(invocation -> invocation.getArguments()[0]); + + when(searchService.toSortFieldIndex(any(String.class), any(String.class))) + .then(invocation -> invocation.getArguments()[0] + "_sort"); + + when(searchService + .getFacetYearRange(eq(context), any(DSpaceObject.class), any(DiscoverySearchFilterFacet.class), any())) + .then(invocation + -> new FacetYearRange((DiscoverySearchFilterFacet) invocation.getArguments()[2])); + + when(searchService.toFilterQuery(any(Context.class), any(String.class), any(String.class), any(String.class))) + .then(invocation -> new DiscoverFilterQuery((String) invocation.getArguments()[1], + invocation.getArguments()[1] + ":\"" + invocation + .getArguments()[3] + "\"", + (String) invocation.getArguments()[3])); + + discoveryConfiguration = new DiscoveryConfiguration(); + discoveryConfiguration.setDefaultFilterQueries(Arrays.asList("archived:true")); + + + DiscoveryHitHighlightingConfiguration discoveryHitHighlightingConfiguration = new + DiscoveryHitHighlightingConfiguration(); + List discoveryHitHighlightFieldConfigurations = new LinkedList<>(); + + DiscoveryHitHighlightFieldConfiguration discoveryHitHighlightFieldConfiguration = new + DiscoveryHitHighlightFieldConfiguration(); + discoveryHitHighlightFieldConfiguration.setField("dc.title"); + + DiscoveryHitHighlightFieldConfiguration discoveryHitHighlightFieldConfiguration1 = new + DiscoveryHitHighlightFieldConfiguration(); + discoveryHitHighlightFieldConfiguration1.setField("fulltext"); + + discoveryHitHighlightFieldConfigurations.add(discoveryHitHighlightFieldConfiguration1); + discoveryHitHighlightFieldConfigurations.add(discoveryHitHighlightFieldConfiguration); + + discoveryHitHighlightingConfiguration.setMetadataFields(discoveryHitHighlightFieldConfigurations); + discoveryConfiguration.setHitHighlightingConfiguration(discoveryHitHighlightingConfiguration); + + + DiscoverySortConfiguration sortConfiguration = new DiscoverySortConfiguration(); + + DiscoverySortFieldConfiguration defaultSort = new DiscoverySortFieldConfiguration(); + defaultSort.setMetadataField("dc.date.accessioned"); + defaultSort.setType(DiscoveryConfigurationParameters.TYPE_DATE); + sortConfiguration.setDefaultSort(defaultSort); + sortConfiguration.setDefaultSortOrder(DiscoverySortConfiguration.SORT_ORDER.desc); + + DiscoverySortFieldConfiguration titleSort = new DiscoverySortFieldConfiguration(); + titleSort.setMetadataField("dc.title"); + sortConfiguration.setSortFields(Arrays.asList(titleSort)); + + discoveryConfiguration.setSearchSortConfiguration(sortConfiguration); + + DiscoverySearchFilterFacet subjectFacet = new DiscoverySearchFilterFacet(); + subjectFacet.setIndexFieldName("subject"); + subjectFacet.setFacetLimit(5); + DiscoverySearchFilterFacet dateFacet = new DiscoverySearchFilterFacet(); + dateFacet.setIndexFieldName("dateIssued"); + dateFacet.setType(DiscoveryConfigurationParameters.TYPE_DATE); + dateFacet.setFacetLimit(6); + HierarchicalSidebarFacetConfiguration hierarchyFacet = new HierarchicalSidebarFacetConfiguration(); + hierarchyFacet.setIndexFieldName("hierarchy"); + hierarchyFacet.setType(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL); + hierarchyFacet.setFacetLimit(7); + hierarchyFacet.setSortOrderSidebar(DiscoveryConfigurationParameters.SORT.VALUE); + discoveryConfiguration.setSidebarFacets(Arrays.asList(subjectFacet, dateFacet, hierarchyFacet)); + discoveryConfiguration.setSearchFilters(Arrays.asList(subjectFacet, dateFacet, hierarchyFacet)); + + query = "my test case"; + searchFilter = new SearchFilter("subject", "equals", "Java"); + page = new PageRequest(1, 10, Sort.Direction.ASC, "dc.title"); + + queryBuilder.afterPropertiesSet(); + } + + @Test + public void testBuildQuery() throws Exception { + + DiscoverQuery discoverQuery = queryBuilder.buildQuery(context, scope, discoveryConfiguration, query, + Arrays.asList(searchFilter), "item", page); + + assertThat(discoverQuery.getFilterQueries(), containsInAnyOrder("archived:true", "subject:\"Java\"")); + assertThat(discoverQuery.getQuery(), is(query)); + assertThat(discoverQuery.getDSpaceObjectFilter(), is(Constants.ITEM)); + assertThat(discoverQuery.getSortField(), is("dc.title_sort")); + assertThat(discoverQuery.getSortOrder(), is(DiscoverQuery.SORT_ORDER.asc)); + assertThat(discoverQuery.getMaxResults(), is(10)); + assertThat(discoverQuery.getStart(), is(10)); + assertThat(discoverQuery.getFacetMinCount(), is(1)); + assertThat(discoverQuery.getFacetOffset(), is(0)); + assertThat(discoverQuery.getFacetFields(), hasSize(2)); + assertThat(discoverQuery.getFacetFields(), containsInAnyOrder( + new ReflectionEquals(new DiscoverFacetField("subject", DiscoveryConfigurationParameters.TYPE_TEXT, 6, + DiscoveryConfigurationParameters.SORT.COUNT)), + new ReflectionEquals( + new DiscoverFacetField("hierarchy", DiscoveryConfigurationParameters.TYPE_HIERARCHICAL, 8, + DiscoveryConfigurationParameters.SORT.VALUE)) + )); + assertThat(discoverQuery.getHitHighlightingFields(), hasSize(2)); + assertThat(discoverQuery.getHitHighlightingFields(), containsInAnyOrder( + new ReflectionEquals(new DiscoverHitHighlightingField("dc.title", 0, 3)), + new ReflectionEquals(new DiscoverHitHighlightingField("fulltext", 0, 3)) + )); + } + + @Test + public void testBuildQueryDefaults() throws Exception { + DiscoverQuery discoverQuery = queryBuilder.buildQuery(context, null, discoveryConfiguration, null, + null, null, null); + + assertThat(discoverQuery.getFilterQueries(), containsInAnyOrder("archived:true")); + assertThat(discoverQuery.getQuery(), isEmptyOrNullString()); + assertThat(discoverQuery.getDSpaceObjectFilter(), is(-1)); + //Note this should actually be "dc.date.accessioned_dt" but remember that our searchService is just a stupid + // mock + assertThat(discoverQuery.getSortField(), is("dc.date.accessioned_sort")); + assertThat(discoverQuery.getSortOrder(), is(DiscoverQuery.SORT_ORDER.desc)); + assertThat(discoverQuery.getMaxResults(), is(100)); + assertThat(discoverQuery.getStart(), is(0)); + assertThat(discoverQuery.getFacetMinCount(), is(1)); + assertThat(discoverQuery.getFacetOffset(), is(0)); + assertThat(discoverQuery.getFacetFields(), hasSize(2)); + assertThat(discoverQuery.getFacetFields(), containsInAnyOrder( + new ReflectionEquals(new DiscoverFacetField("subject", DiscoveryConfigurationParameters.TYPE_TEXT, 6, + DiscoveryConfigurationParameters.SORT.COUNT)), + new ReflectionEquals( + new DiscoverFacetField("hierarchy", DiscoveryConfigurationParameters.TYPE_HIERARCHICAL, 8, + DiscoveryConfigurationParameters.SORT.VALUE)) + )); + assertThat(discoverQuery.getHitHighlightingFields(), hasSize(2)); + assertThat(discoverQuery.getHitHighlightingFields(), containsInAnyOrder( + new ReflectionEquals(new DiscoverHitHighlightingField("dc.title", 0, 3)), + new ReflectionEquals(new DiscoverHitHighlightingField("fulltext", 0, 3)) + )); + } + + @Test + public void testSortByScore() throws Exception { + page = new PageRequest(2, 10, Sort.Direction.ASC, "SCORE"); + + DiscoverQuery discoverQuery = queryBuilder.buildQuery(context, null, discoveryConfiguration, null, + null, null, page); + + assertThat(discoverQuery.getFilterQueries(), containsInAnyOrder("archived:true")); + assertThat(discoverQuery.getQuery(), isEmptyOrNullString()); + assertThat(discoverQuery.getDSpaceObjectFilter(), is(-1)); + //Note this should actually be "dc.date.accessioned_dt" but remember that our searchService is just a stupid + // mock + assertThat(discoverQuery.getSortField(), is("score_sort")); + assertThat(discoverQuery.getSortOrder(), is(DiscoverQuery.SORT_ORDER.asc)); + assertThat(discoverQuery.getMaxResults(), is(10)); + assertThat(discoverQuery.getStart(), is(20)); + assertThat(discoverQuery.getFacetMinCount(), is(1)); + assertThat(discoverQuery.getFacetOffset(), is(0)); + assertThat(discoverQuery.getFacetFields(), hasSize(2)); + assertThat(discoverQuery.getFacetFields(), containsInAnyOrder( + new ReflectionEquals(new DiscoverFacetField("subject", DiscoveryConfigurationParameters.TYPE_TEXT, 6, + DiscoveryConfigurationParameters.SORT.COUNT)), + new ReflectionEquals( + new DiscoverFacetField("hierarchy", DiscoveryConfigurationParameters.TYPE_HIERARCHICAL, 8, + DiscoveryConfigurationParameters.SORT.VALUE)) + )); + assertThat(discoverQuery.getHitHighlightingFields(), hasSize(2)); + assertThat(discoverQuery.getHitHighlightingFields(), containsInAnyOrder( + new ReflectionEquals(new DiscoverHitHighlightingField("dc.title", 0, 3)), + new ReflectionEquals(new DiscoverHitHighlightingField("fulltext", 0, 3)) + )); + } + + @Test(expected = InvalidDSpaceObjectTypeException.class) + public void testInvalidDSOType() throws Exception { + queryBuilder.buildQuery(context, scope, discoveryConfiguration, query, + Arrays.asList(searchFilter), "TEST", page); + } + + @Test(expected = InvalidSortingException.class) + public void testInvalidSortField() throws Exception { + page = new PageRequest(2, 10, Sort.Direction.ASC, "test"); + queryBuilder.buildQuery(context, scope, discoveryConfiguration, query, + Arrays.asList(searchFilter), "ITEM", page); + } + + @Test(expected = InvalidSearchFilterException.class) + public void testInvalidSearchFilter1() throws Exception { + searchFilter = new SearchFilter("test", "equals", "Smith, Donald"); + + queryBuilder.buildQuery(context, scope, discoveryConfiguration, query, + Arrays.asList(searchFilter), "ITEM", page); + } + + @Test(expected = InvalidSearchFilterException.class) + public void testInvalidSearchFilter2() throws Exception { + when(searchService.toFilterQuery(any(Context.class), any(String.class), any(String.class), any(String.class))) + .thenThrow(SQLException.class); + + queryBuilder.buildQuery(context, scope, discoveryConfiguration, query, + Arrays.asList(searchFilter), "ITEM", page); + } + + @Test + public void testBuildFacetQuery() throws Exception { + DiscoverQuery discoverQuery = queryBuilder.buildFacetQuery(context, scope, discoveryConfiguration, + "prefix", query, + Arrays.asList(searchFilter), "item", page, + "subject"); + + assertThat(discoverQuery.getFilterQueries(), containsInAnyOrder("archived:true", "subject:\"Java\"")); + assertThat(discoverQuery.getQuery(), is(query)); + assertThat(discoverQuery.getDSpaceObjectFilter(), is(Constants.ITEM)); + assertThat(discoverQuery.getSortField(), isEmptyOrNullString()); + assertThat(discoverQuery.getMaxResults(), is(0)); + assertThat(discoverQuery.getStart(), is(0)); + assertThat(discoverQuery.getFacetMinCount(), is(1)); + assertThat(discoverQuery.getFacetOffset(), is(10)); + assertThat(discoverQuery.getFacetFields(), hasSize(1)); + assertThat(discoverQuery.getFacetFields(), contains( + new ReflectionEquals(new DiscoverFacetField("subject", DiscoveryConfigurationParameters.TYPE_TEXT, 11, + DiscoveryConfigurationParameters.SORT.COUNT, "prefix")) + )); + } + + @Test(expected = InvalidSearchFacetException.class) + public void testInvalidSearchFacet() throws Exception { + queryBuilder.buildFacetQuery(context, scope, discoveryConfiguration, null, query, + Arrays.asList(searchFilter), "item", page, "test"); + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/utils/MultipartFileSenderTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/utils/MultipartFileSenderTest.java new file mode 100644 index 0000000000..629e5fd1ef --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/utils/MultipartFileSenderTest.java @@ -0,0 +1,536 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Date; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.CharEncoding; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.util.ContentCachingRequestWrapper; +import org.springframework.web.util.ContentCachingResponseWrapper; + +/** + * Test class for MultipartFileSender + * + * @author Tom Desair (tom dot desair at atmire dot com) + * @author Frederic Van Reet (frederic dot vanreet at atmire dot com) + */ +public class MultipartFileSenderTest { + + /** + * log4j category + */ + private static final Logger log = Logger.getLogger(MultipartFileSenderTest.class); + + private InputStream is; + private String mimeType; + private long lastModified; + private long length; + private String fileName; + private String checksum; + + + private HttpServletRequest request; + + private HttpServletResponse response; + + private ContentCachingRequestWrapper requestWrapper; + private ContentCachingResponseWrapper responseWrapper; + + + /** + * This method will be run before every test as per @Before. It will + * initialize resources required for the tests. + *

    + * Other methods can be annotated with @Before here or in subclasses + * but no execution order is guaranteed + */ + @Before + public void init() throws AuthorizeException { + try { + String content = "0123456789"; + + this.is = IOUtils.toInputStream(content, CharEncoding.UTF_8); + this.fileName = "Test-Item.txt"; + this.mimeType = "text/plain"; + this.lastModified = new Date().getTime(); + this.length = content.getBytes().length; + this.checksum = "testsum"; + + this.request = mock(HttpServletRequest.class); + this.response = new MockHttpServletResponse(); + + //Using wrappers so we can save the content of the bodies and use them for tests + this.requestWrapper = new ContentCachingRequestWrapper(request); + this.responseWrapper = new ContentCachingResponseWrapper(response); + } catch (IOException ex) { + log.error("IO Error in init", ex); + fail("SQL Error in init: " + ex.getMessage()); + } + } + + /** + * This method will be run after every test as per @After. It will + * clean resources initialized by the @Before methods. + *

    + * Other methods can be annotated with @After here or in subclasses + * but no execution order is guaranteed + */ + @After + public void destroy() { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * Test if Range header is supported and gives back the right range + * + * @throws Exception + */ + @Test + public void testRangeHeader() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + when(request.getHeader(eq("If-Range"))).thenReturn("not_file_to_serve.txt"); + when(request.getHeader(eq("Range"))).thenReturn("bytes=1-3"); + + multipartFileSender.serveResource(); + + String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8); + + assertEquals("123", content); + } + + /** + * Test if we can just request the full file without ranges + * + * @throws Exception + */ + @Test + public void testFullFileReturn() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + multipartFileSender.serveResource(); + + String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8); + + assertEquals("0123456789", content); + assertEquals(checksum, responseWrapper.getHeader("ETag")); + } + + /** + * Test for support of Open ranges + * + * @throws Exception + */ + @Test + public void testOpenRange() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + when(request.getHeader(eq("Range"))).thenReturn("bytes=5-"); + + multipartFileSender.serveResource(); + + String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8); + + assertEquals("56789", content); + } + + /** + * Test support for multiple ranges + * + * @throws Exception + */ + @Test + public void testMultipleRanges() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + when(request.getHeader(eq("Range"))).thenReturn("bytes=1-2,3-4,5-9"); + + multipartFileSender.serveResource(); + + String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8); + + assertEquals("--MULTIPART_BYTERANGES" + + "Content-Type: text/plain" + + "Content-Range: bytes 1-2/10" + + "12" + + "--MULTIPART_BYTERANGES" + + "Content-Type: text/plain" + + "Content-Range: bytes 3-4/10" + + "34" + + "--MULTIPART_BYTERANGES" + + "Content-Type: text/plain" + + "Content-Range: bytes 5-9/10" + + "56789" + + "--MULTIPART_BYTERANGES--".replace("\n", "").replace("\r", "") + , content.replace("\n", "").replace("\r", "") + ); + + } + + /** + * Test with a unvalid Range header, should return status 416 + * + * @throws Exception + */ + @Test + public void testInvalidRange() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + when(request.getHeader(eq("Range"))).thenReturn("bytes=invalid"); + + multipartFileSender.serveResource(); + + assertEquals(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, responseWrapper.getStatusCode()); + } + + /** + * Test if the ETAG is in the response header + * + * @throws Exception + */ + @Test + public void testEtagInResponse() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + + when(request.getHeader(eq("Range"))).thenReturn("bytes=1-3"); + + multipartFileSender.serveResource(); + + String etag = responseWrapper.getHeader("Etag"); + + assertEquals(checksum, etag); + } + + //Check that a head request doesn't return any body, but returns the headers + @Test + public void testHeadRequest() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + + when(request.getMethod()).thenReturn("HEAD"); + + multipartFileSender.serveResource(); + + String content = new String(responseWrapper.getContentAsByteArray(), CharEncoding.UTF_8); + + assertEquals("bytes", responseWrapper.getHeader("Accept-Ranges")); + assertEquals(checksum, responseWrapper.getHeader("ETag")); + assertEquals("", content); + assertEquals(200, responseWrapper.getStatusCode()); + + } + + /** + * If ETAG is equal to that of the requested Resource then this should return 304 + * + * @throws Exception + */ + @Test + public void testIfNoneMatchFail() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + when(request.getHeader(eq("If-None-Match"))).thenReturn(checksum); + + multipartFileSender.isValid(); + + assertEquals(HttpServletResponse.SC_NOT_MODIFIED, responseWrapper.getStatusCode()); + } + + /** + * Happy path of If-None-Match header + * + * @throws Exception + */ + @Test + public void testIfNoneMatchPass() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withFileName(fileName) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + + when(request.getHeader(eq("If-None-Match"))) + .thenReturn("pretendthisisarandomchecksumnotequaltotherequestedbitstream"); + + multipartFileSender.isValid(); + multipartFileSender.serveResource(); + + assertEquals(HttpServletResponse.SC_OK, responseWrapper.getStatusCode()); + } + + /** + * If the bitstream has no filename this should throw an internal server error + * + * @throws Exception + */ + @Test + public void testNoFileName() throws Exception { + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .with(responseWrapper) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length); + + + multipartFileSender.isValid(); + + + assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, responseWrapper.getStatusCode()); + } + + /** + * Test if the Modified Since precondition works, should return 304 if it hasn't been modified + * + * @throws Exception + */ + @Test + public void testIfModifiedSinceNotModifiedSince() throws Exception { + Long time = new Date().getTime(); + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .withFileName(fileName) + .with(responseWrapper) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length) + .withLastModified(time); + + when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(time + 100000); + when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L); + + multipartFileSender.isValid(); + + assertEquals(HttpServletResponse.SC_NOT_MODIFIED, responseWrapper.getStatusCode()); + + + } + + /** + * Happy path for modified since + * + * @throws Exception + */ + @Test + public void testIfModifiedSinceModifiedSince() throws Exception { + Long time = new Date().getTime(); + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .withFileName(fileName) + .with(responseWrapper) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length) + .withLastModified(time); + + when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(time - 100000); + when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L); + + multipartFileSender.isValid(); + multipartFileSender.serveResource(); + + assertEquals(HttpServletResponse.SC_OK, responseWrapper.getStatusCode()); + + } + + /** + * If the If-Match doesn't match the ETAG then return 416 Status code + * + * @throws Exception + */ + @Test + public void testIfMatchNoMatch() throws Exception { + Long time = new Date().getTime(); + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .withFileName(fileName) + .with(responseWrapper) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length) + .withLastModified(time); + + when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L); + when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L); + when(request.getHeader(eq("If-Match"))).thenReturn("None-Matching-ETAG"); + + multipartFileSender.isValid(); + + assertEquals(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, responseWrapper.getStatusCode()); + } + + /** + * If matches then just return resource + * + * @throws Exception + */ + @Test + public void testIfMatchMatch() throws Exception { + Long time = new Date().getTime(); + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .withFileName(fileName) + .with(responseWrapper) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length) + .withLastModified(time); + + when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L); + when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L); + when(request.getHeader(eq("If-Match"))).thenReturn(checksum); + + multipartFileSender.isValid(); + + assertEquals(HttpServletResponse.SC_OK, responseWrapper.getStatusCode()); + } + + /** + * If not modified since given date then return resource + * + * @throws Exception + */ + @Test + public void testIfUnmodifiedSinceNotModifiedSince() throws Exception { + Long time = new Date().getTime(); + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .withFileName(fileName) + .with(responseWrapper) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length) + .withLastModified(time); + + when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(time + 100000); + when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L); + + multipartFileSender.isValid(); + + assertEquals(HttpServletResponse.SC_OK, responseWrapper.getStatusCode()); + + } + + /** + * If modified since given date then return 412 + * + * @throws Exception + */ + @Test + public void testIfUnmodifiedSinceModifiedSince() throws Exception { + Long time = new Date().getTime(); + MultipartFileSender multipartFileSender = MultipartFileSender + .fromInputStream(is) + .with(requestWrapper) + .withFileName(fileName) + .with(responseWrapper) + .withChecksum(checksum) + .withMimetype(mimeType) + .withLength(length) + .withLastModified(time); + + when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(time - 100000); + when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L); + + multipartFileSender.isValid(); + + assertEquals(HttpServletResponse.SC_PRECONDITION_FAILED, responseWrapper.getStatusCode()); + + } + + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/discovery/MockSolrServiceImpl.java b/dspace-spring-rest/src/test/java/org/dspace/discovery/MockSolrServiceImpl.java new file mode 100644 index 0000000000..37cf6aeb5c --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/discovery/MockSolrServiceImpl.java @@ -0,0 +1,31 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.discovery; + +import org.dspace.solr.MockSolrServer; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Service; + +/** + * Mock SOLR service for the Search Core + */ +@Service +public class MockSolrServiceImpl extends SolrServiceImpl implements InitializingBean, DisposableBean { + + private MockSolrServer mockSolrServer; + + public void afterPropertiesSet() throws Exception { + mockSolrServer = new MockSolrServer("search"); + solr = mockSolrServer.getSolrServer(); + } + + public void destroy() throws Exception { + mockSolrServer.destroy(); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/identifier/MockDOIConnector.java b/dspace-spring-rest/src/test/java/org/dspace/identifier/MockDOIConnector.java new file mode 100644 index 0000000000..73952c4af1 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/identifier/MockDOIConnector.java @@ -0,0 +1,124 @@ +/** + * 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.identifier; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import mockit.Mock; +import mockit.MockUp; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; +import org.dspace.identifier.doi.DOIConnector; +import org.dspace.identifier.doi.DOIIdentifierException; + +/** + * @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de) + */ +public class MockDOIConnector + extends MockUp + implements DOIConnector { + + public Map reserved; + public Map registered; + + public MockDOIConnector() { + reserved = new HashMap(); + registered = new HashMap(); + } + + public void reset() { + reserved.clear(); + registered.clear(); + } + + @Override + @Mock + public boolean isDOIReserved(Context context, String doi) + throws DOIIdentifierException { + return reserved.containsKey(doi); + } + + @Override + @Mock + public boolean isDOIRegistered(Context context, String doi) + throws DOIIdentifierException { + return registered.containsKey(doi); + } + + @Override + @Mock + public void deleteDOI(Context context, String doi) + throws DOIIdentifierException { + if (reserved.remove(doi) == null) { + throw new DOIIdentifierException("Trying to delete a DOI that was " + + "never reserved!", DOIIdentifierException.DOI_DOES_NOT_EXIST); + } + registered.remove(doi); + } + + @Override + @Mock + public void reserveDOI(Context context, DSpaceObject dso, String doi) + throws DOIIdentifierException { + UUID itemId = reserved.get(doi); + if (null != itemId) { + if (dso.getID().equals(itemId)) { + return; + } else { + throw new DOIIdentifierException("Trying to reserve a DOI that " + + "is reserved for another object.", + DOIIdentifierException.MISMATCH); + } + } + reserved.put(doi, dso.getID()); + } + + @Override + @Mock + public void registerDOI(Context context, DSpaceObject dso, String doi) + throws DOIIdentifierException { + if (!reserved.containsKey(doi)) { + throw new DOIIdentifierException("Trying to register an unreserverd " + + "DOI.", DOIIdentifierException.RESERVE_FIRST); + } + + if (!reserved.get(doi).equals(dso.getID())) { + throw new DOIIdentifierException("Trying to register a DOI that is" + + " reserved for another item.", DOIIdentifierException.MISMATCH); + } + + if (registered.containsKey(doi)) { + if (registered.get(doi).equals(dso.getID())) { + return; + } else { + throw new DOIIdentifierException("Trying to register a DOI that " + + "is registered for another item.", + DOIIdentifierException.MISMATCH); + } + } + + registered.put(doi, dso.getID()); + } + + @Override + @Mock + public void updateMetadata(Context context, DSpaceObject dso, String doi) + throws DOIIdentifierException { + if (!reserved.containsKey(doi)) { + throw new DOIIdentifierException("Trying to update a DOI that is not " + + "registered!", DOIIdentifierException.DOI_DOES_NOT_EXIST); + } + if (!reserved.get(doi).equals(dso.getID())) { + throw new DOIIdentifierException("Trying to update metadata of an " + + "unreserved DOI.", DOIIdentifierException.DOI_DOES_NOT_EXIST); + } + } + +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/solr/MockSolrServer.java b/dspace-spring-rest/src/test/java/org/dspace/solr/MockSolrServer.java new file mode 100644 index 0000000000..e5e62e25df --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/solr/MockSolrServer.java @@ -0,0 +1,109 @@ +/** + * 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.solr; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.log4j.Logger; +import org.apache.solr.client.solrj.SolrServer; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer; +import org.apache.solr.core.CoreContainer; +import org.dspace.app.rest.test.AbstractDSpaceIntegrationTest; + +/** + * Abstract class to mock a service that uses SOLR + */ +public class MockSolrServer { + + private static final Logger log = Logger.getLogger(MockSolrServer.class); + private static final ConcurrentMap loadedCores = new ConcurrentHashMap<>(); + private static final ConcurrentMap usersPerCore = new ConcurrentHashMap<>(); + private static CoreContainer container = null; + + private String coreName; + + private SolrServer solrServer = null; + + + public MockSolrServer(final String coreName) throws Exception { + this.coreName = coreName; + initSolrServer(); + } + + public SolrServer getSolrServer() { + return solrServer; + } + + protected void initSolrServer() throws Exception { + solrServer = loadedCores.get(coreName); + if (solrServer == null) { + solrServer = initSolrServerForCore(coreName); + } + + usersPerCore.putIfAbsent(coreName, new AtomicLong(0)); + usersPerCore.get(coreName).incrementAndGet(); + } + + private static synchronized SolrServer initSolrServerForCore(final String coreName) { + SolrServer server = loadedCores.get(coreName); + if (server == null) { + initSolrContainer(); + + server = new EmbeddedSolrServer(container, coreName); + + //Start with an empty index + try { + server.deleteByQuery("*:*"); + server.commit(); + } catch (SolrServerException | IOException e) { + e.printStackTrace(); + } + + loadedCores.put(coreName, server); + log.info("SOLR Server for core " + coreName + " initialized"); + } + return server; + } + + public void destroy() throws Exception { + if (solrServer != null) { + long remainingUsers = usersPerCore.get(coreName).decrementAndGet(); + if (remainingUsers <= 0) { + solrServer.shutdown(); + usersPerCore.remove(coreName); + loadedCores.remove(coreName); + log.info("SOLR Server for core " + coreName + " destroyed"); + } + + if (usersPerCore.isEmpty()) { + destroyContainer(); + } + } + } + + private static synchronized void initSolrContainer() { + if (container == null) { + String solrDir = AbstractDSpaceIntegrationTest.getDspaceDir() + File.separator + "solr"; + log.info("Initializing SOLR CoreContainer with directory " + solrDir); + container = new CoreContainer(solrDir); + container.load(); + log.info("SOLR CoreContainer initialized"); + } + } + + private static synchronized void destroyContainer() { + container = null; + log.info("SOLR CoreContainer destroyed"); + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/statistics/FakeDatabaseReader.java b/dspace-spring-rest/src/test/java/org/dspace/statistics/FakeDatabaseReader.java new file mode 100644 index 0000000000..f40a67f54c --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/statistics/FakeDatabaseReader.java @@ -0,0 +1,118 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.statistics; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.maxmind.geoip2.DatabaseReader; +import com.maxmind.geoip2.model.CityResponse; +import com.maxmind.geoip2.record.City; +import com.maxmind.geoip2.record.Continent; +import com.maxmind.geoip2.record.Country; +import com.maxmind.geoip2.record.Location; +import com.maxmind.geoip2.record.MaxMind; +import com.maxmind.geoip2.record.Postal; +import com.maxmind.geoip2.record.RepresentedCountry; +import com.maxmind.geoip2.record.Subdivision; +import com.maxmind.geoip2.record.Traits; +import mockit.Deencapsulation; +import mockit.Mock; +import mockit.MockUp; + +/** + * Mock service to mock the location Lookup Service used by the SOLR statistics + * logger. + */ +public class FakeDatabaseReader + extends MockUp { + + FakeDatabaseReader() { + } + + public FakeDatabaseReader(Object object) { + } + + public FakeDatabaseReader $init(Builder builder) { + return this; + } + + /* + @Override + public Location getLocation(String str) { + Location location = new Location(); + location.countryCode = "US"; + location.countryName = "United States"; + location.region = "NY"; + location.city = "New York"; + location.postalCode = "10036"; + location.latitude = 40.760498F; + location.longitude = -73.9933F; + location.dma_code = 501; + location.area_code = 212; + location.metro_code = 501; + + return location; + } + */ + + @Mock + public CityResponse city(InetAddress address) { + List names = new ArrayList<>(1); + + names.add("New York"); + City city = new City(names, 1, 1, new HashMap()); + + Continent continent = new Continent(); + + names.clear(); + names.add("United States"); + Country country = new Country(names, 1, 1, "US", new HashMap()); + + Location location = new Location(1, 1, 40.760498D, -73.9933D, 501, 1, "EST"); + + MaxMind maxmind = new MaxMind(); + + Postal postal = new Postal("10036", 1); + + RepresentedCountry representedCountry = new RepresentedCountry(); + + ArrayList subdivisions = new ArrayList<>(0); + + Traits traits = new Traits(); + + CityResponse response = new CityResponse(city, continent, country, + location, maxmind, postal, country, representedCountry, + subdivisions, traits); + return response; + } + + public static class Builder + extends MockUp { + + public Builder() {} + + /** + * Fake constructor. + * @param file ignored. + */ + @Mock + public void $init(File file) { + } + + @Mock + public DatabaseReader build() + throws IOException { + return Deencapsulation.newUninitializedInstance(DatabaseReader.class); + } + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/statistics/MockSolrLoggerServiceImpl.java b/dspace-spring-rest/src/test/java/org/dspace/statistics/MockSolrLoggerServiceImpl.java new file mode 100644 index 0000000000..543146ff36 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/statistics/MockSolrLoggerServiceImpl.java @@ -0,0 +1,53 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.statistics; + +import java.io.File; + +import com.maxmind.geoip2.DatabaseReader; +import org.dspace.services.ConfigurationService; +import org.dspace.solr.MockSolrServer; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Mock service that uses an embedded SOLR server for the statistics core. + */ +public class MockSolrLoggerServiceImpl + extends SolrLoggerServiceImpl + implements InitializingBean, DisposableBean { + + private MockSolrServer mockSolrServer; + + @Autowired(required = true) + private ConfigurationService configurationService; + + public MockSolrLoggerServiceImpl() { + } + + @Override + public void afterPropertiesSet() throws Exception { + mockSolrServer = new MockSolrServer("statistics"); + solr = mockSolrServer.getSolrServer(); + + new FakeDatabaseReader(); // Activate fake + new FakeDatabaseReader.Builder(); // Activate fake + String locationDbPath = configurationService.getProperty("usage-statistics.dbfile"); + File locationDb = new File(locationDbPath); + locationDb.createNewFile(); + locationService = new DatabaseReader.Builder(locationDb).build(); + useProxies = configurationService.getBooleanProperty("useProxies"); + } + + @Override + public void destroy() throws Exception { + mockSolrServer.destroy(); + } + +} diff --git a/dspace-spring-rest/src/test/resources/META-INF/spring.factories b/dspace-spring-rest/src/test/resources/META-INF/spring.factories new file mode 100644 index 0000000000..2c1593d75d --- /dev/null +++ b/dspace-spring-rest/src/test/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.test.context.ContextCustomizerFactory= \ + org.dspace.app.rest.test.DSpaceKernelContextCustomizerFactory diff --git a/dspace-spring-rest/src/test/resources/log4j.properties b/dspace-spring-rest/src/test/resources/log4j.properties new file mode 100644 index 0000000000..2500bc47ea --- /dev/null +++ b/dspace-spring-rest/src/test/resources/log4j.properties @@ -0,0 +1,58 @@ +# +# The contents of this file are subject to the license and copyright +# detailed in the LICENSE and NOTICE files at the root of the source +# tree and available online at +# +# http://www.dspace.org/license/ +# +########################################################################### +# +# log4j.properties +# +# +########################################################################### + +# This is a copy of the log4j configuration file for DSpace, to avoid +# getting errors when running tests. + +# Set root category priority to INFO and its only appender to A1. +log4j.rootCategory=INFO, A1 + +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%d %-5p %c @ %m%n + +########################################################################### +# Other settings +########################################################################### + +# Block passwords from being exposed in Axis logs. +# (DEBUG exposes passwords in Basic Auth) +log4j.logger.org.apache.axis.handlers.http.HTTPAuthHandler=INFO + +# Block services logging except on exceptions +log4j.logger.org.dspace.kernel=ERROR +log4j.logger.org.dspace.services=ERROR +log4j.logger.org.dspace.servicemanager=ERROR +log4j.logger.org.dspace.providers=ERROR +log4j.logger.org.dspace.utils=ERROR + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n +# +# Root logger option +log4j.rootLogger=INFO, stdout + +# Hibernate logging options (INFO only shows startup messages) +log4j.logger.org.hibernate=INFO + +# For detailed Hibernate logging in Unit Tests, you can enable the following +# setting which logs all JDBC bind parameter runtime arguments. +# This will drastically increase the size of Unit Test logs though. +#log4j.logger.org.hibernate.SQL=DEBUG, A1 +#log4j.logger.org.hibernate.type=TRACE, A1 diff --git a/dspace-spring-rest/src/test/resources/logback.xml b/dspace-spring-rest/src/test/resources/logback.xml new file mode 100644 index 0000000000..8455a00b53 --- /dev/null +++ b/dspace-spring-rest/src/test/resources/logback.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dspace-spring-rest/src/test/resources/org/dspace/app/rest/bibtex-test.bib b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/bibtex-test.bib new file mode 100644 index 0000000000..4d197ff90f --- /dev/null +++ b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/bibtex-test.bib @@ -0,0 +1,14 @@ +@misc{ Nobody01, + author = "Nobody Jr", + title = "My Article", + year = "2006" } + +@misc{ Nobody02, + author = "Nobody Jr", + title = "My Article 2", + year = "2006" } + +@misc{ Nobody03, + author = "Nobody Jr", + title = "My Article 3", + year = "2018" } diff --git a/dspace-spring-rest/src/test/resources/org/dspace/app/rest/simple-article.pdf b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/simple-article.pdf new file mode 100644 index 0000000000..abefe17f93 Binary files /dev/null and b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/simple-article.pdf differ diff --git a/dspace-spring-rest/src/test/resources/test-config.properties b/dspace-spring-rest/src/test/resources/test-config.properties new file mode 100644 index 0000000000..273d93c968 --- /dev/null +++ b/dspace-spring-rest/src/test/resources/test-config.properties @@ -0,0 +1,13 @@ +# +# 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/ +# +# Defines the test folder where the unit tests will be run +test.folder = ./target/testing/ +test.folder.assetstore = ./target/testing/dspace/assetstore + +#Path for a test file to create bitstreams +test.bitstream = ./target/testing/dspace/assetstore/ConstitutionofIreland.pdf diff --git a/dspace-sword/example/mets.xml b/dspace-sword/example/mets.xml index 7c1c934ea1..bc83ac72f8 100644 --- a/dspace-sword/example/mets.xml +++ b/dspace-sword/example/mets.xml @@ -1,164 +1,164 @@ + PROFILE="DSpace METS SIP Profile 1.0" xmlns="http://www.loc.gov/METS/" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.loc.gov/METS/ http://www.loc.gov/standards/mets/mets.xsd"> - - - Richard Jones - - - - - + + + Richard Jones + + - - + + - - - - - Attempts to detect retrotransposition - and de novo deletion of Alus and other - dispersed repeats at specific loci in - the human genome - - - - - Dispersed repeat elements contribute to - genome instability by de novo insertion - and unequal recombination between - repeats. To study the dynamics of these - processes, we have developed single DNA - molecule approaches to detect de novo - insertions at a single locus and - Alu-mediated deletions at two different - loci in human genomic DNA. Validation - experiments showed these approaches - could detect insertions and deletions at - frequencies below 10(-6) per cell. - However, bulk analysis of germline - (sperm) and somatic DNA showed no - evidence for genuine mutant molecules, - placing an upper limit of insertion and - deletion rates of 2 x 10(-7) and 3 x - 10(-7), respectively, in the individuals - tested. Such re-arrangements at these - loci therefore occur at a rate lower - than that detectable by the most - sensitive methods currently available. - - - - - Hollies, C.R. - - - - - Monckton, D.G. - - - - - Jeffreys, A.J. - - - - - http://www.myu.ac.uk/some/identifier - - - - + + - - - - en - - - - - 2001-02 - - - - - - Nature Publishing Group - - - - - - - + + + + + Attempts to detect retrotransposition + and de novo deletion of Alus and other + dispersed repeats at specific loci in + the human genome + + + + + Dispersed repeat elements contribute to + genome instability by de novo insertion + and unequal recombination between + repeats. To study the dynamics of these + processes, we have developed single DNA + molecule approaches to detect de novo + insertions at a single locus and + Alu-mediated deletions at two different + loci in human genomic DNA. Validation + experiments showed these approaches + could detect insertions and deletions at + frequencies below 10(-6) per cell. + However, bulk analysis of germline + (sperm) and somatic DNA showed no + evidence for genuine mutant molecules, + placing an upper limit of insertion and + deletion rates of 2 x 10(-7) and 3 x + 10(-7), respectively, in the individuals + tested. Such re-arrangements at these + loci therefore occur at a rate lower + than that detectable by the most + sensitive methods currently available. + + + + + Hollies, C.R. + + + + + Monckton, D.G. + + + + + Jeffreys, A.J. + + + + + http://www.myu.ac.uk/some/identifier + + + + - - - - - - - - - - - - - - - -

    -
    - -
    -
    - -
    -
    - -
    -
    - + + + + en + + + + + 2001-02 + + + + + + Nature Publishing Group + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 78c126c7d3..d93519952d 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -1,23 +1,24 @@ - - 4.0.0 - org.dspace - dspace-sword - war - DSpace SWORD - - DSpace SWORD Deposit Service Provider Web Application - + + 4.0.0 + org.dspace + dspace-sword + war + DSpace SWORD + + DSpace SWORD Deposit Service Provider Web Application + - - - org.dspace - dspace-parent - 7.0-SNAPSHOT - .. - + + + org.dspace + dspace-parent + 7.0-SNAPSHOT + .. + @@ -111,7 +112,7 @@ javax.servlet - servlet-api + javax.servlet-api provided diff --git a/dspace-sword/src/main/java/org/dspace/sword/ATOMCollectionGenerator.java b/dspace-sword/src/main/java/org/dspace/sword/ATOMCollectionGenerator.java index bb5d555a93..8310af7be6 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/ATOMCollectionGenerator.java +++ b/dspace-sword/src/main/java/org/dspace/sword/ATOMCollectionGenerator.java @@ -7,8 +7,8 @@ */ package org.dspace.sword; -import org.purl.sword.base.Collection; import org.dspace.content.DSpaceObject; +import org.purl.sword.base.Collection; /** * @author Richard Jones @@ -16,31 +16,28 @@ import org.dspace.content.DSpaceObject; * Define an abstract interface for classes wishing to generate ATOM Collections * for SWORD service documents */ -public abstract class ATOMCollectionGenerator -{ - /** the sword service definition */ +public abstract class ATOMCollectionGenerator { + /** + * the sword service definition + */ protected SWORDService swordService; /** * Create a new ATOM collection generator using the given SWORD service. * - * @param service - * SWORD service + * @param service SWORD service */ - public ATOMCollectionGenerator(SWORDService service) - { + public ATOMCollectionGenerator(SWORDService service) { this.swordService = service; } /** * Build the ATOM Collection which represents the given DSpace Object. * - * @param dso - * target DSpace object + * @param dso target DSpace object * @return ATOM collection representing the DSpace object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public abstract Collection buildCollection(DSpaceObject dso) - throws DSpaceSWORDException; + throws DSpaceSWORDException; } diff --git a/dspace-sword/src/main/java/org/dspace/sword/BitstreamEntryGenerator.java b/dspace-sword/src/main/java/org/dspace/sword/BitstreamEntryGenerator.java index c65800522d..3ce38aec47 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/BitstreamEntryGenerator.java +++ b/dspace-sword/src/main/java/org/dspace/sword/BitstreamEntryGenerator.java @@ -7,7 +7,14 @@ */ package org.dspace.sword; -import org.dspace.content.*; +import java.sql.SQLException; +import java.util.List; + +import org.apache.log4j.Logger; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.Item; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.purl.sword.atom.Content; @@ -16,30 +23,25 @@ import org.purl.sword.atom.InvalidMediaTypeException; import org.purl.sword.atom.Link; import org.purl.sword.atom.Rights; import org.purl.sword.atom.Title; -import org.apache.log4j.Logger; - -import java.sql.SQLException; -import java.util.List; /** * @author Richard Jones * * Class to generate ATOM Entry documents for DSpace Bitstreams */ -public class BitstreamEntryGenerator extends DSpaceATOMEntry -{ - /** logger */ +public class BitstreamEntryGenerator extends DSpaceATOMEntry { + /** + * logger + */ private static Logger log = Logger.getLogger(BitstreamEntryGenerator.class); /** * Create a new ATOM Entry generator which can provide a SWORD Entry for * a bitstream * - * @param service - * SWORD service + * @param service SWORD service */ - protected BitstreamEntryGenerator(SWORDService service) - { + protected BitstreamEntryGenerator(SWORDService service) { super(service); log.debug("Create new instance of BitstreamEntryGenerator"); } @@ -47,45 +49,35 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry /** * Add all the subject classifications from the bibliographic * metadata. - * */ - protected void addCategories() - { + protected void addCategories() { // do nothing } /** * Set the content type that DSpace received. - * */ protected void addContentElement() - throws DSpaceSWORDException - { - try - { + throws DSpaceSWORDException { + try { // get the things we need out of the service SWORDUrlManager urlManager = swordService.getUrlManager(); // if this is a deposit which is no op we can't do anything here - if (this.deposit != null && this.deposit.isNoOp()) - { + if (this.deposit != null && this.deposit.isNoOp()) { return; } String bsurl = urlManager.getBitstreamUrl(this.bitstream); BitstreamFormat bf = null; - try - { + try { bf = this.bitstream.getFormat(swordService.getContext()); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Exception caught: ", e); throw new DSpaceSWORDException(e); } String format = "application/octet-stream"; - if (bf != null) - { + if (bf != null) { format = bf.getMIMEType(); } @@ -95,9 +87,7 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry entry.setContent(con); log.debug("Adding content element with url=" + bsurl); - } - catch (InvalidMediaTypeException e) - { + } catch (InvalidMediaTypeException e) { log.error("caught and swallowed exception: ", e); // do nothing; we'll live without the content type declaration! } @@ -111,11 +101,9 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry * a real URL). */ protected void addIdentifier() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // if this is a deposit which is no op we can't do anything here - if (this.deposit != null && this.deposit.isNoOp()) - { + if (this.deposit != null && this.deposit.isNoOp()) { // just use the dspace url as the // property String cfg = ConfigurationManager.getProperty("dspace.url"); @@ -139,14 +127,11 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry /** * Add links associated with this item. - * */ protected void addLinks() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // if this is a deposit which is no op we can't do anything here - if (this.deposit != null && this.deposit.isNoOp()) - { + if (this.deposit != null && this.deposit.isNoOp()) { return; } @@ -155,18 +140,14 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry String bsurl = urlManager.getBitstreamUrl(this.bitstream); BitstreamFormat bf; - try - { + try { bf = this.bitstream.getFormat(swordService.getContext()); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Exception caught: ", e); throw new DSpaceSWORDException(e); } String format = "application/octet-stream"; - if (bf != null) - { + if (bf != null) { format = bf.getMIMEType(); } @@ -181,35 +162,28 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry /** * Add the date of publication from the bibliographic metadata - * */ - protected void addPublishDate() - { + protected void addPublishDate() { // do nothing } /** * Add rights information. This attaches an href to the URL * of the item's licence file - * */ protected void addRights() - throws DSpaceSWORDException - { - try - { + throws DSpaceSWORDException { + try { // work our way up to the item List bundle2bitstreams = this.bitstream - .getBundles(); - if (bundle2bitstreams.isEmpty()) - { + .getBundles(); + if (bundle2bitstreams.isEmpty()) { log.error("Found orphaned bitstream: " + bitstream.getID()); throw new DSpaceSWORDException("Orphaned bitstream discovered"); } Bundle bundle = bundle2bitstreams.get(0); List items = bundle.getItems(); - if (items.isEmpty()) - { + if (items.isEmpty()) { log.error("Found orphaned bundle: " + bundle.getID()); throw new DSpaceSWORDException("Orphaned bundle discovered"); } @@ -219,16 +193,13 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry SWORDUrlManager urlManager = swordService.getUrlManager(); StringBuilder rightsString = new StringBuilder(); List lbundles = item.getBundles(); - for (Bundle lbundle : lbundles) - { - if (!Constants.LICENSE_BUNDLE_NAME.equals(lbundle.getName())) - { + for (Bundle lbundle : lbundles) { + if (!Constants.LICENSE_BUNDLE_NAME.equals(lbundle.getName())) { // skip non-license bundles continue; } List bss = lbundle.getBitstreams(); - for (Bitstream bs : bss) - { + for (Bitstream bs : bss) { String url = urlManager.getBitstreamUrl(bs); rightsString.append(url).append(" "); } @@ -239,9 +210,7 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry rights.setType(ContentType.TEXT); entry.setRights(rights); log.debug("Added rights entry to entity"); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -249,19 +218,15 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry /** * Add the summary/abstract from the bibliographic metadata - * */ - protected void addSummary() - { + protected void addSummary() { // do nothing } /** * Add the title from the bibliographic metadata - * */ - protected void addTitle() - { + protected void addTitle() { Title title = new Title(); title.setContent(this.bitstream.getName()); title.setType(ContentType.TEXT); @@ -271,10 +236,8 @@ public class BitstreamEntryGenerator extends DSpaceATOMEntry /** * Add the date that this item was last updated - * */ - protected void addLastUpdatedDate() - { + protected void addLastUpdatedDate() { // do nothing } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/CollectionCollectionGenerator.java b/dspace-sword/src/main/java/org/dspace/sword/CollectionCollectionGenerator.java index 4a2bfc91eb..d2cf664d5c 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/CollectionCollectionGenerator.java +++ b/dspace-sword/src/main/java/org/dspace/sword/CollectionCollectionGenerator.java @@ -7,24 +7,24 @@ */ package org.dspace.sword; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.dspace.content.DSpaceObject; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; -import org.purl.sword.base.Collection; -import org.dspace.content.DSpaceObject; import org.dspace.core.ConfigurationManager; -import org.apache.log4j.Logger; - -import java.util.Map; -import java.util.List; +import org.purl.sword.base.Collection; /** * Class to generate ATOM Collection Elements which represent * DSpace Collections - * */ -public class CollectionCollectionGenerator extends ATOMCollectionGenerator -{ - /** logger */ +public class CollectionCollectionGenerator extends ATOMCollectionGenerator { + /** + * logger + */ private static Logger log = Logger.getLogger(CollectionCollectionGenerator.class); @@ -34,11 +34,9 @@ public class CollectionCollectionGenerator extends ATOMCollectionGenerator /** * Construct an object taking the SWORD service instance an argument * - * @param service - * SWORD service implementation + * @param service SWORD service implementation */ - public CollectionCollectionGenerator(SWORDService service) - { + public CollectionCollectionGenerator(SWORDService service) { super(service); log.debug("Create new instance of CollectionCollectionGenerator"); } @@ -47,16 +45,12 @@ public class CollectionCollectionGenerator extends ATOMCollectionGenerator * Build the collection for the given DSpaceObject. In this implementation, * if the object is not a DSpace Collection, it will throw an exception. * - * @param dso - * target DSpace object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @param dso target DSpace object + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public Collection buildCollection(DSpaceObject dso) - throws DSpaceSWORDException - { - if (!(dso instanceof org.dspace.content.Collection)) - { + throws DSpaceSWORDException { + if (!(dso instanceof org.dspace.content.Collection)) { log.error( "buildCollection passed argument which is not of type Collection"); throw new DSpaceSWORDException( @@ -85,7 +79,7 @@ public class CollectionCollectionGenerator extends ATOMCollectionGenerator // abstract is the short description of the collection String dcAbstract = collectionService - .getMetadata(col, "short_description"); + .getMetadata(col, "short_description"); // we just do support mediation boolean mediation = swordConfig.isMediated(); @@ -94,14 +88,12 @@ public class CollectionCollectionGenerator extends ATOMCollectionGenerator scol.setLocation(location); // add the title if it exists - if (title != null && !"".equals(title)) - { + if (title != null && !"".equals(title)) { scol.setTitle(title); } // add the collection policy if it exists - if (collectionPolicy != null && !"".equals(collectionPolicy)) - { + if (collectionPolicy != null && !"".equals(collectionPolicy)) { scol.setCollectionPolicy(collectionPolicy); } @@ -110,33 +102,29 @@ public class CollectionCollectionGenerator extends ATOMCollectionGenerator // scol.setTreatment(treatment); // add the abstract if it exists - if (dcAbstract != null && !"".equals(dcAbstract)) - { + if (dcAbstract != null && !"".equals(dcAbstract)) { scol.setAbstract(dcAbstract); } scol.setMediation(mediation); List accepts = swordService.getSwordConfig() - .getCollectionAccepts(); - for (String accept : accepts) - { + .getCollectionAccepts(); + for (String accept : accepts) { scol.addAccepts(accept); } // add the accept packaging values Map aps = swordConfig.getAcceptPackaging(col); - for (Map.Entry ap : aps.entrySet()) - { + for (Map.Entry ap : aps.entrySet()) { scol.addAcceptPackaging(ap.getKey(), ap.getValue()); } // should we offer the items in the collection up as deposit // targets? boolean itemService = ConfigurationManager - .getBooleanProperty("sword-server", "expose-items"); - if (itemService) - { + .getBooleanProperty("sword-server", "expose-items"); + if (itemService) { String subService = urlManager.constructSubServiceUrl(col); scol.setService(subService); } diff --git a/dspace-sword/src/main/java/org/dspace/sword/CollectionDepositor.java b/dspace-sword/src/main/java/org/dspace/sword/CollectionDepositor.java index e08a0d1028..5082e96511 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/CollectionDepositor.java +++ b/dspace-sword/src/main/java/org/dspace/sword/CollectionDepositor.java @@ -7,6 +7,13 @@ */ package org.dspace.sword; +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; import org.dspace.content.Bundle; @@ -18,29 +25,21 @@ import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; import org.dspace.content.service.ItemService; -import org.dspace.core.Context; import org.dspace.core.ConfigurationManager; -import org.dspace.authorize.AuthorizeException; +import org.dspace.core.Context; import org.purl.sword.base.Deposit; - -import org.purl.sword.base.SWORDErrorException; import org.purl.sword.base.ErrorCodes; -import org.apache.log4j.Logger; - -import java.io.FileInputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; +import org.purl.sword.base.SWORDErrorException; /** * @author Richard Jones * * A depositor which can deposit content into a DSpace Collection - * */ -public class CollectionDepositor extends Depositor -{ - /** logger */ +public class CollectionDepositor extends Depositor { + /** + * logger + */ private static Logger log = Logger.getLogger(CollectionDepositor.class); protected ItemService itemService = @@ -65,23 +64,18 @@ public class CollectionDepositor extends Depositor * given DSpaceObject. If the DSpaceObject is not an instance of Collection * this constructor will throw an Exception * - * @param swordService - * SWORD service - * @param dso - * target DSpace object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @param swordService SWORD service + * @param dso target DSpace object + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public CollectionDepositor(SWORDService swordService, DSpaceObject dso) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { super(swordService, dso); - if (!(dso instanceof Collection)) - { + if (!(dso instanceof Collection)) { throw new DSpaceSWORDException( "You tried to initialise the collection depositor with something" + - "other than a collection object"); + "other than a collection object"); } this.collection = (Collection) dso; @@ -92,15 +86,12 @@ public class CollectionDepositor extends Depositor /** * Perform a deposit, using the supplied SWORD Deposit object. * - * @param deposit - * deposit request - * @throws SWORDErrorException on generic SWORD exception - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @param deposit deposit request + * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public DepositResult doDeposit(Deposit deposit) - throws SWORDErrorException, DSpaceSWORDException - { + throws SWORDErrorException, DSpaceSWORDException { // get the things out of the service that we need Context context = swordService.getContext(); SWORDConfiguration swordConfig = swordService.getSwordConfig(); @@ -111,28 +102,26 @@ public class CollectionDepositor extends Depositor // // determine if this is an acceptable file format if (!swordConfig - .isAcceptableContentType(context, deposit.getContentType(), - collection)) - { + .isAcceptableContentType(context, deposit.getContentType(), + collection)) { log.error("Unacceptable content type detected: " + - deposit.getContentType() + " for collection " + - collection.getID()); + deposit.getContentType() + " for collection " + + collection.getID()); throw new SWORDErrorException(ErrorCodes.ERROR_CONTENT, - "Unacceptable content type in deposit request: " + - deposit.getContentType()); + "Unacceptable content type in deposit request: " + + deposit.getContentType()); } // determine if this is an acceptable packaging type for the deposit // if not, we throw a 415 HTTP error (Unsupported Media Type, ERROR_CONTENT) if (!swordConfig.isSupportedMediaType( - deposit.getPackaging(), this.collection)) - { + deposit.getPackaging(), this.collection)) { log.error("Unacceptable packaging type detected: " + - deposit.getPackaging() + "for collection" + - collection.getID()); + deposit.getPackaging() + "for collection" + + collection.getID()); throw new SWORDErrorException(ErrorCodes.ERROR_CONTENT, - "Unacceptable packaging type in deposit request: " + - deposit.getPackaging()); + "Unacceptable packaging type in deposit request: " + + deposit.getPackaging()); } // Obtain the relevant ingester from the factory @@ -146,13 +135,11 @@ public class CollectionDepositor extends Depositor // if there's an item availalble, and we want to keep the original // then do that - try - { - if (swordConfig.isKeepOriginal()) - { + try { + if (swordConfig.isKeepOriginal()) { swordService.message( "DSpace will store an original copy of the deposit, " + - "as well as ingesting the item into the archive"); + "as well as ingesting the item into the archive"); // in order to be allowed to add the file back to the item, we need to ignore authorisations // for a moment @@ -160,24 +147,20 @@ public class CollectionDepositor extends Depositor String bundleName = ConfigurationManager.getProperty( "sword-server", "bundle.name"); - if (bundleName == null || "".equals(bundleName)) - { + if (bundleName == null || "".equals(bundleName)) { bundleName = "SWORD"; } Item item = result.getItem(); List bundles = item.getBundles(); Bundle swordBundle = null; - for (Bundle bundle : bundles) - { - if (bundleName.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (bundleName.equals(bundle.getName())) { // we found one swordBundle = bundle; break; } } - if (swordBundle == null) - { + if (swordBundle == null) { swordBundle = bundleService.create( context, item, bundleName); } @@ -186,16 +169,12 @@ public class CollectionDepositor extends Depositor Bitstream bitstream; FileInputStream fis = null; - try - { + try { fis = new FileInputStream(deposit.getFile()); bitstream = bitstreamService.create( context, swordBundle, fis); - } - finally - { - if (fis != null) - { + } finally { + if (fis != null) { fis.close(); } } @@ -205,8 +184,7 @@ public class CollectionDepositor extends Depositor BitstreamFormat bf = bitstreamFormatService.findByMIMEType( context, deposit.getContentType()); - if (bf != null) - { + if (bf != null) { bitstreamService.setFormat(context, bitstream, bf); } @@ -215,22 +193,18 @@ public class CollectionDepositor extends Depositor itemService.update(context, item); swordService.message("Original package stored as " + fn + - ", in item bundle " + swordBundle); + ", in item bundle " + swordBundle); // now reset the context ignore authorisation context.restoreAuthSystemState(); // set the media link for the created item result.setMediaLink(urlManager.getMediaLink(bitstream)); - } - else - { + } else { // set the vanilla media link, which doesn't resolve to anything result.setMediaLink(urlManager.getBaseMediaLinkUrl()); } - } - catch (SQLException | AuthorizeException | IOException e) - { + } catch (SQLException | AuthorizeException | IOException e) { log.error("caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -245,13 +219,10 @@ public class CollectionDepositor extends Depositor * end of such a deposit process in order to remove any temporary files and * to abort the database connection, so no changes are written. * - * @param result - * deposit result to undo - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @param result deposit result to undo + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ - public void undoDeposit(DepositResult result) throws DSpaceSWORDException - { + public void undoDeposit(DepositResult result) throws DSpaceSWORDException { SWORDContext sc = swordService.getSwordContext(); // abort the context, so no database changes are written diff --git a/dspace-sword/src/main/java/org/dspace/sword/CollectionLocation.java b/dspace-sword/src/main/java/org/dspace/sword/CollectionLocation.java index 5a36d4f6cc..d2ff871a72 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/CollectionLocation.java +++ b/dspace-sword/src/main/java/org/dspace/sword/CollectionLocation.java @@ -12,7 +12,6 @@ import java.net.URL; import java.sql.SQLException; import org.apache.log4j.Logger; - import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; import org.dspace.core.ConfigurationManager; @@ -26,30 +25,27 @@ import org.dspace.handle.service.HandleService; * generating SWORD Deposit URLs from Collections * * @author Richard Jones - * */ -public class CollectionLocation -{ - /** Log4j logger */ +public class CollectionLocation { + /** + * Log4j logger + */ public static final Logger log = Logger.getLogger(CollectionLocation.class); protected HandleService handleService = HandleServiceFactory.getInstance() - .getHandleService(); + .getHandleService(); /** * Obtain the deposit URL for the given collection. These URLs * should not be considered persistent, but will remain consistent * unless configuration changes are made to DSpace * - * @param collection - * collection to query + * @param collection collection to query * @return The Deposit URL - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getLocation(Collection collection) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { return this.getBaseUrl() + "/" + collection.getHandle(); } @@ -57,44 +53,35 @@ public class CollectionLocation * Obtain the collection which is represented by the given * URL * - * @param context the DSpace context - * @param location the URL to resolve to a collection + * @param context the DSpace context + * @param location the URL to resolve to a collection * @return The collection to which the url resolves - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public Collection getCollection(Context context, String location) - throws DSpaceSWORDException - { - try - { + throws DSpaceSWORDException { + try { String baseUrl = this.getBaseUrl(); - if (baseUrl.length() == location.length()) - { + if (baseUrl.length() == location.length()) { throw new DSpaceSWORDException("The deposit URL is incomplete"); } String handle = location.substring(baseUrl.length()); - if (handle.startsWith("/")) - { + if (handle.startsWith("/")) { handle = handle.substring(1); } - if ("".equals(handle)) - { + if ("".equals(handle)) { throw new DSpaceSWORDException("The deposit URL is incomplete"); } DSpaceObject dso = handleService.resolveToObject(context, handle); - if (!(dso instanceof Collection)) - { + if (!(dso instanceof Collection)) { throw new DSpaceSWORDException( "The deposit URL does not resolve to a valid collection"); } return (Collection) dso; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception:", e); throw new DSpaceSWORDException( "There was a problem resolving the collection", e); @@ -115,35 +102,29 @@ public class CollectionLocation * where dspace.baseUrl is also in the configuration file. * * @return the base URL for sword deposit - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ private String getBaseUrl() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { String depositUrl = ConfigurationManager.getProperty( "sword-server", "deposit.url"); - if (depositUrl == null || "".equals(depositUrl)) - { + if (depositUrl == null || "".equals(depositUrl)) { String dspaceUrl = ConfigurationManager - .getProperty("dspace.baseUrl"); - if (dspaceUrl == null || "".equals(dspaceUrl)) - { + .getProperty("dspace.baseUrl"); + if (dspaceUrl == null || "".equals(dspaceUrl)) { throw new DSpaceSWORDException( - "Unable to construct deposit urls, due to missing/invalid config in sword.deposit.url and/or dspace.baseUrl"); + "Unable to construct deposit urls, due to missing/invalid config in sword.deposit.url and/or " + + "dspace.baseUrl"); } - try - { + try { URL url = new URL(dspaceUrl); depositUrl = new URL(url.getProtocol(), url.getHost(), - url.getPort(), "/sword/deposit").toString(); - } - catch (MalformedURLException e) - { + url.getPort(), "/sword/deposit").toString(); + } catch (MalformedURLException e) { throw new DSpaceSWORDException( "Unable to construct deposit urls, due to invalid dspace.baseUrl " + - e.getMessage(), e); + e.getMessage(), e); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/CommunityCollectionGenerator.java b/dspace-sword/src/main/java/org/dspace/sword/CommunityCollectionGenerator.java index b34a6c381e..a2fba088f1 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/CommunityCollectionGenerator.java +++ b/dspace-sword/src/main/java/org/dspace/sword/CommunityCollectionGenerator.java @@ -7,40 +7,36 @@ */ package org.dspace.sword; +import java.util.List; + import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CommunityService; import org.purl.sword.base.Collection; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Community; -import org.apache.log4j.Logger; -import java.util.List; - -public class CommunityCollectionGenerator extends ATOMCollectionGenerator -{ +public class CommunityCollectionGenerator extends ATOMCollectionGenerator { private static Logger log = Logger - .getLogger(CommunityCollectionGenerator.class); + .getLogger(CommunityCollectionGenerator.class); protected CommunityService communityService = ContentServiceFactory - .getInstance().getCommunityService(); + .getInstance().getCommunityService(); - public CommunityCollectionGenerator(SWORDService service) - { + public CommunityCollectionGenerator(SWORDService service) { super(service); log.debug("Created instance of CommunityCollectionGenerator"); } public Collection buildCollection(DSpaceObject dso) - throws DSpaceSWORDException - { - if (!(dso instanceof Community)) - { + throws DSpaceSWORDException { + if (!(dso instanceof Community)) { log.error( - "buildCollection passed something other than a Community object"); + "buildCollection passed something other than a Community object"); throw new DSpaceSWORDException( - "Incorrect ATOMCollectionGenerator instantiated"); + "Incorrect ATOMCollectionGenerator instantiated"); } // get the things we need out of the service @@ -56,8 +52,7 @@ public class CommunityCollectionGenerator extends ATOMCollectionGenerator // collection title is just the community name String title = communityService.getName(com); - if (StringUtils.isNotBlank(title)) - { + if (StringUtils.isNotBlank(title)) { scol.setTitle(title); } @@ -67,12 +62,10 @@ public class CommunityCollectionGenerator extends ATOMCollectionGenerator // abstract is the short description of the collection List abstracts = communityService - .getMetadataByMetadataString(com, "short_description"); - if (abstracts != null && !abstracts.isEmpty()) - { + .getMetadataByMetadataString(com, "short_description"); + if (abstracts != null && !abstracts.isEmpty()) { String firstValue = abstracts.get(0).getValue(); - if (StringUtils.isNotBlank(firstValue)) - { + if (StringUtils.isNotBlank(firstValue)) { scol.setAbstract(firstValue); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/DSpaceATOMEntry.java b/dspace-sword/src/main/java/org/dspace/sword/DSpaceATOMEntry.java index 1c027de0a6..d99c1de424 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/DSpaceATOMEntry.java +++ b/dspace-sword/src/main/java/org/dspace/sword/DSpaceATOMEntry.java @@ -11,13 +11,11 @@ import org.dspace.content.Bitstream; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.core.ConfigurationManager; - -import org.purl.sword.base.SWORDEntry; -import org.purl.sword.base.Deposit; - import org.purl.sword.atom.Author; import org.purl.sword.atom.Contributor; import org.purl.sword.atom.Generator; +import org.purl.sword.base.Deposit; +import org.purl.sword.base.SWORDEntry; /** * Class to represent a DSpace Item as an ATOM Entry. This @@ -26,44 +24,51 @@ import org.purl.sword.atom.Generator; * representation if necessary. * * @author Richard Jones - * */ -public abstract class DSpaceATOMEntry -{ - /** the SWORD ATOM entry which this class effectively decorates */ +public abstract class DSpaceATOMEntry { + /** + * the SWORD ATOM entry which this class effectively decorates + */ protected SWORDEntry entry; - /** the item this ATOM entry represents */ + /** + * the item this ATOM entry represents + */ protected Item item = null; - /** The bitstream this ATOM entry represents */ + /** + * The bitstream this ATOM entry represents + */ protected Bitstream bitstream = null; - /** the deposit result */ + /** + * the deposit result + */ protected DepositResult result = null; - /** sword service implementation */ + /** + * sword service implementation + */ protected SWORDService swordService; - /** the original deposit */ + /** + * the original deposit + */ protected Deposit deposit = null; /** * Create a new ATOM entry object around the given service * - * @param service - * SWORD service implementation + * @param service SWORD service implementation */ - protected DSpaceATOMEntry(SWORDService service) - { + protected DSpaceATOMEntry(SWORDService service) { this.swordService = service; } /** * Reset all the internal variables of the class to their original values */ - public void reset() - { + public void reset() { this.entry = new SWORDEntry(); this.item = null; this.bitstream = null; @@ -77,26 +82,20 @@ public abstract class DSpaceATOMEntry * method will throw an error unless the DSpace object is an instance * of the Bitstream. * - * @param dso - * target DSpace object + * @param dso target DSpace object * @return SWORD entry for the given DSpace object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public SWORDEntry getSWORDEntry(DSpaceObject dso) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // reset the object, just in case this.reset(); // NOTE: initially this exists just for the purposes of responding to media-link // requests, so should only ever respond to entries on Bitstreams - if (dso instanceof Bitstream) - { + if (dso instanceof Bitstream) { this.bitstream = (Bitstream) dso; - } - else - { + } else { throw new DSpaceSWORDException( "Can only recover a sword entry for a bitstream via this method"); } @@ -113,15 +112,13 @@ public abstract class DSpaceATOMEntry * assigned identifier for the item will not be added to the * SWORDEntry as it will be invalid. * - * @param result the result of the deposit operation - * @param deposit the original deposit request + * @param result the result of the deposit operation + * @param deposit the original deposit request * @return the SWORDEntry for the item - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public SWORDEntry getSWORDEntry(DepositResult result, Deposit deposit) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { this.reset(); this.entry = new SWORDEntry(); @@ -138,12 +135,10 @@ public abstract class DSpaceATOMEntry /** * Construct the entry * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ protected void constructEntry() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // set the generator this.addGenerator(); @@ -191,10 +186,8 @@ public abstract class DSpaceATOMEntry /** * Add deposit treatment text */ - protected void addTreatment() - { - if (result != null) - { + protected void addTreatment() { + if (result != null) { entry.setTreatment(result.getTreatment()); } } @@ -202,14 +195,12 @@ public abstract class DSpaceATOMEntry /** * add the generator field content */ - protected void addGenerator() - { + protected void addGenerator() { boolean identify = ConfigurationManager.getBooleanProperty( "sword-server", "identify-version"); SWORDUrlManager urlManager = swordService.getUrlManager(); String softwareUri = urlManager.getGeneratorUrl(); - if (identify) - { + if (identify) { Generator generator = new Generator(); generator.setUri(softwareUri); generator.setVersion(SWORDProperties.VERSION); @@ -220,10 +211,8 @@ public abstract class DSpaceATOMEntry /** * set the packaging format of the deposit */ - protected void addPackagingElement() - { - if (deposit != null) - { + protected void addPackagingElement() { + if (deposit != null) { entry.setPackaging(deposit.getPackaging()); } } @@ -232,12 +221,9 @@ public abstract class DSpaceATOMEntry * add the author names from the bibliographic metadata. Does * not supply email addresses or URIs, both for privacy, and * because the data is not so readily available in DSpace. - * */ - protected void addAuthors() - { - if (deposit != null) - { + protected void addAuthors() { + if (deposit != null) { String username = this.deposit.getUsername(); Author author = new Author(); author.setName(username); @@ -249,15 +235,11 @@ public abstract class DSpaceATOMEntry * Add the list of contributors to the item. This will include * the authors, and any other contributors that are supplied * in the bibliographic metadata - * */ - protected void addContributors() - { - if (deposit != null) - { + protected void addContributors() { + if (deposit != null) { String obo = deposit.getOnBehalfOf(); - if (obo != null) - { + if (obo != null) { Contributor cont = new Contributor(); cont.setName(obo); entry.addContributor(cont); @@ -269,8 +251,7 @@ public abstract class DSpaceATOMEntry * Add all the subject classifications from the bibliographic * metadata. * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addCategories() throws DSpaceSWORDException; @@ -278,8 +259,7 @@ public abstract class DSpaceATOMEntry * Set the content type that DSpace received. This is just * "application/zip" in this default implementation. * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addContentElement() throws DSpaceSWORDException; @@ -290,24 +270,21 @@ public abstract class DSpaceATOMEntry * they can be used to access the resource over http (i.e. * a real URL). * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addIdentifier() throws DSpaceSWORDException; /** * Add links associated with this item. * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addLinks() throws DSpaceSWORDException; /** * Add the date of publication from the bibliographic metadata * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addPublishDate() throws DSpaceSWORDException; @@ -315,32 +292,28 @@ public abstract class DSpaceATOMEntry * Add rights information. This attaches an href to the URL * of the item's licence file * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addRights() throws DSpaceSWORDException; /** * Add the summary/abstract from the bibliographic metadata * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addSummary() throws DSpaceSWORDException; /** * Add the title from the bibliographic metadata * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addTitle() throws DSpaceSWORDException; /** * Add the date that this item was last updated * - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ abstract void addLastUpdatedDate() throws DSpaceSWORDException; } diff --git a/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDErrorCodes.java b/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDErrorCodes.java index 50080f7e3c..56feaf5432 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDErrorCodes.java +++ b/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDErrorCodes.java @@ -10,40 +10,55 @@ package org.dspace.sword; /** * Some URIs for DSpace specific errors which may be reported through the SWORDErrorException */ -public interface DSpaceSWORDErrorCodes -{ - /** if unpackaging the package fails */ +public interface DSpaceSWORDErrorCodes { + /** + * if unpackaging the package fails + */ public static final String UNPACKAGE_FAIL = - SWORDProperties.SOFTWARE_URI + "/errors/UnpackageFail"; + SWORDProperties.SOFTWARE_URI + "/errors/UnpackageFail"; - /** if the url of the request does not resolve to something meaningful */ + /** + * if the url of the request does not resolve to something meaningful + */ public static final String BAD_URL = - SWORDProperties.SOFTWARE_URI + "/errors/BadUrl"; + SWORDProperties.SOFTWARE_URI + "/errors/BadUrl"; - /** if the media requested is unavailable */ + /** + * if the media requested is unavailable + */ public static final String MEDIA_UNAVAILABLE = - SWORDProperties.SOFTWARE_URI + "/errors/MediaUnavailable"; + SWORDProperties.SOFTWARE_URI + "/errors/MediaUnavailable"; /* additional codes */ - /** Invalid package */ + /** + * Invalid package + */ public static final String PACKAGE_ERROR = - SWORDProperties.SOFTWARE_URI + "/errors/PackageError"; + SWORDProperties.SOFTWARE_URI + "/errors/PackageError"; - /** Missing resources in package */ + /** + * Missing resources in package + */ public static final String PACKAGE_VALIDATION_ERROR = - SWORDProperties.SOFTWARE_URI + "/errors/PackageValidationError"; + SWORDProperties.SOFTWARE_URI + "/errors/PackageValidationError"; - /** Crosswalk error */ + /** + * Crosswalk error + */ public static final String CROSSWALK_ERROR = - SWORDProperties.SOFTWARE_URI + "/errors/CrosswalkError"; + SWORDProperties.SOFTWARE_URI + "/errors/CrosswalkError"; - /** Invalid collection for linking */ + /** + * Invalid collection for linking + */ public static final String COLLECTION_LINK_ERROR = - SWORDProperties.SOFTWARE_URI + "/errors/CollectionLinkError"; + SWORDProperties.SOFTWARE_URI + "/errors/CollectionLinkError"; - /** Database or IO Error when installing new item */ + /** + * Database or IO Error when installing new item + */ public static final String REPOSITORY_ERROR = - SWORDProperties.SOFTWARE_URI + "/errors/RepositoryError"; + SWORDProperties.SOFTWARE_URI + "/errors/RepositoryError"; } diff --git a/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDException.java b/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDException.java index c6c2d68e4a..334ef90526 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDException.java +++ b/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDException.java @@ -12,28 +12,22 @@ package org.dspace.sword; * DSpace SWORD implementation * * @author Richard Jones - * */ -public class DSpaceSWORDException extends Exception -{ +public class DSpaceSWORDException extends Exception { - public DSpaceSWORDException() - { + public DSpaceSWORDException() { super(); } - public DSpaceSWORDException(String arg0, Throwable arg1) - { + public DSpaceSWORDException(String arg0, Throwable arg1) { super(arg0, arg1); } - public DSpaceSWORDException(String arg0) - { + public DSpaceSWORDException(String arg0) { super(arg0); } - public DSpaceSWORDException(Throwable arg0) - { + public DSpaceSWORDException(Throwable arg0) { super(arg0); } diff --git a/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDServer.java b/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDServer.java index c58cb80405..d742bc1eae 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDServer.java +++ b/dspace-sword/src/main/java/org/dspace/sword/DSpaceSWORDServer.java @@ -8,11 +8,8 @@ package org.dspace.sword; import org.apache.log4j.Logger; - import org.dspace.core.Context; import org.dspace.core.LogManager; - -import org.purl.sword.server.SWORDServer; import org.purl.sword.base.AtomDocumentRequest; import org.purl.sword.base.AtomDocumentResponse; import org.purl.sword.base.Deposit; @@ -22,6 +19,7 @@ import org.purl.sword.base.SWORDErrorException; import org.purl.sword.base.SWORDException; import org.purl.sword.base.ServiceDocument; import org.purl.sword.base.ServiceDocumentRequest; +import org.purl.sword.server.SWORDServer; /** * An implementation of the SWORDServer interface to allow SWORD deposit @@ -31,9 +29,10 @@ import org.purl.sword.base.ServiceDocumentRequest; * * @author Richard Jones */ -public class DSpaceSWORDServer implements SWORDServer -{ - /** Log4j logger */ +public class DSpaceSWORDServer implements SWORDServer { + /** + * Log4j logger + */ public static final Logger log = Logger.getLogger(DSpaceSWORDServer.class); // methods required by SWORDServer interface @@ -43,54 +42,46 @@ public class DSpaceSWORDServer implements SWORDServer * @see org.purl.sword.SWORDServer#doServiceDocument(org.purl.sword.base.ServiceDocumentRequest) */ public ServiceDocument doServiceDocument(ServiceDocumentRequest request) - throws SWORDAuthenticationException, SWORDException, - SWORDErrorException - { + throws SWORDAuthenticationException, SWORDException, + SWORDErrorException { // gah. bloody variable scoping. // set up a dummy sword context for the "finally" block SWORDContext sc = null; - try - { + try { // first authenticate the request // note: this will build our various DSpace contexts for us SWORDAuthenticator auth = new SWORDAuthenticator(); sc = auth.authenticate(request); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager - .getHeader(context, "sword_do_service_document", "")); + .getHeader(context, "sword_do_service_document", "")); } // log the request log.info(LogManager - .getHeader(context, "sword_service_document_request", - "username=" + request.getUsername() + - ",on_behalf_of=" + - request.getOnBehalfOf())); + .getHeader(context, "sword_service_document_request", + "username=" + request.getUsername() + + ",on_behalf_of=" + + request.getOnBehalfOf())); // prep the service request, then get the service document out of it SWORDService service = new SWORDService(sc); ServiceDocumentManager manager = new ServiceDocumentManager( - service); + service); ServiceDocument doc = manager - .getServiceDocument(request.getLocation()); + .getServiceDocument(request.getLocation()); return doc; - } - catch (DSpaceSWORDException e) - { + } catch (DSpaceSWORDException e) { log.error("caught exception: ", e); throw new SWORDException( - "The DSpace SWORD interface experienced an error", e); - } - finally - { + "The DSpace SWORD interface experienced an error", e); + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } @@ -100,31 +91,28 @@ public class DSpaceSWORDServer implements SWORDServer * @see org.purl.sword.SWORDServer#doSWORDDeposit(org.purl.sword.server.Deposit) */ public DepositResponse doDeposit(Deposit deposit) - throws SWORDAuthenticationException, SWORDException, - SWORDErrorException - { + throws SWORDAuthenticationException, SWORDException, + SWORDErrorException { // gah. bloody variable scoping. // set up a dummy sword context for the "finally" block SWORDContext sc = null; - try - { + try { // first authenticate the request // note: this will build our various DSpace contexts for us SWORDAuthenticator auth = new SWORDAuthenticator(); sc = auth.authenticate(deposit); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug( - LogManager.getHeader(context, "sword_do_deposit", "")); + LogManager.getHeader(context, "sword_do_deposit", "")); } // log the request log.info(LogManager.getHeader(context, "sword_deposit_request", - "username=" + deposit.getUsername() + ",on_behalf_of=" + - deposit.getOnBehalfOf())); + "username=" + deposit.getUsername() + ",on_behalf_of=" + + deposit.getOnBehalfOf())); // prep and execute the deposit SWORDService service = new SWORDService(sc); @@ -136,19 +124,14 @@ public class DSpaceSWORDServer implements SWORDServer sc.commit(); return response; - } - catch (DSpaceSWORDException e) - { + } catch (DSpaceSWORDException e) { log.error("caught exception:", e); throw new SWORDException("There was a problem depositing the item", - e); - } - finally - { + e); + } finally { // if, for some reason, we wind up here with a not null context // then abort it (the above should commit it if everything works fine) - if (sc != null) - { + if (sc != null) { sc.abort(); } } @@ -158,49 +141,41 @@ public class DSpaceSWORDServer implements SWORDServer * @see org.purl.sword.SWORDServer#doSWORDDeposit(org.purl.sword.server.Deposit) */ public AtomDocumentResponse doAtomDocument(AtomDocumentRequest adr) - throws SWORDAuthenticationException, SWORDException, - SWORDErrorException - { + throws SWORDAuthenticationException, SWORDException, + SWORDErrorException { // gah. bloody variable scoping. // set up a dummy sword context for the "finally" block SWORDContext sc = null; - try - { + try { // first authenticate the request // note: this will build our various DSpace contexts for us SWORDAuthenticator auth = new SWORDAuthenticator(); sc = auth.authenticate(adr); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager - .getHeader(context, "sword_do_atom_document", "")); + .getHeader(context, "sword_do_atom_document", "")); } // log the request log.info(LogManager - .getHeader(context, "sword_atom_document_request", - "username=" + adr.getUsername())); + .getHeader(context, "sword_atom_document_request", + "username=" + adr.getUsername())); // prep the service request, then get the service document out of it SWORDService service = new SWORDService(sc); MediaEntryManager manager = new MediaEntryManager(service); return manager.getMediaEntry(adr.getLocation()); - } - catch (DSpaceSWORDException e) - { + } catch (DSpaceSWORDException e) { log.error("caught exception: ", e); throw new SWORDException( - "The DSpace SWORD interface experienced an error", e); - } - finally - { + "The DSpace SWORD interface experienced an error", e); + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/DepositManager.java b/dspace-sword/src/main/java/org/dspace/sword/DepositManager.java index d177baf0d9..78f08dd99a 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/DepositManager.java +++ b/dspace-sword/src/main/java/org/dspace/sword/DepositManager.java @@ -7,12 +7,21 @@ */ package org.dspace.sword; -import java.io.*; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +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.util.Date; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; - import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; @@ -21,7 +30,6 @@ import org.dspace.content.service.CollectionService; import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.core.Utils; - import org.purl.sword.base.Deposit; import org.purl.sword.base.DepositResponse; import org.purl.sword.base.SWORDAuthenticationException; @@ -29,36 +37,35 @@ import org.purl.sword.base.SWORDEntry; import org.purl.sword.base.SWORDErrorException; /** - * This class is responsible for initiating the process of + * This class is responsible for initiating the process of * deposit of SWORD Deposit objects into the DSpace repository * * @author Richard Jones - * */ -public class DepositManager -{ - /** Log4j logger */ +public class DepositManager { + /** + * Log4j logger + */ public static final Logger log = Logger.getLogger(DepositManager.class); - /** The SWORD service implementation */ + /** + * The SWORD service implementation + */ private SWORDService swordService; /** * Construct a new DepositManager using the given instantiation of * the SWORD service implementation * - * @param service - * SWORD service + * @param service SWORD service */ - public DepositManager(SWORDService service) - { + public DepositManager(SWORDService service) { this.swordService = service; log.debug("Created instance of DepositManager"); } public DSpaceObject getDepositTarget(Deposit deposit) - throws DSpaceSWORDException, SWORDErrorException - { + throws DSpaceSWORDException, SWORDErrorException { SWORDUrlManager urlManager = swordService.getUrlManager(); Context context = swordService.getContext(); @@ -68,20 +75,17 @@ public class DepositManager swordService.message("Performing deposit using location: " + loc); - if (dso instanceof Collection) - { + if (dso instanceof Collection) { CollectionService collectionService = ContentServiceFactory .getInstance().getCollectionService(); swordService.message( "Location resolves to collection with handle: " + - dso.getHandle() + - " and name: " + - collectionService.getName((Collection) dso)); - } - else if (dso instanceof Item) - { + dso.getHandle() + + " and name: " + + collectionService.getName((Collection) dso)); + } else if (dso instanceof Item) { swordService.message("Location resolves to item with handle: " + - dso.getHandle()); + dso.getHandle()); } return dso; @@ -92,18 +96,15 @@ public class DepositManager * the deposit process. The returned DepositRequest can be * used then to assemble the SWORD response. * - * @param deposit - * deposit request + * @param deposit deposit request * @return the response to the deposit request - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception * @throws SWORDAuthenticationException Thrown if the authentication fails */ public DepositResponse deposit(Deposit deposit) - throws DSpaceSWORDException, SWORDErrorException, - SWORDAuthenticationException - { + throws DSpaceSWORDException, SWORDErrorException, + SWORDAuthenticationException { // start the timer, and initialise the verboseness of the request Date start = new Date(); swordService.message("Initialising verbose deposit"); @@ -118,48 +119,41 @@ public class DepositManager // find out if the supplied SWORDContext can submit to the given // dspace object SWORDAuthenticator auth = new SWORDAuthenticator(); - if (!auth.canSubmit(swordService, deposit, dso)) - { + if (!auth.canSubmit(swordService, deposit, dso)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (swordContext.getOnBehalfOf() != null) - { + if (swordContext.getOnBehalfOf() != null) { oboEmail = swordContext.getOnBehalfOf().getEmail(); } log.info(LogManager.getHeader(context, - "deposit_failed_authorisation", - "user=" + swordContext.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + "deposit_failed_authorisation", + "user=" + swordContext.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SWORDAuthenticationException( "Cannot submit to the given collection with this context"); } // make a note of the authentication in the verbose string swordService.message("Authenticated user: " + - swordContext.getAuthenticated().getEmail()); - if (swordContext.getOnBehalfOf() != null) - { + swordContext.getAuthenticated().getEmail()); + if (swordContext.getOnBehalfOf() != null) { swordService.message("Depositing on behalf of: " + - swordContext.getOnBehalfOf().getEmail()); + swordContext.getOnBehalfOf().getEmail()); } // determine which deposit engine we initialise Depositor dep = null; - if (dso instanceof Collection) - { + if (dso instanceof Collection) { swordService.message( "Initialising depositor for an Item in a Collection"); dep = new CollectionDepositor(swordService, dso); - } - else if (dso instanceof Item) - { + } else if (dso instanceof Item) { swordService.message( "Initialising depositor for a Bitstream in an Item"); dep = new ItemDepositor(swordService, dso); } - if (dep == null) - { + if (dep == null) { log.error( "The specified deposit target does not exist, or is not a collection or an item"); throw new DSpaceSWORDException( @@ -168,20 +162,13 @@ public class DepositManager DepositResult result = null; - try - { + try { result = dep.doDeposit(deposit); - } - catch (DSpaceSWORDException | SWORDErrorException | RuntimeException e) - { - if (swordService.getSwordConfig().isKeepPackageOnFailedIngest()) - { - try - { + } catch (DSpaceSWORDException | SWORDErrorException | RuntimeException e) { + if (swordService.getSwordConfig().isKeepPackageOnFailedIngest()) { + try { storePackageAsFile(deposit); - } - catch (IOException e2) - { + } catch (IOException e2) { log.warn("Unable to store SWORD package as file: " + e); } } @@ -195,8 +182,7 @@ public class DepositManager // a record of the handle straight away. String handle = result.getHandle(); int state = Deposit.CREATED; - if (StringUtils.isBlank(handle)) - { + if (StringUtils.isBlank(handle)) { state = Deposit.ACCEPTED; } @@ -204,19 +190,15 @@ public class DepositManager response.setLocation(result.getMediaLink()); DSpaceATOMEntry dsatom = null; - if (result.getItem() != null) - { + if (result.getItem() != null) { swordService.message("Initialising ATOM entry generator for an Item"); dsatom = new ItemEntryGenerator(swordService); - } - else if (result.getBitstream() != null) - { + } else if (result.getBitstream() != null) { swordService.message( "Initialising ATOM entry generator for a Bitstream"); dsatom = new BitstreamEntryGenerator(swordService); } - if (dsatom == null) - { + if (dsatom == null) { log.error("The deposit failed, see exceptions for explanation"); throw new DSpaceSWORDException( "Result of deposit did not yield an Item or a Bitstream"); @@ -225,8 +207,7 @@ public class DepositManager // if this was a no-op, we need to remove the files we just // deposited, and abort the transaction - if (deposit.isNoOp()) - { + if (deposit.isNoOp()) { dep.undoDeposit(result); swordService.message( "NoOp Requested: Removed all traces of submission"); @@ -251,15 +232,13 @@ public class DepositManager * headers as found in the deposit object * Also write companion file with header info from the deposit object. * - * @param deposit the original deposit request + * @param deposit the original deposit request */ - private void storePackageAsFile(Deposit deposit) throws IOException - { + private void storePackageAsFile(Deposit deposit) throws IOException { String path = swordService.getSwordConfig().getFailedPackageDir(); File dir = new File(path); - if (!dir.exists() || !dir.isDirectory()) - { + if (!dir.exists() || !dir.isDirectory()) { throw new IOException( "Directory does not exist for writing packages on ingest error."); } diff --git a/dspace-sword/src/main/java/org/dspace/sword/DepositResult.java b/dspace-sword/src/main/java/org/dspace/sword/DepositResult.java index 1c7a44599e..48bb37d30c 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/DepositResult.java +++ b/dspace-sword/src/main/java/org/dspace/sword/DepositResult.java @@ -7,8 +7,8 @@ */ package org.dspace.sword; -import org.dspace.content.Item; import org.dspace.content.Bitstream; +import org.dspace.content.Item; /** * The DSpace class for representing the results of a deposit @@ -16,84 +16,82 @@ import org.dspace.content.Bitstream; * components required to later build the SWORD response * * @author Richard Jones - * */ -public class DepositResult -{ - /** the handle assigned to the item, if available */ +public class DepositResult { + /** + * the handle assigned to the item, if available + */ private String handle; - /** the item created during deposit */ + /** + * the item created during deposit + */ private Item item; - /** Bitstream created as a result of the deposit */ + /** + * Bitstream created as a result of the deposit + */ private Bitstream bitstream; - /** The treatment of the item during deposit */ + /** + * The treatment of the item during deposit + */ private String treatment; - /** The media linkto the created object */ + /** + * The media linkto the created object + */ private String mediaLink; - public Bitstream getBitstream() - { + public Bitstream getBitstream() { return bitstream; } - public void setBitstream(Bitstream bitstream) - { + public void setBitstream(Bitstream bitstream) { this.bitstream = bitstream; } - public String getTreatment() - { + public String getTreatment() { return treatment; } - public void setTreatment(String treatment) - { + public void setTreatment(String treatment) { this.treatment = treatment; } /** * @return the item */ - public Item getItem() - { + public Item getItem() { return item; } /** * @param item the item to set */ - public void setItem(Item item) - { + public void setItem(Item item) { this.item = item; } /** * @return the handle */ - public String getHandle() - { + public String getHandle() { return handle; } /** - * @param handle the item handle + * @param handle the item handle */ - public void setHandle(String handle) - { + public void setHandle(String handle) { this.handle = handle; } - public String getMediaLink() - { + public String getMediaLink() { return mediaLink; } - public void setMediaLink(String mediaLink) - { + public void setMediaLink(String mediaLink) { this.mediaLink = mediaLink; } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/Depositor.java b/dspace-sword/src/main/java/org/dspace/sword/Depositor.java index cf47281d25..725f3649cf 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/Depositor.java +++ b/dspace-sword/src/main/java/org/dspace/sword/Depositor.java @@ -16,8 +16,7 @@ import org.purl.sword.base.SWORDErrorException; * * Abstract class for depositing content into the archive. */ -public abstract class Depositor -{ +public abstract class Depositor { /** * The SWORD service implementation */ @@ -28,37 +27,30 @@ public abstract class Depositor * dspace object. It is anticipated that extensions of this class will * specialise in certain kinds of dspace object * - * @param swordService - * SWORD service - * @param dso - * DSpace object + * @param swordService SWORD service + * @param dso DSpace object */ - public Depositor(SWORDService swordService, DSpaceObject dso) - { + public Depositor(SWORDService swordService, DSpaceObject dso) { this.swordService = swordService; } /** * Execute the deposit process with the given SWORD deposit. * - * @param deposit - * deposit request + * @param deposit deposit request * @return deposit result - * @throws SWORDErrorException on generic SWORD exception - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public abstract DepositResult doDeposit(Deposit deposit) - throws SWORDErrorException, DSpaceSWORDException; + throws SWORDErrorException, DSpaceSWORDException; /** * Undo any changes to the archive effected by the deposit * - * @param result - * deposit result - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @param result deposit result + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public abstract void undoDeposit(DepositResult result) - throws DSpaceSWORDException; + throws DSpaceSWORDException; } diff --git a/dspace-sword/src/main/java/org/dspace/sword/ItemCollectionGenerator.java b/dspace-sword/src/main/java/org/dspace/sword/ItemCollectionGenerator.java index 45fc529e9c..1b1ade604f 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/ItemCollectionGenerator.java +++ b/dspace-sword/src/main/java/org/dspace/sword/ItemCollectionGenerator.java @@ -7,27 +7,27 @@ */ package org.dspace.sword; +import java.util.List; + import org.apache.commons.lang.StringUtils; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; -import org.purl.sword.base.Collection; -import org.dspace.content.*; import org.dspace.core.Context; - -import java.util.List; +import org.purl.sword.base.Collection; /** * @author Richard Jones * * Class to generate ATOM Collection elements for DSpace Items */ -public class ItemCollectionGenerator extends ATOMCollectionGenerator -{ +public class ItemCollectionGenerator extends ATOMCollectionGenerator { protected ItemService itemService = ContentServiceFactory.getInstance() - .getItemService(); + .getItemService(); - public ItemCollectionGenerator(SWORDService service) - { + public ItemCollectionGenerator(SWORDService service) { super(service); } @@ -40,12 +40,10 @@ public class ItemCollectionGenerator extends ATOMCollectionGenerator * @throws DSpaceSWORDException if the dso is not an instance of Item */ public Collection buildCollection(DSpaceObject dso) - throws DSpaceSWORDException - { - if (!(dso instanceof Item)) - { + throws DSpaceSWORDException { + if (!(dso instanceof Item)) { throw new DSpaceSWORDException( - "Incorrect ATOMCollectionGenerator instantiated"); + "Incorrect ATOMCollectionGenerator instantiated"); } // get the things we need out of the service @@ -63,12 +61,10 @@ public class ItemCollectionGenerator extends ATOMCollectionGenerator // the item title is the sword collection title, or "untitled" otherwise String title = "Untitled"; List dcv = itemService - .getMetadataByMetadataString(item, "dc.title"); - if (!dcv.isEmpty()) - { + .getMetadataByMetadataString(item, "dc.title"); + if (!dcv.isEmpty()) { String firstValue = dcv.get(0).getValue(); - if (StringUtils.isNotBlank(firstValue)) - { + if (StringUtils.isNotBlank(firstValue)) { title = firstValue; } } @@ -81,17 +77,14 @@ public class ItemCollectionGenerator extends ATOMCollectionGenerator // abstract is the short description of the item, if it exists String dcAbstract = ""; List dcva = itemService - .getMetadataByMetadataString(item, "dc.description.abstract"); - if (!dcva.isEmpty()) - { + .getMetadataByMetadataString(item, "dc.description.abstract"); + if (!dcva.isEmpty()) { String firstValue = dcva.get(0).getValue(); - if (StringUtils.isNotBlank(firstValue)) - { + if (StringUtils.isNotBlank(firstValue)) { dcAbstract = firstValue; } } - if (StringUtils.isNotBlank(dcAbstract)) - { + if (StringUtils.isNotBlank(dcAbstract)) { scol.setAbstract(dcAbstract); } @@ -101,8 +94,7 @@ public class ItemCollectionGenerator extends ATOMCollectionGenerator // the list of mime types that we accept, which we take from the // bitstream format registry List acceptFormats = swordConfig.getAccepts(context, item); - for (String acceptFormat : acceptFormats) - { + for (String acceptFormat : acceptFormats) { scol.addAccepts(acceptFormat); } diff --git a/dspace-sword/src/main/java/org/dspace/sword/ItemDepositor.java b/dspace-sword/src/main/java/org/dspace/sword/ItemDepositor.java index 38d4465c37..e174a9ec2c 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/ItemDepositor.java +++ b/dspace-sword/src/main/java/org/dspace/sword/ItemDepositor.java @@ -7,9 +7,19 @@ */ package org.dspace.sword; +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; + import org.apache.commons.lang.StringUtils; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamService; @@ -21,46 +31,36 @@ import org.purl.sword.base.Deposit; import org.purl.sword.base.ErrorCodes; import org.purl.sword.base.SWORDErrorException; -import java.io.FileInputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; - -public class ItemDepositor extends Depositor -{ +public class ItemDepositor extends Depositor { protected ItemService itemService = ContentServiceFactory.getInstance() - .getItemService(); + .getItemService(); protected BundleService bundleService = ContentServiceFactory.getInstance() - .getBundleService(); + .getBundleService(); protected BitstreamService bitstreamService = ContentServiceFactory - .getInstance().getBitstreamService(); + .getInstance().getBitstreamService(); protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory - .getInstance().getBitstreamFormatService(); + .getInstance().getBitstreamFormatService(); private Item item; public ItemDepositor(SWORDService swordService, DSpaceObject dso) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { super(swordService, dso); - if (!(dso instanceof Item)) - { + if (!(dso instanceof Item)) { throw new DSpaceSWORDException( - "You tried to initialise the item depositor with something" + - "other than an item object"); + "You tried to initialise the item depositor with something" + + "other than an item object"); } this.item = (Item) dso; } public DepositResult doDeposit(Deposit deposit) - throws SWORDErrorException, DSpaceSWORDException - { + throws SWORDErrorException, DSpaceSWORDException { // get the things out of the service that we need Context context = swordService.getContext(); SWORDConfiguration swordConfig = swordService.getSwordConfig(); @@ -71,27 +71,25 @@ public class ItemDepositor extends Depositor // // determine if this is an acceptable file format if (!swordConfig - .isAcceptableContentType(context, deposit.getContentType(), - item)) - { + .isAcceptableContentType(context, deposit.getContentType(), + item)) { throw new SWORDErrorException(ErrorCodes.ERROR_CONTENT, - "Unacceptable content type in deposit request: " + - deposit.getContentType()); + "Unacceptable content type in deposit request: " + + deposit.getContentType()); } // determine if this is an acceptable packaging type for the deposit // if not, we throw a 415 HTTP error (Unsupported Media Type, ERROR_CONTENT) if (!swordConfig - .isSupportedMediaType(deposit.getPackaging(), this.item)) - { + .isSupportedMediaType(deposit.getPackaging(), this.item)) { throw new SWORDErrorException(ErrorCodes.ERROR_CONTENT, - "Unacceptable packaging type in deposit request: " + - deposit.getPackaging()); + "Unacceptable packaging type in deposit request: " + + deposit.getPackaging()); } // Obtain the relevant ingester from the factory SWORDIngester si = SWORDIngesterFactory - .getInstance(context, deposit, item); + .getInstance(context, deposit, item); swordService.message("Loaded ingester: " + si.getClass().getName()); // do the deposit @@ -100,67 +98,56 @@ public class ItemDepositor extends Depositor // if there's an item availalble, and we want to keep the original // then do that - try - { - if (swordConfig.isKeepOriginal()) - { + try { + if (swordConfig.isKeepOriginal()) { swordService.message( - "DSpace will store an original copy of the deposit file, " + - "as well as attaching it to the item"); + "DSpace will store an original copy of the deposit file, " + + "as well as attaching it to the item"); // in order to be allowed to add the file back to the item, we need to ignore authorisations // for a moment context.turnOffAuthorisationSystem(); String bundleName = ConfigurationManager - .getProperty("sword-server", "bundle.name"); - if (StringUtils.isBlank(bundleName)) - { + .getProperty("sword-server", "bundle.name"); + if (StringUtils.isBlank(bundleName)) { bundleName = "SWORD"; } List bundles = item.getBundles(); Bundle swordBundle = null; - for (Bundle bundle : bundles) - { - if (bundleName.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (bundleName.equals(bundle.getName())) { // we found one swordBundle = bundle; break; } } - if (swordBundle == null) - { + if (swordBundle == null) { swordBundle = bundleService - .create(context, item, bundleName); + .create(context, item, bundleName); } String fn = swordService.getFilename(context, deposit, true); Bitstream bitstream; FileInputStream fis = null; - try - { + try { fis = new FileInputStream(deposit.getFile()); bitstream = bitstreamService - .create(context, swordBundle, fis); - } - finally - { - if (fis != null) - { + .create(context, swordBundle, fis); + } finally { + if (fis != null) { fis.close(); } } bitstream.setName(context, fn); bitstream.setDescription(context, - "Original file deposited via SWORD"); + "Original file deposited via SWORD"); BitstreamFormat bf = bitstreamFormatService - .findByMIMEType(context, deposit.getContentType()); - if (bf != null) - { + .findByMIMEType(context, deposit.getContentType()); + if (bf != null) { bitstreamService.setFormat(context, bitstream, bf); } @@ -169,44 +156,37 @@ public class ItemDepositor extends Depositor itemService.update(context, item); swordService.message("Original package stored as " + fn + - ", in item bundle " + swordBundle); + ", in item bundle " + swordBundle); // now reset the context ignore authorisation context.restoreAuthSystemState(); // set the media link for the created item result.setMediaLink(urlManager.getMediaLink(bitstream)); - } - else - { + } else { // set the media link for the created item using the archived version (since it's just a file) result.setMediaLink( - urlManager.getMediaLink(result.getBitstream())); + urlManager.getMediaLink(result.getBitstream())); } - } - catch (SQLException | AuthorizeException | IOException e) - { + } catch (SQLException | AuthorizeException | IOException e) { throw new DSpaceSWORDException(e); } return result; } - public void undoDeposit(DepositResult result) throws DSpaceSWORDException - { - try - { + public void undoDeposit(DepositResult result) throws DSpaceSWORDException { + try { SWORDContext sc = swordService.getSwordContext(); BundleService bundleService = ContentServiceFactory.getInstance() - .getBundleService(); + .getBundleService(); // obtain the bitstream's owning bundles and remove the bitstream // from them. This will ensure that the bitstream is physically // removed from the disk. Bitstream bs = result.getBitstream(); Iterator bundles = bs.getBundles().iterator(); - while (bundles.hasNext()) - { + while (bundles.hasNext()) { Bundle bundle = bundles.next(); bundles.remove(); bundleService.removeBitstream(sc.getContext(), bundle, bs); @@ -218,9 +198,7 @@ public class ItemDepositor extends Depositor // abort the context, so no database changes are written sc.abort(); swordService.message("Database changes aborted"); - } - catch (IOException | AuthorizeException | SQLException e) - { + } catch (IOException | AuthorizeException | SQLException e) { throw new DSpaceSWORDException(e); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/ItemEntryGenerator.java b/dspace-sword/src/main/java/org/dspace/sword/ItemEntryGenerator.java index c5fb4e6787..73ca67fc3e 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/ItemEntryGenerator.java +++ b/dspace-sword/src/main/java/org/dspace/sword/ItemEntryGenerator.java @@ -7,54 +7,60 @@ */ package org.dspace.sword; +import java.sql.SQLException; +import java.util.List; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.DCDate; +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.Constants; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; -import org.purl.sword.atom.*; - -import java.sql.SQLException; -import java.util.List; +import org.purl.sword.atom.Content; +import org.purl.sword.atom.ContentType; +import org.purl.sword.atom.InvalidMediaTypeException; +import org.purl.sword.atom.Link; +import org.purl.sword.atom.Rights; +import org.purl.sword.atom.Summary; +import org.purl.sword.atom.Title; /** * @author Richard Jones * * Class to generate an ATOM Entry document for a DSpace Item */ -public class ItemEntryGenerator extends DSpaceATOMEntry -{ - /** logger */ +public class ItemEntryGenerator extends DSpaceATOMEntry { + /** + * logger + */ private static Logger log = Logger.getLogger(ItemEntryGenerator.class); protected HandleService handleService = HandleServiceFactory.getInstance() - .getHandleService(); + .getHandleService(); protected ItemService itemService = ContentServiceFactory.getInstance() - .getItemService(); + .getItemService(); - protected ItemEntryGenerator(SWORDService service) - { + protected ItemEntryGenerator(SWORDService service) { super(service); } /** * Add all the subject classifications from the bibliographic * metadata. - * */ - protected void addCategories() - { + protected void addCategories() { List dcv = itemService - .getMetadataByMetadataString(item, "dc.subject.*"); - if (dcv != null) - { - for (MetadataValue aDcv : dcv) - { + .getMetadataByMetadataString(item, "dc.subject.*"); + if (dcv != null) { + for (MetadataValue aDcv : dcv) { entry.addCategory(aDcv.getValue()); } } @@ -63,63 +69,51 @@ public class ItemEntryGenerator extends DSpaceATOMEntry /** * Set the content type that DSpace received. This is just * "application/zip" in this default implementation. - * */ protected void addContentElement() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // get the things we need out of the service SWORDUrlManager urlManager = swordService.getUrlManager(); - try - { - if (!this.deposit.isNoOp()) - { + try { + if (!this.deposit.isNoOp()) { String handle = ""; - if (item.getHandle() != null) - { + if (item.getHandle() != null) { handle = item.getHandle(); } - if (StringUtils.isNotBlank(handle)) - { + if (StringUtils.isNotBlank(handle)) { boolean keepOriginal = ConfigurationManager - .getBooleanProperty("sword-server", - "keep-original-package"); + .getBooleanProperty("sword-server", + "keep-original-package"); String swordBundle = ConfigurationManager - .getProperty("sword-server", "bundle.name"); - if (StringUtils.isBlank(swordBundle)) - { + .getProperty("sword-server", "bundle.name"); + if (StringUtils.isBlank(swordBundle)) { swordBundle = "SWORD"; } // if we keep the original, then expose this as the content element // otherwise, expose the unpacked version - if (keepOriginal) - { + if (keepOriginal) { Content con = new Content(); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (swordBundle.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (swordBundle.equals(bundle.getName())) { List bss = bundle - .getBitstreams(); - for (Bitstream bs : bss) - { + .getBitstreams(); + for (Bitstream bs : bss) { BitstreamFormat bf = bs - .getFormat( - swordService.getContext()); + .getFormat( + swordService.getContext()); String format = "application/octet-stream"; - if (bf != null) - { + if (bf != null) { format = bf.getMIMEType(); } con.setType(format); // calculate the bitstream link. String bsLink = urlManager - .getBitstreamUrl(bs); + .getBitstreamUrl(bs); con.setSource(bsLink); entry.setContent(con); @@ -127,25 +121,19 @@ public class ItemEntryGenerator extends DSpaceATOMEntry break; } } - } - else - { + } else { // return a link to the DSpace entry page Content content = new Content(); content.setType("text/html"); content.setSource( - handleService.getCanonicalForm(handle)); + handleService.getCanonicalForm(handle)); entry.setContent(content); } } } - } - catch (InvalidMediaTypeException e) - { + } catch (InvalidMediaTypeException e) { // do nothing; we'll live without the content type declaration! - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -158,19 +146,15 @@ public class ItemEntryGenerator extends DSpaceATOMEntry * they can be used to access the resource over http (i.e. * a real URL). */ - protected void addIdentifier() - { + protected void addIdentifier() { // it's possible that the item hasn't been assigned a handle yet - if (!this.deposit.isNoOp()) - { + if (!this.deposit.isNoOp()) { String handle = ""; - if (item.getHandle() != null) - { + if (item.getHandle() != null) { handle = item.getHandle(); } - if (StringUtils.isNotBlank(handle)) - { + if (StringUtils.isNotBlank(handle)) { entry.setId(handleService.getCanonicalForm(handle)); return; } @@ -187,45 +171,35 @@ public class ItemEntryGenerator extends DSpaceATOMEntry /** * Add links associated with this item. - * */ protected void addLinks() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { SWORDUrlManager urlManager = swordService.getUrlManager(); - try - { + try { // if there is no handle, we can't generate links String handle = ""; - if (item.getHandle() != null) - { + if (item.getHandle() != null) { handle = item.getHandle(); - } - else - { + } else { return; } // link to all the files in the item List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { List bss = bundle.getBitstreams(); - for (Bitstream bs : bss) - { + for (Bitstream bs : bss) { Link link = new Link(); String url = urlManager - .getBitstreamUrl(bs); + .getBitstreamUrl(bs); link.setHref(url); link.setRel("part"); BitstreamFormat bsf = bs - .getFormat(swordService.getContext()); - if (bsf != null) - { + .getFormat(swordService.getContext()); + if (bsf != null) { link.setType(bsf.getMIMEType()); } @@ -241,23 +215,18 @@ public class ItemEntryGenerator extends DSpaceATOMEntry splash.setRel("alternate"); splash.setType("text/html"); entry.addLink(splash); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSWORDException(e); } } /** * Add the date of publication from the bibliographic metadata - * */ - protected void addPublishDate() - { + protected void addPublishDate() { List dcv = itemService - .getMetadataByMetadataString(item, "dc.date.issued"); - if (dcv != null && !dcv.isEmpty()) - { + .getMetadataByMetadataString(item, "dc.date.issued"); + if (dcv != null && !dcv.isEmpty()) { entry.setPublished(dcv.get(0).getValue()); } } @@ -265,38 +234,31 @@ public class ItemEntryGenerator extends DSpaceATOMEntry /** * Add rights information. This attaches an href to the URL * of the item's licence file - * */ protected void addRights() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { SWORDUrlManager urlManager = swordService.getUrlManager(); String handle = this.item.getHandle(); // if there's no handle, we can't give a link - if (StringUtils.isBlank(handle)) - { + if (StringUtils.isBlank(handle)) { return; } String base = ConfigurationManager.getProperty("dspace.url"); // if there's no base URL, we are stuck - if (base == null) - { + if (base == null) { return; } StringBuilder rightsString = new StringBuilder(); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (Constants.LICENSE_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.LICENSE_BUNDLE_NAME.equals(bundle.getName())) { List bss = bundle.getBitstreams(); - for (Bitstream bs : bss) - { + for (Bitstream bs : bss) { String url = urlManager.getBitstreamUrl(bs); rightsString.append(url).append(" "); } @@ -312,16 +274,12 @@ public class ItemEntryGenerator extends DSpaceATOMEntry /** * Add the summary/abstract from the bibliographic metadata - * */ - protected void addSummary() - { + protected void addSummary() { List dcv = itemService - .getMetadataByMetadataString(item, "dc.description.abstract"); - if (dcv != null) - { - for (MetadataValue aDcv : dcv) - { + .getMetadataByMetadataString(item, "dc.description.abstract"); + if (dcv != null) { + for (MetadataValue aDcv : dcv) { Summary summary = new Summary(); summary.setContent(aDcv.getValue()); summary.setType(ContentType.TEXT); @@ -332,16 +290,12 @@ public class ItemEntryGenerator extends DSpaceATOMEntry /** * Add the title from the bibliographic metadata - * */ - protected void addTitle() - { + protected void addTitle() { List dcv = itemService - .getMetadataByMetadataString(item, "dc.title"); - if (dcv != null) - { - for (MetadataValue aDcv : dcv) - { + .getMetadataByMetadataString(item, "dc.title"); + if (dcv != null) { + for (MetadataValue aDcv : dcv) { Title title = new Title(); title.setContent(aDcv.getValue()); title.setType(ContentType.TEXT); @@ -352,16 +306,13 @@ public class ItemEntryGenerator extends DSpaceATOMEntry /** * Add the date that this item was last updated - * */ - protected void addLastUpdatedDate() - { + protected void addLastUpdatedDate() { String config = ConfigurationManager - .getProperty("sword-server", "updated.field"); + .getProperty("sword-server", "updated.field"); List dcv = itemService - .getMetadataByMetadataString(item, config); - if (dcv != null && dcv.size() == 1) - { + .getMetadataByMetadataString(item, config); + if (dcv != null && dcv.size() == 1) { DCDate dcd = new DCDate(dcv.get(0).getValue()); entry.setUpdated(dcd.toString()); } diff --git a/dspace-sword/src/main/java/org/dspace/sword/MediaEntryManager.java b/dspace-sword/src/main/java/org/dspace/sword/MediaEntryManager.java index 7faed279eb..41b14fed55 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/MediaEntryManager.java +++ b/dspace-sword/src/main/java/org/dspace/sword/MediaEntryManager.java @@ -7,25 +7,24 @@ */ package org.dspace.sword; -import org.purl.sword.base.AtomDocumentResponse; -import org.purl.sword.base.SWORDErrorException; -import org.purl.sword.base.SWORDEntry; -import org.dspace.content.DSpaceObject; import org.dspace.content.Bitstream; +import org.dspace.content.DSpaceObject; +import org.purl.sword.base.AtomDocumentResponse; +import org.purl.sword.base.SWORDEntry; +import org.purl.sword.base.SWORDErrorException; /** * @author Richard Jones * * Class to provide tools to manage media links and media entries for sword - * */ -public class MediaEntryManager -{ - /** SWORD service implementation */ +public class MediaEntryManager { + /** + * SWORD service implementation + */ private SWORDService swordService; - public MediaEntryManager(SWORDService swordService) - { + public MediaEntryManager(SWORDService swordService) { this.swordService = swordService; } @@ -34,22 +33,18 @@ public class MediaEntryManager * unavailable this method will throw the appropriate SWORD errors, * with DSpace custom URLs. * - * @param url - * URL to check + * @param url URL to check * @return media entry for the given URL request - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ public AtomDocumentResponse getMediaEntry(String url) - throws DSpaceSWORDException, SWORDErrorException - { + throws DSpaceSWORDException, SWORDErrorException { SWORDUrlManager urlManager = swordService.getUrlManager(); AtomDocumentResponse response = new AtomDocumentResponse(200); - if (url == null || urlManager.isBaseMediaLinkUrl(url)) - { + if (url == null || urlManager.isBaseMediaLinkUrl(url)) { // we are dealing with a default media-link, indicating that something // is wrong @@ -64,10 +59,9 @@ public class MediaEntryManager DSpaceObject dso = urlManager.extractDSpaceObject(url); // now, the media entry should always be to an actual file, so we only care that this is a bitstream - if (!(dso instanceof Bitstream)) - { + if (!(dso instanceof Bitstream)) { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "The url you provided does not resolve to an appropriate object"); + "The url you provided does not resolve to an appropriate object"); } // now construct the atom entry for the bitstream diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDAuthentication.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDAuthentication.java index 3d2d3d02eb..c243364ed0 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDAuthentication.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDAuthentication.java @@ -7,34 +7,28 @@ */ package org.dspace.sword; +import org.dspace.authenticate.AuthenticationMethod; import org.dspace.authenticate.factory.AuthenticateServiceFactory; import org.dspace.authenticate.service.AuthenticationService; import org.dspace.core.Context; -import org.dspace.authenticate.AuthenticationMethod; /** * This class offers a thin wrapper for the default DSpace * authentication module for the SWORD implementation * * @author Richard Jones - * */ -public class SWORDAuthentication -{ +public class SWORDAuthentication { /** * Does the given username and password authenticate for the * given DSpace Context? * - * @param context - * The relevant DSpace Context. - * @param un - * username - * @param pw - * password + * @param context The relevant DSpace Context. + * @param un username + * @param pw password * @return true if yes, false if not */ - public boolean authenticates(Context context, String un, String pw) - { + public boolean authenticates(Context context, String un, String pw) { AuthenticationService authService = AuthenticateServiceFactory.getInstance().getAuthenticationService(); int auth = authService.authenticate(context, un, pw, null, null); diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDAuthenticator.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDAuthenticator.java index b33b63c5ac..4497532c25 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDAuthenticator.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDAuthenticator.java @@ -7,43 +7,52 @@ */ package org.dspace.sword; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; +import org.dspace.authenticate.AuthenticationMethod; import org.dspace.authenticate.factory.AuthenticateServiceFactory; import org.dspace.authenticate.service.AuthenticationService; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.Bundle; 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.CollectionService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; -import org.dspace.core.Context; import org.dspace.core.ConfigurationManager; -import org.dspace.core.LogManager; import org.dspace.core.Constants; -import org.dspace.authenticate.AuthenticationMethod; +import org.dspace.core.Context; +import org.dspace.core.LogManager; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import org.dspace.content.*; -import org.apache.log4j.Logger; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; -import org.purl.sword.base.*; - -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; -import java.util.ArrayList; +import org.purl.sword.base.AtomDocumentRequest; +import org.purl.sword.base.Deposit; +import org.purl.sword.base.ErrorCodes; +import org.purl.sword.base.SWORDAuthenticationException; +import org.purl.sword.base.SWORDErrorException; +import org.purl.sword.base.SWORDException; +import org.purl.sword.base.ServiceDocumentRequest; /** * This class offers a thin wrapper for the default DSpace * authentication module for the SWORD implementation * * @author Richard Jones - * */ -public class SWORDAuthenticator -{ - /** logger */ +public class SWORDAuthenticator { + /** + * logger + */ private static Logger log = Logger.getLogger(SWORDAuthenticator.class); protected AuthenticationService authenticationService = @@ -68,16 +77,12 @@ public class SWORDAuthenticator * Does the given username and password authenticate for the * given DSpace Context? * - * @param context - * The relevant DSpace Context. - * @param un - * username - * @param pw - * password + * @param context The relevant DSpace Context. + * @param un username + * @param pw password * @return true if yes, false if not */ - public boolean authenticates(Context context, String un, String pw) - { + public boolean authenticates(Context context, String un, String pw) { int auth = authenticationService.authenticate( context, un, pw, null, null); return auth == AuthenticationMethod.SUCCESS; @@ -88,12 +93,11 @@ public class SWORDAuthenticator * using the passed IP address as part of the loggable * information * - * @param ip the ip address of the incoming request + * @param ip the ip address of the incoming request * @throws org.purl.sword.base.SWORDException */ private Context constructContext(String ip) - throws SWORDException - { + throws SWORDException { Context context = new Context(); // Set the session ID and IP address context.setExtraLogInfo("session_id=0:ip_addr=" + ip); @@ -106,27 +110,21 @@ public class SWORDAuthenticator * the appropriate information from the request and forwards to the * appropriate authentication method. * - * @param request - * service document request + * @param request service document request * @return authenticated SWORD context - * @throws SWORDException passed through. - * @throws SWORDErrorException on generic SWORD exception + * @throws SWORDException passed through. + * @throws SWORDErrorException on generic SWORD exception * @throws SWORDAuthenticationException Thrown if the authentication fails */ public SWORDContext authenticate(ServiceDocumentRequest request) - throws SWORDException, SWORDErrorException, - SWORDAuthenticationException - { + throws SWORDException, SWORDErrorException, + SWORDAuthenticationException { Context context = this.constructContext(request.getIPAddress()); SWORDContext sc; - try - { + try { sc = this.authenticate(context, request); - } - catch (SWORDException | SWORDErrorException | RuntimeException | SWORDAuthenticationException e) - { - if (context != null && context.isValid()) - { + } catch (SWORDException | SWORDErrorException | RuntimeException | SWORDAuthenticationException e) { + if (context != null && context.isValid()) { context.abort(); } throw e; @@ -139,27 +137,21 @@ public class SWORDAuthenticator * appropriate information from the request, and forwards to the * appropriate authentication method. * - * @param request - * ATOM document request + * @param request ATOM document request * @return a SWORDContext object containing the relevant users - * @throws SWORDException passed through. - * @throws SWORDErrorException on generic SWORD exception + * @throws SWORDException passed through. + * @throws SWORDErrorException on generic SWORD exception * @throws SWORDAuthenticationException Thrown if the authentication fails */ public SWORDContext authenticate(AtomDocumentRequest request) - throws SWORDException, SWORDErrorException, - SWORDAuthenticationException - { + throws SWORDException, SWORDErrorException, + SWORDAuthenticationException { Context context = this.constructContext(request.getIPAddress()); SWORDContext sc = null; - try - { + try { sc = this.authenticate(context, request); - } - catch (SWORDException | SWORDErrorException | SWORDAuthenticationException | RuntimeException e) - { - if (context != null && context.isValid()) - { + } catch (SWORDException | SWORDErrorException | SWORDAuthenticationException | RuntimeException e) { + if (context != null && context.isValid()) { context.abort(); } throw e; @@ -172,19 +164,17 @@ public class SWORDAuthenticator * * authenticatate(username, password, onBehalfOf) * - * @param request - * ATOM document request + * @param request ATOM document request * @return a SWORDContext object containing the relevant users * @throws org.purl.sword.base.SWORDAuthenticationException * @throws SWORDException */ private SWORDContext authenticate(Context context, - AtomDocumentRequest request) - throws SWORDAuthenticationException, SWORDException, - SWORDErrorException - { + AtomDocumentRequest request) + throws SWORDAuthenticationException, SWORDException, + SWORDErrorException { return this.authenticate(context, request.getUsername(), - request.getPassword(), null, request.getIPAddress()); + request.getPassword(), null, request.getIPAddress()); } /** @@ -192,47 +182,38 @@ public class SWORDAuthenticator * * authenticatate(username, password, onBehalfOf) * - * @param request - * service document request - * @return a SWORDContext object containing the relevant users + * @param request service document request * @return a SWORDContext object containing the relevant users * @throws org.purl.sword.base.SWORDAuthenticationException * @throws SWORDException */ private SWORDContext authenticate(Context context, - ServiceDocumentRequest request) - throws SWORDAuthenticationException, SWORDException, - SWORDErrorException - { + ServiceDocumentRequest request) + throws SWORDAuthenticationException, SWORDException, + SWORDErrorException { return this.authenticate(context, request.getUsername(), - request.getPassword(), request.getOnBehalfOf(), - request.getIPAddress()); + request.getPassword(), request.getOnBehalfOf(), + request.getIPAddress()); } /** * Authenticate the deposit request. * - * @param deposit - * deposit request + * @param deposit deposit request * @return a SWORDContext object containing the relevant users - * @throws SWORDException passed through. - * @throws SWORDErrorException on generic SWORD exception + * @throws SWORDException passed through. + * @throws SWORDErrorException on generic SWORD exception * @throws SWORDAuthenticationException Thrown if the authentication fails */ public SWORDContext authenticate(Deposit deposit) - throws SWORDException, SWORDErrorException, - SWORDAuthenticationException - { + throws SWORDException, SWORDErrorException, + SWORDAuthenticationException { Context context = this.constructContext(deposit.getIPAddress()); SWORDContext sc = null; - try - { + try { sc = this.authenticate(context, deposit); - } - catch (SWORDException | SWORDErrorException | RuntimeException | SWORDAuthenticationException e) - { - if (context != null && context.isValid()) - { + } catch (SWORDException | SWORDErrorException | RuntimeException | SWORDAuthenticationException e) { + if (context != null && context.isValid()) { context.abort(); } throw e; @@ -245,19 +226,17 @@ public class SWORDAuthenticator * * authenticate(username, password, onBehalfOf) * - * @param deposit - * deposit request + * @param deposit deposit request * @return a SWORDContext object containing the relevant users * @throws SWORDAuthenticationException Thrown if the authentication fails * @throws SWORDException */ private SWORDContext authenticate(Context context, Deposit deposit) - throws SWORDAuthenticationException, SWORDException, - SWORDErrorException - { + throws SWORDAuthenticationException, SWORDException, + SWORDErrorException { return this.authenticate(context, deposit.getUsername(), - deposit.getPassword(), deposit.getOnBehalfOf(), - deposit.getIPAddress()); + deposit.getPassword(), deposit.getOnBehalfOf(), + deposit.getIPAddress()); } /** @@ -266,64 +245,54 @@ public class SWORDAuthenticator * must successfully authenticate the user, and the onBehalfOf user * must exist in the user database. * - * @param un - * username - * @param pw - * username - * @param obo - * onBehalfOf user + * @param un username + * @param pw username + * @param obo onBehalfOf user * @return a SWORD context holding the various user information * @throws SWORDAuthenticationException Thrown if the authentication fails * @throws SWORDException */ private SWORDContext authenticate(Context context, String un, String pw, - String obo, String ip) - throws SWORDAuthenticationException, SWORDException, - SWORDErrorException - { + String obo, String ip) + throws SWORDAuthenticationException, SWORDException, + SWORDErrorException { // smooth out the OnBehalfOf request, so that empty strings are // treated as null - if ("".equals(obo)) - { + if ("".equals(obo)) { obo = null; } // first find out if we support on-behalf-of deposit boolean mediated = ConfigurationManager.getBooleanProperty( "sword-server", "on-behalf-of.enable"); - if (!mediated && obo != null) - { + if (!mediated && obo != null) { // user is trying to do a mediated deposit on a repository which does not support it log.error( "Attempted mediated deposit on service not configured to do so"); throw new SWORDErrorException(ErrorCodes.MEDIATION_NOT_ALLOWED, - "Mediated deposit to this service is not permitted"); + "Mediated deposit to this service is not permitted"); } log.info(LogManager.getHeader(context, "sword_authenticate", - "username=" + un + ",on_behalf_of=" + obo)); + "username=" + un + ",on_behalf_of=" + obo)); - try - { + try { // attempt to authenticate the primary user SWORDContext sc = new SWORDContext(); EPerson ep = null; boolean authenticated = false; - if (this.authenticates(context, un, pw)) - { + if (this.authenticates(context, un, pw)) { // if authenticated, obtain the eperson object ep = context.getCurrentUser(); - if (ep != null) - { + if (ep != null) { authenticated = true; sc.setAuthenticated(ep); // Set any special groups - invoke the authentication mgr. List groups = authenticationService - .getSpecialGroups(context, null); + .getSpecialGroups(context, null); - for (Group group : groups) - { + for (Group group : groups) { context.setSpecialGroup(group.getID()); log.debug("Adding Special Group id=" + group.getID()); } @@ -336,16 +305,13 @@ public class SWORDAuthenticator // record, and if it exists set it. If not, then the // authentication process fails EPerson epObo = null; - if (obo != null) - { + if (obo != null) { epObo = ePersonService.findByEmail(context, obo); - if (epObo == null) - { + if (epObo == null) { epObo = ePersonService.findByNetid(context, obo); } - if (epObo != null) - { + if (epObo != null) { sc.setOnBehalfOf(epObo); Context oboContext = this.constructContext(ip); oboContext.setCurrentUser(epObo); @@ -353,16 +319,13 @@ public class SWORDAuthenticator List groups = authenticationService .getSpecialGroups(oboContext, null); - for (Group group : groups) - { + for (Group group : groups) { oboContext.setSpecialGroup(group.getID()); log.debug( "Adding Special Group id=" + group.getID()); } sc.setContext(oboContext); - } - else - { + } else { authenticated = false; throw new SWORDErrorException( ErrorCodes.TARGET_OWNER_UKNOWN, @@ -371,32 +334,26 @@ public class SWORDAuthenticator } } - if (!authenticated) - { + if (!authenticated) { // decide what kind of error to throw - if (ep != null) - { + if (ep != null) { log.info(LogManager.getHeader(context, - "sword_unable_to_set_user", "username=" + un)); + "sword_unable_to_set_user", "username=" + un)); throw new SWORDAuthenticationException( "Unable to authenticate the supplied used"); - } - else - { + } else { // FIXME: this shouldn't ever happen now, but may as well leave it in just in case // there's a bug elsewhere log.info(LogManager.getHeader(context, - "sword_unable_to_set_on_behalf_of", - "username=" + un + ",on_behalf_of=" + obo)); + "sword_unable_to_set_on_behalf_of", + "username=" + un + ",on_behalf_of=" + obo)); throw new SWORDAuthenticationException( "Unable to authenticate the onBehalfOf account"); } } return sc; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("caught exception: ", e); throw new SWORDException( "There was a problem accessing the repository user database", @@ -411,33 +368,25 @@ public class SWORDAuthenticator * See javadocs for individual canSubmitTo methods to see the conditions * which are applied in each situation * - * @param swordService - * SWORD service - * @param deposit - * unused - * @param dso - * target DSpace object + * @param swordService SWORD service + * @param deposit unused + * @param dso target DSpace object * @return true if yes, false if not - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ public boolean canSubmit(SWORDService swordService, Deposit deposit, - DSpaceObject dso) - throws DSpaceSWORDException, SWORDErrorException - { + DSpaceObject dso) + throws DSpaceSWORDException, SWORDErrorException { // get the things we need out of the service SWORDContext swordContext = swordService.getSwordContext(); // determine if we can submit boolean submit = this.canSubmitTo(swordContext, dso); - if (submit) - { + if (submit) { swordService.message("User is authorised to submit to collection"); - } - else - { + } else { swordService.message( "User is not authorised to submit to collection"); } @@ -450,23 +399,17 @@ public class SWORDAuthenticator * as asking the question of whether the given eperson is a member * of the special DSpace group Administrator, with id 1 * - * @param swordContext - * The relevant SWORD Context. + * @param swordContext The relevant SWORD Context. * @return true if administrator, false if not - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isUserAdmin(SWORDContext swordContext) - throws DSpaceSWORDException - { - try - { + throws DSpaceSWORDException { + try { EPerson authenticated = swordContext.getAuthenticated(); return authenticated != null && authorizeService.isAdmin( swordContext.getAuthenticatorContext()); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -477,23 +420,17 @@ public class SWORDAuthenticator * as asking the question of whether the given eperson is a member * of the special DSpace group Administrator, with id 1 * - * @param swordContext - * The relevant SWORD Context. + * @param swordContext The relevant SWORD Context. * @return true if administrator, false if not - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isOnBehalfOfAdmin(SWORDContext swordContext) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { EPerson onBehalfOf = swordContext.getOnBehalfOf(); - try - { + try { return onBehalfOf != null && authorizeService.isAdmin( swordContext.getOnBehalfOfContext()); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -503,13 +440,11 @@ public class SWORDAuthenticator * Is the authenticated user a member of the given group * or one of its sub groups? * - * @param swordContext - * The relevant SWORD Context. - * @param group group to search recursively + * @param swordContext The relevant SWORD Context. + * @param group group to search recursively * @return true if the authenticated user is a member of group or its subgroups */ - public boolean isUserInGroup(SWORDContext swordContext, Group group) - { + public boolean isUserInGroup(SWORDContext swordContext, Group group) { EPerson authenticated = swordContext.getAuthenticated(); return authenticated != null && isInGroup(group, authenticated); } @@ -518,13 +453,11 @@ public class SWORDAuthenticator * Is the onBehalfOf user a member of the given group or * one of its sub groups? * - * @param swordContext - * The relevant SWORD Context. - * @param group group to search recursively + * @param swordContext The relevant SWORD Context. + * @param group group to search recursively * @return true if the onBehalfOf user is a member of group or its subgroups */ - public boolean isOnBehalfOfInGroup(SWORDContext swordContext, Group group) - { + public boolean isOnBehalfOfInGroup(SWORDContext swordContext, Group group) { EPerson onBehalfOf = swordContext.getOnBehalfOf(); return onBehalfOf != null && isInGroup(group, onBehalfOf); } @@ -535,31 +468,25 @@ public class SWORDAuthenticator * until it has exhausted the tree of groups or finds the given * eperson * - * @param group group to search recursively + * @param group group to search recursively * @param eperson EPerson to find * @return true if in group, false if not */ - public boolean isInGroup(Group group, EPerson eperson) - { + public boolean isInGroup(Group group, EPerson eperson) { List eps = group.getMembers(); List groups = group.getMemberGroups(); // is the user in the current group - for (EPerson ep : eps) - { - if (eperson.getID().equals(ep.getID())) - { + for (EPerson ep : eps) { + if (eperson.getID().equals(ep.getID())) { return true; } } // is the eperson in the sub-groups (recurse) - if (groups != null && !groups.isEmpty()) - { - for (Group group1 : groups) - { - if (isInGroup(group1, eperson)) - { + if (groups != null && !groups.isEmpty()) { + for (Group group1 : groups) { + if (isInGroup(group1, eperson)) { return true; } } @@ -577,25 +504,22 @@ public class SWORDAuthenticator * are met: * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to READ - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to READ + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to READ - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to READ - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to READ + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. + * @param swordContext The relevant SWORD Context. * @return the array of allowed collections - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public List getAllowedCommunities(SWORDContext swordContext) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // a community is allowed if the following conditions are met // // - the authenticated user is an administrator @@ -606,27 +530,24 @@ public class SWORDAuthenticator // -- the on-behalf-of user is an administrator // -- the on-behalf-of user is authorised to READ // -- the on-behalf-of user is null - try - { + try { // locate all the top level communities Context context = swordContext.getContext(); List allowed = new ArrayList<>(); List comms = communityService.findAllTop(context); - for (Community comm : comms) - { + for (Community comm : comms) { boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } - // look up the READ policy on the community. This will include determining if the user is an administrator + // look up the READ policy on the community. This will include determining if the user is an + // administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { authAllowed = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), comm, Constants.READ); @@ -634,23 +555,19 @@ public class SWORDAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { oboAllowed = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), comm, Constants.READ); } // final check to see if we are allowed to READ - if (authAllowed && oboAllowed) - { + if (authAllowed && oboAllowed) { allowed.add(comm); } } return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -664,28 +581,24 @@ public class SWORDAuthenticator * are met: * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to READ - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to READ + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to READ - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to READ - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to READ + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param community - * target community + * @param swordContext The relevant SWORD Context. + * @param community target community * @return the array of allowed collections - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public List getCommunities(SWORDContext swordContext, - Community community) - throws DSpaceSWORDException - { + Community community) + throws DSpaceSWORDException { // a community is allowed if the following conditions are met // // - the authenticated user is an administrator @@ -696,26 +609,23 @@ public class SWORDAuthenticator // -- the on-behalf-of user is an administrator // -- the on-behalf-of user is authorised to READ // -- the on-behalf-of user is null - try - { + try { List comms = community.getSubcommunities(); List allowed = new ArrayList<>(); - for (Community comm : comms) - { + for (Community comm : comms) { boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } - // look up the READ policy on the community. This will include determining if the user is an administrator + // look up the READ policy on the community. This will include determining if the user is an + // administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { authAllowed = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), comm, Constants.READ); @@ -723,24 +633,20 @@ public class SWORDAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { oboAllowed = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), comm, Constants.READ); } // final check to see if we are allowed to READ - if (authAllowed && oboAllowed) - { + if (authAllowed && oboAllowed) { allowed.add(comm); } } return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -756,16 +662,13 @@ public class SWORDAuthenticator * * See that method for details of the conditions applied * - * @param swordContext - * The relevant SWORD Context. + * @param swordContext The relevant SWORD Context. * @return the array of allowed collections - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public List getAllowedCollections( - SWORDContext swordContext) - throws DSpaceSWORDException - { + SWORDContext swordContext) + throws DSpaceSWORDException { return this.getAllowedCollections(swordContext, null); } @@ -774,28 +677,24 @@ public class SWORDAuthenticator * context will allow deposit onto in the given DSpace context * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to ADD - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to ADD + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to ADD - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to ADD - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to ADD + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param community - * target community + * @param swordContext The relevant SWORD Context. + * @param community target community * @return the array of allowed collections - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public List getAllowedCollections( - SWORDContext swordContext, Community community) - throws DSpaceSWORDException - { + SWORDContext swordContext, Community community) + throws DSpaceSWORDException { // a collection is allowed if the following conditions are met // // - the authenticated user is an administrator @@ -807,8 +706,7 @@ public class SWORDAuthenticator // -- the on-behalf-of user is authorised to ADD // -- the on-behalf-of user is null - try - { + try { // get the context of the authenticated user Context authContext = swordContext.getAuthenticatorContext(); @@ -818,36 +716,30 @@ public class SWORDAuthenticator List allowed = new ArrayList<>(); // now find out if the obo user is allowed to submit to any of these collections - for (Collection col : cols) - { + for (Collection col : cols) { boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { oboAllowed = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), col, Constants.ADD); } // final check to see if we are allowed to READ - if (oboAllowed) - { + if (oboAllowed) { allowed.add(col); } } return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -858,28 +750,24 @@ public class SWORDAuthenticator * context will allow deposit onto in the given DSpace context * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param collection - * target collection + * @param swordContext The relevant SWORD Context. + * @param collection target collection * @return the array of allowed collections - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public List getAllowedItems(SWORDContext swordContext, - org.dspace.content.Collection collection) - throws DSpaceSWORDException - { + org.dspace.content.Collection collection) + throws DSpaceSWORDException { // an item is allowed if the following conditions are met // // - the authenticated user is an administrator @@ -891,47 +779,41 @@ public class SWORDAuthenticator // -- the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle // -- the on-behalf-of user is null - try - { + try { List allowed = new ArrayList<>(); Iterator ii = itemService.findByCollection( swordContext.getContext(), collection); - while (ii.hasNext()) - { + while (ii.hasNext()) { Item item = ii.next(); boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } // get the "ORIGINAL" bundle(s) List bundles = item.getBundles(); - // look up the READ policy on the community. This will include determining if the user is an administrator + // look up the READ policy on the community. This will include determining if the user is an + // administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { boolean write = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), item, Constants.WRITE); boolean add = false; - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { if (Constants.CONTENT_BUNDLE_NAME - .equals(bundle.getName())) - { + .equals(bundle.getName())) { add = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), bundle, Constants.ADD); - if (!add) - { + if (!add) { break; } } @@ -942,22 +824,20 @@ public class SWORDAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { boolean write = authorizeService.authorizeActionBoolean( - swordContext.getOnBehalfOfContext(), item, - Constants.WRITE); + swordContext.getOnBehalfOfContext(), item, + Constants.WRITE); boolean add = false; - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { if (Constants.CONTENT_BUNDLE_NAME - .equals(bundle.getName())) + .equals(bundle.getName())) { add = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), bundle, Constants.ADD); - if (!add) - { + } + if (!add) { break; } } @@ -966,16 +846,13 @@ public class SWORDAuthenticator } // final check to see if we are allowed to READ - if (authAllowed && oboAllowed) - { + if (authAllowed && oboAllowed) { allowed.add(item); } } return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSWORDException(e); } } @@ -985,28 +862,24 @@ public class SWORDAuthenticator * collection in the given DSpace Context? * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to ADD - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to ADD + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to ADD - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to ADD - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to ADD + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param collection - * target collection + * @param swordContext The relevant SWORD Context. + * @param collection target collection * @return true if collection permits submission by current context - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public boolean canSubmitTo(SWORDContext swordContext, - org.dspace.content.Collection collection) - throws DSpaceSWORDException - { + org.dspace.content.Collection collection) + throws DSpaceSWORDException { // a user can submit to a collection in the following conditions: // // - the authenticated user is an administrator @@ -1018,21 +891,18 @@ public class SWORDAuthenticator // -- the on-behalf-of user is authorised to ADD/in the submission group // -- the on-behalf-of user is null - try - { + try { boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } // look up the READ policy on the collection. This will include determining if the user is an administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { authAllowed = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), collection, Constants.ADD); @@ -1040,8 +910,7 @@ public class SWORDAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { oboAllowed = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), collection, Constants.ADD); @@ -1050,9 +919,7 @@ public class SWORDAuthenticator // final check to see if we are allowed to READ return (authAllowed && oboAllowed); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -1064,27 +931,23 @@ public class SWORDAuthenticator * The context has permission of the following conditions are met: * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param item - * target item + * @param swordContext The relevant SWORD Context. + * @param item target item * @return the array of allowed collections - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public boolean canSubmitTo(SWORDContext swordContext, Item item) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // a user can submit to a collection in the following conditions: // // - the authenticated user is an administrator @@ -1096,14 +959,12 @@ public class SWORDAuthenticator // -- the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle // -- the on-behalf-of user is null - try - { + try { boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } @@ -1112,22 +973,18 @@ public class SWORDAuthenticator // look up the READ policy on the community. This will include determining if the user is an administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { boolean write = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), item, Constants.WRITE); boolean add = false; - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { add = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), bundle, Constants.ADD); - if (!add) - { + if (!add) { break; } } @@ -1138,22 +995,18 @@ public class SWORDAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { boolean write = authorizeService.authorizeActionBoolean( - swordContext.getOnBehalfOfContext(), item, - Constants.WRITE); + swordContext.getOnBehalfOfContext(), item, + Constants.WRITE); boolean add = false; - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { add = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), bundle, Constants.ADD); - if (!add) - { + if (!add) { break; } } @@ -1165,9 +1018,7 @@ public class SWORDAuthenticator // final check to see if we are allowed to READ return (authAllowed && oboAllowed); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -1179,24 +1030,17 @@ public class SWORDAuthenticator * This forwards to the individual methods for different object types; see * their documentation for details of the conditions. * - * @param context - * The relevant DSpace Context. - * @param dso - * target DSpace object + * @param context The relevant DSpace Context. + * @param dso target DSpace object * @return true if the given context can submit to the specified DSpace object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public boolean canSubmitTo(SWORDContext context, DSpaceObject dso) - throws DSpaceSWORDException - { - if (dso instanceof org.dspace.content.Collection) - { + throws DSpaceSWORDException { + if (dso instanceof org.dspace.content.Collection) { return this.canSubmitTo( context, (org.dspace.content.Collection) dso); - } - else - { + } else { return dso instanceof Item && this.canSubmitTo(context, (Item) dso); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDConfiguration.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDConfiguration.java index 1616855bbd..ad52eba956 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDConfiguration.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDConfiguration.java @@ -7,24 +7,23 @@ */ package org.dspace.sword; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.BitstreamFormatService; -import org.dspace.core.Context; -import org.dspace.content.Collection; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; -import org.dspace.content.BitstreamFormat; -import org.dspace.services.ConfigurationService; -import org.dspace.services.factory.DSpaceServicesFactory; -import org.purl.sword.base.SWORDErrorException; - +import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.sql.SQLException; import org.apache.log4j.Logger; +import org.dspace.content.BitstreamFormat; +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.BitstreamFormatService; +import org.dspace.core.Context; +import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.purl.sword.base.SWORDErrorException; /** * @author Richard Jones @@ -39,58 +38,74 @@ import org.apache.log4j.Logger; * * For detailed descriptions of configuration values, see the sword * configuration documentation - * */ -public class SWORDConfiguration -{ +public class SWORDConfiguration { - /** logger */ + /** + * logger + */ public static final Logger log = Logger.getLogger(SWORDConfiguration.class); protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory .getInstance().getBitstreamFormatService(); - + protected ConfigurationService configurationService = DSpaceServicesFactory .getInstance().getConfigurationService(); - /** whether we can support noOp */ + /** + * whether we can support noOp + */ private boolean noOp = true; - /** whether we can be verbose */ + /** + * whether we can be verbose + */ private boolean verbose = true; - /** what our default max upload size is */ + /** + * what our default max upload size is + */ private int maxUploadSize = -1; - /** do we support mediation */ + /** + * do we support mediation + */ private boolean mediated = false; - /** should we keep the original package as bitstream */ + /** + * should we keep the original package as bitstream + */ private boolean keepOriginal = false; - /** item bundle in which sword deposits are stored */ + /** + * item bundle in which sword deposits are stored + */ private String swordBundle = "SWORD"; - /** should we keep the original package as a file on ingest error */ + /** + * should we keep the original package as a file on ingest error + */ private boolean keepPackageOnFailedIngest = false; - /** location of directory to store packages on ingest error */ + /** + * location of directory to store packages on ingest error + */ private String failedPackageDir = null; - /** Accepted formats */ + /** + * Accepted formats + */ private List swordaccepts; /** * Initialise the sword configuration. It is at this stage that the * object will interrogate the DSpace Configuration for details */ - public SWORDConfiguration() - { + public SWORDConfiguration() { // set the max upload size int mus = configurationService.getIntProperty( "sword-server.max-upload-size"); - if (mus > 0) - { + if (mus > 0) { this.maxUploadSize = mus; } @@ -105,8 +120,7 @@ public class SWORDConfiguration // get the sword bundle String bundle = configurationService.getProperty( "sword-server.bundle.name"); - if (bundle != null && "".equals(bundle)) - { + if (bundle != null && "".equals(bundle)) { this.swordBundle = bundle; } @@ -120,14 +134,12 @@ public class SWORDConfiguration // Get the accepted formats String[] acceptsFormats = configurationService - .getArrayProperty("sword-server.accepts"); + .getArrayProperty("sword-server.accepts"); swordaccepts = new ArrayList(); - if (acceptsFormats == null) - { - acceptsFormats = new String[]{"application/zip"}; + if (acceptsFormats == null) { + acceptsFormats = new String[] {"application/zip"}; } - for (String element : acceptsFormats) - { + for (String element : acceptsFormats) { swordaccepts.add(element.trim()); } } @@ -138,8 +150,7 @@ public class SWORDConfiguration * * @return bundle name where to store the original deposit packages */ - public String getSwordBundle() - { + public String getSwordBundle() { return swordBundle; } @@ -148,10 +159,9 @@ public class SWORDConfiguration * packages in, when storing them inside an item. * * @param swordBundle set bundle name where to store the original - * deposit packages + * deposit packages */ - public void setSwordBundle(String swordBundle) - { + public void setSwordBundle(String swordBundle) { this.swordBundle = swordBundle; } @@ -160,8 +170,7 @@ public class SWORDConfiguration * * @return true if this is a no-op deposit */ - public boolean isNoOp() - { + public boolean isNoOp() { return noOp; } @@ -170,8 +179,7 @@ public class SWORDConfiguration * * @param noOp sets whether this is a no-op deposit */ - public void setNoOp(boolean noOp) - { + public void setNoOp(boolean noOp) { this.noOp = noOp; } @@ -180,8 +188,7 @@ public class SWORDConfiguration * * @return true if is verbose deposit */ - public boolean isVerbose() - { + public boolean isVerbose() { return verbose; } @@ -190,8 +197,7 @@ public class SWORDConfiguration * * @param verbose is verbose deposit? */ - public void setVerbose(boolean verbose) - { + public void setVerbose(boolean verbose) { this.verbose = verbose; } @@ -200,8 +206,7 @@ public class SWORDConfiguration * * @return maximum upload size */ - public int getMaxUploadSize() - { + public int getMaxUploadSize() { return maxUploadSize; } @@ -210,8 +215,7 @@ public class SWORDConfiguration * * @param maxUploadSize maximum upload size to set */ - public void setMaxUploadSize(int maxUploadSize) - { + public void setMaxUploadSize(int maxUploadSize) { this.maxUploadSize = maxUploadSize; } @@ -220,8 +224,7 @@ public class SWORDConfiguration * * @return true if server supports mediated deposit */ - public boolean isMediated() - { + public boolean isMediated() { return mediated; } @@ -230,8 +233,7 @@ public class SWORDConfiguration * * @param mediated set whether server supports mediated deposit */ - public void setMediated(boolean mediated) - { + public void setMediated(boolean mediated) { this.mediated = mediated; } @@ -240,8 +242,7 @@ public class SWORDConfiguration * * @return true if repository keeps copies of original package */ - public boolean isKeepOriginal() - { + public boolean isKeepOriginal() { return keepOriginal; } @@ -250,8 +251,7 @@ public class SWORDConfiguration * * @param keepOriginal set whether to keep copies of original package */ - public void setKeepOriginal(boolean keepOriginal) - { + public void setKeepOriginal(boolean keepOriginal) { this.keepOriginal = keepOriginal; } @@ -259,10 +259,9 @@ public class SWORDConfiguration * set whether the repository should write file of the original package if ingest fails * * @param keepOriginalOnFail set whether to keep copies of original - * package if ingest fails + * package if ingest fails */ - public void setKeepPackageOnFailedIngest(boolean keepOriginalOnFail) - { + public void setKeepPackageOnFailedIngest(boolean keepOriginalOnFail) { keepPackageOnFailedIngest = keepOriginalOnFail; } @@ -270,10 +269,9 @@ public class SWORDConfiguration * should the repository write file of the original package if ingest fails * * @return true if repository keeps copies of original package if ingest - * fails + * fails */ - public boolean isKeepPackageOnFailedIngest() - { + public boolean isKeepPackageOnFailedIngest() { return keepPackageOnFailedIngest; } @@ -282,8 +280,7 @@ public class SWORDConfiguration * * @param dir directory where original package is kept */ - public void setFailedPackageDir(String dir) - { + public void setFailedPackageDir(String dir) { failedPackageDir = dir; } @@ -293,8 +290,7 @@ public class SWORDConfiguration * * @return dir directory where original package is kept */ - public String getFailedPackageDir() - { + public String getFailedPackageDir() { return failedPackageDir; } @@ -302,42 +298,30 @@ public class SWORDConfiguration * Get the list of MIME types that the given DSpace object will * accept as packages. * - * @param context - * The relevant DSpace Context. - * @param dso - * target DSpace object + * @param context The relevant DSpace Context. + * @param dso target DSpace object * @return the list of MIME types that the given DSpace object will * accept as packages. - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public List getAccepts(Context context, DSpaceObject dso) - throws DSpaceSWORDException - { - try - { + throws DSpaceSWORDException { + try { List accepts = new ArrayList(); - if (dso instanceof Collection) - { - for (String format : swordaccepts) - { + if (dso instanceof Collection) { + for (String format : swordaccepts) { accepts.add(format); } - } - else if (dso instanceof Item) - { + } else if (dso instanceof Item) { List bfs = bitstreamFormatService - .findNonInternal(context); - for (BitstreamFormat bf : bfs) - { + .findNonInternal(context); + for (BitstreamFormat bf : bfs) { accepts.add(bf.getMIMEType()); } } return accepts; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSWORDException(e); } } @@ -346,14 +330,11 @@ public class SWORDConfiguration * Get the list of MIME types that a Collection will accept as packages * * @return the list of MIME types - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ - public List getCollectionAccepts() throws DSpaceSWORDException - { + public List getCollectionAccepts() throws DSpaceSWORDException { List accepts = new ArrayList(); - for (String format : swordaccepts) - { + for (String format : swordaccepts) { accepts.add(format); } return accepts; @@ -371,13 +352,11 @@ public class SWORDConfiguration * and the Q value is a floating point between 0 and 1 which defines * how much the server "likes" this packaging type * - * @param col - * target collection + * @param col target collection * @return map of packaging URIs to Q values for the packaging types which - * the given collection will accept. + * the given collection will accept. */ - public Map getAcceptPackaging(Collection col) - { + public Map getAcceptPackaging(Collection col) { Map identifiers = new HashMap(); Map qs = new HashMap(); String handle = col.getHandle(); @@ -385,37 +364,28 @@ public class SWORDConfiguration // build the holding maps of identifiers and q values String acceptPackagingPrefix = "sword-server.accept-packaging"; List keys = configurationService.getPropertyKeys(acceptPackagingPrefix); - for (String key : keys) - { + for (String key : keys) { // extract the configuration into the holding Maps - String suffix = key.substring(acceptPackagingPrefix.length()+1); + String suffix = key.substring(acceptPackagingPrefix.length() + 1); String[] bits = suffix.split("\\."); - if (bits.length == 2) - { + if (bits.length == 2) { // global settings String value = configurationService.getProperty(key); - if (bits[1].equals("identifier")) - { + if (bits[1].equals("identifier")) { identifiers.put(bits[0], value); - } - else if (bits[1].equals("q")) - { + } else if (bits[1].equals("q")) { qs.put(bits[0], value); } } // collection settings - if (bits.length == 3 && bits[0].equals(handle)) - { + if (bits.length == 3 && bits[0].equals(handle)) { // this is configuration for our collection String value = configurationService.getProperty(key); - if (bits[2].equals("identifier")) - { + if (bits[2].equals("identifier")) { identifiers.put(bits[1], value); - } - else if (bits[2].equals("q")) - { + } else if (bits[2].equals("q")) { qs.put(bits[1], value); } } @@ -423,8 +393,7 @@ public class SWORDConfiguration // merge the holding maps into the Accept Packaging settings Map ap = new HashMap(); - for (String ik : identifiers.keySet()) - { + for (String ik : identifiers.keySet()) { String id = identifiers.get(ik); String qv = qs.get(ik); Float qf = Float.parseFloat(qv); @@ -438,38 +407,28 @@ public class SWORDConfiguration * Is the given packaging/media type supported by the given DSpace * object? * - * @param mediaType - * packaging/media type to check - * @param dso - * target DSpace object + * @param mediaType packaging/media type to check + * @param dso target DSpace object * @return true if the given packaging/media type is supported by the - * given DSpace object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * given DSpace object + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ public boolean isSupportedMediaType(String mediaType, DSpaceObject dso) - throws DSpaceSWORDException, SWORDErrorException - { - if (mediaType == null || "".equals(mediaType)) - { + throws DSpaceSWORDException, SWORDErrorException { + if (mediaType == null || "".equals(mediaType)) { return true; } - if (dso instanceof Collection) - { + if (dso instanceof Collection) { Map accepts = this - .getAcceptPackaging((Collection) dso); - for (String accept : accepts.keySet()) - { - if (accept.equals(mediaType)) - { + .getAcceptPackaging((Collection) dso); + for (String accept : accepts.keySet()) { + if (accept.equals(mediaType)) { return true; } } - } - else if (dso instanceof Item) - { + } else if (dso instanceof Item) { // items don't unpackage, so they don't care what the media type is return true; } @@ -479,21 +438,16 @@ public class SWORDConfiguration /** * Is the given content MIME type acceptable to the given DSpace object? * - * @param context - * The relevant DSpace Context. - * @param type - * MIME type to check - * @param dso - * target DSpace object + * @param context The relevant DSpace Context. + * @param type MIME type to check + * @param dso target DSpace object * @return true if the given content MIME type is acceptable - * to the given DSpace object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * to the given DSpace object + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isAcceptableContentType(Context context, String type, - DSpaceObject dso) - throws DSpaceSWORDException - { + DSpaceObject dso) + throws DSpaceSWORDException { List accepts = this.getAccepts(context, dso); return accepts.contains(type); } @@ -502,14 +456,12 @@ public class SWORDConfiguration * Get the temp directory for storing files during deposit. * * @return temp directory for storing files during deposit - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getTempDir() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { return (configurationService.getProperty("upload.temp.dir") != null) - ? configurationService.getProperty("upload.temp.dir") + ? configurationService.getProperty("upload.temp.dir") : System.getProperty("java.io.tmpdir"); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDContext.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDContext.java index 2c167e37b6..c473ea8714 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDContext.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDContext.java @@ -33,51 +33,53 @@ import org.dspace.eperson.EPerson; * class * * @author Richard Jones - * */ -public class SWORDContext -{ - /** The primary authenticated user for the request */ +public class SWORDContext { + /** + * The primary authenticated user for the request + */ private EPerson authenticated = null; - /** The onBehalfOf user for the request */ + /** + * The onBehalfOf user for the request + */ private EPerson onBehalfOf = null; - /** The primary context, representing the on behalf of user if exists, and the authenticated user if not */ + /** + * The primary context, representing the on behalf of user if exists, and the authenticated user if not + */ private Context context; - /** the context for the authenticated user, which may not, therefore, be the primary context also */ + /** + * the context for the authenticated user, which may not, therefore, be the primary context also + */ private Context authenticatorContext; /** * @return the authenticated user */ - public EPerson getAuthenticated() - { + public EPerson getAuthenticated() { return authenticated; } /** - * @param authenticated the eperson to set + * @param authenticated the eperson to set */ - public void setAuthenticated(EPerson authenticated) - { + public void setAuthenticated(EPerson authenticated) { this.authenticated = authenticated; } /** * @return the onBehalfOf user */ - public EPerson getOnBehalfOf() - { + public EPerson getOnBehalfOf() { return onBehalfOf; } /** - * @param onBehalfOf the eperson to set + * @param onBehalfOf the eperson to set */ - public void setOnBehalfOf(EPerson onBehalfOf) - { + public void setOnBehalfOf(EPerson onBehalfOf) { this.onBehalfOf = onBehalfOf; } @@ -88,13 +90,11 @@ public class SWORDContext * * @return appropriate DSpace context */ - public Context getContext() - { + public Context getContext() { return context; } - public void setContext(Context context) - { + public void setContext(Context context) { this.context = context; } @@ -109,13 +109,11 @@ public class SWORDContext * * @return DSpace context of the user who authenticated */ - public Context getAuthenticatorContext() - { + public Context getAuthenticatorContext() { return authenticatorContext; } - public void setAuthenticatorContext(Context authenticatorContext) - { + public void setAuthenticatorContext(Context authenticatorContext) { this.authenticatorContext = authenticatorContext; } @@ -130,11 +128,9 @@ public class SWORDContext * * @return DSpace context of the on-behalf-of user */ - public Context getOnBehalfOfContext() - { + public Context getOnBehalfOfContext() { // return the obo context if this is an obo deposit, else return null - if (this.onBehalfOf != null) - { + if (this.onBehalfOf != null) { return context; } return null; @@ -144,16 +140,13 @@ public class SWORDContext * Abort all of the contexts held by this class. No changes will * be written to the database */ - public void abort() - { + public void abort() { // abort both contexts - if (context != null && context.isValid()) - { + if (context != null && context.isValid()) { context.abort(); } - if (authenticatorContext != null && authenticatorContext.isValid()) - { + if (authenticatorContext != null && authenticatorContext.isValid()) { authenticatorContext.abort(); } } @@ -168,25 +161,19 @@ public class SWORDContext * @throws DSpaceSWORDException on database error. */ public void commit() - throws DSpaceSWORDException - { - try - { + throws DSpaceSWORDException { + try { // commit the primary context - if (context != null && context.isValid()) - { + if (context != null && context.isValid()) { context.complete(); } // the secondary context is for filtering permissions by only, and is // never committed, so we abort here - if (authenticatorContext != null && authenticatorContext.isValid()) - { + if (authenticatorContext != null && authenticatorContext.isValid()) { authenticatorContext.abort(); } - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSWORDException(e); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDIngester.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDIngester.java index 212e02d3f5..ee581977be 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDIngester.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDIngester.java @@ -8,7 +8,6 @@ package org.dspace.sword; import org.dspace.content.DSpaceObject; - import org.purl.sword.base.Deposit; import org.purl.sword.base.SWORDErrorException; @@ -18,26 +17,20 @@ import org.purl.sword.base.SWORDErrorException; * be obtained via the SWORDIngesterFactory class. * * @author Richard Jones - * */ -public interface SWORDIngester -{ +public interface SWORDIngester { /** * Ingest the package as described in the given Deposit object * within the given DSpace Context * - * @param service - * SWORD service - * @param deposit - * deposit request - * @param target - * target DSpace object + * @param service SWORD service + * @param deposit deposit request + * @param target target DSpace object * @return the result of the deposit - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ DepositResult ingest(SWORDService service, Deposit deposit, - DSpaceObject target) - throws DSpaceSWORDException, SWORDErrorException; + DSpaceObject target) + throws DSpaceSWORDException, SWORDErrorException; } diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDIngesterFactory.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDIngesterFactory.java index a2d8ecdba8..41afe67fd5 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDIngesterFactory.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDIngesterFactory.java @@ -7,26 +7,29 @@ */ package org.dspace.sword; -import org.dspace.core.Context; -import org.dspace.content.DSpaceObject; import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; import org.dspace.content.Item; +import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.core.service.PluginService; - import org.purl.sword.base.Deposit; -import org.purl.sword.base.SWORDErrorException; import org.purl.sword.base.ErrorCodes; +import org.purl.sword.base.SWORDErrorException; /** * Factory class which will mint objects conforming to the * SWORDIngester interface. * * @author Richard Jones - * */ -public class SWORDIngesterFactory -{ +public class SWORDIngesterFactory { + + /** + * Default constructor + */ + private SWORDIngesterFactory() { } + /** * Generate an object which conforms to the SWORDIngester interface. * This Factory method may use the given DSpace context and the given @@ -37,40 +40,30 @@ public class SWORDIngesterFactory * for the appropriate media types and defaults. See the SWORD configuration * documentation for more details. * - * @param context - * The relevant DSpace Context. - * @param deposit - * deposit request - * @param dso - * target DSpace object + * @param context The relevant DSpace Context. + * @param deposit deposit request + * @param dso target DSpace object * @return SWORD ingester implementation - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ public static SWORDIngester getInstance(Context context, Deposit deposit, - DSpaceObject dso) - throws DSpaceSWORDException, SWORDErrorException - { + DSpaceObject dso) + throws DSpaceSWORDException, SWORDErrorException { PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); - if (dso instanceof Collection) - { + if (dso instanceof Collection) { SWORDIngester ingester = (SWORDIngester) pluginService .getNamedPlugin(SWORDIngester.class, deposit.getPackaging()); - if (ingester == null) - { + if (ingester == null) { throw new SWORDErrorException(ErrorCodes.ERROR_CONTENT, - "No ingester configured for this package type"); + "No ingester configured for this package type"); } return ingester; - } - else if (dso instanceof Item) - { + } else if (dso instanceof Item) { SWORDIngester ingester = (SWORDIngester) pluginService .getNamedPlugin(SWORDIngester.class, "SimpleFileIngester"); - if (ingester == null) - { + if (ingester == null) { throw new DSpaceSWORDException( "SimpleFileIngester is not configured in plugin manager"); } diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDMETSIngester.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDMETSIngester.java index c02035fbe5..d734256501 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDMETSIngester.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDMETSIngester.java @@ -13,8 +13,10 @@ import java.util.Date; import java.util.StringTokenizer; import org.apache.log4j.Logger; - -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.packager.PackageIngester; import org.dspace.content.packager.PackageParameters; @@ -22,36 +24,33 @@ import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; - import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; import org.purl.sword.base.Deposit; import org.purl.sword.base.SWORDErrorException; -public class SWORDMETSIngester implements SWORDIngester -{ +public class SWORDMETSIngester implements SWORDIngester { private SWORDService swordService; protected ItemService itemService = ContentServiceFactory.getInstance() - .getItemService(); + .getItemService(); - /** Log4j logger */ + /** + * Log4j logger + */ public static final Logger log = Logger.getLogger(SWORDMETSIngester.class); /* (non-Javadoc) * @see org.dspace.sword.SWORDIngester#ingest(org.dspace.core.Context, org.purl.sword.base.Deposit) */ public DepositResult ingest(SWORDService service, Deposit deposit, - DSpaceObject dso) - throws DSpaceSWORDException, SWORDErrorException - { - try - { + DSpaceObject dso) + throws DSpaceSWORDException, SWORDErrorException { + try { // first, make sure this is the right kind of ingester, and set the collection - if (!(dso instanceof Collection)) - { + if (!(dso instanceof Collection)) { throw new DSpaceSWORDException( - "Tried to run an ingester on wrong target type"); + "Tried to run an ingester on wrong target type"); } Collection collection = (Collection) dso; @@ -66,17 +65,16 @@ public class SWORDMETSIngester implements SWORDIngester // load the plugin manager for the required configuration String cfg = ConfigurationManager.getProperty("sword-server", - "mets-ingester.package-ingester"); - if (cfg == null || "".equals(cfg)) - { + "mets-ingester.package-ingester"); + if (cfg == null || "".equals(cfg)) { cfg = "METS"; // default to METS } swordService.message("Using package manifest format: " + cfg); PackageIngester pi = (PackageIngester) CoreServiceFactory.getInstance().getPluginService() - .getNamedPlugin(PackageIngester.class, cfg); + .getNamedPlugin(PackageIngester.class, cfg); swordService.message( - "Loaded package ingester: " + pi.getClass().getName()); + "Loaded package ingester: " + pi.getClass().getName()); // the licence is either in the zip or the mets manifest. Either way // it's none of our business here @@ -90,38 +88,33 @@ public class SWORDMETSIngester implements SWORDIngester // Should restore mode be enabled, i.e. keep existing handle? if (ConfigurationManager - .getBooleanProperty("sword-server", "restore-mode.enable", - false)) - { + .getBooleanProperty("sword-server", "restore-mode.enable", + false)) { params.setRestoreModeEnabled(true); } // Whether or not to use the collection template params.setUseCollectionTemplate(ConfigurationManager - .getBooleanProperty( - "mets.default.ingest.useCollectionTemplate", - false)); + .getBooleanProperty( + "mets.default.ingest.useCollectionTemplate", + false)); // ingest the item from the temp file DSpaceObject ingestedObject = pi - .ingest(context, collection, depositFile, params, licence); - if (ingestedObject == null) - { + .ingest(context, collection, depositFile, params, licence); + if (ingestedObject == null) { swordService.message( - "Failed to ingest the package; throwing exception"); + "Failed to ingest the package; throwing exception"); throw new SWORDErrorException( - DSpaceSWORDErrorCodes.UNPACKAGE_FAIL, - "METS package ingester failed to unpack package"); + DSpaceSWORDErrorCodes.UNPACKAGE_FAIL, + "METS package ingester failed to unpack package"); } //Verify we have an Item as a result -- SWORD can only ingest Items - if (!(ingestedObject instanceof Item)) - { + if (!(ingestedObject instanceof Item)) { throw new DSpaceSWORDException( - "DSpace Ingester returned wrong object type -- not an Item result."); - } - else - { + "DSpace Ingester returned wrong object type -- not an Item result."); + } else { //otherwise, we have an item, and a workflow should have already been started for it. swordService.message("Workflow process started"); } @@ -148,21 +141,18 @@ public class SWORDMETSIngester implements SWORDIngester // for some reason, DSpace will not give you the handle automatically, // so we have to look it up HandleService handleService = HandleServiceFactory.getInstance() - .getHandleService(); + .getHandleService(); String handle = handleService.findHandle(context, installedItem); swordService.message("Ingest successful"); swordService.message("Item created with internal identifier: " + - installedItem.getID()); - if (handle != null) - { + installedItem.getID()); + if (handle != null) { swordService.message( - "Item created with external identifier: " + handle); - } - else - { + "Item created with external identifier: " + handle); + } else { swordService.message( - "No external identifier available at this stage (item in workflow)"); + "No external identifier available at this stage (item in workflow)"); } DepositResult dr = new DepositResult(); @@ -171,14 +161,10 @@ public class SWORDMETSIngester implements SWORDIngester dr.setTreatment(this.getTreatment()); return dr; - } - catch (RuntimeException re) - { + } catch (RuntimeException re) { log.error("caught exception: ", re); throw re; - } - catch (Exception e) - { + } catch (Exception e) { log.error("caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -189,39 +175,33 @@ public class SWORDMETSIngester implements SWORDIngester * the field in which to store this metadata in the configuration * sword.updated.field * - * * @param context * @param item * @throws DSpaceSWORDException */ private void setUpdatedDate(Context context, Item item) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { String field = ConfigurationManager - .getProperty("sword-server", "updated.field"); - if (field == null || "".equals(field)) - { + .getProperty("sword-server", "updated.field"); + if (field == null || "".equals(field)) { throw new DSpaceSWORDException( - "No configuration, or configuration is invalid for: sword.updated.field"); + "No configuration, or configuration is invalid for: sword.updated.field"); } MetadataFieldInfo dc = this.configToDC(field, null); - try - { + try { itemService.clearMetadata(context, item, dc.schema, dc.element, - dc.qualifier, Item.ANY); + dc.qualifier, Item.ANY); DCDate date = new DCDate(new Date()); itemService.addMetadata(context, item, dc.schema, dc.element, - dc.qualifier, null, date.toString()); - } - catch (SQLException e) - { + dc.qualifier, null, date.toString()); + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } swordService.message( - "Updated date added to response from item metadata where available"); + "Updated date added to response from item metadata where available"); } /** @@ -235,33 +215,27 @@ public class SWORDMETSIngester implements SWORDIngester * @throws DSpaceSWORDException */ private void setSlug(Item item, String slugVal) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // if there isn't a slug value, don't set it - if (slugVal == null) - { + if (slugVal == null) { return; } String field = ConfigurationManager - .getProperty("sword-server", "slug.field"); - if (field == null || "".equals(field)) - { + .getProperty("sword-server", "slug.field"); + if (field == null || "".equals(field)) { throw new DSpaceSWORDException( - "No configuration, or configuration is invalid for: sword.slug.field"); + "No configuration, or configuration is invalid for: sword.slug.field"); } MetadataFieldInfo mfi = this.configToDC(field, null); - try - { + try { itemService - .clearMetadata(swordService.getContext(), item, mfi.schema, - mfi.element, mfi.qualifier, Item.ANY); + .clearMetadata(swordService.getContext(), item, mfi.schema, + mfi.element, mfi.qualifier, Item.ANY); itemService.addMetadata(swordService.getContext(), item, mfi.schema, - mfi.element, mfi.qualifier, null, slugVal); - } - catch (SQLException e) - { + mfi.element, mfi.qualifier, null, slugVal); + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } @@ -271,18 +245,17 @@ public class SWORDMETSIngester implements SWORDIngester /** * utility method to turn given metadata fields of the form - schema.element.qualifier into Metadatum objects which can be - used to access metadata in items. + * schema.element.qualifier into Metadatum objects which can be + * used to access metadata in items. * * The def parameter should be null, * or "" depending on how - you intend to use the Metadatum object + * you intend to use the Metadatum object * * @param config * @param def * @return */ - private MetadataFieldInfo configToDC(String config, String def) - { + private MetadataFieldInfo configToDC(String config, String def) { MetadataFieldInfo mfi = new MetadataFieldInfo(); mfi.schema = def; mfi.element = def; @@ -291,8 +264,7 @@ public class SWORDMETSIngester implements SWORDIngester StringTokenizer stz = new StringTokenizer(config, "."); mfi.schema = stz.nextToken(); mfi.element = stz.nextToken(); - if (stz.hasMoreTokens()) - { + if (stz.hasMoreTokens()) { mfi.qualifier = stz.nextToken(); } @@ -306,16 +278,14 @@ public class SWORDMETSIngester implements SWORDIngester * @return * @throws DSpaceSWORDException */ - private String getTreatment() throws DSpaceSWORDException - { + private String getTreatment() throws DSpaceSWORDException { return "The package has been deposited into DSpace. Each file has been unpacked " + - "and provided with a unique identifier. The metadata in the manifest has been " + - "extracted and attached to the DSpace item, which has been provided with " + - "an identifier leading to an HTML splash page."; + "and provided with a unique identifier. The metadata in the manifest has been " + + "extracted and attached to the DSpace item, which has been provided with " + + "an identifier leading to an HTML splash page."; } - private class MetadataFieldInfo - { + private class MetadataFieldInfo { private String schema; private String element; diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDProperties.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDProperties.java index 28fb8db1d5..d84ef6fe4f 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDProperties.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDProperties.java @@ -7,9 +7,10 @@ */ package org.dspace.sword; -public interface SWORDProperties -{ - /** The version of the SWORD service we are offering */ +public interface SWORDProperties { + /** + * The version of the SWORD service we are offering + */ public static final String VERSION = "1.3"; public static final String SOFTWARE_URI = "http://www.dspace.org/ns/sword/1.3.1"; diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDService.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDService.java index daf7acc306..6bb30e2f23 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDService.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDService.java @@ -8,17 +8,15 @@ package org.dspace.sword; import java.sql.SQLException; -import java.util.Date; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.List; import org.apache.log4j.Logger; - +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.content.BitstreamFormat; - import org.purl.sword.base.Deposit; /** @@ -30,97 +28,97 @@ import org.purl.sword.base.Deposit; * * It is ubiquitous in the sword implementation, and all related * information and services should be retrieved via this API. - * */ -public class SWORDService -{ - /** Log4j logging instance */ +public class SWORDService { + /** + * Log4j logging instance + */ public static final Logger log = Logger.getLogger(SWORDService.class); protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory - .getInstance().getBitstreamFormatService(); + .getInstance().getBitstreamFormatService(); - /** The SWORD context of the request */ + /** + * The SWORD context of the request + */ private SWORDContext swordContext; - /** The configuration of the sword server instance */ + /** + * The configuration of the sword server instance + */ private SWORDConfiguration swordConfig; - /** The URL Generator */ + /** + * The URL Generator + */ private SWORDUrlManager urlManager; - /** a holder for the messages coming through from the implementation */ + /** + * a holder for the messages coming through from the implementation + */ private StringBuilder verboseDescription = new StringBuilder(); - /** is this a verbose operation */ + /** + * is this a verbose operation + */ private boolean verbose = false; - /** date formatter */ + /** + * date formatter + */ private SimpleDateFormat dateFormat; /** * Construct a new service instance around the given authenticated * SWORD context * - * @param sc - * authenticated SWORD context + * @param sc authenticated SWORD context */ - public SWORDService(SWORDContext sc) - { + public SWORDService(SWORDContext sc) { this.swordContext = sc; this.swordConfig = new SWORDConfiguration(); this.urlManager = new SWORDUrlManager(this.swordConfig, - this.swordContext.getContext()); + this.swordContext.getContext()); dateFormat = new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss.S]"); } - public SWORDUrlManager getUrlManager() - { + public SWORDUrlManager getUrlManager() { return urlManager; } - public void setUrlManager(SWORDUrlManager urlManager) - { + public void setUrlManager(SWORDUrlManager urlManager) { this.urlManager = urlManager; } - public SWORDContext getSwordContext() - { + public SWORDContext getSwordContext() { return swordContext; } - public void setSwordContext(SWORDContext swordContext) - { + public void setSwordContext(SWORDContext swordContext) { this.swordContext = swordContext; } - public SWORDConfiguration getSwordConfig() - { + public SWORDConfiguration getSwordConfig() { return swordConfig; } - public void setSwordConfig(SWORDConfiguration swordConfig) - { + public void setSwordConfig(SWORDConfiguration swordConfig) { this.swordConfig = swordConfig; } - public Context getContext() - { + public Context getContext() { return this.swordContext.getContext(); } - public boolean isVerbose() - { + public boolean isVerbose() { return verbose; } - public void setVerbose(boolean verbose) - { + public void setVerbose(boolean verbose) { this.verbose = verbose; } - public StringBuilder getVerboseDescription() - { + public StringBuilder getVerboseDescription() { return verboseDescription; } @@ -130,17 +128,14 @@ public class SWORDService * verbose, meaning we don't have to do it inline and break nice * looking code up * - * @param message - * message to register with the verboseDescription member variable + * @param message message to register with the verboseDescription member variable */ - public void message(String message) - { + public void message(String message) { // build the processing message String msg = dateFormat.format(new Date()) + " " + message + "; \n\n"; // if this is a verbose deposit, then log it - if (this.verbose) - { + if (this.verbose) { verboseDescription.append(msg); } @@ -151,48 +146,37 @@ public class SWORDService /** * Construct the most appropriate filename for the incoming deposit. * - * @param context - * The relevant DSpace Context. - * @param deposit - * deposit request - * @param original - * is original? + * @param context The relevant DSpace Context. + * @param deposit deposit request + * @param original is original? * @return the most appropriate filename for the incoming deposit * @throws DSpaceSWORDException on database error. */ public String getFilename(Context context, Deposit deposit, - boolean original) - throws DSpaceSWORDException - { - try - { + boolean original) + throws DSpaceSWORDException { + try { BitstreamFormat bf = bitstreamFormatService.findByMIMEType( context, deposit.getContentType()); List exts = null; - if (bf != null) - { + if (bf != null) { exts = bf.getExtensions(); } String fn = deposit.getFilename(); - if (fn == null || "".equals(fn)) - { + if (fn == null || "".equals(fn)) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); fn = "sword-" + sdf.format(new Date()); - if (original) - { + if (original) { fn = fn + ".original"; } - if (exts != null && !exts.isEmpty()) - { + if (exts != null && !exts.isEmpty()) { fn = fn + "." + exts.get(0); } } return fn; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSWORDException(e); } } @@ -202,8 +186,7 @@ public class SWORDService * * @return the name of the temp file that should be used */ - public String getTempFilename() - { + public String getTempFilename() { return "sword-" + (new Date()).getTime(); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/SWORDUrlManager.java b/dspace-sword/src/main/java/org/dspace/sword/SWORDUrlManager.java index c3f1861cb1..ab0409c9e5 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SWORDUrlManager.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SWORDUrlManager.java @@ -7,8 +7,18 @@ */ package org.dspace.sword; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.SQLException; +import java.util.List; + import org.apache.commons.lang.StringUtils; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +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.BitstreamService; import org.dspace.core.ConfigurationManager; @@ -17,23 +27,21 @@ import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; import org.purl.sword.base.SWORDErrorException; -import java.sql.SQLException; -import java.net.URL; -import java.net.MalformedURLException; -import java.util.List; - /** * @author Richard Jones * * Class responsible for constructing and de-constructing sword url space * urls */ -public class SWORDUrlManager -{ - /** the SWORD configuration */ +public class SWORDUrlManager { + /** + * the SWORD configuration + */ private SWORDConfiguration config; - /** the active DSpace context */ + /** + * the active DSpace context + */ private Context context; protected HandleService handleService = @@ -42,8 +50,7 @@ public class SWORDUrlManager protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - public SWORDUrlManager(SWORDConfiguration config, Context context) - { + public SWORDUrlManager(SWORDConfiguration config, Context context) { this.config = config; this.context = context; } @@ -54,12 +61,10 @@ public class SWORDUrlManager * * @return the generator URL for ATOM entry documents */ - public String getGeneratorUrl() - { + public String getGeneratorUrl() { String cfg = ConfigurationManager.getProperty( "sword-server", "generator.url"); - if (cfg == null || "".equals(cfg)) - { + if (cfg == null || "".equals(cfg)) { return SWORDProperties.SOFTWARE_URI; } return cfg; @@ -70,15 +75,12 @@ public class SWORDUrlManager * should not be considered persistent, but will remain consistent * unless configuration changes are made to DSpace * - * @param collection - * the collection to query + * @param collection the collection to query * @return The Deposit URL - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getDepositLocation(Collection collection) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { return this.getBaseDepositUrl() + "/" + collection.getHandle(); } @@ -87,15 +89,12 @@ public class SWORDUrlManager * should not be considered persistent, but will remain consistent * unless configuration changes are made to DSpace * - * @param item - * the item to query + * @param item the item to query * @return The Deposit URL - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getDepositLocation(Item item) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { return this.getBaseDepositUrl() + "/" + item.getHandle(); } @@ -104,15 +103,12 @@ public class SWORDUrlManager * should not be considered persistent, but will remain consistent * unless configuration changes are made to DSpace * - * @param community - * the community to query + * @param community the community to query * @return The Deposit URL - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getDepositLocation(Community community) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { // FIXME: there is no deposit url for communities yet, so this could // be misleading return this.getBaseDepositUrl() + "/" + community.getHandle(); @@ -122,49 +118,40 @@ public class SWORDUrlManager * Obtain the collection which is represented by the given * URL * - * @param context the DSpace context - * @param location the URL to resolve to a collection + * @param context the DSpace context + * @param location the URL to resolve to a collection * @return The collection to which the url resolves - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ // FIXME: we need to generalise this to DSpaceObjects, so that we can support // Communities, Collections and Items separately public Collection getCollection(Context context, String location) - throws DSpaceSWORDException, SWORDErrorException - { - try - { + throws DSpaceSWORDException, SWORDErrorException { + try { String baseUrl = this.getBaseDepositUrl(); - if (baseUrl.length() == location.length()) - { + if (baseUrl.length() == location.length()) { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "The deposit URL is incomplete"); + "The deposit URL is incomplete"); } String handle = location.substring(baseUrl.length()); - if (handle.startsWith("/")) - { + if (handle.startsWith("/")) { handle = handle.substring(1); } - if ("".equals(handle)) - { + if ("".equals(handle)) { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "The deposit URL is incomplete"); + "The deposit URL is incomplete"); } DSpaceObject dso = handleService.resolveToObject(context, handle); - if (!(dso instanceof Collection)) - { + if (!(dso instanceof Collection)) { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "The deposit URL does not resolve to a valid collection"); + "The deposit URL does not resolve to a valid collection"); } return (Collection) dso; - } - catch (SQLException e) - { + } catch (SQLException e) { // log.error("Caught exception:", e); throw new DSpaceSWORDException( "There was a problem resolving the collection", e); @@ -175,47 +162,38 @@ public class SWORDUrlManager * Obtain the collection which is represented by the given * URL * - * @param context the DSpace context - * @param location the URL to resolve to a collection + * @param context the DSpace context + * @param location the URL to resolve to a collection * @return The collection to which the url resolves - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ public DSpaceObject getDSpaceObject(Context context, String location) - throws DSpaceSWORDException, SWORDErrorException - { - try - { + throws DSpaceSWORDException, SWORDErrorException { + try { String baseUrl = this.getBaseDepositUrl(); - if (baseUrl.length() == location.length()) - { + if (baseUrl.length() == location.length()) { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "The deposit URL is incomplete"); + "The deposit URL is incomplete"); } String handle = location.substring(baseUrl.length()); - if (handle.startsWith("/")) - { + if (handle.startsWith("/")) { handle = handle.substring(1); } - if ("".equals(handle)) - { + if ("".equals(handle)) { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "The deposit URL is incomplete"); + "The deposit URL is incomplete"); } DSpaceObject dso = handleService.resolveToObject(context, handle); - if (!(dso instanceof Collection) && !(dso instanceof Item)) - { + if (!(dso instanceof Collection) && !(dso instanceof Item)) { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "The deposit URL does not resolve to a valid deposit target"); + "The deposit URL does not resolve to a valid deposit target"); } return dso; - } - catch (SQLException e) - { + } catch (SQLException e) { // log.error("Caught exception:", e); throw new DSpaceSWORDException( "There was a problem resolving the collection", e); @@ -227,15 +205,12 @@ public class SWORDUrlManager * be supplied in the sword:service element of other service document * entries. * - * @param community - * target community + * @param community target community * @return service document URL for the given object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String constructSubServiceUrl(Community community) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { String base = this.getBaseServiceDocumentUrl(); String handle = community.getHandle(); return base + "/" + handle; @@ -246,15 +221,12 @@ public class SWORDUrlManager * be supplied in the sword:service element of other service document * entries. * - * @param collection - * target collection + * @param collection target collection * @return service document URL for the given object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String constructSubServiceUrl(Collection collection) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { String base = this.getBaseServiceDocumentUrl(); String handle = collection.getHandle(); return base + "/" + handle; @@ -265,49 +237,38 @@ public class SWORDUrlManager * locate a meaningful and appropriate DSpace object it will throw the * appropriate SWORD error. * - * @param url - * URL to get DSpace object from + * @param url URL to get DSpace object from * @return DSpace object corresponding to given URL - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ public DSpaceObject extractDSpaceObject(String url) - throws DSpaceSWORDException, SWORDErrorException - { - try - { + throws DSpaceSWORDException, SWORDErrorException { + try { String sdBase = this.getBaseServiceDocumentUrl(); String mlBase = this.getBaseMediaLinkUrl(); - if (url.startsWith(sdBase)) - { + if (url.startsWith(sdBase)) { // we are dealing with a service document request // first, let's find the beginning of the handle url = url.substring(sdBase.length()); - if (url.startsWith("/")) - { + if (url.startsWith("/")) { url = url.substring(1); } - if (url.endsWith("/")) - { + if (url.endsWith("/")) { url = url.substring(0, url.length() - 1); } DSpaceObject dso = handleService.resolveToObject(context, url); - if (dso instanceof Collection || dso instanceof Community) - { + if (dso instanceof Collection || dso instanceof Community) { return dso; - } - else - { + } else { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "Service Document request does not refer to a DSpace Collection or Community"); + "Service Document request does not refer to a DSpace Collection or " + + "Community"); } - } - else if (url.startsWith(mlBase)) - { + } else if (url.startsWith(mlBase)) { // we are dealing with a bitstream media link // find the index of the "/bitstream/" segment of the url @@ -317,21 +278,16 @@ public class SWORDUrlManager String bsid = url.substring(bsi + 11); // strip off extraneous slashes - if (bsid.endsWith("/")) - { + if (bsid.endsWith("/")) { bsid = bsid.substring(0, url.length() - 1); } return bitstreamService.findByIdOrLegacyId(context, bsid); - } - else - { + } else { throw new SWORDErrorException(DSpaceSWORDErrorCodes.BAD_URL, - "Unable to recognise URL as a valid service document: " + - url); + "Unable to recognise URL as a valid service document: " + + url); } - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSWORDException(e); } } @@ -340,36 +296,29 @@ public class SWORDUrlManager * Get the base URL for service document requests. * * @return the base URL for service document requests - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getBaseServiceDocumentUrl() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { String depositUrl = ConfigurationManager.getProperty( "sword-server", "servicedocument.url"); - if (depositUrl == null || "".equals(depositUrl)) - { + if (depositUrl == null || "".equals(depositUrl)) { String dspaceUrl = ConfigurationManager.getProperty( "dspace.baseUrl"); - if (dspaceUrl == null || "".equals(dspaceUrl)) - { + if (dspaceUrl == null || "".equals(dspaceUrl)) { throw new DSpaceSWORDException( "Unable to construct service document urls, due to missing/invalid " + - "config in sword.servicedocument.url and/or dspace.baseUrl"); + "config in sword.servicedocument.url and/or dspace.baseUrl"); } - try - { + try { URL url = new URL(dspaceUrl); depositUrl = new URL(url.getProtocol(), url.getHost(), - url.getPort(), "/sword/servicedocument").toString(); - } - catch (MalformedURLException e) - { + url.getPort(), "/sword/servicedocument").toString(); + } catch (MalformedURLException e) { throw new DSpaceSWORDException( "Unable to construct service document urls, due to invalid dspace.baseUrl " + - e.getMessage(), e); + e.getMessage(), e); } } @@ -390,36 +339,29 @@ public class SWORDUrlManager * where dspace.baseUrl is also in the configuration file. * * @return the base URL for SWORD deposit - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getBaseDepositUrl() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { String depositUrl = ConfigurationManager.getProperty( "sword-server", "deposit.url"); - if (depositUrl == null || "".equals(depositUrl)) - { + if (depositUrl == null || "".equals(depositUrl)) { String dspaceUrl = ConfigurationManager.getProperty( "dspace.baseUrl"); - if (dspaceUrl == null || "".equals(dspaceUrl)) - { + if (dspaceUrl == null || "".equals(dspaceUrl)) { throw new DSpaceSWORDException( "Unable to construct deposit urls, due to missing/invalid config in " + - "sword.deposit.url and/or dspace.baseUrl"); + "sword.deposit.url and/or dspace.baseUrl"); } - try - { + try { URL url = new URL(dspaceUrl); depositUrl = new URL(url.getProtocol(), url.getHost(), - url.getPort(), "/sword/deposit").toString(); - } - catch (MalformedURLException e) - { + url.getPort(), "/sword/deposit").toString(); + } catch (MalformedURLException e) { throw new DSpaceSWORDException( "Unable to construct deposit urls, due to invalid dspace.baseUrl " + - e.getMessage(), e); + e.getMessage(), e); } } @@ -429,29 +371,24 @@ public class SWORDUrlManager /** * Is the given URL the base service document URL? * - * @param url - * URL to check + * @param url URL to check * @return true if the given URL the base service document URL - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isBaseServiceDocumentUrl(String url) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { return this.getBaseServiceDocumentUrl().equals(url); } /** * Is the given URL the base media link URL? * - * @param url - * URL to check + * @param url URL to check * @return true if the given URL the base media link URL * @throws DSpaceSWORDException passed through. */ public boolean isBaseMediaLinkUrl(String url) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { return this.getBaseMediaLinkUrl().equals(url); } @@ -459,57 +396,42 @@ public class SWORDUrlManager * Central location for constructing usable URLs for DSpace bitstreams. * There is no place in the main DSpace code base for doing this. * - * @param bitstream - * target bitstream + * @param bitstream target bitstream * @return a URL to the given Bitstream. - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getBitstreamUrl(Bitstream bitstream) - throws DSpaceSWORDException - { - try - { + throws DSpaceSWORDException { + try { List bundles = bitstream.getBundles(); Bundle parent = null; - if (!bundles.isEmpty()) - { + if (!bundles.isEmpty()) { parent = bundles.get(0); - } - else - { + } else { throw new DSpaceSWORDException( "Encountered orphaned bitstream"); } List items = parent.getItems(); Item item; - if (!items.isEmpty()) - { + if (!items.isEmpty()) { item = items.get(0); - } - else - { + } else { throw new DSpaceSWORDException("Encountered orphaned bundle"); } String handle = item.getHandle(); String bsLink = ConfigurationManager.getProperty("dspace.url"); - if (handle != null && !"".equals(handle)) - { + if (handle != null && !"".equals(handle)) { bsLink = bsLink + "/bitstream/" + handle + "/" + - bitstream.getSequenceID() + "/" + bitstream.getName(); - } - else - { + bitstream.getSequenceID() + "/" + bitstream.getName(); + } else { bsLink = bsLink + "/retrieve/" + bitstream.getID(); } return bsLink; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSWORDException(e); } } @@ -521,36 +443,29 @@ public class SWORDUrlManager * {@code /sword/media-link}. * * @return that URL. - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getBaseMediaLinkUrl() - throws DSpaceSWORDException - { + throws DSpaceSWORDException { String mlUrl = ConfigurationManager.getProperty( "sword-server", "media-link.url"); - if (StringUtils.isBlank(mlUrl)) - { + if (StringUtils.isBlank(mlUrl)) { String dspaceUrl = ConfigurationManager.getProperty( "dspace.baseUrl"); - if (dspaceUrl == null || "".equals(dspaceUrl)) - { + if (dspaceUrl == null || "".equals(dspaceUrl)) { throw new DSpaceSWORDException( "Unable to construct media-link urls, due to missing/invalid config in " + - "media-link.url and/or dspace.baseUrl"); + "media-link.url and/or dspace.baseUrl"); } - try - { + try { URL url = new URL(dspaceUrl); mlUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), - "/sword/media-link").toString(); - } - catch (MalformedURLException e) - { + "/sword/media-link").toString(); + } catch (MalformedURLException e) { throw new DSpaceSWORDException( "Unable to construct media-link urls, due to invalid dspace.baseUrl " + - e.getMessage(), e); + e.getMessage(), e); } } @@ -560,19 +475,15 @@ public class SWORDUrlManager /** * get the media link URL for the given item * - * @param dso - * target DSpace object + * @param dso target DSpace object * @return media link URL for the given item - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ private String getMediaLink(Item dso) - throws DSpaceSWORDException - { + throws DSpaceSWORDException { String ml = this.getBaseMediaLinkUrl(); String handle = dso.getHandle(); - if (handle != null) - { + if (handle != null) { ml = ml + "/" + dso.getHandle(); } return ml; @@ -581,50 +492,37 @@ public class SWORDUrlManager /** * Get the media link URL for the given bitstream. * - * @param bitstream - * target bitstream + * @param bitstream target bitstream * @return media link URL for the given bitstream - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation */ public String getMediaLink(Bitstream bitstream) - throws DSpaceSWORDException - { - try - { + throws DSpaceSWORDException { + try { List bundles = bitstream.getBundles(); Bundle parent = null; - if (!bundles.isEmpty()) - { + if (!bundles.isEmpty()) { parent = bundles.get(0); - } - else - { + } else { throw new DSpaceSWORDException( "Encountered orphaned bitstream"); } List items = parent.getItems(); Item item; - if (!items.isEmpty()) - { + if (!items.isEmpty()) { item = items.get(0); - } - else - { + } else { throw new DSpaceSWORDException("Encountered orphaned bundle"); } String itemUrl = this.getMediaLink(item); - if (itemUrl.equals(this.getBaseMediaLinkUrl())) - { + if (itemUrl.equals(this.getBaseMediaLinkUrl())) { return itemUrl; } return itemUrl + "/bitstream/" + bitstream.getID(); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSWORDException(e); } } diff --git a/dspace-sword/src/main/java/org/dspace/sword/ServiceDocumentManager.java b/dspace-sword/src/main/java/org/dspace/sword/ServiceDocumentManager.java index 187f53f86c..63ac543648 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/ServiceDocumentManager.java +++ b/dspace-sword/src/main/java/org/dspace/sword/ServiceDocumentManager.java @@ -7,37 +7,35 @@ */ package org.dspace.sword; +import java.util.List; + +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.CollectionService; import org.dspace.content.service.CommunityService; -import org.purl.sword.base.ServiceDocument; -import org.purl.sword.base.SWORDErrorException; -import org.purl.sword.base.Service; -import org.purl.sword.base.Workspace; -import org.purl.sword.atom.Generator; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; -import org.dspace.content.Community; -import org.dspace.content.Collection; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; +import org.purl.sword.atom.Generator; +import org.purl.sword.base.SWORDErrorException; +import org.purl.sword.base.Service; +import org.purl.sword.base.ServiceDocument; +import org.purl.sword.base.Workspace; -import java.util.List; - -public class ServiceDocumentManager -{ +public class ServiceDocumentManager { protected CollectionService collectionService = ContentServiceFactory - .getInstance().getCollectionService(); + .getInstance().getCollectionService(); protected CommunityService communityService = ContentServiceFactory - .getInstance().getCommunityService(); + .getInstance().getCommunityService(); private SWORDService swordService; private SWORDAuthenticator swordAuth; - public ServiceDocumentManager(SWORDService service) - { + public ServiceDocumentManager(SWORDService service) { this.swordService = service; this.swordAuth = new SWORDAuthenticator(); } @@ -48,19 +46,16 @@ public class ServiceDocumentManager * this object prior to calling this method. * * @return The service document based on the context of the request - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ public ServiceDocument getServiceDocument() - throws DSpaceSWORDException, SWORDErrorException - { + throws DSpaceSWORDException, SWORDErrorException { return this.getServiceDocument(null); } public ServiceDocument getServiceDocument(String url) - throws DSpaceSWORDException, SWORDErrorException - { + throws DSpaceSWORDException, SWORDErrorException { // extract the things we need from the service Context context = swordService.getContext(); SWORDContext swordContext = swordService.getSwordContext(); @@ -69,29 +64,27 @@ public class ServiceDocumentManager // construct the ATOM collection generators that we might use ATOMCollectionGenerator comGen = new CommunityCollectionGenerator( - swordService); + swordService); ATOMCollectionGenerator colGen = new CollectionCollectionGenerator( - swordService); + swordService); ATOMCollectionGenerator itemGen = new ItemCollectionGenerator( - swordService); + swordService); // first check that the context and sword context have // been set - if (context == null) - { + if (context == null) { throw new DSpaceSWORDException( "The Context is null; please set it before calling getServiceDocument"); } - if (swordContext == null) - { + if (swordContext == null) { throw new DSpaceSWORDException( "The SWORD Context is null; please set it before calling getServiceDocument"); } // construct a new service document Service service = new Service(SWORDProperties.VERSION, - swordConfig.isNoOp(), swordConfig.isVerbose()); + swordConfig.isNoOp(), swordConfig.isVerbose()); // set the max upload size service.setMaxUploadSize(swordConfig.getMaxUploadSize()); @@ -100,8 +93,7 @@ public class ServiceDocumentManager this.addGenerator(service); // - if (url == null || urlManager.isBaseServiceDocumentUrl(url)) - { + if (url == null || urlManager.isBaseServiceDocumentUrl(url)) { // we are dealing with the default service document // set the title of the workspace as per the name of the DSpace installation @@ -113,76 +105,63 @@ public class ServiceDocumentManager boolean swordCommunities = ConfigurationManager.getBooleanProperty( "sword-server", "expose-communities"); - if (swordCommunities) - { + if (swordCommunities) { List comms = swordAuth.getAllowedCommunities( swordContext); - for (Community comm : comms) - { + for (Community comm : comms) { org.purl.sword.base.Collection scol = comGen - .buildCollection(comm); + .buildCollection(comm); workspace.addCollection(scol); } - } - else - { + } else { List cols = swordAuth - .getAllowedCollections(swordContext); - for (Collection col : cols) - { + .getAllowedCollections(swordContext); + for (Collection col : cols) { org.purl.sword.base.Collection scol = colGen - .buildCollection(col); + .buildCollection(col); workspace.addCollection(scol); } } service.addWorkspace(workspace); - } - else - { + } else { // we are dealing with a partial or sub-service document DSpaceObject dso = urlManager.extractDSpaceObject(url); - if (dso instanceof Collection) - { + if (dso instanceof Collection) { Collection collection = (Collection) dso; Workspace workspace = new Workspace(); workspace.setTitle( - collectionService.getMetadata(collection, "name")); + collectionService.getMetadata(collection, "name")); List items = swordAuth - .getAllowedItems(swordContext, collection); - for (Item item : items) - { + .getAllowedItems(swordContext, collection); + for (Item item : items) { org.purl.sword.base.Collection scol = itemGen - .buildCollection(item); + .buildCollection(item); workspace.addCollection(scol); } service.addWorkspace(workspace); - } - else if (dso instanceof Community) - { + } else if (dso instanceof Community) { Community community = (Community) dso; Workspace workspace = new Workspace(); workspace.setTitle( - communityService.getMetadata(community, "name")); + communityService.getMetadata(community, "name")); List collections = swordAuth - .getAllowedCollections(swordContext, community); - for (Collection collection : collections) - { + .getAllowedCollections(swordContext, community); + for (Collection collection : collections) { org.purl.sword.base.Collection scol = colGen - .buildCollection(collection); + .buildCollection(collection); workspace.addCollection(scol); } List communities = swordAuth - .getCommunities(swordContext, community); - for (Community comm : communities) - { + .getCommunities(swordContext, community); + for (Community comm : communities) { org.purl.sword.base.Collection scol = comGen - .buildCollection(comm); + .buildCollection(comm); workspace.addCollection(scol); } @@ -198,14 +177,12 @@ public class ServiceDocumentManager * * @param service The service document to add the generator to */ - private void addGenerator(Service service) - { + private void addGenerator(Service service) { boolean identify = ConfigurationManager.getBooleanProperty( "sword-server", "identify-version", false); SWORDUrlManager urlManager = swordService.getUrlManager(); String softwareUri = urlManager.getGeneratorUrl(); - if (identify) - { + if (identify) { Generator generator = new Generator(); generator.setUri(softwareUri); generator.setVersion(SWORDProperties.VERSION); diff --git a/dspace-sword/src/main/java/org/dspace/sword/SimpleFileIngester.java b/dspace-sword/src/main/java/org/dspace/sword/SimpleFileIngester.java index 28bdbd3639..7db6764e7c 100644 --- a/dspace-sword/src/main/java/org/dspace/sword/SimpleFileIngester.java +++ b/dspace-sword/src/main/java/org/dspace/sword/SimpleFileIngester.java @@ -8,36 +8,33 @@ package org.dspace.sword; import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; import org.dspace.content.service.ItemService; import org.dspace.core.Constants; +import org.dspace.core.Context; import org.purl.sword.base.Deposit; import org.purl.sword.base.SWORDErrorException; -import org.dspace.content.Bitstream; -import org.dspace.content.BitstreamFormat; -import org.dspace.content.Bundle; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Item; -import org.dspace.core.Context; -import org.dspace.authorize.AuthorizeException; - -import java.sql.SQLException; -import java.io.IOException; -import java.util.List; /** * @author Richard Jones * * An implementation of the SWORDIngester interface for ingesting single * files into a DSpace Item - * */ -public class SimpleFileIngester implements SWORDIngester -{ +public class SimpleFileIngester implements SWORDIngester { protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); @@ -55,24 +52,17 @@ public class SimpleFileIngester implements SWORDIngester * Perform the ingest using the given deposit object onto the specified * target DSpace object, using the SWORD service implementation. * - * @param service - * SWORD service implementation - * @param deposit - * deposit request - * @param target - * target DSpace object - * @throws DSpaceSWORDException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SWORDErrorException on generic SWORD exception + * @param service SWORD service implementation + * @param deposit deposit request + * @param target target DSpace object + * @throws DSpaceSWORDException can be thrown by the internals of the DSpace SWORD implementation + * @throws SWORDErrorException on generic SWORD exception */ public DepositResult ingest(SWORDService service, Deposit deposit, - DSpaceObject target) - throws DSpaceSWORDException, SWORDErrorException - { - try - { - if (!(target instanceof Item)) - { + DSpaceObject target) + throws DSpaceSWORDException, SWORDErrorException { + try { + if (!(target instanceof Item)) { throw new DSpaceSWORDException( "SimpleFileIngester can only be loaded for deposit onto DSpace Items"); } @@ -87,32 +77,25 @@ public class SimpleFileIngester implements SWORDIngester List bundles = item.getBundles(); Bundle original = null; - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { original = bundle; break; } } - if (original == null) - { + if (original == null) { original = bundleService - .create(context, item, Constants.CONTENT_BUNDLE_NAME); + .create(context, item, Constants.CONTENT_BUNDLE_NAME); } Bitstream bs; FileInputStream fis = null; - try - { + try { fis = new FileInputStream(deposit.getFile()); bs = bitstreamService.create(context, original, fis); - } - finally - { - if (fis != null) - { + } finally { + if (fis != null) { fis.close(); } } @@ -124,8 +107,7 @@ public class SimpleFileIngester implements SWORDIngester BitstreamFormat bf = bitstreamFormatService.findByMIMEType( context, deposit.getContentType()); - if (bf != null) - { + if (bf != null) { bs.setFormat(context, bf); } @@ -145,9 +127,7 @@ public class SimpleFileIngester implements SWORDIngester result.setBitstream(bs); return result; - } - catch (SQLException | AuthorizeException | IOException e) - { + } catch (SQLException | AuthorizeException | IOException e) { throw new DSpaceSWORDException(e); } } @@ -157,8 +137,7 @@ public class SimpleFileIngester implements SWORDIngester * * @return the description */ - private String getTreatment() - { + private String getTreatment() { return "The file has been attached to the specified item"; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Accept.java b/dspace-sword/src/main/java/org/purl/sword/atom/Accept.java index 9028efb817..bfe92116f9 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Accept.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Accept.java @@ -7,29 +7,27 @@ */ package org.purl.sword.atom; -import org.purl.sword.base.*; +import org.purl.sword.base.BasicStringContentElement; +import org.purl.sword.base.Namespaces; +import org.purl.sword.base.XmlName; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class Accept extends BasicStringContentElement -{ +public class Accept extends BasicStringContentElement { /** - * The XmlName representation for this element. + * The XmlName representation for this element. */ private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_APP, "accept", Namespaces.NS_APP); + new XmlName(Namespaces.PREFIX_APP, "accept", Namespaces.NS_APP); - public Accept() - { + public Accept() { super(XML_NAME.getPrefix(), XML_NAME.getLocalName(), XML_NAME.getNamespace()); } - public Accept(String version) - { + public Accept(String version) { this(); - setContent(version); + setContent(version); } /** @@ -37,8 +35,7 @@ public class Accept extends BasicStringContentElement * * @return The prefix, localname and namespace for this element. */ - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Author.java b/dspace-sword/src/main/java/org/purl/sword/atom/Author.java index 3d544177ee..0eeba1716e 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Author.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Author.java @@ -10,342 +10,303 @@ package org.purl.sword.atom; import java.util.ArrayList; import java.util.List; import java.util.Properties; + import nu.xom.Element; import nu.xom.Elements; - import org.purl.sword.base.Namespaces; import org.purl.sword.base.SwordElementInterface; -import org.purl.sword.base.UnmarshallException; -import org.purl.sword.base.XmlElement; import org.purl.sword.base.SwordValidationInfo; import org.purl.sword.base.SwordValidationInfoType; +import org.purl.sword.base.UnmarshallException; +import org.purl.sword.base.XmlElement; import org.purl.sword.base.XmlName; /** - * Represents an Author type, as used in ATOM. This class is used as the - * base class for the different areas of ATOM that represent information + * Represents an Author type, as used in ATOM. This class is used as the + * base class for the different areas of ATOM that represent information * about people. This includes the atom:author and atom:contributor - * elements. - * + * elements. + * * @author Neil Taylor */ -public class Author extends XmlElement implements SwordElementInterface -{ +public class Author extends XmlElement implements SwordElementInterface { /** - * Local name for the element. - */ + * Local name for the element. + */ @Deprecated public static final String ELEMENT_NAME = "author"; - + /** - * Label for the 'name' attribute. + * Label for the 'name' attribute. */ @Deprecated public static final String ELEMENT_AUTHOR_NAME = "name"; - + /** - * Label for the 'uri' attribute. + * Label for the 'uri' attribute. */ @Deprecated public static final String ELEMENT_URI = "uri"; - + /** - * Label for the 'email' attribute. + * Label for the 'email' attribute. */ @Deprecated public static final String ELEMENT_EMAIL = "email"; - + /** - * The author's name. + * The author's name. */ private Name name; - + /** - * The author's URI. + * The author's URI. */ private Uri uri; - + /** - * The author's email. + * The author's email. */ private Email email; - + /** * */ private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "author", Namespaces.NS_ATOM); - + new XmlName(Namespaces.PREFIX_ATOM, "author", Namespaces.NS_ATOM); + /** - * Create a new instance and set the prefix to - * 'atom' and the local name to 'author'. + * Create a new instance and set the prefix to + * 'atom' and the local name to 'author'. */ - public Author() - { + public Author() { this(XML_NAME); } - - public Author(XmlName name) - { - super(name); + + public Author(XmlName name) { + super(name); } - + /** - * Create a new instance and set the element name. - * - * @param prefix The prefix to use when marshalling the data. - * @param localName The localName to use when marshalling the data. + * Create a new instance and set the element name. + * + * @param prefix The prefix to use when marshalling the data. + * @param localName The localName to use when marshalling the data. */ - public Author(String prefix, String localName ) - { + public Author(String prefix, String localName) { this(prefix, localName, XML_NAME.getNamespace()); } - + /** - * - * @param prefix The prefix to use when marshalling the data. - * @param localName The localName to use when marshalling the data. + * @param prefix The prefix to use when marshalling the data. + * @param localName The localName to use when marshalling the data. * @param namespaceUri The namespace URI. */ - public Author(String prefix, String localName, String namespaceUri) - { + public Author(String prefix, String localName, String namespaceUri) { super(prefix, localName, XML_NAME.getNamespace()); } - + /** - * Get the XmlName for this class. - * - * @return The prefix, localname and namespace for this element. - */ - public static XmlName elementName() - { - return XML_NAME; - } - + * Get the XmlName for this class. + * + * @return The prefix, localname and namespace for this element. + */ + public static XmlName elementName() { + return XML_NAME; + } + /** * Marshall the data in this object to a XOM Element. The element - * will have the full name that is specified in the constructor. - * - * @return A XOM Element. + * will have the full name that is specified in the constructor. + * + * @return A XOM Element. */ - public Element marshall() - { + public Element marshall() { Element element = new Element(getQualifiedName(), xmlName.getNamespace()); - - if ( name != null ) - { + + if (name != null) { element.appendChild(name.marshall()); } - - if ( uri != null ) - { + + if (uri != null) { element.appendChild(uri.marshall()); } - - if ( email != null ) - { + + if (email != null) { element.appendChild(email.marshall()); } - + return element; } - - + + /** * Unmarshall the author details from the specified element. The element * is a XOM element. * - * @param author The element to unmarshall. + * @param author The element to unmarshall. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info * @throws org.purl.sword.base.UnmarshallException passed through */ public SwordValidationInfo unmarshall(Element author, Properties validationProperties) - throws UnmarshallException - { - if ( ! isInstanceOf( author, xmlName) ) - { + throws UnmarshallException { + if (!isInstanceOf(author, xmlName)) { handleIncorrectElement(author, validationProperties); } - + ArrayList validationItems = new ArrayList(); ArrayList attributeItems = new ArrayList(); - + processUnexpectedAttributes(author, attributeItems); - + // retrieve all of the sub-elements Elements elements = author.getChildElements(); Element element = null; int length = elements.size(); - - for (int i = 0; i < length; i++ ) - { + + for (int i = 0; i < length; i++) { element = elements.get(i); - - if ( isInstanceOf(element, Name.elementName() )) - { + + if (isInstanceOf(element, Name.elementName())) { name = new Name(); validationItems.add(name.unmarshall(element, validationProperties)); - } - else if ( isInstanceOf(element, Uri.elementName())) - { + } else if (isInstanceOf(element, Uri.elementName())) { uri = new Uri(); validationItems.add(uri.unmarshall(element, validationProperties)); - } - else if ( isInstanceOf(element, Email.elementName() )) - { + } else if (isInstanceOf(element, Email.elementName())) { email = new Email(); validationItems.add(email.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(new XmlName(element), - SwordValidationInfo.UNKNOWN_ELEMENT, - SwordValidationInfoType.INFO); + SwordValidationInfo.UNKNOWN_ELEMENT, + SwordValidationInfoType.INFO); info.setContentDescription(element.getValue()); validationItems.add(info); } - + } // for - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(validationItems, attributeItems, validationProperties); } return result; } - - public SwordValidationInfo validate(Properties validationContext) - { + + public SwordValidationInfo validate(Properties validationContext) { return validate(null, null, validationContext); } - + public SwordValidationInfo validate(List elements, - List attributes, - Properties validationContext) - { + List attributes, + Properties validationContext) { SwordValidationInfo result = new SwordValidationInfo(xmlName); - - if ( name == null ) - { + + if (name == null) { SwordValidationInfo info = new SwordValidationInfo(Name.elementName(), - SwordValidationInfo.MISSING_ELEMENT_ERROR, - SwordValidationInfoType.ERROR); + SwordValidationInfo.MISSING_ELEMENT_ERROR, + SwordValidationInfoType.ERROR); result.addValidationInfo(info); + } else if (elements == null && name != null) { + result.addValidationInfo(name.validate(validationContext)); } - else if ( elements == null && name != null) - { - result.addValidationInfo(name.validate(validationContext)); - } - - if ( elements == null && uri != null ) - { + + if (elements == null && uri != null) { result.addValidationInfo(uri.validate(validationContext)); } - - if ( elements == null && email != null ) - { + + if (elements == null && email != null) { result.addValidationInfo(email.validate(validationContext)); } - + result.addUnmarshallValidationInfo(elements, attributes); return result; } - + /** - * Unmarshall the author details from the specified element. The element - * is a XOM element. - * - * @param author The element to unmarshall. + * Unmarshall the author details from the specified element. The element + * is a XOM element. + * + * @param author The element to unmarshall. */ public void unmarshall(Element author) - throws UnmarshallException - { + throws UnmarshallException { unmarshall(author, null); } - + /** - * Retrieve the author name. - * - * @return The name. + * Retrieve the author name. + * + * @return The name. */ - public String getName() - { - if ( name == null ) - { + public String getName() { + if (name == null) { return null; } return name.getContent(); } - + /** - * Set the author name. - * - * @param name The name. + * Set the author name. + * + * @param name The name. */ - public void setName(String name) - { + public void setName(String name) { this.name = new Name(name); } - + /** - * Get the author URI. - * - * @return The URI. + * Get the author URI. + * + * @return The URI. */ - public String getUri() - { - if ( uri == null ) - { + public String getUri() { + if (uri == null) { return null; } return uri.getContent(); } - + /** - * Set the author URI. - * - * @param uri the URI. + * Set the author URI. + * + * @param uri the URI. */ - public void setUri(String uri) - { + public void setUri(String uri) { this.uri = new Uri(uri); } - + /** - * Get the author email. - * - * @return The email. + * Get the author email. + * + * @return The email. */ - public String getEmail() - { - if ( email == null ) - { + public String getEmail() { + if (email == null) { return null; } return email.getContent(); } - + /** - * Set the author email. - * - * @param email The email. + * Set the author email. + * + * @param email The email. */ - public void setEmail(String email) - { + public void setEmail(String email) { this.email = new Email(email); - } - + } + /** - * Return the string. + * Return the string. + * * @return String. */ @Override - public String toString() - { + public String toString() { return "name: " + getName() + - " email: " + getEmail() + " uri: " + getUri(); + " email: " + getEmail() + " uri: " + getUri(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Category.java b/dspace-sword/src/main/java/org/purl/sword/atom/Category.java index 233810ebb4..78af057ab5 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Category.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Category.java @@ -7,30 +7,27 @@ */ package org.purl.sword.atom; -import org.purl.sword.base.*; +import org.purl.sword.base.BasicStringContentElement; +import org.purl.sword.base.Namespaces; +import org.purl.sword.base.XmlName; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class Category extends BasicStringContentElement -{ +public class Category extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "category", Namespaces.NS_ATOM); + new XmlName(Namespaces.PREFIX_ATOM, "category", Namespaces.NS_ATOM); - public Category() - { + public Category() { super(XML_NAME); } - public Category(String uri) - { + public Category(String uri) { this(); setContent(uri); } - public static XmlName elementName() - { - return XML_NAME; + public static XmlName elementName() { + return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Content.java b/dspace-sword/src/main/java/org/purl/sword/atom/Content.java index d786d39ecd..35e4bcf0ce 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Content.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Content.java @@ -10,276 +10,244 @@ package org.purl.sword.atom; import java.util.ArrayList; import java.util.List; import java.util.Properties; + import nu.xom.Attribute; import nu.xom.Element; - +import org.apache.log4j.Logger; import org.purl.sword.base.Namespaces; import org.purl.sword.base.SwordElementInterface; -import org.purl.sword.base.UnmarshallException; -import org.purl.sword.base.XmlElement; - -import org.apache.log4j.Logger; import org.purl.sword.base.SwordValidationInfo; import org.purl.sword.base.SwordValidationInfoType; +import org.purl.sword.base.UnmarshallException; +import org.purl.sword.base.XmlElement; import org.purl.sword.base.XmlName; /** - * Represents an ATOM Content element. - * + * Represents an ATOM Content element. + * * @author Neil Taylor */ -public class Content extends XmlElement implements SwordElementInterface -{ +public class Content extends XmlElement implements SwordElementInterface { /** - * The identifier for the src attribute. + * The identifier for the src attribute. */ public static final String ATTRIBUTE_SRC = "src"; - + /** - * The identifier for the type attribute. + * The identifier for the type attribute. */ public static final String ATTRIBUTE_TYPE = "type"; - + /** - * The data for the type attribute. + * The data for the type attribute. */ - private String type; - + private String type; + /** - * The data for the source attribute. + * The data for the source attribute. */ - private String source; - + private String source; + /** * The log. */ private static Logger log = Logger.getLogger(Content.class); - + /** - * + * */ private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "content", Namespaces.NS_ATOM); - + new XmlName(Namespaces.PREFIX_ATOM, "content", Namespaces.NS_ATOM); + /** - * Create a new instance and set the prefix to - * 'atom' and the local name to 'content'. + * Create a new instance and set the prefix to + * 'atom' and the local name to 'content'. */ - public Content() - { + public Content() { super(XML_NAME); } - - public static XmlName elementName() - { + + public static XmlName elementName() { return XML_NAME; } - + /** - * Get the Source. - * - * @return The Source. + * Get the Source. + * + * @return The Source. */ - public String getSource() - { + public String getSource() { return source; } - + /** - * Set the Source. - * - * @param source The source. + * Set the Source. + * + * @param source The source. */ - public void setSource(String source) - { + public void setSource(String source) { this.source = source; } - + /** - * Get the type. - * - * @return The type. + * Get the type. + * + * @return The type. */ - public String getType() - { + public String getType() { return type; } - + /** - * Set the type for the content. This should match the pattern + * Set the type for the content. This should match the pattern * ".* /.*" [Note, there is no space before the /, this has been added - * to allow this text to be written in a Java comment.]. - * - * An example of the type is application/zip. - * - * @param type The specified type. + * to allow this text to be written in a Java comment.]. + * + * An example of the type is application/zip. + * + * @param type The specified type. * @throws InvalidMediaTypeException If the specified type is null or - * it does not match the specified pattern. + * it does not match the specified pattern. */ public void setType(String type) - throws InvalidMediaTypeException - { - if ( type == null || ! type.matches(".*/.*") ) - { - throw new InvalidMediaTypeException("Type: '" + type + "' does not match .*/.*"); + throws InvalidMediaTypeException { + if (type == null || !type.matches(".*/.*")) { + throw new InvalidMediaTypeException("Type: '" + type + "' does not match .*/.*"); } - + this.type = type; } - + /** * Marshall the data in this object to an Element object. - * - * @return A XOM Element that holds the data for this Content element. + * + * @return A XOM Element that holds the data for this Content element. */ - public Element marshall() - { + public Element marshall() { Element content = new Element(getQualifiedName(), Namespaces.NS_ATOM); - - if ( type != null ) - { + + if (type != null) { Attribute typeAttribute = new Attribute(ATTRIBUTE_TYPE, type); content.addAttribute(typeAttribute); } - - if ( source != null ) - { + + if (source != null) { Attribute typeAttribute = new Attribute(ATTRIBUTE_SRC, source); content.addAttribute(typeAttribute); } - + return content; } - + public void unmarshall(Element content) - throws UnmarshallException - { + throws UnmarshallException { unmarshall(content, null); } - + /** - * Unmarshall the content element into the data in this object. - * - * @param content the element to unmarshall. + * Unmarshall the content element into the data in this object. + * + * @param content the element to unmarshall. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info * @throws UnmarshallException If the element does not contain a * content element or if there are problems - * accessing the data. + * accessing the data. */ public SwordValidationInfo unmarshall(Element content, Properties validationProperties) - throws UnmarshallException - { - if ( ! isInstanceOf( content, xmlName.getLocalName(), Namespaces.NS_ATOM)) - { + throws UnmarshallException { + if (!isInstanceOf(content, xmlName.getLocalName(), Namespaces.NS_ATOM)) { return handleIncorrectElement(content, validationProperties); } - + ArrayList elements = new ArrayList(); ArrayList attributes = new ArrayList(); - - try - { + + try { // get the attributes int attributeCount = content.getAttributeCount(); - Attribute attribute = null; - for ( int i = 0; i < attributeCount; i++ ) - { + Attribute attribute = null; + for (int i = 0; i < attributeCount; i++) { attribute = content.getAttribute(i); String name = attribute.getQualifiedName(); - if ( ATTRIBUTE_TYPE.equals(name)) - { + if (ATTRIBUTE_TYPE.equals(name)) { type = attribute.getValue(); - if ( validationProperties != null ) - { + if (validationProperties != null) { attributes.add(createValidAttributeInfo(ATTRIBUTE_TYPE, type)); } - } - else if ( ATTRIBUTE_SRC.equals(name) ) - { + } else if (ATTRIBUTE_SRC.equals(name)) { source = attribute.getValue(); - if ( validationProperties != null ) - { + if (validationProperties != null) { attributes.add(createValidAttributeInfo(ATTRIBUTE_SRC, source)); } - } - else - { + } else { SwordValidationInfo info = new SwordValidationInfo(xmlName, - new XmlName(attribute), - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO ); - info.setContentDescription(attribute.getValue()); - attributes.add(info); + new XmlName(attribute), + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); + info.setContentDescription(attribute.getValue()); + attributes.add(info); } } - + // check if there is any content. If there is, add a simple message to // say that there are sub elements that are not used in this profile - if ( content.getChildCount() > 0 ) - { + if (content.getChildCount() > 0) { elements.add(new SwordValidationInfo(xmlName, - "This element has child elements. These are not expected as part of the SWORD profile", - SwordValidationInfoType.INFO)); + "This element has child elements. These are not expected as part" + + " of the SWORD profile", + SwordValidationInfoType.INFO)); } - + + } catch (Exception ex) { + log.error("Unable to parse an element in Content: " + ex.getMessage()); + throw new UnmarshallException("Error parsing Content", ex); } - catch ( Exception ex ) - { - log.error("Unable to parse an element in Content: " + ex.getMessage()); - throw new UnmarshallException("Error parsing Content", ex); - } - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(elements, attributes, validationProperties); } return result; } - - public SwordValidationInfo validate(Properties validationContext) - { + + public SwordValidationInfo validate(Properties validationContext) { return validate(null, null, validationContext); } - + /** - * - * @param elements add results to this. - * @param attributes add these too. + * @param elements add results to this. + * @param attributes add these too. * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info */ protected SwordValidationInfo validate(List elements, - List attributes, - Properties validationContext) - { + List attributes, + Properties validationContext) { SwordValidationInfo info = new SwordValidationInfo(xmlName); - - if ( source == null ) - { + + if (source == null) { XmlName attributeName = new XmlName(xmlName.getPrefix(), - ATTRIBUTE_SRC, - xmlName.getNamespace()); - + ATTRIBUTE_SRC, + xmlName.getNamespace()); + SwordValidationInfo item = new SwordValidationInfo(xmlName, attributeName, - SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, - SwordValidationInfoType.ERROR); + SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, + SwordValidationInfoType.ERROR); info.addValidationInfo(item); } - + info.addUnmarshallValidationInfo(elements, attributes); - return info; + return info; } - + /** - * Get a string representation. - * + * Get a string representation. + * * @return String */ @Override - public String toString() - { + public String toString() { return "Content - source: " + getSource() + " type: " + getType(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/ContentType.java b/dspace-sword/src/main/java/org/purl/sword/atom/ContentType.java index 23f02541b0..c844bb3500 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/ContentType.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/ContentType.java @@ -8,37 +8,37 @@ package org.purl.sword.atom; /** - * Represents a content type for a text element. - * + * Represents a content type for a text element. + * * @author Neil Taylor */ -public enum ContentType -{ - TEXT ("text"), - HTML ("html"), - XHTML ("xhtml"); - +public enum ContentType { + TEXT("text"), + HTML("html"), + XHTML("xhtml"); + /** - * String representation of the type. + * String representation of the type. */ - private final String type; - + private final String type; + /** - * Create a new instance and set the string - * representation of the type. - * - * @param type The type, expressed as a string. + * Create a new instance and set the string + * representation of the type. + * + * @param type The type, expressed as a string. */ - private ContentType(String type) - { - this.type = type; + private ContentType(String type) { + this.type = type; } - + /** * Retrieve a string representation of this object. - * - * @return A string. + * + * @return A string. */ @Override - public String toString() { return this.type; } + public String toString() { + return this.type; + } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Contributor.java b/dspace-sword/src/main/java/org/purl/sword/atom/Contributor.java index ed1fc2f67f..f9815fe089 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Contributor.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Contributor.java @@ -11,31 +11,28 @@ import org.purl.sword.base.Namespaces; import org.purl.sword.base.XmlName; /** - * Represents an ATOM Contributor. - * + * Represents an ATOM Contributor. + * * @author Neil Taylor */ -public class Contributor extends Author -{ +public class Contributor extends Author { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "contributor", Namespaces.NS_ATOM); - + new XmlName(Namespaces.PREFIX_ATOM, "contributor", Namespaces.NS_ATOM); + /** - * Create a new instance and set the prefix to - * 'atom' and the local name to 'contributor'. + * Create a new instance and set the prefix to + * 'atom' and the local name to 'contributor'. */ - public Contributor() - { + public Contributor() { super(XML_NAME); } - + /** * Get the element name for this Xml Element. * - * @return The details of prefix, localname and namespace. + * @return The details of prefix, localname and namespace. */ - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Email.java b/dspace-sword/src/main/java/org/purl/sword/atom/Email.java index 0b057351fd..e04031c348 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Email.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Email.java @@ -7,30 +7,27 @@ */ package org.purl.sword.atom; -import org.purl.sword.base.*; +import org.purl.sword.base.BasicStringContentElement; +import org.purl.sword.base.Namespaces; +import org.purl.sword.base.XmlName; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class Email extends BasicStringContentElement -{ +public class Email extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "email", Namespaces.NS_ATOM); + new XmlName(Namespaces.PREFIX_ATOM, "email", Namespaces.NS_ATOM); - public Email() - { + public Email() { super(XML_NAME); } - public Email(String email) - { + public Email(String email) { this(); setContent(email); } - public static XmlName elementName() - { - return XML_NAME; + public static XmlName elementName() { + return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Entry.java b/dspace-sword/src/main/java/org/purl/sword/atom/Entry.java index 4a745f3ab8..09ceb31dc5 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Entry.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Entry.java @@ -10,11 +10,10 @@ package org.purl.sword.atom; import java.util.ArrayList; import java.util.Iterator; import java.util.List; - import java.util.Properties; + import nu.xom.Element; import nu.xom.Elements; - import org.apache.log4j.Logger; import org.purl.sword.base.HttpHeaders; import org.purl.sword.base.Namespaces; @@ -26,913 +25,775 @@ import org.purl.sword.base.XmlElement; import org.purl.sword.base.XmlName; /** - * Represents an ATOM entry. - * - * @author Neil Taylor + * Represents an ATOM entry. * + * @author Neil Taylor */ -public class Entry extends XmlElement implements SwordElementInterface -{ +public class Entry extends XmlElement implements SwordElementInterface { /** - * Local name for the element. + * Local name for the element. */ @Deprecated public static final String ELEMENT_NAME = "entry"; - + /** - * Local name for the atom id element. + * Local name for the atom id element. */ @Deprecated public static final String ELEMENT_ID = "id"; - + /** - * Local name for the atom published element. + * Local name for the atom published element. */ @Deprecated public static final String ELEMENT_PUBLISHED = "published"; - + /** - * Local name for the atom updated element. + * Local name for the atom updated element. */ @Deprecated public static final String ELEMENT_UPDATED = "updated"; - + /** - * Local name for the atom category element. + * Local name for the atom category element. */ @Deprecated public static final String ELEMENT_CATEGORY = "category"; - + /** - * Local name for the atom generator element. + * Local name for the atom generator element. */ @Deprecated public static final String ELEMENT_GENERATOR = "generator"; - + /** - * A list of authors associated with this entry. There can be 0 - * or more of these elements. + * A list of authors associated with this entry. There can be 0 + * or more of these elements. */ - private List authors; - + private List authors; + /** * The atom:category data. There can be 0 or more of these elements. */ private List categories; - + /** - * A single content element for the Entry. + * A single content element for the Entry. */ - private Content content; - + private Content content; + /** - * A single content element for the Entry. + * A single content element for the Entry. */ - private Generator generator; - + private Generator generator; + /** * A list of contributors associated with this entry. There can be 0 or - * more of these elements. + * more of these elements. */ - private List contributors; - + private List contributors; + /** - * This is a simplified version. The ID can also have atomCommonAttributes, - * but these have not been modeled in this version. The content of - * ID is an unconstrained string, which is intended to represent a URI. + * This is a simplified version. The ID can also have atomCommonAttributes, + * but these have not been modeled in this version. The content of + * ID is an unconstrained string, which is intended to represent a URI. */ private Id id; - + /** - * A list of link elements. This can contain 0 or more entries. + * A list of link elements. This can contain 0 or more entries. */ - private List links; - + private List links; + /** - * Simplified version of the atom:published element. This implementation - * does not record the general atomCommonAttributes. The date is - * taken from an xsd:dateTime value. - * - * This item is optional. + * Simplified version of the atom:published element. This implementation + * does not record the general atomCommonAttributes. The date is + * taken from an xsd:dateTime value. + * + * This item is optional. */ private Published published; - + /** - * A single, optional, content element for the Entry. + * A single, optional, content element for the Entry. */ - private Rights rights; - + private Rights rights; + /** - * A single, optional, content element for the Entry. + * A single, optional, content element for the Entry. */ @Deprecated - private Source source; - + private Source source; + /** - * A single, optional, summary element for the Entry. + * A single, optional, summary element for the Entry. */ - private Summary summary; - + private Summary summary; + /** - * A required title element for the entry. + * A required title element for the entry. */ - private Title title; - + private Title title; + /** - * The date on which the entry was last updated. + * The date on which the entry was last updated. */ private Updated updated; - + /** - * The log. + * The log. */ private static Logger log = Logger.getLogger(Entry.class); - + /** * The prefix, local name and namespace used for this element. */ private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "entry", Namespaces.NS_ATOM); - + new XmlName(Namespaces.PREFIX_ATOM, "entry", Namespaces.NS_ATOM); + /** - * Create a new instance of the class and initialise it. - * Also, set the prefix to 'atom' and the local name to 'entry'. + * Create a new instance of the class and initialise it. + * Also, set the prefix to 'atom' and the local name to 'entry'. */ - public Entry() - { + public Entry() { this(XML_NAME.getPrefix(), - XML_NAME.getLocalName(), - XML_NAME.getNamespace()); + XML_NAME.getLocalName(), + XML_NAME.getNamespace()); } - + /** * Create a new instance of the class an initalise it, setting the * element namespace and name. - * - * @param prefix The namespace prefix of the element + * + * @param prefix The namespace prefix of the element * @param element The element name */ - public Entry(String prefix, String element) - { + public Entry(String prefix, String element) { this(prefix, element, XML_NAME.getNamespace()); } - + /** - * - * @param prefix The prefix. - * @param element element name. + * @param prefix The prefix. + * @param element element name. * @param namespaceUri The namespace URI. */ - public Entry(String prefix, String element, String namespaceUri) - { + public Entry(String prefix, String element, String namespaceUri) { super(prefix, element, namespaceUri); initialise(); } - - public Entry(XmlName name) - { + + public Entry(XmlName name) { this(name.getPrefix(), name.getLocalName(), name.getNamespace()); } - - - - public static XmlName elementName() - { + + + public static XmlName elementName() { return XML_NAME; } - - protected boolean isElementChecked(XmlName elementName) - { - if ( elementName == null ) - { + + protected boolean isElementChecked(XmlName elementName) { + if (elementName == null) { return false; } - + return elementName.equals(Author.elementName()) | - elementName.equals(Category.elementName()) | - elementName.equals(Content.elementName()) | - elementName.equals(Generator.elementName()) | - elementName.equals(Contributor.elementName()) | - elementName.equals(Id.elementName()) | - elementName.equals(Link.elementName()) | - elementName.equals(Published.elementName()) | - elementName.equals(Rights.elementName()) | - elementName.equals(Source.elementName()) | - elementName.equals(Summary.elementName()) | - elementName.equals(Title.elementName()) | - elementName.equals(Updated.elementName()); + elementName.equals(Category.elementName()) | + elementName.equals(Content.elementName()) | + elementName.equals(Generator.elementName()) | + elementName.equals(Contributor.elementName()) | + elementName.equals(Id.elementName()) | + elementName.equals(Link.elementName()) | + elementName.equals(Published.elementName()) | + elementName.equals(Rights.elementName()) | + elementName.equals(Source.elementName()) | + elementName.equals(Summary.elementName()) | + elementName.equals(Title.elementName()) | + elementName.equals(Updated.elementName()); } - + /** - * + * */ - protected void initialise() - { + protected void initialise() { authors = new ArrayList(); categories = new ArrayList(); contributors = new ArrayList(); links = new ArrayList(); } - + /** - * Marshal the data stored in this object into Element objects. - * - * @return An element that holds the data associated with this object. + * Marshal the data stored in this object into Element objects. + * + * @return An element that holds the data associated with this object. */ - public Element marshall() - { + public Element marshall() { Element entry = new Element(getQualifiedName(), Namespaces.NS_ATOM); entry.addNamespaceDeclaration(Namespaces.PREFIX_SWORD, Namespaces.NS_SWORD); entry.addNamespaceDeclaration(Namespaces.PREFIX_ATOM, Namespaces.NS_ATOM); this.marshallElements(entry); - return entry; + return entry; } - - protected void marshallElements(Element entry) - { - if (id != null) - { - entry.appendChild(id.marshall()); - } - - for (Author author : authors) - { - entry.appendChild(author.marshall()); - } - - if (content != null) - { - entry.appendChild(content.marshall()); - } - - if (generator != null) - { - entry.appendChild(generator.marshall()); - } - - for (Author contributor : contributors) - { - entry.appendChild(contributor.marshall()); - } - - for (Link link : links) - { - entry.appendChild(link.marshall()); - } - - if (published != null) - { - entry.appendChild(published.marshall()); - } - - if (rights != null) - { - entry.appendChild(rights.marshall()); - } - - if (summary != null) - { - entry.appendChild(summary.marshall()); - } - - if (title != null) - { - entry.appendChild(title.marshall()); - } - - if (source != null) - { - entry.appendChild(source.marshall()); - } - - if (updated != null) - { - entry.appendChild(updated.marshall()); - } - - for (Category category : categories) - { - entry.appendChild(category.marshall()); - } + + protected void marshallElements(Element entry) { + if (id != null) { + entry.appendChild(id.marshall()); + } + + for (Author author : authors) { + entry.appendChild(author.marshall()); + } + + if (content != null) { + entry.appendChild(content.marshall()); + } + + if (generator != null) { + entry.appendChild(generator.marshall()); + } + + for (Author contributor : contributors) { + entry.appendChild(contributor.marshall()); + } + + for (Link link : links) { + entry.appendChild(link.marshall()); + } + + if (published != null) { + entry.appendChild(published.marshall()); + } + + if (rights != null) { + entry.appendChild(rights.marshall()); + } + + if (summary != null) { + entry.appendChild(summary.marshall()); + } + + if (title != null) { + entry.appendChild(title.marshall()); + } + + if (source != null) { + entry.appendChild(source.marshall()); + } + + if (updated != null) { + entry.appendChild(updated.marshall()); + } + + for (Category category : categories) { + entry.appendChild(category.marshall()); + } } - + /** * Unmarshal the contents of the Entry element into the internal data objects - * in this object. - * - * @param entry The Entry element to process. + * in this object. * + * @param entry The Entry element to process. * @throws UnmarshallException If the element does not contain an ATOM entry - * element, or if there is a problem processing the element or any - * subelements. + * element, or if there is a problem processing the element or any + * subelements. */ public void unmarshall(Element entry) - throws UnmarshallException - { + throws UnmarshallException { unmarshall(entry, null); } - + public SwordValidationInfo unmarshallWithoutValidate(Element entry, Properties validationProperties) - throws UnmarshallException - { - if (! isInstanceOf(entry, xmlName) ) - { + throws UnmarshallException { + if (!isInstanceOf(entry, xmlName)) { return handleIncorrectElement(entry, validationProperties); } - + // used to hold the element and attribute unmarshal info results SwordValidationInfo result = new SwordValidationInfo(xmlName); - - try - { + + try { initialise(); - - // FIXME - attributes? - + + // FIXME - attributes? + // retrieve all of the sub-elements Elements elements = entry.getChildElements(); - Element element = null; + Element element = null; int length = elements.size(); - - for (int i = 0; i < length; i++) - { + + for (int i = 0; i < length; i++) { element = elements.get(i); - - if (isInstanceOf(element, Author.elementName())) - { - Author author = new Author(); + + if (isInstanceOf(element, Author.elementName())) { + Author author = new Author(); result.addUnmarshallElementInfo(author.unmarshall(element, validationProperties)); authors.add(author); - } - else if (isInstanceOf(element, Category.elementName())) - { + } else if (isInstanceOf(element, Category.elementName())) { Category category = new Category(); result.addUnmarshallElementInfo(category.unmarshall(element, validationProperties)); - categories.add(category); - } - else if (isInstanceOf(element, Content.elementName())) - { - if ( content == null ) - { + categories.add(category); + } else if (isInstanceOf(element, Content.elementName())) { + if (content == null) { content = new Content(); result.addUnmarshallElementInfo(content.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Content.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - - } - else if (isInstanceOf(element, Generator.elementName())) - { - if ( generator == null ) - { + + } else if (isInstanceOf(element, Generator.elementName())) { + if (generator == null) { generator = new Generator(); result.addUnmarshallElementInfo(generator.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Generator.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (isInstanceOf(element, Contributor.elementName())) - { - Contributor contributor = new Contributor(); + } else if (isInstanceOf(element, Contributor.elementName())) { + Contributor contributor = new Contributor(); result.addUnmarshallElementInfo(contributor.unmarshall(element, validationProperties)); contributors.add(contributor); - } - else if (isInstanceOf(element, Id.elementName())) - { - if ( id == null ) - { + } else if (isInstanceOf(element, Id.elementName())) { + if (id == null) { id = new Id(); result.addUnmarshallElementInfo(id.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Id.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (isInstanceOf(element, Link.elementName())) - { - Link link = new Link(); + } else if (isInstanceOf(element, Link.elementName())) { + Link link = new Link(); result.addUnmarshallElementInfo(link.unmarshall(element, validationProperties)); links.add(link); - } - else if (isInstanceOf(element, Published.elementName())) - { - if ( published == null ) - { + } else if (isInstanceOf(element, Published.elementName())) { + if (published == null) { published = new Published(); result.addUnmarshallElementInfo(published.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Published.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (isInstanceOf(element, Rights.elementName())) - { - if ( rights == null ) - { + } else if (isInstanceOf(element, Rights.elementName())) { + if (rights == null) { rights = new Rights(); result.addUnmarshallElementInfo(rights.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Rights.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (isInstanceOf(element, Summary.elementName())) - { - if ( summary == null ) - { + } else if (isInstanceOf(element, Summary.elementName())) { + if (summary == null) { summary = new Summary(); result.addUnmarshallElementInfo(summary.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Summary.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (isInstanceOf(element, Title.elementName())) - { - if ( title == null ) - { + } else if (isInstanceOf(element, Title.elementName())) { + if (title == null) { title = new Title(); result.addUnmarshallElementInfo(title.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Title.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (isInstanceOf(element, Updated.elementName())) - { - if ( updated == null ) - { + } else if (isInstanceOf(element, Updated.elementName())) { + if (updated == null) { updated = new Updated(); result.addUnmarshallElementInfo(updated.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Updated.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (isInstanceOf(element, Source.elementName())) - { - if ( source == null ) - { + } else if (isInstanceOf(element, Source.elementName())) { + if (source == null) { source = new Source(); result.addUnmarshallElementInfo(source.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(Source.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); + info.setContentDescription(element.getValue()); + result.addUnmarshallElementInfo(info); + } + } else if (validationProperties != null) { + XmlName name = new XmlName(element); + if (!isElementChecked(name)) { + SwordValidationInfo info = new SwordValidationInfo(name, + SwordValidationInfo.UNKNOWN_ELEMENT, + SwordValidationInfoType.INFO); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } } - else if ( validationProperties != null ) - { - XmlName name = new XmlName(element); - if ( ! isElementChecked(name) ) - { - SwordValidationInfo info = new SwordValidationInfo(name, - SwordValidationInfo.UNKNOWN_ELEMENT, - SwordValidationInfoType.INFO); - info.setContentDescription(element.getValue()); - result.addUnmarshallElementInfo(info); - } - } - - } // for - } - catch (Exception ex) - { + + } // for + } catch (Exception ex) { log.error("Unable to parse an element in Entry: " + ex.getMessage()); ex.printStackTrace(); throw new UnmarshallException("Unable to parse an element in " + getQualifiedName(), ex); } - - return result; + + return result; } - + public SwordValidationInfo unmarshall(Element entry, Properties validationProperties) - throws UnmarshallException - { - + throws UnmarshallException { + SwordValidationInfo result = unmarshallWithoutValidate(entry, validationProperties); - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(result, validationProperties); } - return result; + return result; } - + /** * */ - public SwordValidationInfo validate(Properties validationContext) - { + public SwordValidationInfo validate(Properties validationContext) { return validate(null, validationContext); } - + /** - * - * @param info add results to this. If null, a new one is created. + * @param info add results to this. If null, a new one is created. * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info */ protected SwordValidationInfo validate(SwordValidationInfo info, - Properties validationContext) - { - // determine if a full validation is required + Properties validationContext) { + // determine if a full validation is required boolean validateAll = (info == null); - + SwordValidationInfo result = info; - if ( result == null ) - { - result = new SwordValidationInfo(xmlName); + if (result == null) { + result = new SwordValidationInfo(xmlName); } - + // id, title an updated are required - if ( id == null ) - { - result.addValidationInfo(new SwordValidationInfo(Id.elementName(), - SwordValidationInfo.MISSING_ELEMENT_ERROR, - SwordValidationInfoType.ERROR)); - } - else if ( id != null && validateAll ) - { + if (id == null) { + result.addValidationInfo(new SwordValidationInfo(Id.elementName(), + SwordValidationInfo.MISSING_ELEMENT_ERROR, + SwordValidationInfoType.ERROR)); + } else if (id != null && validateAll) { result.addValidationInfo(id.validate(validationContext)); } - - if ( title == null ) - { - result.addValidationInfo(new SwordValidationInfo(Title.elementName(), - SwordValidationInfo.MISSING_ELEMENT_ERROR, - SwordValidationInfoType.ERROR)); - } - else if ( title != null && validateAll ) - { + + if (title == null) { + result.addValidationInfo(new SwordValidationInfo(Title.elementName(), + SwordValidationInfo.MISSING_ELEMENT_ERROR, + SwordValidationInfoType.ERROR)); + } else if (title != null && validateAll) { result.addValidationInfo(title.validate(validationContext)); } - - if ( updated == null ) - { - result.addValidationInfo(new SwordValidationInfo(Updated.elementName(), - SwordValidationInfo.MISSING_ELEMENT_ERROR, - SwordValidationInfoType.ERROR)); - } - else if ( updated != null && validateAll ) - { + + if (updated == null) { + result.addValidationInfo(new SwordValidationInfo(Updated.elementName(), + SwordValidationInfo.MISSING_ELEMENT_ERROR, + SwordValidationInfoType.ERROR)); + } else if (updated != null && validateAll) { result.addValidationInfo(updated.validate(validationContext)); } - + // additional sword requirements on the element - if ( contributors.isEmpty() ) - { - String contributor = validationContext.getProperty(HttpHeaders.X_ON_BEHALF_OF); - if ( contributor != null ) - { - result.addValidationInfo(new SwordValidationInfo(Contributor.elementName(), - SwordValidationInfo.MISSING_ELEMENT_ERROR + - " This item SHOULD contain the value of the X-On-Behalf-Of header, if one was present in the POST request.", - SwordValidationInfoType.ERROR)); - } - } - else if ( (! contributors.isEmpty()) && validateAll ) - { + if (contributors.isEmpty()) { + String contributor = validationContext.getProperty(HttpHeaders.X_ON_BEHALF_OF); + if (contributor != null) { + result.addValidationInfo(new SwordValidationInfo(Contributor.elementName(), + SwordValidationInfo.MISSING_ELEMENT_ERROR + + " This item SHOULD contain the value of the " + + "X-On-Behalf-Of header, if one was present in " + + "the POST request.", + SwordValidationInfoType.ERROR)); + } + } else if ((!contributors.isEmpty()) && validateAll) { Iterator iterator = contributors.iterator(); - while ( iterator.hasNext() ) - { - Contributor contributor = iterator.next(); - result.addValidationInfo(contributor.validate(validationContext)); + while (iterator.hasNext()) { + Contributor contributor = iterator.next(); + result.addValidationInfo(contributor.validate(validationContext)); } } - - if ( generator == null ) - { + + if (generator == null) { result.addValidationInfo(new SwordValidationInfo(Generator.elementName(), - SwordValidationInfo.MISSING_ELEMENT_ERROR + - " SHOULD contain the URI and version of the server software.", - SwordValidationInfoType.ERROR)); - } - else if ( generator != null && validateAll ) - { + SwordValidationInfo.MISSING_ELEMENT_ERROR + + " SHOULD contain the URI and version of the server " + + "software.", + SwordValidationInfoType.ERROR)); + } else if (generator != null && validateAll) { result.addValidationInfo(generator.validate(validationContext)); } - - if ( validateAll ) - { + + if (validateAll) { // process the remaining items Iterator linksIterator = links.iterator(); - while ( linksIterator.hasNext() ) - { - Link link = linksIterator.next(); - result.addValidationInfo(link.validate(validationContext)); + while (linksIterator.hasNext()) { + Link link = linksIterator.next(); + result.addValidationInfo(link.validate(validationContext)); } - + Iterator authorIterator = authors.iterator(); - while ( authorIterator.hasNext() ) - { - Author author = authorIterator.next(); - result.addValidationInfo(author.validate(validationContext)); + while (authorIterator.hasNext()) { + Author author = authorIterator.next(); + result.addValidationInfo(author.validate(validationContext)); } - - if ( content != null ) - { + + if (content != null) { result.addValidationInfo(content.validate(validationContext)); } - - if ( published != null ) - { + + if (published != null) { result.addValidationInfo(published.validate(validationContext)); } - - if ( rights != null ) - { + + if (rights != null) { result.addValidationInfo(rights.validate(validationContext)); } - - if ( summary != null ) - { + + if (summary != null) { result.addValidationInfo(summary.validate(validationContext)); } - + Iterator categoryIterator = categories.iterator(); - while ( categoryIterator.hasNext() ) - { - Category category = categoryIterator.next(); - result.addValidationInfo(category.validate(validationContext)); + while (categoryIterator.hasNext()) { + Category category = categoryIterator.next(); + result.addValidationInfo(category.validate(validationContext)); } - + } - + return result; } - + /** - * Get an iterator for the authors in the Entry. - * - * @return An iterator. + * Get an iterator for the authors in the Entry. + * + * @return An iterator. */ - public Iterator getAuthors() - { + public Iterator getAuthors() { return authors.iterator(); } - + /** - * Add an author to the Entry. - * - * @param author The author to add. + * Add an author to the Entry. + * + * @param author The author to add. */ - public void addAuthors(Author author) - { + public void addAuthors(Author author) { this.authors.add(author); } - + /** - * Clear the list of authors. + * Clear the list of authors. */ - public void clearAuthors() - { + public void clearAuthors() { this.authors.clear(); } - + /** - * Get an iterator for the categories in this Entry. - * - * @return An iterator. + * Get an iterator for the categories in this Entry. + * + * @return An iterator. */ public Iterator getCategories() { ArrayList items = new ArrayList(); - for ( int i = 0; i < categories.size(); i++ ) - { + for (int i = 0; i < categories.size(); i++) { items.add(categories.get(i).getContent()); } - + return items.iterator(); } - + /** - * Add a category. - * - * @param category the category to add. + * Add a category. + * + * @param category the category to add. */ public void addCategory(String category) { this.categories.add(new Category(category)); } - + /** - * Clear the list of categories. + * Clear the list of categories. */ - public void clearCategories() - { + public void clearCategories() { this.categories.clear(); } - + /** - * Get the content element for this Entry. - * - * @return The content element. + * Get the content element for this Entry. + * + * @return The content element. */ - public Content getContent() - { + public Content getContent() { return content; } - + /** - * Set the content element for this Entry. + * Set the content element for this Entry. * - * @param content - * content element to set + * @param content content element to set */ - public void setContent(Content content) - { + public void setContent(Content content) { this.content = content; - } - + } + /** - * Get the generator for this Entry. - * - * @return The generator element. + * Get the generator for this Entry. + * + * @return The generator element. */ - public Generator getGenerator() - { + public Generator getGenerator() { return generator; } - + /** - * Set the generator for this Entry. + * Set the generator for this Entry. * - * @param generator - * generator element to set + * @param generator generator element to set */ - public void setGenerator(Generator generator) - { + public void setGenerator(Generator generator) { this.generator = generator; - } - + } + /** - * Get a list of contributors. - * - * @return An iterator. + * Get a list of contributors. + * + * @return An iterator. */ public Iterator getContributors() { return contributors.iterator(); } - + /** - * Add a contributor. - * - * @param contributor The contributor. + * Add a contributor. + * + * @param contributor The contributor. */ - public void addContributor(Contributor contributor) - { + public void addContributor(Contributor contributor) { this.contributors.add(contributor); } - + /** - * Clear the list of contributors. + * Clear the list of contributors. */ - public void clearContributors() - { + public void clearContributors() { this.contributors.clear(); } - + /** - * Get the ID for this Entry. - * - * @return The ID. + * Get the ID for this Entry. + * + * @return The ID. */ - public String getId() - { - if ( id == null ) - { + public String getId() { + if (id == null) { return null; } return id.getContent(); } - + /** - * Set the ID for this Entry. - * - * @param id The ID. + * Set the ID for this Entry. + * + * @param id The ID. */ - public void setId(String id) - { + public void setId(String id) { this.id = new Id(id); } - + /** - * Get the list of links for this Entry. - * - * @return An iterator. + * Get the list of links for this Entry. + * + * @return An iterator. */ - public Iterator getLinks() - { + public Iterator getLinks() { return links.iterator(); } - + /** - * Get the link for this Entry. - * - * @param link The link. + * Get the link for this Entry. + * + * @param link The link. */ - public void addLink(Link link) - { + public void addLink(Link link) { this.links.add(link); } - + /** - * Clear the list of links. + * Clear the list of links. */ - public void clearLinks() - { + public void clearLinks() { this.links.clear(); } - + /** - * Get the published date, expressed as a String. - * - * @return The date. + * Get the published date, expressed as a String. + * + * @return The date. */ - public String getPublished() - { - if ( published == null ) - { + public String getPublished() { + if (published == null) { return null; } return published.getContent(); } - + /** - * Set the published date. The date should be in one of the - * supported formats. This method will not check that the string - * is in the correct format. - * - * @param published The string. + * Set the published date. The date should be in one of the + * supported formats. This method will not check that the string + * is in the correct format. + * + * @param published The string. */ - public void setPublished(String published) - { + public void setPublished(String published) { this.published = new Published(published); } - + /** - * Get the rights for this Entry. - * @return The rights. + * Get the rights for this Entry. + * + * @return The rights. */ public Rights getRights() { return rights; } - + /** - * Set the rights for this Entry. - * - * @param rights The rights. + * Set the rights for this Entry. + * + * @param rights The rights. */ public void setRights(Rights rights) { this.rights = rights; } - + /** - * Get the source for this Entry. + * Get the source for this Entry. + * * @return The source. * @deprecated */ @@ -940,86 +801,78 @@ public class Entry extends XmlElement implements SwordElementInterface public Source getSource() { return source; } - + /** - * Set the source for this entry. - * + * Set the source for this entry. + * * @param source The source. * @deprecated */ @Deprecated - public void setSource(Source source) - { + public void setSource(Source source) { this.source = source; } - - /** - * Get the summary. - * - * @return The summary. + + /** + * Get the summary. + * + * @return The summary. */ - public Summary getSummary() - { + public Summary getSummary() { return summary; } - - /** - * Set the summary. - * - * @param summary The summary. + + /** + * Set the summary. + * + * @param summary The summary. */ - public void setSummary(Summary summary) - { + public void setSummary(Summary summary) { this.summary = summary; } - + /** - * Get the title. - * - * @return The title. + * Get the title. + * + * @return The title. */ - public Title getTitle() - { + public Title getTitle() { return title; } - + /** - * Set the title. - * - * @param title The title. + * Set the title. + * + * @param title The title. */ - public void setTitle(Title title) - { + public void setTitle(Title title) { this.title = title; } - + /** * Get the updated date, expressed as a String. See - * org.purl.sword.XmlElement.stringToDate for the - * list of supported formats. This particular method - * will not check if the date is formatted correctly. - * - * @return The date. + * org.purl.sword.XmlElement.stringToDate for the + * list of supported formats. This particular method + * will not check if the date is formatted correctly. + * + * @return The date. */ - public String getUpdated() - { - if ( updated == null ) - { + public String getUpdated() { + if (updated == null) { return null; } return updated.getContent(); } - + /** - * Set the updated date. The date should match one of the - * supported formats. This method will not check the format of the - * string. - * - * @param updated The string. + * Set the updated date. The date should match one of the + * supported formats. This method will not check the format of the + * string. + * + * @param updated The string. * @see Entry#setPublished(String) setPublished - */ - public void setUpdated(String updated) - { + */ + public void setUpdated(String updated) { this.updated = new Updated(updated); - } + } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Generator.java b/dspace-sword/src/main/java/org/purl/sword/atom/Generator.java index ecd2ca3d2c..8f28b8589a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Generator.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Generator.java @@ -10,341 +10,305 @@ package org.purl.sword.atom; import java.util.ArrayList; import java.util.List; import java.util.Properties; + import nu.xom.Attribute; import nu.xom.Element; - +import org.apache.log4j.Logger; import org.purl.sword.base.Namespaces; import org.purl.sword.base.SwordElementInterface; -import org.purl.sword.base.UnmarshallException; -import org.purl.sword.base.XmlElement; - -import org.apache.log4j.Logger; import org.purl.sword.base.SwordValidationInfo; import org.purl.sword.base.SwordValidationInfoType; +import org.purl.sword.base.UnmarshallException; +import org.purl.sword.base.XmlElement; import org.purl.sword.base.XmlName; /** - * Represents an ATOM Generator element. - * + * Represents an ATOM Generator element. + * * @author Neil Taylor */ -public class Generator extends XmlElement implements SwordElementInterface -{ +public class Generator extends XmlElement implements SwordElementInterface { /** - * Label for the URI attribute. + * Label for the URI attribute. */ public static final String ATTRIBUTE_URI = "uri"; - + /** - * Label for the version attribute. + * Label for the version attribute. */ public static final String ATTRIBUTE_VERSION = "version"; - + /** - * Local name for the element. + * Local name for the element. */ @Deprecated public static final String ELEMENT_NAME = "generator"; - + /** - * The content for the element. + * The content for the element. */ - private String content; - + private String content; + /** - * The URI attribute. + * The URI attribute. */ private String uri; - + /** - * The version attribute. + * The version attribute. */ private String version; - + /** - * The logger. + * The logger. */ private static Logger log = Logger.getLogger(Generator.class); - + /** - * The Xml name details for the element. + * The Xml name details for the element. */ private static final XmlName XML_NAME = new XmlName( - Namespaces.PREFIX_ATOM, "generator", Namespaces.NS_ATOM); - - /** - * Create a new instance and set the prefix to - * 'atom' and the local name to 'generator'. + Namespaces.PREFIX_ATOM, "generator", Namespaces.NS_ATOM); + + /** + * Create a new instance and set the prefix to + * 'atom' and the local name to 'generator'. */ - public Generator() - { + public Generator() { super(XML_NAME); - initialise(); + initialise(); } - - public static XmlName elementName() - { + + public static XmlName elementName() { return XML_NAME; } - - protected final void initialise() - { + + protected final void initialise() { content = null; version = null; - uri = null; + uri = null; } - + /** - * Marshal the data in the object to an Element object. - * - * @return The element. + * Marshal the data in the object to an Element object. + * + * @return The element. */ - public Element marshall() - { + public Element marshall() { Element element = new Element(getQualifiedName(), xmlName.getNamespace()); - - if ( content != null ) - { - element.appendChild(content); + + if (content != null) { + element.appendChild(content); } - - if ( uri != null ) - { - Attribute uriAttribute = new Attribute(ATTRIBUTE_URI, uri); - element.addAttribute(uriAttribute); + + if (uri != null) { + Attribute uriAttribute = new Attribute(ATTRIBUTE_URI, uri); + element.addAttribute(uriAttribute); } - - if ( version != null ) - { - Attribute versionAttribute = new Attribute(ATTRIBUTE_VERSION, version); - element.addAttribute(versionAttribute); + + if (version != null) { + Attribute versionAttribute = new Attribute(ATTRIBUTE_VERSION, version); + element.addAttribute(versionAttribute); } - - + + return element; } - + /** - * Unmarshal the specified Generator element into the data in this object. - * - * @param generator The generator element. - * - * @throws UnmarshallException If the specified element is not an atom:generator - * element, or if there is an error accessing the data. + * Unmarshal the specified Generator element into the data in this object. + * + * @param generator The generator element. + * @throws UnmarshallException If the specified element is not an atom:generator + * element, or if there is an error accessing the data. */ public void unmarshall(Element generator) - throws UnmarshallException - { + throws UnmarshallException { unmarshall(generator, null); } - + public SwordValidationInfo unmarshall(Element generator, Properties validationProperties) - throws UnmarshallException - { - if ( ! isInstanceOf(generator, xmlName)) - { + throws UnmarshallException { + if (!isInstanceOf(generator, xmlName)) { return handleIncorrectElement(generator, validationProperties); } - + ArrayList validationItems = new ArrayList(); ArrayList attributeValidationItems = new ArrayList(); - - try - { + + try { initialise(); - + // get the attributes int attributeCount = generator.getAttributeCount(); Attribute attribute = null; - for ( int i = 0; i < attributeCount; i++ ) - { + for (int i = 0; i < attributeCount; i++) { attribute = generator.getAttribute(i); - if ( ATTRIBUTE_URI.equals(attribute.getQualifiedName())) - { + if (ATTRIBUTE_URI.equals(attribute.getQualifiedName())) { uri = attribute.getValue(); - + XmlName uriName = new XmlName(Namespaces.PREFIX_ATOM, ATTRIBUTE_URI, Namespaces.NS_ATOM); SwordValidationInfo info = new SwordValidationInfo(xmlName, uriName); info.setContentDescription(uri); - attributeValidationItems.add(info); - } - else if ( ATTRIBUTE_VERSION.equals(attribute.getQualifiedName())) - { + attributeValidationItems.add(info); + } else if (ATTRIBUTE_VERSION.equals(attribute.getQualifiedName())) { version = attribute.getValue(); XmlName versionName = new XmlName(Namespaces.PREFIX_ATOM, ATTRIBUTE_VERSION, Namespaces.NS_ATOM); SwordValidationInfo info = new SwordValidationInfo(xmlName, versionName); info.setContentDescription(version); attributeValidationItems.add(info); - } - else - { + } else { XmlName attributeName = new XmlName(attribute.getNamespacePrefix(), - attribute.getLocalName(), - attribute.getNamespaceURI()); - + attribute.getLocalName(), + attribute.getNamespaceURI()); + SwordValidationInfo info = new SwordValidationInfo(xmlName, attributeName, - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO); + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); info.setContentDescription(attribute.getValue()); validationItems.add(info); } } - + int length = generator.getChildCount(); - if ( length > 0 ) - { + if (length > 0) { content = unmarshallString(generator); } - } - catch ( Exception ex ) - { + } catch (Exception ex) { log.error("Unable to parse an element in Generator: " + ex.getMessage()); throw new UnmarshallException("Unable to parse element in Generator", ex); } - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(validationItems, attributeValidationItems, validationProperties); } return result; } - + /** - * * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info. */ @Override - public SwordValidationInfo validate(Properties validationContext) - { + public SwordValidationInfo validate(Properties validationContext) { return validate(null, null, validationContext); } - + /** - * - * @param existing add results to this. - * @param attributeItems add these too. + * @param existing add results to this. + * @param attributeItems add these too. * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info */ public SwordValidationInfo validate(List existing, - List attributeItems, - Properties validationContext) - { + List attributeItems, + Properties validationContext) { boolean validateAll = (existing == null); - + SwordValidationInfo result = new SwordValidationInfo(xmlName); result.setContentDescription(content); - + XmlName attributeName; - - if ( content == null ) - { + + if (content == null) { result.addValidationInfo( - new SwordValidationInfo(xmlName, - SwordValidationInfo.MISSING_CONTENT, - SwordValidationInfoType.WARNING)); + new SwordValidationInfo(xmlName, + SwordValidationInfo.MISSING_CONTENT, + SwordValidationInfoType.WARNING)); } - - - if ( uri == null ) - { - attributeName = new XmlName(Namespaces.PREFIX_ATOM, - ATTRIBUTE_URI, + + + if (uri == null) { + attributeName = new XmlName(Namespaces.PREFIX_ATOM, + ATTRIBUTE_URI, Namespaces.NS_ATOM); - + result.addAttributeValidationInfo( new SwordValidationInfo(xmlName, attributeName, - SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, - SwordValidationInfoType.WARNING)); - } - else if ( validateAll && uri != null ) - { + SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, + SwordValidationInfoType.WARNING)); + } else if (validateAll && uri != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_URI, uri)); } - - if ( version == null ) - { + + if (version == null) { attributeName = new XmlName(Namespaces.PREFIX_ATOM, ATTRIBUTE_VERSION, Namespaces.NS_ATOM); - + result.addAttributeValidationInfo( new SwordValidationInfo(xmlName, attributeName, - SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, - SwordValidationInfoType.WARNING)); - } - else if ( validateAll && version != null ) - { + SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, + SwordValidationInfoType.WARNING)); + } else if (validateAll && version != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_VERSION, version)); } - + result.addUnmarshallValidationInfo(existing, attributeItems); - return result; + return result; } - + /** - * Get the content. - * - * @return The content. + * Get the content. + * + * @return The content. */ public String getContent() { return content; } - + /** - * Set the content. - * - * @param content The content. + * Set the content. + * + * @param content The content. */ public void setContent(String content) { this.content = content; } - + /** - * Get the URI. - * - * @return The URI. + * Get the URI. + * + * @return The URI. */ public String getUri() { return uri; } - + /** - * Set the URI. - * - * @param uri The URI. + * Set the URI. + * + * @param uri The URI. */ public void setUri(String uri) { this.uri = uri; } - + /** - * Get the version. - * - * @return The version. + * Get the version. + * + * @return The version. */ public String getVersion() { return version; } - + /** - * Set the version. - * - * @param version The version. + * Set the version. + * + * @param version The version. */ public void setVersion(String version) { this.version = version; } - + /** - * Get a string representation. + * Get a string representation. */ - public String toString() - { - return "Generator - content: " + getContent() + - " version: " + getVersion() + - " uri: " + getUri(); + public String toString() { + return "Generator - content: " + getContent() + + " version: " + getVersion() + + " uri: " + getUri(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Id.java b/dspace-sword/src/main/java/org/purl/sword/atom/Id.java index 9996b0e823..a5c6d28bcc 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Id.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Id.java @@ -7,30 +7,27 @@ */ package org.purl.sword.atom; -import org.purl.sword.base.*; +import org.purl.sword.base.BasicStringContentElement; +import org.purl.sword.base.Namespaces; +import org.purl.sword.base.XmlName; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class Id extends BasicStringContentElement -{ +public class Id extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "id", Namespaces.NS_ATOM); + new XmlName(Namespaces.PREFIX_ATOM, "id", Namespaces.NS_ATOM); - public Id() - { + public Id() { super(XML_NAME); } - public Id(String uri) - { + public Id(String uri) { this(); setContent(uri); } - public static XmlName elementName() - { - return XML_NAME; + public static XmlName elementName() { + return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/InvalidMediaTypeException.java b/dspace-sword/src/main/java/org/purl/sword/atom/InvalidMediaTypeException.java index bac22e550a..44dc0c864a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/InvalidMediaTypeException.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/InvalidMediaTypeException.java @@ -8,19 +8,17 @@ package org.purl.sword.atom; /** - * An invalid media type has been detected during parsing. - * + * An invalid media type has been detected during parsing. + * * @author Neil Taylor */ -public class InvalidMediaTypeException extends Exception -{ +public class InvalidMediaTypeException extends Exception { /** - * Create a new instance and store the message. - * - * @param message The exception's message. + * Create a new instance and store the message. + * + * @param message The exception's message. */ - public InvalidMediaTypeException( String message ) - { + public InvalidMediaTypeException(String message) { super(message); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Link.java b/dspace-sword/src/main/java/org/purl/sword/atom/Link.java index 46056c4e84..c7658ba999 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Link.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Link.java @@ -10,9 +10,9 @@ package org.purl.sword.atom; import java.util.ArrayList; import java.util.List; import java.util.Properties; + import nu.xom.Attribute; import nu.xom.Element; - import org.apache.log4j.Logger; import org.purl.sword.base.Namespaces; import org.purl.sword.base.SwordElementInterface; @@ -23,34 +23,33 @@ import org.purl.sword.base.XmlElement; import org.purl.sword.base.XmlName; /** - * Represents an ATOM Link element. - * + * Represents an ATOM Link element. + * * @author Neil Taylor */ -public class Link extends XmlElement implements SwordElementInterface -{ +public class Link extends XmlElement implements SwordElementInterface { /** - * Label for the href attribute. + * Label for the href attribute. */ public static final String ATTRIBUTE_HREF = "href"; /** - * Label for the rel attribute. + * Label for the rel attribute. */ public static final String ATTRIBUTE_REL = "rel"; /** - * Label for the type attribute. + * Label for the type attribute. */ public static final String ATTRIBUTE_TYPE = "type"; /** - * Label for the hreflang attribute. + * Label for the hreflang attribute. */ public static final String ATTRIBUTE_HREF_LANG = "hreflang"; /** - * Label for the title attribute. + * Label for the title attribute. */ public static final String ATTRIBUTE_TITLE = "title"; @@ -58,441 +57,393 @@ public class Link extends XmlElement implements SwordElementInterface * Label for the length attribute. */ public static final String ATTRIBUTE_LENGTH = "length"; - + /** - * Local name for the element. + * Local name for the element. */ @Deprecated public static final String ELEMENT_NAME = "link"; - + /** - * Stores the href. + * Stores the href. */ - private String href; - + private String href; + /** - * Stores the Rel attribute. + * Stores the Rel attribute. */ - private String rel; - + private String rel; + /** - * Stores the type. + * Stores the type. */ - private String type; - + private String type; + /** - * Stores the HREF lang. + * Stores the HREF lang. */ private String hreflang; - + /** - * Stores the title. + * Stores the title. */ - private String title; - + private String title; + /** - * Stores the length. + * Stores the length. */ private String length; - + /** - * Stores the content. + * Stores the content. */ - private String content; - + private String content; + /** - * The logger. + * The logger. */ private static Logger log = Logger.getLogger(Link.class); - + private static final XmlName XML_NAME = new XmlName( - Namespaces.PREFIX_ATOM, "link", Namespaces.NS_ATOM); - + Namespaces.PREFIX_ATOM, "link", Namespaces.NS_ATOM); + /** - * Create a new instance and set prefix and local name to 'atom' and 'link', - * respectively. + * Create a new instance and set prefix and local name to 'atom' and 'link', + * respectively. */ - public Link() - { + public Link() { super(XML_NAME); } - - public static XmlName elementName() - { + + public static XmlName elementName() { return XML_NAME; } - + /** - * Mashall the data stored in this object into Element objects. - * - * @return An element that holds the data associated with this object. + * Mashall the data stored in this object into Element objects. + * + * @return An element that holds the data associated with this object. */ - public Element marshall() - { + public Element marshall() { Element element = new Element(getQualifiedName(), xmlName.getNamespace()); - - if ( content != null ) - { + + if (content != null) { element.appendChild(content); } - - if ( href != null ) - { + + if (href != null) { Attribute hrefAttribute = new Attribute(ATTRIBUTE_HREF, href); element.addAttribute(hrefAttribute); } - - if ( rel != null ) - { + + if (rel != null) { Attribute relAttribute = new Attribute(ATTRIBUTE_REL, rel); element.addAttribute(relAttribute); } - - if ( type != null ) - { + + if (type != null) { Attribute typeAttribute = new Attribute(ATTRIBUTE_TYPE, type); element.addAttribute(typeAttribute); } - - if ( hreflang != null ) - { + + if (hreflang != null) { Attribute hreflangAttribute = new Attribute(ATTRIBUTE_HREF_LANG, hreflang); element.addAttribute(hreflangAttribute); } - - if ( title != null ) - { + + if (title != null) { Attribute titleAttribute = new Attribute(ATTRIBUTE_TITLE, title); element.addAttribute(titleAttribute); } - - if ( length != null ) - { + + if (length != null) { Attribute lengthAttribute = new Attribute(ATTRIBUTE_LENGTH, length); element.addAttribute(lengthAttribute); } - + return element; } - + /** * Unmarshall the contents of the Link element into the internal data objects - * in this object. - * - * @param link The Link element to process. + * in this object. * + * @param link The Link element to process. * @throws UnmarshallException If the element does not contain an ATOM link - * element, or if there is a problem processing the element or any - * subelements. + * element, or if there is a problem processing the element or any + * subelements. */ public void unmarshall(Element link) - throws UnmarshallException - { - unmarshall(link, null); + throws UnmarshallException { + unmarshall(link, null); } - - + + public SwordValidationInfo unmarshall(Element link, Properties validationProperties) - throws UnmarshallException - { - if ( ! isInstanceOf(link, xmlName) ) - { + throws UnmarshallException { + if (!isInstanceOf(link, xmlName)) { return handleIncorrectElement(link, validationProperties); } - + ArrayList validationItems = new ArrayList(); ArrayList attributeItems = new ArrayList(); - - try - { + + try { // get the attributes int attributeCount = link.getAttributeCount(); - Attribute attribute = null; - for ( int i = 0; i < attributeCount; i++ ) - { + Attribute attribute = null; + for (int i = 0; i < attributeCount; i++) { attribute = link.getAttribute(i); - if ( ATTRIBUTE_HREF.equals(attribute.getQualifiedName())) - { + if (ATTRIBUTE_HREF.equals(attribute.getQualifiedName())) { href = attribute.getValue(); - if ( validationProperties != null) - { + if (validationProperties != null) { attributeItems.add(createValidAttributeInfo(ATTRIBUTE_HREF, href)); } - } - else if ( ATTRIBUTE_REL.equals(attribute.getQualifiedName())) - { + } else if (ATTRIBUTE_REL.equals(attribute.getQualifiedName())) { rel = attribute.getValue(); - if ( validationProperties != null) - { + if (validationProperties != null) { attributeItems.add(createValidAttributeInfo(ATTRIBUTE_REL, rel)); } - } - else if ( ATTRIBUTE_TYPE.equals(attribute.getQualifiedName())) - { + } else if (ATTRIBUTE_TYPE.equals(attribute.getQualifiedName())) { type = attribute.getValue(); - if ( validationProperties != null) - { + if (validationProperties != null) { attributeItems.add(createValidAttributeInfo(ATTRIBUTE_TYPE, type)); } - } - else if ( ATTRIBUTE_HREF_LANG.equals(attribute.getQualifiedName())) - { + } else if (ATTRIBUTE_HREF_LANG.equals(attribute.getQualifiedName())) { hreflang = attribute.getValue(); - if ( validationProperties != null) - { + if (validationProperties != null) { attributeItems.add(createValidAttributeInfo(ATTRIBUTE_HREF_LANG, hreflang)); } - } - else if ( ATTRIBUTE_TITLE.equals(attribute.getQualifiedName())) - { + } else if (ATTRIBUTE_TITLE.equals(attribute.getQualifiedName())) { title = attribute.getValue(); - if ( validationProperties != null) - { + if (validationProperties != null) { attributeItems.add(createValidAttributeInfo(ATTRIBUTE_TITLE, title)); } - } - else if ( ATTRIBUTE_LENGTH.equals(attribute.getQualifiedName())) - { + } else if (ATTRIBUTE_LENGTH.equals(attribute.getQualifiedName())) { length = attribute.getValue(); - if ( validationProperties != null) - { + if (validationProperties != null) { attributeItems.add(createValidAttributeInfo(ATTRIBUTE_LENGTH, length)); } - } - else - { + } else { XmlName attributeName = new XmlName(attribute); - + SwordValidationInfo unknown = new SwordValidationInfo(xmlName, - attributeName, - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO); + attributeName, + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); unknown.setContentDescription(attribute.getValue()); attributeItems.add(unknown); } } - - if ( link.getChildCount() > 0 ) - { + + if (link.getChildCount() > 0) { SwordValidationInfo content = new SwordValidationInfo(xmlName, - "This element has content, but it is not used by SWORD", - SwordValidationInfoType.INFO); + "This element has content, but it is not used " + + "by SWORD", + SwordValidationInfoType.INFO); validationItems.add(content); } - + + } catch (Exception ex) { + log.error("Unable to parse an element in Link: " + ex.getMessage()); + throw new UnmarshallException("Unable to parse element in link", ex); } - catch ( Exception ex ) - { - log.error("Unable to parse an element in Link: " + ex.getMessage()); - throw new UnmarshallException("Unable to parse element in link", ex); - } - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { - result = validate(validationItems, attributeItems, validationProperties); + if (validationProperties != null) { + result = validate(validationItems, attributeItems, validationProperties); } - return result; + return result; } - - public SwordValidationInfo validate(Properties validationContext) - { - return validate(null, null, validationContext); + + public SwordValidationInfo validate(Properties validationContext) { + return validate(null, null, validationContext); } - + public SwordValidationInfo validate(List elements, - List attributes, - Properties validationContext) - { + List attributes, + Properties validationContext) { boolean validateAll = (elements == null); - + SwordValidationInfo result = new SwordValidationInfo(xmlName); - - if ( href == null ) - { + + if (href == null) { XmlName attributeName = new XmlName(xmlName.getPrefix(), - ATTRIBUTE_HREF, - xmlName.getNamespace()); - + ATTRIBUTE_HREF, + xmlName.getNamespace()); + SwordValidationInfo item = new SwordValidationInfo(xmlName, attributeName, - SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, - SwordValidationInfoType.ERROR); + SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, + SwordValidationInfoType.ERROR); result.addAttributeValidationInfo(item); } - - if ( validateAll ) - { - if ( href != null ) - { + + if (validateAll) { + if (href != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_HREF, href)); } - - if ( rel != null ) - { + + if (rel != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_REL, rel)); } - - if ( type != null ) - { + + if (type != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_TYPE, type)); } - - if ( hreflang != null ) - { + + if (hreflang != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_HREF_LANG, hreflang)); } - - if ( title != null ) - { + + if (title != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_TITLE, title)); } - - if ( length != null ) - { + + if (length != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_LENGTH, length)); } - + } - + result.addUnmarshallValidationInfo(elements, attributes); - return result; + return result; } - + /** - * Get the HREF attribute. - * - * @return The HREF. + * Get the HREF attribute. + * + * @return The HREF. */ public String getHref() { return href; } - + /** - * Set the HREF attribute. - * - * @param href The href. + * Set the HREF attribute. + * + * @param href The href. */ public void setHref(String href) { this.href = href; } - + /** - * Get the Rel attribute. - * - * @return The Rel. + * Get the Rel attribute. + * + * @return The Rel. */ public String getRel() { return rel; } - + /** - * Set the Rel attribute. - * - * @param rel The Rel. + * Set the Rel attribute. + * + * @param rel The Rel. */ public void setRel(String rel) { this.rel = rel; } - + /** - * Get the type. - * - * @return The type. + * Get the type. + * + * @return The type. */ public String getType() { return type; } - + /** - * Set the type. - * @param type The type. + * Set the type. + * + * @param type The type. */ public void setType(String type) { this.type = type; } - + /** - * Get the HREF Lang attribute. - * - * @return The HREF Lang. + * Get the HREF Lang attribute. + * + * @return The HREF Lang. */ public String getHreflang() { return hreflang; } - + /** - * Set the HREF Lang attribute. - * - * @param hreflang The HREF Lang. + * Set the HREF Lang attribute. + * + * @param hreflang The HREF Lang. */ public void setHreflang(String hreflang) { this.hreflang = hreflang; } - + /** - * Get the title. - * - * @return The title. + * Get the title. + * + * @return The title. */ public String getTitle() { return title; } - + /** - * Set the title. - * - * @param title The title. + * Set the title. + * + * @param title The title. */ public void setTitle(String title) { this.title = title; } - + /** - * Get the length. - * - * @return The length. + * Get the length. + * + * @return The length. */ public String getLength() { return length; } - + /** - * Set the length. - * - * @param length The length. + * Set the length. + * + * @param length The length. */ public void setLength(String length) { this.length = length; } - + /** - * Get the content. - * - * @return The content. + * Get the content. + * + * @return The content. */ public String getContent() { return content; } - + /** - * Set the content. - * - * @param content The content. + * Set the content. + * + * @param content The content. */ public void setContent(String content) { this.content = content; } - - public String toString() - { - return "Link -" + - " href: " + getHref() + - " hreflang: " + getHreflang() + - " title: " + getTitle() + - " rel: " + getRel() + - " content: " + getContent() + - " type: " + getType() + - " length: " + getLength(); + + public String toString() { + return "Link -" + + " href: " + getHref() + + " hreflang: " + getHreflang() + + " title: " + getTitle() + + " rel: " + getRel() + + " content: " + getContent() + + " type: " + getType() + + " length: " + getLength(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Name.java b/dspace-sword/src/main/java/org/purl/sword/atom/Name.java index d53bc33097..494dff5cfb 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Name.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Name.java @@ -7,32 +7,29 @@ */ package org.purl.sword.atom; -import org.purl.sword.base.*; +import org.purl.sword.base.BasicStringContentElement; +import org.purl.sword.base.Namespaces; +import org.purl.sword.base.XmlName; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class Name extends BasicStringContentElement -{ +public class Name extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "name", Namespaces.NS_ATOM); + new XmlName(Namespaces.PREFIX_ATOM, "name", Namespaces.NS_ATOM); - public Name() - { + public Name() { super(XML_NAME); } - public Name(String name) - { + public Name(String name) { this(); setContent(name); } - public static XmlName elementName() - { - return XML_NAME; + public static XmlName elementName() { + return XML_NAME; } - + } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Published.java b/dspace-sword/src/main/java/org/purl/sword/atom/Published.java index d4b01ae96a..7a10d6c203 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Published.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Published.java @@ -7,30 +7,27 @@ */ package org.purl.sword.atom; -import org.purl.sword.base.*; +import org.purl.sword.base.BasicStringContentElement; +import org.purl.sword.base.Namespaces; +import org.purl.sword.base.XmlName; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class Published extends BasicStringContentElement -{ +public class Published extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "published", Namespaces.NS_ATOM); + new XmlName(Namespaces.PREFIX_ATOM, "published", Namespaces.NS_ATOM); - public Published() - { + public Published() { super(XML_NAME); } - public Published(String uri) - { + public Published(String uri) { this(); setContent(uri); } - public static XmlName elementName() - { - return XML_NAME; + public static XmlName elementName() { + return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Rights.java b/dspace-sword/src/main/java/org/purl/sword/atom/Rights.java index a3bbdfa508..6b8b165cc7 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Rights.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Rights.java @@ -11,32 +11,28 @@ import org.purl.sword.base.Namespaces; import org.purl.sword.base.XmlName; /** - * Represents an ATOM Rights element. This is a simple subclass of the - * TextConstruct class. - * + * Represents an ATOM Rights element. This is a simple subclass of the + * TextConstruct class. + * * @author Neil Taylor */ -public class Rights extends TextConstruct -{ +public class Rights extends TextConstruct { /** - * Local name for the element. + * Local name for the element. */ private static final XmlName XML_NAME = new XmlName( - Namespaces.PREFIX_ATOM, "rights", Namespaces.NS_ATOM); - - - - /** - * Create a new instance and set the prefix to - * 'atom' and the local name to 'rights'. + Namespaces.PREFIX_ATOM, "rights", Namespaces.NS_ATOM); + + + /** + * Create a new instance and set the prefix to + * 'atom' and the local name to 'rights'. */ - public Rights() - { + public Rights() { super(XML_NAME); } - - public static XmlName elementName() - { + + public static XmlName elementName() { return XML_NAME; } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Source.java b/dspace-sword/src/main/java/org/purl/sword/atom/Source.java index c1a6ab8387..6b23d5429a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Source.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Source.java @@ -10,183 +10,161 @@ package org.purl.sword.atom; import java.util.ArrayList; import java.util.List; import java.util.Properties; + import nu.xom.Element; import nu.xom.Elements; - +import org.apache.log4j.Logger; import org.purl.sword.base.Namespaces; import org.purl.sword.base.SwordElementInterface; +import org.purl.sword.base.SwordValidationInfo; +import org.purl.sword.base.SwordValidationInfoType; import org.purl.sword.base.UnmarshallException; import org.purl.sword.base.XmlElement; import org.purl.sword.base.XmlName; -import org.apache.log4j.Logger; -import org.purl.sword.base.SwordValidationInfo; -import org.purl.sword.base.SwordValidationInfoType; /** - * Represents an ATOM Generator element. - * + * Represents an ATOM Generator element. + * * @author Neil Taylor */ -public class Source extends XmlElement implements SwordElementInterface -{ +public class Source extends XmlElement implements SwordElementInterface { /** - * Local name for the element. + * Local name for the element. */ private static final XmlName XML_NAME = new XmlName(Namespaces.PREFIX_ATOM, "source", Namespaces.NS_ATOM); - + /** - * The generator data for this object. + * The generator data for this object. */ - private Generator generator; - + private Generator generator; + /** - * The log. + * The log. */ private static Logger log = Logger.getLogger(Source.class); - + /** - * Create a new instance and set the prefix to - * 'atom' and the local name to 'source'. + * Create a new instance and set the prefix to + * 'atom' and the local name to 'source'. */ - public Source() - { - super(XML_NAME); + public Source() { + super(XML_NAME); } - - public static XmlName elementName() - { + + public static XmlName elementName() { return XML_NAME; } - + /** - * Marshal the data stored in this object into Element objects. - * - * @return An element that holds the data associated with this object. + * Marshal the data stored in this object into Element objects. + * + * @return An element that holds the data associated with this object. */ - public Element marshall() - { - Element source = new Element(getQualifiedName(), xmlName.getNamespace()); - - if ( generator != null ) - { - source.appendChild(generator.marshall()); - } - - return source; + public Element marshall() { + Element source = new Element(getQualifiedName(), xmlName.getNamespace()); + + if (generator != null) { + source.appendChild(generator.marshall()); + } + + return source; } - + /** * Unmarshal the contents of the source element into the internal data objects - * in this object. - * - * @param source The Source element to process. + * in this object. * + * @param source The Source element to process. * @throws UnmarshallException If the element does not contain an ATOM Source - * element, or if there is a problem processing the element or any - * sub-elements. + * element, or if there is a problem processing the element or any + * sub-elements. */ - public void unmarshall(Element source) - throws UnmarshallException - { - unmarshall(source, null); + public void unmarshall(Element source) + throws UnmarshallException { + unmarshall(source, null); } - + /** - * - * @param source the element to unmarshall. + * @param source the element to unmarshall. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info - * @throws UnmarshallException If there was an error unmarshalling the data. + * @throws UnmarshallException If there was an error unmarshalling the data. */ public SwordValidationInfo unmarshall(Element source, Properties validationProperties) - throws UnmarshallException - { - if ( ! isInstanceOf(source, xmlName.getLocalName(), Namespaces.NS_ATOM)) - { - //throw new UnmarshallException( "Not an atom:source element" ); - return handleIncorrectElement(source, validationProperties); - } - - ArrayList validationItems = new ArrayList(); - ArrayList attributeItems = new ArrayList(); - - try - { - processUnexpectedAttributes(source, attributeItems); - - // retrieve all of the sub-elements - Elements elements = source.getChildElements(); - Element element = null; - int length = elements.size(); - - for (int i = 0; i < length; i++ ) - { - element = elements.get(i); - if ( isInstanceOf(element, Generator.elementName()) ) - { - generator = new Generator(); - generator.unmarshall(element); - } - else - { - SwordValidationInfo info = new SwordValidationInfo(new XmlName(element), - SwordValidationInfo.UNKNOWN_ELEMENT, - SwordValidationInfoType.INFO); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } - } - } - catch ( Exception ex ) - { - log.error("Unable to parse an element in Source: " + ex.getMessage()); - throw new UnmarshallException("Unable to parse an element in Source", ex); - } - - SwordValidationInfo result = null; - if ( validationProperties != null ) - { - result = validate(validationItems, attributeItems, validationProperties); - } - return result; - + throws UnmarshallException { + if (!isInstanceOf(source, xmlName.getLocalName(), Namespaces.NS_ATOM)) { + //throw new UnmarshallException( "Not an atom:source element" ); + return handleIncorrectElement(source, validationProperties); + } + + ArrayList validationItems = new ArrayList(); + ArrayList attributeItems = new ArrayList(); + + try { + processUnexpectedAttributes(source, attributeItems); + + // retrieve all of the sub-elements + Elements elements = source.getChildElements(); + Element element = null; + int length = elements.size(); + + for (int i = 0; i < length; i++) { + element = elements.get(i); + if (isInstanceOf(element, Generator.elementName())) { + generator = new Generator(); + generator.unmarshall(element); + } else { + SwordValidationInfo info = new SwordValidationInfo(new XmlName(element), + SwordValidationInfo.UNKNOWN_ELEMENT, + SwordValidationInfoType.INFO); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } + } + } catch (Exception ex) { + log.error("Unable to parse an element in Source: " + ex.getMessage()); + throw new UnmarshallException("Unable to parse an element in Source", ex); + } + + SwordValidationInfo result = null; + if (validationProperties != null) { + result = validate(validationItems, attributeItems, validationProperties); + } + return result; + } - - public SwordValidationInfo validate(Properties validationContext) - { + + public SwordValidationInfo validate(Properties validationContext) { return validate(null, null, validationContext); } - + public SwordValidationInfo validate(List elements, - List attributes, - Properties validationContext) - { + List attributes, + Properties validationContext) { SwordValidationInfo result = new SwordValidationInfo(xmlName); - - + + result.addUnmarshallValidationInfo(elements, attributes); return result; } - - + + /** - * Get the generator. - * - * @return The generator. + * Get the generator. + * + * @return The generator. */ - public Generator getGenerator() - { - return generator; + public Generator getGenerator() { + return generator; } - + /** - * Set the generator. - * - * @param generator The generator. + * Set the generator. + * + * @param generator The generator. */ - public void setGenerator(Generator generator) - { - this.generator = generator; + public void setGenerator(Generator generator) { + this.generator = generator; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Summary.java b/dspace-sword/src/main/java/org/purl/sword/atom/Summary.java index bc5370808d..3db3116d6b 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Summary.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Summary.java @@ -8,30 +8,27 @@ package org.purl.sword.atom; import org.purl.sword.base.Namespaces; -import org.purl.sword.base.XmlName; +import org.purl.sword.base.XmlName; /** - * Represents an ATOM Summary element. This is a simple subclass of the - * TextConstruct class. - * + * Represents an ATOM Summary element. This is a simple subclass of the + * TextConstruct class. + * * @author Neil Taylor */ -public class Summary extends TextConstruct -{ +public class Summary extends TextConstruct { private static final XmlName XML_NAME = new XmlName(Namespaces.PREFIX_ATOM, "summary", Namespaces.NS_ATOM); - - /** - * Create a new instance and set the prefix to - * 'atom' and the local name to 'summary'. + + /** + * Create a new instance and set the prefix to + * 'atom' and the local name to 'summary'. */ - public Summary() - { + public Summary() { super(XML_NAME); } - - public static XmlName elementName() - { + + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/TextConstruct.java b/dspace-sword/src/main/java/org/purl/sword/atom/TextConstruct.java index 47f62dba81..98dee816ea 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/TextConstruct.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/TextConstruct.java @@ -10,328 +10,287 @@ package org.purl.sword.atom; import java.util.ArrayList; import java.util.List; import java.util.Properties; + import nu.xom.Attribute; import nu.xom.Element; - +import org.apache.log4j.Logger; import org.purl.sword.base.Namespaces; import org.purl.sword.base.SwordElementInterface; -import org.purl.sword.base.UnmarshallException; -import org.purl.sword.base.XmlElement; - -import org.apache.log4j.Logger; import org.purl.sword.base.SwordValidationInfo; import org.purl.sword.base.SwordValidationInfoType; +import org.purl.sword.base.UnmarshallException; +import org.purl.sword.base.XmlElement; import org.purl.sword.base.XmlName; /** - * Represents a text construct in the ATOM elements. This is a superclass of - * several elements within this implementation. - * + * Represents a text construct in the ATOM elements. This is a superclass of + * several elements within this implementation. + * * @author Neil Taylor */ -public class TextConstruct extends XmlElement -implements SwordElementInterface -{ +public class TextConstruct extends XmlElement + implements SwordElementInterface { /** - * The content in the element. - */ - private String content; + * The content in the element. + */ + private String content; /** - * The type of the element. + * The type of the element. */ private ContentType type; /** - * The log. + * The log. */ private static Logger log = Logger.getLogger(TextConstruct.class); - - /** - * label for the type attribute. + + /** + * label for the type attribute. */ public static final String ATTRIBUTE_TYPE = "type"; - + /** - * Create a new instance, specifying the prefix and local name. - * - * @param prefix The prefix. - * @param name The local name. + * Create a new instance, specifying the prefix and local name. + * + * @param prefix The prefix. + * @param name The local name. */ - public TextConstruct(String prefix, String name) - { - this(prefix, name, Namespaces.NS_ATOM); + public TextConstruct(String prefix, String name) { + this(prefix, name, Namespaces.NS_ATOM); } - + /** * Create a new instance. Set the default type to TextConstructType.TEXT. - * + * * @param name The name that will be applied. */ - public TextConstruct(String name) - { - this(Namespaces.PREFIX_ATOM, name); + public TextConstruct(String name) { + this(Namespaces.PREFIX_ATOM, name); } /** * Create a new instance. Set the XML name for the element. * - * @param name The name to set. + * @param name The name to set. */ - public TextConstruct(XmlName name) - { - super(name); + public TextConstruct(XmlName name) { + super(name); } /** - * - * @param prefix The prefix. - * @param name The local name. + * @param prefix The prefix. + * @param name The local name. * @param namespaceUri The namespace URI. */ - public TextConstruct(String prefix, String name, String namespaceUri) - { + public TextConstruct(String prefix, String name, String namespaceUri) { super(prefix, name, namespaceUri); initialise(); } /** - * + * */ - protected final void initialise() - { + protected final void initialise() { this.type = ContentType.TEXT; - this.content = null; + this.content = null; } /** - * Marshal the data in this object to an Element object. - * - * @return The data expressed in an Element. + * Marshal the data in this object to an Element object. + * + * @return The data expressed in an Element. */ - public Element marshall() - { + public Element marshall() { Element element = new Element(getQualifiedName(), Namespaces.NS_ATOM); - if ( type != null ) - { + if (type != null) { Attribute typeAttribute = new Attribute(ATTRIBUTE_TYPE, type.toString()); element.addAttribute(typeAttribute); } - - if ( content != null ) - { + + if (content != null) { element.appendChild(content); } return element; } - + /** * Unmarshal the text element into this object. - * - * This unmarshaller only handles plain text content, although it can + * + * This unmarshaller only handles plain text content, although it can * recognise the three different type elements of text, html and xhtml. This - * is an area that can be improved in a future implementation, if necessary. - * - * @param text The text element. - * + * is an area that can be improved in a future implementation, if necessary. + * + * @param text The text element. * @throws UnmarshallException If the specified element is not of * the correct type, where the localname is used - * to specify the valid name. Also thrown - * if there is an issue accessing the data. + * to specify the valid name. Also thrown + * if there is an issue accessing the data. */ public void unmarshall(Element text) - throws UnmarshallException - { + throws UnmarshallException { unmarshall(text, null); } - + /** - * - * @param text The text element. + * @param text The text element. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info * @throws UnmarshallException If the specified element is not of * the correct type, where the localname is used - * to specify the valid name. Also thrown - * if there is an issue accessing the data. + * to specify the valid name. Also thrown + * if there is an issue accessing the data. */ public SwordValidationInfo unmarshall(Element text, Properties validationProperties) - throws UnmarshallException - { - if ( ! isInstanceOf(text, xmlName)) - { + throws UnmarshallException { + if (!isInstanceOf(text, xmlName)) { return handleIncorrectElement(text, validationProperties); } - + ArrayList validationItems = new ArrayList(); ArrayList attributeItems = new ArrayList(); - - try - { + + try { initialise(); - + // get the attributes int attributeCount = text.getAttributeCount(); Attribute attribute = null; - for ( int i = 0; i < attributeCount; i++ ) - { + for (int i = 0; i < attributeCount; i++) { attribute = text.getAttribute(i); - if ( ATTRIBUTE_TYPE.equals(attribute.getQualifiedName())) - { + if (ATTRIBUTE_TYPE.equals(attribute.getQualifiedName())) { boolean success = true; String value = attribute.getValue(); - if ( ContentType.TEXT.toString().equals(value) ) - { + if (ContentType.TEXT.toString().equals(value)) { type = ContentType.TEXT; - } - else if ( ContentType.HTML.toString().equals(value) ) - { + } else if (ContentType.HTML.toString().equals(value)) { type = ContentType.HTML; - } - else if ( ContentType.XHTML.toString().equals(value) ) - { + } else if (ContentType.XHTML.toString().equals(value)) { type = ContentType.XHTML; - } - else - { - log.error("Unable to parse extract type in " + getQualifiedName() ); + } else { + log.error("Unable to parse extract type in " + getQualifiedName()); SwordValidationInfo info = new SwordValidationInfo(xmlName, - new XmlName(attribute), - "Invalid content type has been specified", - SwordValidationInfoType.ERROR); + new XmlName(attribute), + "Invalid content type has been specified", + SwordValidationInfoType.ERROR); info.setContentDescription(value); attributeItems.add(info); success = false; } - - if ( success ) - { + + if (success) { SwordValidationInfo info = new SwordValidationInfo(xmlName, new XmlName(attribute)); info.setContentDescription(type.toString()); attributeItems.add(info); } - } - else - { + } else { SwordValidationInfo info = new SwordValidationInfo(xmlName, - new XmlName(attribute), - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO); + new XmlName(attribute), + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); info.setContentDescription(attribute.getValue()); attributeItems.add(info); } } - + // retrieve all of the sub-elements int length = text.getChildCount(); - if ( length > 0 ) - { + if (length > 0) { content = unmarshallString(text); } - - } - catch ( Exception ex ) - { + + } catch (Exception ex) { log.error("Unable to parse an element in " + getQualifiedName() + ": " + ex.getMessage()); throw new UnmarshallException("Unable to parse an element in " + getQualifiedName(), ex); } - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(validationItems, attributeItems, validationProperties); } - return result; + return result; } - - public SwordValidationInfo validate(Properties validationContext) - { + + public SwordValidationInfo validate(Properties validationContext) { return validate(null, null, validationContext); } - + /** - * - * @param existing add results to this. - * @param attributeItems add these too. + * @param existing add results to this. + * @param attributeItems add these too. * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info */ protected SwordValidationInfo validate(List existing, - List attributeItems, - Properties validationContext) - { + List attributeItems, + Properties validationContext) { boolean validateAll = (existing == null); - - SwordValidationInfo result = new SwordValidationInfo(xmlName); + + SwordValidationInfo result = new SwordValidationInfo(xmlName); result.setContentDescription(content); - + // item specific rules - if ( content == null ) - { + if (content == null) { result.addValidationInfo( new SwordValidationInfo(xmlName, "Missing content for element", - SwordValidationInfoType.WARNING)); + SwordValidationInfoType.WARNING)); } - - if ( validateAll ) - { + + if (validateAll) { SwordValidationInfo info = new SwordValidationInfo(xmlName, - new XmlName(xmlName.getPrefix(), ATTRIBUTE_TYPE, xmlName.getNamespace())); + new XmlName(xmlName.getPrefix(), ATTRIBUTE_TYPE, + xmlName.getNamespace())); info.setContentDescription(type.toString()); result.addAttributeValidationInfo(info); } - + result.addUnmarshallValidationInfo(existing, attributeItems); - return result; + return result; } - - + + /** - * Get the content in this TextConstruct. - * - * @return The content, expressed as a string. + * Get the content in this TextConstruct. + * + * @return The content, expressed as a string. */ public String getContent() { return content; } - + /** - * Set the content. This only supports text content. - * - * @param content The content. + * Set the content. This only supports text content. + * + * @param content The content. */ - public void setContent(String content) - { + public void setContent(String content) { this.content = content; } - + /** - * Get the type. - * - * @return The type. + * Get the type. + * + * @return The type. */ - public ContentType getType() - { - return type; + public ContentType getType() { + return type; } - + /** - * Set the type. - * - * @param type The type. + * Set the type. + * + * @param type The type. */ - public void setType(ContentType type) - { + public void setType(ContentType type) { this.type = type; } - - /** - * Get a string representation. - * - * @return The string. + + /** + * Get a string representation. + * + * @return The string. */ - public String toString() - { + public String toString() { return "Summary - content: " + getContent() + " type: " + getType(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Title.java b/dspace-sword/src/main/java/org/purl/sword/atom/Title.java index 64f6195c84..2e5c434f1c 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Title.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Title.java @@ -11,37 +11,34 @@ import org.purl.sword.base.Namespaces; import org.purl.sword.base.XmlName; /** - * Represents an ATOM Title element. This is a simple subclass of the - * TextConstruct class. - * + * Represents an ATOM Title element. This is a simple subclass of the + * TextConstruct class. + * * @author Neil Taylor */ -public class Title extends TextConstruct -{ +public class Title extends TextConstruct { /** - * Local name part of the element. + * Local name part of the element. */ @Deprecated public static final String ELEMENT_NAME = "title"; /** - * XML Name representation. + * XML Name representation. */ private static final XmlName XML_NAME = new XmlName(Namespaces.PREFIX_ATOM, - "title", Namespaces.NS_ATOM); + "title", Namespaces.NS_ATOM); - /** - * Create a new instance and set the prefix to - * 'atom' and the local name to 'title'. + /** + * Create a new instance and set the prefix to + * 'atom' and the local name to 'title'. */ - public Title() - { + public Title() { super(XML_NAME); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Updated.java b/dspace-sword/src/main/java/org/purl/sword/atom/Updated.java index 49d48d981b..d5f643862d 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Updated.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Updated.java @@ -7,30 +7,27 @@ */ package org.purl.sword.atom; -import org.purl.sword.base.*; +import org.purl.sword.base.BasicStringContentElement; +import org.purl.sword.base.Namespaces; +import org.purl.sword.base.XmlName; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class Updated extends BasicStringContentElement -{ +public class Updated extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "updated", Namespaces.NS_ATOM); + new XmlName(Namespaces.PREFIX_ATOM, "updated", Namespaces.NS_ATOM); - public Updated() - { + public Updated() { super(XML_NAME); } - public Updated(String uri) - { + public Updated(String uri) { this(); setContent(uri); } - public static XmlName elementName() - { - return XML_NAME; + public static XmlName elementName() { + return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/atom/Uri.java b/dspace-sword/src/main/java/org/purl/sword/atom/Uri.java index 9fb051238b..58fd48d861 100644 --- a/dspace-sword/src/main/java/org/purl/sword/atom/Uri.java +++ b/dspace-sword/src/main/java/org/purl/sword/atom/Uri.java @@ -7,30 +7,27 @@ */ package org.purl.sword.atom; -import org.purl.sword.base.*; +import org.purl.sword.base.BasicStringContentElement; +import org.purl.sword.base.Namespaces; +import org.purl.sword.base.XmlName; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class Uri extends BasicStringContentElement -{ +public class Uri extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_ATOM, "uri", Namespaces.NS_ATOM); + new XmlName(Namespaces.PREFIX_ATOM, "uri", Namespaces.NS_ATOM); - public Uri() - { + public Uri() { super(XML_NAME); } - public Uri(String uri) - { + public Uri(String uri) { this(); setContent(uri); } - public static XmlName elementName() - { - return XML_NAME; + public static XmlName elementName() { + return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/AtomDocumentRequest.java b/dspace-sword/src/main/java/org/purl/sword/base/AtomDocumentRequest.java index f3a0461e63..da2a431a58 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/AtomDocumentRequest.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/AtomDocumentRequest.java @@ -8,95 +8,102 @@ package org.purl.sword.base; /** - * Represents an AtomDocumentRequest. - * - * @author Stuart Lewis + * Represents an AtomDocumentRequest. + * + * @author Stuart Lewis */ -public class AtomDocumentRequest -{ - /** The username */ - private String username; - - /** The password */ - private String password; - - /** The IP address */ - private String IPAddress; - - /** The location */ - private String location; - +public class AtomDocumentRequest { + /** + * The username + */ + private String username; - /** - * Retrieve the username. - * - * @return the authenticatedUserName - */ - public String getUsername() { - return username; - } + /** + * The password + */ + private String password; - /** - * Set the username. - * - * @param username the authenticated UserName to set - */ - public void setUsername(String username) { - this.username = username; - } + /** + * The IP address + */ + private String IPAddress; - /** - * Get the password. - * - * @return the authenticatedUserPassword - */ - public String getPassword() { - return password; - } + /** + * The location + */ + private String location; - /** - * Set the password. - * - * @param password the password to set - */ - public void setPassword(String password) { - this.password = password; - } - - /** - * Get the IP address of the user - * - * @return the the IP address - */ - public String getIPAddress() { - return IPAddress; - } - - /** - * Set the IP address of the user - * - * @param IPAddress the IP address - */ - public void setIPAddress(String IPAddress) { - this.IPAddress = IPAddress; - } - - /** - * Get the location of the service document - * - * @return the location of the service document - */ - public String getLocation() { - return location; - } - - /** - * Set the location of the service document - * - * @param location the location - */ - public void setLocation(String location) { - this.location = location; - } + + /** + * Retrieve the username. + * + * @return the authenticatedUserName + */ + public String getUsername() { + return username; + } + + /** + * Set the username. + * + * @param username the authenticated UserName to set + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Get the password. + * + * @return the authenticatedUserPassword + */ + public String getPassword() { + return password; + } + + /** + * Set the password. + * + * @param password the password to set + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Get the IP address of the user + * + * @return the the IP address + */ + public String getIPAddress() { + return IPAddress; + } + + /** + * Set the IP address of the user + * + * @param IPAddress the IP address + */ + public void setIPAddress(String IPAddress) { + this.IPAddress = IPAddress; + } + + /** + * Get the location of the service document + * + * @return the location of the service document + */ + public String getLocation() { + return location; + } + + /** + * Set the location of the service document + * + * @param location the location + */ + public void setLocation(String location) { + this.location = location; + } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/AtomDocumentResponse.java b/dspace-sword/src/main/java/org/purl/sword/base/AtomDocumentResponse.java index 73f40216fd..e6f3683e3d 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/AtomDocumentResponse.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/AtomDocumentResponse.java @@ -8,20 +8,18 @@ package org.purl.sword.base; /** - * Represents a deposit response. This holds the SWORD Entry element. - * + * Represents a deposit response. This holds the SWORD Entry element. + * * @author Stuart Lewis */ -public class AtomDocumentResponse extends DepositResponse -{ +public class AtomDocumentResponse extends DepositResponse { - /** - * Create a new response with the specified http code. - * - * @param httpResponse Response code. + /** + * Create a new response with the specified http code. + * + * @param httpResponse Response code. */ - public AtomDocumentResponse(int httpResponse) - { + public AtomDocumentResponse(int httpResponse) { super(httpResponse); } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/BasicBooleanContentElement.java b/dspace-sword/src/main/java/org/purl/sword/base/BasicBooleanContentElement.java index c09a8c83ff..01b2a7e6aa 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/BasicBooleanContentElement.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/BasicBooleanContentElement.java @@ -8,69 +8,58 @@ package org.purl.sword.base; import java.util.Properties; + import nu.xom.Element; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class BasicBooleanContentElement extends BasicContentElement -{ +public class BasicBooleanContentElement extends BasicContentElement { private boolean content; private boolean isSet; - public BasicBooleanContentElement(String prefix, String localName, String namespaceUri) - { + public BasicBooleanContentElement(String prefix, String localName, String namespaceUri) { super(prefix, localName, namespaceUri); } - public BasicBooleanContentElement(XmlName name) - { + public BasicBooleanContentElement(XmlName name) { super(name); } - public boolean getContent() - { + public boolean getContent() { return content; } - public void setContent(boolean value) - { - isSet = true; - content = value; + public void setContent(boolean value) { + isSet = true; + content = value; } - public boolean isSet() - { + public boolean isSet() { return isSet; } - protected void marshallContent(Element element) - { - element.appendChild(Boolean.toString(content)); + protected void marshallContent(Element element) { + element.appendChild(Boolean.toString(content)); } protected void unmarshallContent(Element element) - throws UnmarshallException - { - setContent(unmarshallBoolean(element)); + throws UnmarshallException { + setContent(unmarshallBoolean(element)); } - protected SwordValidationInfo validateContent(Properties validationContext) - { + protected SwordValidationInfo validateContent(Properties validationContext) { SwordValidationInfo result = null; - if ( ! isSet ) - { + if (!isSet) { result = new SwordValidationInfo(xmlName, - SwordValidationInfo.MISSING_CONTENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.MISSING_CONTENT, + SwordValidationInfoType.WARNING); } - return result; + return result; } - protected String getContentAsString() - { + protected String getContentAsString() { return Boolean.toString(content); } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/BasicContentElement.java b/dspace-sword/src/main/java/org/purl/sword/base/BasicContentElement.java index 69a487760f..2ed1ba9400 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/BasicContentElement.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/BasicContentElement.java @@ -10,166 +10,142 @@ package org.purl.sword.base; import java.util.ArrayList; import java.util.List; import java.util.Properties; + import nu.xom.Element; - - import org.apache.log4j.Logger; -import org.purl.sword.base.XmlName; /** - * Represents a text construct in the ATOM elements. This is a superclass of - * several elements within this implementation. - * + * Represents a text construct in the ATOM elements. This is a superclass of + * several elements within this implementation. + * * @author Neil Taylor */ public abstract class BasicContentElement extends XmlElement -implements SwordElementInterface -{ + implements SwordElementInterface { /** - * The log. + * The log. */ private static Logger log = Logger.getLogger(BasicContentElement.class); - - public BasicContentElement(String prefix, String name, String namespaceUri) - { + + public BasicContentElement(String prefix, String name, String namespaceUri) { super(prefix, name, namespaceUri); } - public BasicContentElement(XmlName name) - { + public BasicContentElement(XmlName name) { super(name); } /** - * Marshal the data in this object to an Element object. - * - * @return The data expressed in an Element. + * Marshal the data in this object to an Element object. + * + * @return The data expressed in an Element. */ - public Element marshall() - { + public Element marshall() { Element element = new Element(getQualifiedName(), xmlName.getNamespace()); - marshallContent(element); + marshallContent(element); return element; } - + protected abstract void marshallContent(Element element); - + /** * Unmarshal the text element into this object. - * - * This unmarshaller only handles plain text content, although it can + * + * This unmarshaller only handles plain text content, although it can * recognise the three different type elements of text, html and xhtml. This - * is an area that can be improved in a future implementation, if necessary. - * - * @param element The text element. + * is an area that can be improved in a future implementation, if necessary. + * + * @param element The text element. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return object representing the text element * @throws UnmarshallException If the specified element is not of * the correct type, where the localname is used - * to specify the valid name. Also thrown - * if there is an issue accessing the data. + * to specify the valid name. Also thrown + * if there is an issue accessing the data. */ public SwordValidationInfo unmarshall(Element element, Properties validationProperties) - throws UnmarshallException - { - if ( ! isInstanceOf(element, xmlName) ) - { + throws UnmarshallException { + if (!isInstanceOf(element, xmlName)) { return handleIncorrectElement(element, validationProperties); } - + ArrayList validationItems = new ArrayList(); ArrayList attributeItems = new ArrayList(); - - try - { + + try { processUnexpectedAttributes(element, attributeItems); - + int length = element.getChildCount(); - if ( length > 0 ) - { - try - { - unmarshallContent(element); - } - catch ( UnmarshallException ume ) - { - log.error("Error accessing the content of the " + xmlName.getQualifiedName() + " element"); - if ( validationProperties == null ) - { - throw ume; - } - else - { - SwordValidationInfo info = new SwordValidationInfo(xmlName, - SwordValidationInfo.ERROR_WITH_CONTENT, SwordValidationInfoType.ERROR); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } + if (length > 0) { + try { + unmarshallContent(element); + } catch (UnmarshallException ume) { + log.error("Error accessing the content of the " + xmlName.getQualifiedName() + " element"); + if (validationProperties == null) { + throw ume; + } else { + SwordValidationInfo info = new SwordValidationInfo(xmlName, + SwordValidationInfo.ERROR_WITH_CONTENT, + SwordValidationInfoType.ERROR); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } } } - - } - catch ( Exception ex ) - { + + } catch (Exception ex) { log.error("Unable to parse an element in " + getQualifiedName() + ": " + ex.getMessage()); - if ( validationProperties == null ) - { - throw new UnmarshallException("Unable to parse an element in " + getQualifiedName(), ex); + if (validationProperties == null) { + throw new UnmarshallException("Unable to parse an element in " + getQualifiedName(), ex); } } - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(validationItems, attributeItems, validationProperties); } return result; } - + public void unmarshall(Element element) - throws UnmarshallException - { - + throws UnmarshallException { + } - + @Override - public SwordValidationInfo validate(Properties validationContext) - { + public SwordValidationInfo validate(Properties validationContext) { return validate(null, null, validationContext); } - + /** - * - * @param existing add results to this. - * @param attributeItems FIXME: PLEASE DOCUMENT. + * @param existing add results to this. + * @param attributeItems FIXME: PLEASE DOCUMENT. * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info */ protected SwordValidationInfo validate(List existing, - List attributeItems, - Properties validationContext) - { - SwordValidationInfo result = new SwordValidationInfo(xmlName); + List attributeItems, + Properties validationContext) { + SwordValidationInfo result = new SwordValidationInfo(xmlName); result.setContentDescription(getContentAsString()); - + SwordValidationInfo contentResult = validateContent(validationContext); - if ( contentResult != null ) - { + if (contentResult != null) { result.addValidationInfo(contentResult); } - + result.addUnmarshallValidationInfo(existing, attributeItems); return result; } - - + + protected abstract void unmarshallContent(Element element) - throws UnmarshallException; - - + throws UnmarshallException; + + protected abstract SwordValidationInfo validateContent(Properties validationContext); - - + + protected abstract String getContentAsString(); - + } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/BasicIntegerContentElement.java b/dspace-sword/src/main/java/org/purl/sword/base/BasicIntegerContentElement.java index b144f2a86d..ca873f7c5d 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/BasicIntegerContentElement.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/BasicIntegerContentElement.java @@ -8,69 +8,58 @@ package org.purl.sword.base; import java.util.Properties; + import nu.xom.Element; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class BasicIntegerContentElement extends BasicContentElement -{ +public class BasicIntegerContentElement extends BasicContentElement { private int content = 0; private boolean isSet; - public BasicIntegerContentElement(String prefix, String localName, String namespaceUri) - { + public BasicIntegerContentElement(String prefix, String localName, String namespaceUri) { super(prefix, localName, namespaceUri); } - public BasicIntegerContentElement(XmlName name) - { + public BasicIntegerContentElement(XmlName name) { super(name); } - public int getContent() - { + public int getContent() { return content; } - public void setContent(int value) - { - isSet = true; - content = value; + public void setContent(int value) { + isSet = true; + content = value; } - public boolean isSet() - { + public boolean isSet() { return isSet; } - protected void marshallContent(Element element) - { - element.appendChild(Integer.toString(content)); + protected void marshallContent(Element element) { + element.appendChild(Integer.toString(content)); } protected void unmarshallContent(Element element) - throws UnmarshallException - { - setContent(unmarshallInteger(element)); + throws UnmarshallException { + setContent(unmarshallInteger(element)); } - protected SwordValidationInfo validateContent(Properties validationContext) - { + protected SwordValidationInfo validateContent(Properties validationContext) { SwordValidationInfo result = null; - if ( ! isSet ) - { - result = new SwordValidationInfo(xmlName, - SwordValidationInfo.MISSING_CONTENT, - SwordValidationInfoType.WARNING); + if (!isSet) { + result = new SwordValidationInfo(xmlName, + SwordValidationInfo.MISSING_CONTENT, + SwordValidationInfoType.WARNING); } return result; } - protected String getContentAsString() - { + protected String getContentAsString() { return Integer.toString(content); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/BasicStringContentElement.java b/dspace-sword/src/main/java/org/purl/sword/base/BasicStringContentElement.java index cc45a1ce5f..bf1a811ca0 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/BasicStringContentElement.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/BasicStringContentElement.java @@ -8,65 +8,54 @@ package org.purl.sword.base; import java.util.Properties; + import nu.xom.Element; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class BasicStringContentElement extends BasicContentElement -{ +public class BasicStringContentElement extends BasicContentElement { private String content; - public BasicStringContentElement(String prefix, String localName, String namespaceUri) - { + public BasicStringContentElement(String prefix, String localName, String namespaceUri) { super(prefix, localName, namespaceUri); } - public BasicStringContentElement(XmlName name) - { - super(name); + public BasicStringContentElement(XmlName name) { + super(name); } - public String getContent() - { + public String getContent() { return content; } - public void setContent(String value) - { - content = value; + public void setContent(String value) { + content = value; } - protected void marshallContent(Element element) - { - if ( content != null ) - { + protected void marshallContent(Element element) { + if (content != null) { element.appendChild(content); } } protected void unmarshallContent(Element element) - throws UnmarshallException - { - setContent(unmarshallString(element)); + throws UnmarshallException { + setContent(unmarshallString(element)); } - protected SwordValidationInfo validateContent(Properties validationContext) - { + protected SwordValidationInfo validateContent(Properties validationContext) { SwordValidationInfo result = null; - if ( content == null ) - { + if (content == null) { result = new SwordValidationInfo(xmlName, - SwordValidationInfo.MISSING_CONTENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.MISSING_CONTENT, + SwordValidationInfoType.WARNING); } - return result; + return result; } - protected String getContentAsString() - { + protected String getContentAsString() { return content; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/ChecksumUtils.java b/dspace-sword/src/main/java/org/purl/sword/base/ChecksumUtils.java index 926b24277c..c2b2a6563a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/ChecksumUtils.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/ChecksumUtils.java @@ -12,155 +12,141 @@ import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; + import org.apache.log4j.Logger; /** - * Utility class that holds Checksum related methods. - * + * Utility class that holds Checksum related methods. + * * @author Neil Taylor - * @author Stuart Lewis + * @author Stuart Lewis */ -public class ChecksumUtils -{ - /** Logger */ - private static Logger log = Logger.getLogger(ChecksumUtils.class); - +public class ChecksumUtils { /** - * Generate an MD5 hash for the file that is specified in the - * filepath. The hash is returned as a String representation. - * - * @param filepath The path to the file to load. - * @return A string hash of the file. - * @throws NoSuchAlgorithmException If the MD5 algorithm is - * not supported by the installed virtual machine. - * - * @throws IOException If there is an error accessing the file. + * Logger + */ + private static Logger log = Logger.getLogger(ChecksumUtils.class); + + /** + * Default constructor + */ + private ChecksumUtils() { } + + /** + * Generate an MD5 hash for the file that is specified in the + * filepath. The hash is returned as a String representation. + * + * @param filepath The path to the file to load. + * @return A string hash of the file. + * @throws NoSuchAlgorithmException If the MD5 algorithm is + * not supported by the installed virtual machine. + * @throws IOException If there is an error accessing the file. */ public static String generateMD5(String filepath) - throws NoSuchAlgorithmException, IOException - { - return generateMD5(new FileInputStream(filepath)); + throws NoSuchAlgorithmException, IOException { + return generateMD5(new FileInputStream(filepath)); } - + /** - * Generate an MD5 hash for the file that is specified in the - * filepath. The hash is returned as a String representation. - * - * @param md5Stream The InputStream to checksum. - * @return A string hash of the file. - * @throws NoSuchAlgorithmException If the MD5 algorithm is - * not supported by the installed virtual machine. - * - * @throws IOException If there is an error accessing the file. + * Generate an MD5 hash for the file that is specified in the + * filepath. The hash is returned as a String representation. + * + * @param md5Stream The InputStream to checksum. + * @return A string hash of the file. + * @throws NoSuchAlgorithmException If the MD5 algorithm is + * not supported by the installed virtual machine. + * @throws IOException If there is an error accessing the file. */ public static String generateMD5(InputStream md5Stream) - throws NoSuchAlgorithmException, IOException - { - String md5 = null; - - try - { - MessageDigest md = MessageDigest.getInstance("MD5"); - md.reset(); - - byte[] bytes = new byte[1024]; - int count = 0; - while ( (count = md5Stream.read(bytes)) != -1 ) - { - md.update(bytes, 0, count); - } - - byte[] md5Digest = md.digest(); - - StringBuffer buffer = new StringBuffer(); - for ( byte b : md5Digest ) - { - // 0xFF is used to handle the issue of negative numbers in the bytes - String hex = Integer.toHexString(b & 0xFF); - if ( hex.length() == 1 ) - { - buffer.append("0"); - } - buffer.append(hex); - } - - md5 = buffer.toString(); - } - catch (NoSuchAlgorithmException ex ) - { - log.error("MD5 Algorithm Not found"); - throw ex; - } - finally - { - if ( md5Stream != null ) - { - md5Stream.close(); - } - } - - return md5; + throws NoSuchAlgorithmException, IOException { + String md5 = null; + + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.reset(); + + byte[] bytes = new byte[1024]; + int count = 0; + while ((count = md5Stream.read(bytes)) != -1) { + md.update(bytes, 0, count); + } + + byte[] md5Digest = md.digest(); + + StringBuffer buffer = new StringBuffer(); + for (byte b : md5Digest) { + // 0xFF is used to handle the issue of negative numbers in the bytes + String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + buffer.append("0"); + } + buffer.append(hex); + } + + md5 = buffer.toString(); + } catch (NoSuchAlgorithmException ex) { + log.error("MD5 Algorithm Not found"); + throw ex; + } finally { + if (md5Stream != null) { + md5Stream.close(); + } + } + + return md5; } - + /** - * Generate an MD5 hash for the file that is specified in the - * filepath. The hash is returned as a String representation. - * - * @param bytes The byte array to checksum. - * @return A string hash of the file. - * @throws NoSuchAlgorithmException If the MD5 algorithm is - * not supported by the installed virtual machine. - * - * @throws IOException If there is an error accessing the file. + * Generate an MD5 hash for the file that is specified in the + * filepath. The hash is returned as a String representation. + * + * @param bytes The byte array to checksum. + * @return A string hash of the file. + * @throws NoSuchAlgorithmException If the MD5 algorithm is + * not supported by the installed virtual machine. + * @throws IOException If there is an error accessing the file. */ public static String generateMD5(byte[] bytes) - throws NoSuchAlgorithmException, IOException - { - String md5 = null; - - try - { - MessageDigest md = MessageDigest.getInstance("MD5"); - md.reset(); - - md.update(bytes); - - - byte[] md5Digest = md.digest(); - - StringBuffer buffer = new StringBuffer(); - for ( byte b : md5Digest ) - { - // 0xFF is used to handle the issue of negative numbers in the bytes - String hex = Integer.toHexString(b & 0xFF); - if ( hex.length() == 1 ) - { - buffer.append("0"); - } - buffer.append(hex); - } - - md5 = buffer.toString(); - } - catch (NoSuchAlgorithmException ex) - { - log.error("MD5 Algorithm Not found"); - throw ex; // rethrow - } - - return md5; + throws NoSuchAlgorithmException, IOException { + String md5 = null; + + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.reset(); + + md.update(bytes); + + + byte[] md5Digest = md.digest(); + + StringBuffer buffer = new StringBuffer(); + for (byte b : md5Digest) { + // 0xFF is used to handle the issue of negative numbers in the bytes + String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + buffer.append("0"); + } + buffer.append(hex); + } + + md5 = buffer.toString(); + } catch (NoSuchAlgorithmException ex) { + log.error("MD5 Algorithm Not found"); + throw ex; // rethrow + } + + return md5; } - + /** - * Run a simple test to process the file. - * + * Run a simple test to process the file. + * * @param args the command line arguments given - * @throws NoSuchAlgorithmException If there was an error generating the MD5. - * @throws IOException If there is an error accessing the file. + * @throws NoSuchAlgorithmException If there was an error generating the MD5. + * @throws IOException If there is an error accessing the file. */ - public static void main(String[] args) - throws NoSuchAlgorithmException, IOException - { + public static void main(String[] args) + throws NoSuchAlgorithmException, IOException { System.out.println(ChecksumUtils.generateMD5(args[0])); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/Collection.java b/dspace-sword/src/main/java/org/purl/sword/base/Collection.java index 0b782a5963..34c2f3817d 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/Collection.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/Collection.java @@ -10,99 +10,94 @@ package org.purl.sword.base; import java.util.ArrayList; import java.util.Iterator; import java.util.List; - import java.util.Properties; + import nu.xom.Attribute; import nu.xom.Element; import nu.xom.Elements; - import org.apache.log4j.Logger; +import org.purl.sword.atom.Accept; import org.purl.sword.atom.ContentType; import org.purl.sword.atom.Title; -import org.purl.sword.atom.Accept; /** * A representation of a SWORD Collection. - * + * * @author Stuart Lewis * @author Neil Taylor */ -public class Collection extends XmlElement implements SwordElementInterface -{ - /** - * Collection location, expressed as a URL. +public class Collection extends XmlElement implements SwordElementInterface { + /** + * Collection location, expressed as a URL. */ private String location; - + /** - * Holds the ATOM Title for the collection. + * Holds the ATOM Title for the collection. */ private Title title; - - /** - * List of the APP:Accept elements. + + /** + * List of the APP:Accept elements. */ private List accepts; - + /** - * Holds the SWORD Collection policy. + * Holds the SWORD Collection policy. */ //private String collectionPolicy; - - /** - * The SWORD mediation value. Indicates if mediation is allowed. + + /** + * The SWORD mediation value. Indicates if mediation is allowed. */ //private boolean mediation; private SwordMediation swordMediation; - + private SwordService swordService; - + private DcAbstract dcTermsAbstract; - + private SwordTreatment swordTreatment; - - private SwordCollectionPolicy swordCollectionPolicy; - + + private SwordCollectionPolicy swordCollectionPolicy; + /** * The SWORD acceptsPackaging details. */ private List acceptPackaging; - + /** - * The logger. + * The logger. */ private static Logger log = Logger.getLogger(Collection.class); - + /** - * Label for the Href attribute. + * Label for the Href attribute. */ public static final String ATTRIBUTE_HREF = "href"; - + /** - * Label for the local part of this element. + * Label for the local part of this element. */ @Deprecated public static final String ELEMENT_NAME = "collection"; - + private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_APP, "collection", Namespaces.NS_APP); - + new XmlName(Namespaces.PREFIX_APP, "collection", Namespaces.NS_APP); + /** * Create a new instance. */ - public Collection() - { + public Collection() { super(XML_NAME); - initialise(); + initialise(); } - - public static XmlName elementName() - { + + public static XmlName elementName() { return XML_NAME; } - - protected final void initialise() - { + + protected final void initialise() { location = null; title = null; accepts = new ArrayList(); @@ -113,667 +108,566 @@ public class Collection extends XmlElement implements SwordElementInterface dcTermsAbstract = null; swordTreatment = null; } - + /** - * Create a new instance and set the initial location for the collection. - * - * @param location The initial location, expressed as a URL. + * Create a new instance and set the initial location for the collection. + * + * @param location The initial location, expressed as a URL. */ - public Collection(String location) - { + public Collection(String location) { this(); this.location = location; } - + /** - * Retrieve an array that holds all of the Accept details. - * - * @return An array of strings. Each string represents an - * individual accept element. The array will have a length - * of 0 if no accepts elements are stored in this collection. + * Retrieve an array that holds all of the Accept details. + * + * @return An array of strings. Each string represents an + * individual accept element. The array will have a length + * of 0 if no accepts elements are stored in this collection. */ - public String[] getAccepts() - { + public String[] getAccepts() { String[] values = new String[this.accepts.size()]; Iterator iterator = accepts.iterator(); - for (int i = 0; iterator.hasNext(); i++ ) - { + for (int i = 0; iterator.hasNext(); i++) { Accept accept = iterator.next(); values[i] = accept.getContent(); } - return values; + return values; } - + /** - * Retrieve an array that holds all of the Accept details. - * - * @return An array of strings. Each string represents an - * individual accept element. The array will have a length - * of 0 if no accepts elements are stored in this collection. + * Retrieve an array that holds all of the Accept details. + * + * @return An array of strings. Each string represents an + * individual accept element. The array will have a length + * of 0 if no accepts elements are stored in this collection. */ @Deprecated - public List getAcceptsList() - { + public List getAcceptsList() { ArrayList items = new ArrayList(); - for (Accept item : accepts ) - { + for (Accept item : accepts) { items.add(item.getContent()); } return items; - } - + } + /** * Return the list of accepts entries. * * @return the list of accepts entries */ - public List getAcceptList() - { + public List getAcceptList() { return accepts; } - + /** - * Add an accepts entry. - * - * @param accepts The accepts value. + * Add an accepts entry. + * + * @param accepts The accepts value. */ public void addAccepts(String accepts) { this.accepts.add(new Accept(accepts)); } - + /** - * Remove all of the accepts associated with this Collection. + * Remove all of the accepts associated with this Collection. */ - public void clearAccepts( ) - { + public void clearAccepts() { this.accepts.clear(); } - + /** - * Retrieve a hashtable that holds all the acceptsPackaging details. - * + * Retrieve a hashtable that holds all the acceptsPackaging details. + * * @return A hashtable. The keys are accepted packaging formats, - * and the values the quality values (stored as QualityValue objects) + * and the values the quality values (stored as QualityValue objects) */ - public List getAcceptPackaging() - { + public List getAcceptPackaging() { return acceptPackaging; } - + /** - * Add an acceptPackaging format. - * + * Add an acceptPackaging format. + * * @param acceptPackaging the packaging format. - * @param qualityValue the quality value of accepted packaging format. + * @param qualityValue the quality value of accepted packaging format. */ public void addAcceptPackaging(String acceptPackaging, float qualityValue) { - - this.acceptPackaging.add(new SwordAcceptPackaging(acceptPackaging, qualityValue)); + + this.acceptPackaging.add(new SwordAcceptPackaging(acceptPackaging, qualityValue)); } - + /** * Add an acceptPackaging format. A default quality vale is given. - * + * * @param acceptPackaging the packaging format. */ public void addAcceptPackaging(String acceptPackaging) { this.acceptPackaging.add(new SwordAcceptPackaging(acceptPackaging, new QualityValue())); } - + /** - * Remove all of the accepted packaging formats associated with this Collection. + * Remove all of the accepted packaging formats associated with this Collection. */ - public void clearAcceptPackaging( ) - { + public void clearAcceptPackaging() { this.acceptPackaging.clear(); } - + /** - * Get the collection policy. - * + * Get the collection policy. + * * @return The SWORD collectionPolicy. */ - public String getCollectionPolicy() - { - if ( swordCollectionPolicy == null ) - { - return null; + public String getCollectionPolicy() { + if (swordCollectionPolicy == null) { + return null; } return swordCollectionPolicy.getContent(); } - + /** - * Set the collection policy. - * + * Set the collection policy. + * * @param collectionPolicy The collection policy. */ - public void setCollectionPolicy(String collectionPolicy) - { + public void setCollectionPolicy(String collectionPolicy) { swordCollectionPolicy = new SwordCollectionPolicy(collectionPolicy); } - + /** - * Get the location. - * + * Get the location. + * * @return TShe location */ public String getLocation() { return location; } - + /** - * Set the location. - * + * Set the location. + * * @param location The location. */ public void setLocation(String location) { this.location = location; } - + /** - * Get the mediation value. - * + * Get the mediation value. + * * @return The mediation */ public boolean getMediation() { - if ( swordMediation == null ) - { - return false; + if (swordMediation == null) { + return false; } return swordMediation.getContent(); } - - public boolean isMediationSet() - { - if ( swordMediation == null ) - { + + public boolean isMediationSet() { + if (swordMediation == null) { return false; } return swordMediation.isSet(); } - + /** - * Set the mediation value. - * - * @param mediation The mediation value. + * Set the mediation value. + * + * @param mediation The mediation value. */ - public void setMediation(boolean mediation) - { - swordMediation = new SwordMediation(mediation); + public void setMediation(boolean mediation) { + swordMediation = new SwordMediation(mediation); } - + /** * Get the DC Term abstract. - * - * @return The abstract. + * + * @return The abstract. */ - public String getAbstract() - { - if ( dcTermsAbstract == null ) - { + public String getAbstract() { + if (dcTermsAbstract == null) { return null; } return dcTermsAbstract.getContent(); } - + /** - * Set the abstract. - * - * @param abstractString The abstract. + * Set the abstract. + * + * @param abstractString The abstract. */ - public void setAbstract(String abstractString) - { + public void setAbstract(String abstractString) { dcTermsAbstract = new DcAbstract(abstractString); } - + /** * Get the sword service. - * - * @return The service. + * + * @return The service. */ - public String getService() - { - if ( swordService == null ) - { + public String getService() { + if (swordService == null) { return null; } return swordService.getContent(); } - + /** - * Set the sword service. - * - * @param serviceString The service. + * Set the sword service. + * + * @param serviceString The service. */ - public void setService(String serviceString) - { + public void setService(String serviceString) { swordService = new SwordService(serviceString); } - + /** - * Set the title. This will set the title type to ContentType.TEXT. - * - * @param title The title. + * Set the title. This will set the title type to ContentType.TEXT. + * + * @param title The title. */ - public void setTitle( String title ) - { - if ( this.title == null) - { + public void setTitle(String title) { + if (this.title == null) { this.title = new Title(); } this.title.setContent(title); this.title.setType(ContentType.TEXT); } - + /** - * Get the title. - * - * @return The title, or null if no title has been set. + * Get the title. + * + * @return The title, or null if no title has been set. */ - public String getTitle( ) - { - if ( title == null ) - { + public String getTitle() { + if (title == null) { return null; } - return title.getContent(); + return title.getContent(); } - + /** - * Get the treatment value. - * + * Get the treatment value. + * * @return The treatment. */ - public String getTreatment() - { - if ( swordTreatment == null ) - { + public String getTreatment() { + if (swordTreatment == null) { return null; } return swordTreatment.getContent(); } - + /** - * Set the treatment. - * + * Set the treatment. + * * @param treatment The treatment. */ - public void setTreatment(String treatment) - { + public void setTreatment(String treatment) { swordTreatment = new SwordTreatment(treatment); - } - + } + /** - * Get a string representation of this object. This is + * Get a string representation of this object. This is * equivalent to calling marshall().toString(). */ @Override - public String toString() - { - Element element = marshall(); - return element.toString(); + public String toString() { + Element element = marshall(); + return element.toString(); } - + /** - * Marshall the data in this object to an Element object. - * - * @return A XOM Element that holds the data for this Content element. + * Marshall the data in this object to an Element object. + * + * @return A XOM Element that holds the data for this Content element. */ - public Element marshall( ) - { - // convert data into XOM elements and return the 'root', i.e. the one - // that represents the collection. + public Element marshall() { + // convert data into XOM elements and return the 'root', i.e. the one + // that represents the collection. Element collection = new Element(getQualifiedName(), Namespaces.NS_APP); Attribute href = new Attribute(ATTRIBUTE_HREF, location); collection.addAttribute(href); - - if (title == null) - { + + if (title == null) { title = new Title(); title.setContent("Untitled"); } collection.appendChild(title.marshall()); - - for (Accept item:accepts) - { + + for (Accept item : accepts) { collection.appendChild(item.marshall()); } - + Iterator apIterator = acceptPackaging.iterator(); - while ( apIterator.hasNext() ) - { + while (apIterator.hasNext()) { collection.appendChild(apIterator.next().marshall()); } - - if (swordCollectionPolicy != null) - { + + if (swordCollectionPolicy != null) { collection.appendChild(swordCollectionPolicy.marshall()); } - - if (dcTermsAbstract != null) - { + + if (dcTermsAbstract != null) { collection.appendChild(dcTermsAbstract.marshall()); } - - if (swordService != null) - { - collection.appendChild(swordService.marshall()); + + if (swordService != null) { + collection.appendChild(swordService.marshall()); } - - if (swordMediation != null ) - { + + if (swordMediation != null) { collection.appendChild(swordMediation.marshall()); } - - if (swordTreatment != null) - { - collection.appendChild(swordTreatment.marshall()); + + if (swordTreatment != null) { + collection.appendChild(swordTreatment.marshall()); } - - return collection; + + return collection; } - + /** - * Unmarshall the content element into the data in this object. - * + * Unmarshall the content element into the data in this object. + * * @throws UnmarshallException If the element does not contain a * content element or if there are problems - * accessing the data. + * accessing the data. */ public void unmarshall(Element collection) - throws UnmarshallException - { + throws UnmarshallException { unmarshall(collection, null); } - - + + public SwordValidationInfo unmarshall(Element collection, Properties validationProperties) - throws UnmarshallException - { - if (!isInstanceOf(collection, xmlName)) - { + throws UnmarshallException { + if (!isInstanceOf(collection, xmlName)) { return handleIncorrectElement(collection, validationProperties); } - + ArrayList validationItems = new ArrayList(); ArrayList attributeValidationItems = new ArrayList(); - - try - { + + try { initialise(); - + // retrieve the attributes int count = collection.getAttributeCount(); Attribute a = null; - for ( int i = 0; i < count; i++ ) - { + for (int i = 0; i < count; i++) { a = collection.getAttribute(i); - if (ATTRIBUTE_HREF.equals(a.getQualifiedName())) - { + if (ATTRIBUTE_HREF.equals(a.getQualifiedName())) { location = a.getValue(); SwordValidationInfo info = new SwordValidationInfo(xmlName, new XmlName(a)); info.setContentDescription(location); attributeValidationItems.add(info); - } - else - { + } else { SwordValidationInfo info = new SwordValidationInfo(xmlName, new XmlName(a), - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO ); + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); info.setContentDescription(a.getValue()); attributeValidationItems.add(info); } } - + // retrieve all of the sub-elements Elements elements = collection.getChildElements(); Element element = null; int length = elements.size(); - - for (int i = 0; i < length; i++) - { - element = elements.get(i); - if (isInstanceOf(element, Title.elementName())) - { - if ( title == null ) - { - title = new Title(); - validationItems.add(title.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo( - Title.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.INFO); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } - } - else if (isInstanceOf(element, Accept.elementName()) ) - { - Accept accept = new Accept(); - SwordValidationInfo info = accept.unmarshall(element, validationProperties); - accepts.add(accept); - validationItems.add(info); - } - else if (isInstanceOf(element, SwordAcceptPackaging.elementName())) - { - SwordAcceptPackaging packaging = new SwordAcceptPackaging(); - validationItems.add(packaging.unmarshall(element, validationProperties)); - acceptPackaging.add(packaging); - } - else if (isInstanceOf(element, SwordCollectionPolicy.elementName())) - { - if (swordCollectionPolicy == null) { - swordCollectionPolicy = new SwordCollectionPolicy(); - validationItems.add(swordCollectionPolicy.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo( - SwordCollectionPolicy.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.INFO); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } - - } - else if (isInstanceOf(element, DcAbstract.elementName())) - { - if ( dcTermsAbstract == null ) - { - dcTermsAbstract = new DcAbstract(); - validationItems.add(dcTermsAbstract.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(DcAbstract.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, SwordValidationInfoType.INFO); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } - } - else if (isInstanceOf(element, SwordService.elementName())) - { - if ( swordService == null ) - { - swordService = new SwordService(); - validationItems.add(swordService.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(SwordService.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.INFO); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } - } - else if (isInstanceOf(element, SwordMediation.elementName())) - { - if ( swordMediation == null ) - { - swordMediation = new SwordMediation(); - validationItems.add(swordMediation.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(SwordMediation.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } - } - else if (isInstanceOf(element, SwordTreatment.elementName())) - { - if ( swordTreatment == null ) - { - swordTreatment = new SwordTreatment(); - validationItems.add(swordTreatment.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(SwordTreatment.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(new XmlName(element), - SwordValidationInfo.UNKNOWN_ELEMENT, - SwordValidationInfoType.INFO); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } + + for (int i = 0; i < length; i++) { + element = elements.get(i); + if (isInstanceOf(element, Title.elementName())) { + if (title == null) { + title = new Title(); + validationItems.add(title.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo( + Title.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.INFO); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } + } else if (isInstanceOf(element, Accept.elementName())) { + Accept accept = new Accept(); + SwordValidationInfo info = accept.unmarshall(element, validationProperties); + accepts.add(accept); + validationItems.add(info); + } else if (isInstanceOf(element, SwordAcceptPackaging.elementName())) { + SwordAcceptPackaging packaging = new SwordAcceptPackaging(); + validationItems.add(packaging.unmarshall(element, validationProperties)); + acceptPackaging.add(packaging); + } else if (isInstanceOf(element, SwordCollectionPolicy.elementName())) { + if (swordCollectionPolicy == null) { + swordCollectionPolicy = new SwordCollectionPolicy(); + validationItems.add(swordCollectionPolicy.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo( + SwordCollectionPolicy.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.INFO); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } + + } else if (isInstanceOf(element, DcAbstract.elementName())) { + if (dcTermsAbstract == null) { + dcTermsAbstract = new DcAbstract(); + validationItems.add(dcTermsAbstract.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(DcAbstract.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.INFO); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } + } else if (isInstanceOf(element, SwordService.elementName())) { + if (swordService == null) { + swordService = new SwordService(); + validationItems.add(swordService.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(SwordService.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.INFO); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } + } else if (isInstanceOf(element, SwordMediation.elementName())) { + if (swordMediation == null) { + swordMediation = new SwordMediation(); + validationItems.add(swordMediation.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(SwordMediation.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } + } else if (isInstanceOf(element, SwordTreatment.elementName())) { + if (swordTreatment == null) { + swordTreatment = new SwordTreatment(); + validationItems.add(swordTreatment.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(SwordTreatment.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(new XmlName(element), + SwordValidationInfo.UNKNOWN_ELEMENT, + SwordValidationInfoType.INFO); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } } - } - catch (Exception ex) - { + } catch (Exception ex) { log.error("Unable to parse an element in collection: " + ex.getMessage()); throw new UnmarshallException("Unable to parse an element in Collection", ex); } - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(validationItems, attributeValidationItems, validationProperties); } - return result; - + return result; + } - + /** * */ @Override - public SwordValidationInfo validate(Properties validationContext) - { + public SwordValidationInfo validate(Properties validationContext) { return validate(null, null, validationContext); } - + /** - * - * @param existing add results to this. - * @param attributes FIXME: PLEASE DOCUMENT. + * @param existing add results to this. + * @param attributes FIXME: PLEASE DOCUMENT. * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info */ protected SwordValidationInfo validate(List existing, - List attributes, - Properties validationContext) - { + List attributes, + Properties validationContext) { boolean validateAll = (existing == null); - + SwordValidationInfo result = new SwordValidationInfo(xmlName); - - if ( accepts == null || accepts.size() == 0 ) - { + + if (accepts == null || accepts.size() == 0) { result.addValidationInfo(new SwordValidationInfo(Accept.elementName(), - SwordValidationInfo.MISSING_ELEMENT_ERROR, - SwordValidationInfoType.WARNING )); + SwordValidationInfo.MISSING_ELEMENT_ERROR, + SwordValidationInfoType.WARNING)); } - - if ( location == null ) - { - XmlName attribute = new XmlName(Namespaces.PREFIX_ATOM, - ATTRIBUTE_HREF, + + if (location == null) { + XmlName attribute = new XmlName(Namespaces.PREFIX_ATOM, + ATTRIBUTE_HREF, Namespaces.NS_ATOM); - + result.addAttributeValidationInfo(new SwordValidationInfo(xmlName, - attribute, SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, - SwordValidationInfoType.WARNING )); + attribute, + SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, + SwordValidationInfoType.WARNING)); } - - if ( swordMediation == null ) - { + + if (swordMediation == null) { result.addValidationInfo(new SwordValidationInfo(SwordMediation.elementName(), - SwordValidationInfo.MISSING_ELEMENT_WARNING, - SwordValidationInfoType.WARNING)); + SwordValidationInfo.MISSING_ELEMENT_WARNING, + SwordValidationInfoType.WARNING)); } - - if ( validateAll ) - { - if ( accepts.size() > 0 ) - { - Iterator acceptIterator = accepts.iterator(); - while ( acceptIterator.hasNext() ) - { - result.addValidationInfo(acceptIterator.next().validate(validationContext)); - } + + if (validateAll) { + if (accepts.size() > 0) { + Iterator acceptIterator = accepts.iterator(); + while (acceptIterator.hasNext()) { + result.addValidationInfo(acceptIterator.next().validate(validationContext)); + } } - - if ( acceptPackaging.size() > 0 ) - { - Iterator apIterator = acceptPackaging.iterator(); - while ( apIterator.hasNext() ) - { - result.addValidationInfo(apIterator.next().validate(validationContext)); - } + + if (acceptPackaging.size() > 0) { + Iterator apIterator = acceptPackaging.iterator(); + while (apIterator.hasNext()) { + result.addValidationInfo(apIterator.next().validate(validationContext)); + } } - - if ( location != null ) - { + + if (location != null) { result.addAttributeValidationInfo(createValidAttributeInfo(ATTRIBUTE_HREF, location)); } - - if ( title != null ) - { + + if (title != null) { result.addValidationInfo(title.validate(validationContext)); } - - if ( swordMediation != null ) - { + + if (swordMediation != null) { result.addValidationInfo(swordMediation.validate(validationContext)); } - - if ( swordService != null ) - { + + if (swordService != null) { result.addValidationInfo(swordService.validate(validationContext)); } - - if ( swordTreatment != null ) - { + + if (swordTreatment != null) { result.addValidationInfo(swordTreatment.validate(validationContext)); } - - if ( swordCollectionPolicy != null ) - { + + if (swordCollectionPolicy != null) { result.addValidationInfo(swordCollectionPolicy.validate(validationContext)); } - - if ( dcTermsAbstract != null ) - { + + if (dcTermsAbstract != null) { result.addValidationInfo(dcTermsAbstract.validate(validationContext)); } } - + result.addUnmarshallValidationInfo(existing, attributes); - return result; + return result; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/DcAbstract.java b/dspace-sword/src/main/java/org/purl/sword/base/DcAbstract.java index 3694c07e50..ec68f013ec 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/DcAbstract.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/DcAbstract.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class DcAbstract extends BasicStringContentElement -{ +public class DcAbstract extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_DC_TERMS, "abstract", Namespaces.NS_DC_TERMS); + new XmlName(Namespaces.PREFIX_DC_TERMS, "abstract", Namespaces.NS_DC_TERMS); - public DcAbstract() - { + public DcAbstract() { super(XML_NAME); } - public DcAbstract(String version) - { + public DcAbstract(String version) { this(); - setContent(version); + setContent(version); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/Deposit.java b/dspace-sword/src/main/java/org/purl/sword/base/Deposit.java index d0063e4ffa..3c1e76a2f1 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/Deposit.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/Deposit.java @@ -7,255 +7,283 @@ */ package org.purl.sword.base; -import org.apache.log4j.Logger; - import java.io.File; import java.util.regex.Matcher; import java.util.regex.Pattern; - import javax.servlet.http.HttpServletResponse; +import org.apache.log4j.Logger; + /** - * Represents a deposit. - * - * @author Stuart Lewis + * Represents a deposit. + * + * @author Stuart Lewis */ -public class Deposit -{ +public class Deposit { private static final Logger log = Logger.getLogger(Deposit.class); - - /** The File deposited */ + + /** + * The File deposited + */ private File file; - - /** The content type */ + + /** + * The content type + */ private String contentType; - - /** The content length */ + + /** + * The content length + */ private int contentLength; - - /** The username */ + + /** + * The username + */ private String username; - - /** The password */ + + /** + * The password + */ private String password; - - /** The onBehalfOf value */ + + /** + * The onBehalfOf value + */ private String onBehalfOf; - - /** The slug string */ + + /** + * The slug string + */ private String slug; - - /** MD5 hash */ + + /** + * MD5 hash + */ private String md5; - - /** True if verbose should be used */ + + /** + * True if verbose should be used + */ private boolean verbose; - - /** True if this is a no-operation command */ + + /** + * True if this is a no-operation command + */ private boolean noOp; - - /** The packaging format */ + + /** + * The packaging format + */ private String packaging; - - /** Deposit ID */ + + /** + * Deposit ID + */ private String depositID; - - /** The IP address */ + + /** + * The IP address + */ private String IPAddress; - - /** The location */ + + /** + * The location + */ private String location; - - /** The content disposition */ - private String contentDisposition; - + + /** + * The content disposition + */ + private String contentDisposition; + /** * Submission created */ public static final int CREATED = HttpServletResponse.SC_CREATED; - + /** * Submission accepted. */ - public static final int ACCEPTED = HttpServletResponse.SC_ACCEPTED; - + public static final int ACCEPTED = HttpServletResponse.SC_ACCEPTED; + /** * @return the authenticatedUserName */ public String getUsername() { return username; } - + /** * @param username the authenticated UserName to set */ public void setUsername(String username) { this.username = username; } - + /** * @return the authenticatedUserPassword */ public String getPassword() { return password; } - + /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } - + /** * @return the contentLength */ public int getContentLength() { return contentLength; } - + /** * @param contentLength the contentLength to set */ public void setContentLength(int contentLength) { this.contentLength = contentLength; } - + /** * @return the contentType */ public String getContentType() { return contentType; } - + /** * @param contentType the contentType to set */ public void setContentType(String contentType) { this.contentType = contentType; } - + /** * @return the depositID */ public String getDepositID() { return depositID; } - + /** * @param depositID the depositID to set */ public void setDepositID(String depositID) { this.depositID = depositID; } - + /** * @return the file */ public File getFile() { return file; } - + /** * @param file the file to set */ public void setFile(File file) { this.file = file; } - + /** * @return the packaging */ public String getPackaging() { return packaging; } - + /** * @param packaging the packaging to set */ public void setPackaging(String packaging) { this.packaging = packaging; } - + /** * @return the md5 */ public String getMd5() { return md5; } - + /** * @param md5 the md5 to set */ public void setMd5(String md5) { this.md5 = md5; } - + /** * @return the noOp */ public boolean isNoOp() { return noOp; } - + /** * @param noOp the noOp to set */ public void setNoOp(boolean noOp) { this.noOp = noOp; } - + /** * @return the onBehalfOf */ public String getOnBehalfOf() { return onBehalfOf; } - + /** * @param onBehalfOf the onBehalfOf to set */ public void setOnBehalfOf(String onBehalfOf) { this.onBehalfOf = onBehalfOf; } - + /** * @return the slug */ public String getSlug() { return slug; } - + /** * @param slug the slug to set */ public void setSlug(String slug) { this.slug = slug; } - + /** * @return the verbose */ public boolean isVerbose() { return verbose; } - + /** * @param verbose the verbose to set */ public void setVerbose(boolean verbose) { this.verbose = verbose; } - + /** * Get the IP address of the user - * + * * @return the IP address */ public String getIPAddress() { return IPAddress; } - + /** * Set the IP address of the user * @@ -264,16 +292,16 @@ public class Deposit public void setIPAddress(String IPAddress) { this.IPAddress = IPAddress; } - + /** * Get the location of the deposit - * + * * @return the location of the deposit */ public String getLocation() { return location; } - + /** * Set the location of the deposit * @@ -282,56 +310,48 @@ public class Deposit public void setLocation(String location) { this.location = location; } - + /** * Retrieve the filename that is associated with this deposit. This - * is extracted from the content disposition value. - * - * @return The filename. + * is extracted from the content disposition value. + * + * @return The filename. */ - public String getFilename() - { + public String getFilename() { String filename = null; // default return value - if ( contentDisposition != null ) - { - try - { + if (contentDisposition != null) { + try { String filePattern = ".*filename=(.*?)((; *.*)|( +)){0,1}"; Pattern p = Pattern.compile(filePattern); Matcher m = p.matcher(contentDisposition); - - if ( m.matches() && m.groupCount() > 2 ) - { + + if (m.matches() && m.groupCount() > 2) { filename = m.group(1); } - } - catch ( Exception ex ) - { + } catch (Exception ex) { log.error("Unable to extract filename", ex); } } - return filename; + return filename; } - + /** - * Set the content disposition that is to be used for this deposit. - * This will include the filename, if specified. - * - * @param disposition The content disposition value. + * Set the content disposition that is to be used for this deposit. + * This will include the filename, if specified. + * + * @param disposition The content disposition value. */ - public void setContentDisposition(String disposition) - { + public void setContentDisposition(String disposition) { this.contentDisposition = disposition; } - + /** - * Return the content disposition value. - * - * @return The value. + * Return the content disposition value. + * + * @return The value. */ - public String getContentDisposition() - { + public String getContentDisposition() { return this.contentDisposition; } - + } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/DepositResponse.java b/dspace-sword/src/main/java/org/purl/sword/base/DepositResponse.java index 15b45bcf1f..a731c020ed 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/DepositResponse.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/DepositResponse.java @@ -9,234 +9,214 @@ package org.purl.sword.base; import java.io.ByteArrayOutputStream; import java.io.IOException; - import java.util.Properties; -import org.apache.log4j.Logger; import nu.xom.Builder; import nu.xom.Document; import nu.xom.Element; import nu.xom.ParsingException; import nu.xom.Serializer; +import org.apache.log4j.Logger; /** - * Represents a deposit response. This holds the SWORD Entry element. - * + * Represents a deposit response. This holds the SWORD Entry element. + * * @author Stuart Lewis * @author Neil Taylor - * */ -public class DepositResponse -{ - /** The entry returned in the response */ - private SWORDEntry entry; - - /** The HTTP Response code */ +public class DepositResponse { + /** + * The entry returned in the response + */ + private SWORDEntry entry; + + /** + * The HTTP Response code + */ private int httpResponse; - - /** The value to set in the Location header (typically the atom edit link) */ + + /** + * The value to set in the Location header (typically the atom edit link) + */ private String location; - - /** Logger */ + + /** + * Logger + */ private static Logger log = Logger.getLogger(DepositResponse.class); - + /** - * Create a new response with the specified http code. - * - * @param httpResponse Response code. + * Create a new response with the specified http code. + * + * @param httpResponse Response code. */ - public DepositResponse( int httpResponse ) - { - entry = new SWORDEntry(); - this.httpResponse = httpResponse; - location = null; + public DepositResponse(int httpResponse) { + entry = new SWORDEntry(); + this.httpResponse = httpResponse; + location = null; } - + /** - * Set the entry element for this response. - * - * @param entry The SWORD Entry. + * Set the entry element for this response. + * + * @param entry The SWORD Entry. */ - public void setEntry( SWORDEntry entry ) - { - this.entry = entry; + public void setEntry(SWORDEntry entry) { + this.entry = entry; } - + /** * Get the SWORD Entry * * @return The entry */ - public SWORDEntry getEntry( ) - { - return entry; + public SWORDEntry getEntry() { + return entry; } - + /** * Get the SWORD Entry as an error document * * @return The error document * @throws SWORDException If this DespositResponse does not contain a * SWORDErrorDocumentTest. If this is thrown, then - * the document stores an Entry. + * the document stores an Entry. */ - public SWORDErrorDocument getErrorDocument( ) - throws SWORDException - { - if ( entry instanceof SWORDErrorDocument) - { - return (SWORDErrorDocument)entry; + public SWORDErrorDocument getErrorDocument() + throws SWORDException { + if (entry instanceof SWORDErrorDocument) { + return (SWORDErrorDocument) entry; } - + throw new SWORDException("Requested document is not an Error Document."); } - + /** - * Retrieve the HTTP Response code. - * - * @return The response code. + * Retrieve the HTTP Response code. + * + * @return The response code. */ public int getHttpResponse() { - return httpResponse; + return httpResponse; } - + /** - * Set the HTTP Response code. - * - * @param httpResponse The code. + * Set the HTTP Response code. + * + * @param httpResponse The code. */ public void setHttpResponse(int httpResponse) { - this.httpResponse = httpResponse; + this.httpResponse = httpResponse; } - + /** * Retrieve the Location header. - * + * * @return The Location header */ public String getLocation() { - return location; + return location; } - + /** - * Set the HTTP Location header. - * - * @param location The Location header. + * Set the HTTP Location header. + * + * @param location The Location header. */ public void setLocation(String location) { - this.location = location; + this.location = location; } - + /** - * Marshall the data in the enclosed SWORD Entry. - * - * @return The string representation. Null if there was an error. + * Marshall the data in the enclosed SWORD Entry. + * + * @return The string representation. Null if there was an error. */ - public String marshall( ) - { - try - { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - Serializer serializer = new Serializer(stream, "UTF-8"); - serializer.setIndent(3); - - if ( entry != null ) - { - Document doc = new Document(entry.marshall()); - serializer.write(doc); - log.info(stream.toString()); - return stream.toString(); - } - } - catch (IOException ex) - { - log.error(ex.getMessage()); - } - - return null; // default return value. + public String marshall() { + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Serializer serializer = new Serializer(stream, "UTF-8"); + serializer.setIndent(3); + + if (entry != null) { + Document doc = new Document(entry.marshall()); + serializer.write(doc); + log.info(stream.toString()); + return stream.toString(); + } + } catch (IOException ex) { + log.error(ex.getMessage()); + } + + return null; // default return value. } - + /** - * Unmarshall the specified XML data into a SWORD Entry. - * - * @param xml The XML data as a string. - * @throws UnmarshallException If there was an error unmarshalling the data. + * Unmarshall the specified XML data into a SWORD Entry. + * + * @param xml The XML data as a string. + * @throws UnmarshallException If there was an error unmarshalling the data. */ - public void unmarshall(String xml) throws UnmarshallException - { - unmarshall(xml, null); + public void unmarshall(String xml) throws UnmarshallException { + unmarshall(xml, null); } - + public SwordValidationInfo unmarshall(String xml, Properties validationContext) - throws UnmarshallException - { - try - { - Builder builder = new Builder(); - Document doc = builder.build(xml, Namespaces.NS_ATOM); - Element root = doc.getRootElement(); - - entry = new SWORDEntry( ); - return entry.unmarshall(root, validationContext); - } - catch ( ParsingException ex ) - { - throw new UnmarshallException("Unable to parse the XML", ex ); - } - catch ( IOException ex ) - { - throw new UnmarshallException("Error acessing the file?", ex); - } + throws UnmarshallException { + try { + Builder builder = new Builder(); + Document doc = builder.build(xml, Namespaces.NS_ATOM); + Element root = doc.getRootElement(); + + entry = new SWORDEntry(); + return entry.unmarshall(root, validationContext); + } catch (ParsingException ex) { + throw new UnmarshallException("Unable to parse the XML", ex); + } catch (IOException ex) { + throw new UnmarshallException("Error acessing the file?", ex); + } } - + public void unmarshallErrorDocument(String xml) - throws UnmarshallException - { - unmarshallErrorDocument(xml, null); + throws UnmarshallException { + unmarshallErrorDocument(xml, null); } - + /** - * Unmarshall the specified XML data into a SWORD error document. - * - * @param xml The XML data as a string. + * Unmarshall the specified XML data into a SWORD error document. + * + * @param xml The XML data as a string. * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info - * @throws UnmarshallException If there was an error unmarshalling the data. + * @throws UnmarshallException If there was an error unmarshalling the data. */ public SwordValidationInfo unmarshallErrorDocument( - String xml, Properties validationContext ) - throws UnmarshallException - { - try - { - Builder builder = new Builder(); - Document doc = builder.build(xml, Namespaces.NS_SWORD); - Element root = doc.getRootElement(); - - SWORDErrorDocument sed = new SWORDErrorDocument(); - SwordValidationInfo info = sed.unmarshall(root, validationContext); - entry = sed; - return info; - } - catch ( ParsingException ex ) - { - throw new UnmarshallException("Unable to parse the XML", ex ); - } - catch ( IOException ex ) - { - throw new UnmarshallException("Error acessing the file?", ex); - } + String xml, Properties validationContext) + throws UnmarshallException { + try { + Builder builder = new Builder(); + Document doc = builder.build(xml, Namespaces.NS_SWORD); + Element root = doc.getRootElement(); + + SWORDErrorDocument sed = new SWORDErrorDocument(); + SwordValidationInfo info = sed.unmarshall(root, validationContext); + entry = sed; + return info; + } catch (ParsingException ex) { + throw new UnmarshallException("Unable to parse the XML", ex); + } catch (IOException ex) { + throw new UnmarshallException("Error acessing the file?", ex); + } } - + /** - * Retrieve a string representation of this data. This is equivalent to - * calling unmarshall(). - * - * @return The marshalled data. + * Retrieve a string representation of this data. This is equivalent to + * calling unmarshall(). + * + * @return The marshalled data. */ - public String toString() - { - return marshall(); - } - + public String toString() { + return marshall(); + } + } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/ErrorCodes.java b/dspace-sword/src/main/java/org/purl/sword/base/ErrorCodes.java index cada757838..6af5ca603c 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/ErrorCodes.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/ErrorCodes.java @@ -8,48 +8,46 @@ package org.purl.sword.base; /** - * Definition of the error codes that will be used in + * Definition of the error codes that will be used in * SWORD error documents. - * - * @see SWORDErrorDocument - * + * * @author Stuart Lewis + * @see SWORDErrorDocument */ -public interface ErrorCodes -{ - /** - * ErrorContent - where the supplied format is not the same as that +public interface ErrorCodes { + /** + * ErrorContent - where the supplied format is not the same as that * identified in the X-Format-Namespace and/or that supported by the * server */ - public static final String ERROR_CONTENT = "http://purl.org/net/sword/error/ErrorContent"; - - /** - * ErrorChecksumMismatch - where the checksum of the file received does - * not match the checksum given in the header - */ - public static final String ERROR_CHECKSUM_MISMATCH = "http://purl.org/net/sword/error/ErrorChecksumMismatch"; - - /** - * ErrorBadRequest - where parameters are not understood - */ - public static final String ERROR_BAD_REQUEST = "http://purl.org/net/sword/error/ErrorBadRequest"; - - /** - * TargetOwnerUnknown - where the server cannot identify the specified - * TargetOwner - */ - public static final String TARGET_OWNER_UKNOWN = "http://purl.org/net/sword/error/TargetOwnerUnknown"; - - /** - * MediationNotAllowed - where a client has attempted a mediated deposit, - * but this is not supported by the server - */ - public static final String MEDIATION_NOT_ALLOWED = "http://purl.org/net/sword/error/MediationNotAllowed"; - - /** - * MediationNotAllowed - where a client has attempted a mediated deposit, - * but this is not supported by the server - */ - public static final String MAX_UPLOAD_SIZE_EXCEEDED = "http://purl.org/net/sword/error/MAX_UPLOAD_SIZE_EXCEEDED"; + public static final String ERROR_CONTENT = "http://purl.org/net/sword/error/ErrorContent"; + + /** + * ErrorChecksumMismatch - where the checksum of the file received does + * not match the checksum given in the header + */ + public static final String ERROR_CHECKSUM_MISMATCH = "http://purl.org/net/sword/error/ErrorChecksumMismatch"; + + /** + * ErrorBadRequest - where parameters are not understood + */ + public static final String ERROR_BAD_REQUEST = "http://purl.org/net/sword/error/ErrorBadRequest"; + + /** + * TargetOwnerUnknown - where the server cannot identify the specified + * TargetOwner + */ + public static final String TARGET_OWNER_UKNOWN = "http://purl.org/net/sword/error/TargetOwnerUnknown"; + + /** + * MediationNotAllowed - where a client has attempted a mediated deposit, + * but this is not supported by the server + */ + public static final String MEDIATION_NOT_ALLOWED = "http://purl.org/net/sword/error/MediationNotAllowed"; + + /** + * MediationNotAllowed - where a client has attempted a mediated deposit, + * but this is not supported by the server + */ + public static final String MAX_UPLOAD_SIZE_EXCEEDED = "http://purl.org/net/sword/error/MAX_UPLOAD_SIZE_EXCEEDED"; } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/HttpHeaders.java b/dspace-sword/src/main/java/org/purl/sword/base/HttpHeaders.java index 1f3f86ddd8..9a5aacc5a3 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/HttpHeaders.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/HttpHeaders.java @@ -10,40 +10,38 @@ package org.purl.sword.base; import javax.servlet.http.HttpServletResponse; /** - * Definition of the additional HTTP Header tags that will be used in - * the SWORD protocol. - * + * Definition of the additional HTTP Header tags that will be used in + * the SWORD protocol. + * * @author Neil Taylor * @author Stuart Lewis - * */ -public interface HttpHeaders -{ - /** - * The HTTP Header label that specifies the MD5 label. - */ - public static final String CONTENT_MD5 = "Content-MD5"; - - /** - * The HTTP Header label that specifies the MD5 label. - */ - public static final String CONTENT_LENGTH = "Content-Length"; - - /** - * The HTTP Header label that specifies the On Behalf Of information. - */ - public static final String X_ON_BEHALF_OF = "X-On-Behalf-Of"; - +public interface HttpHeaders { + /** + * The HTTP Header label that specifies the MD5 label. + */ + public static final String CONTENT_MD5 = "Content-MD5"; + + /** + * The HTTP Header label that specifies the MD5 label. + */ + public static final String CONTENT_LENGTH = "Content-Length"; + + /** + * The HTTP Header label that specifies the On Behalf Of information. + */ + public static final String X_ON_BEHALF_OF = "X-On-Behalf-Of"; + /** * The HTTP Header label that specifies the Packaging information. */ public static final String X_PACKAGING = "X-Packaging"; - + /** - * The HTTP Header label that specifies the desired Verbose status. + * The HTTP Header label that specifies the desired Verbose status. */ public static final String X_VERBOSE = "X-Verbose"; - + /** * The HTTP Header label that specifies the desired NoOp status. */ @@ -56,33 +54,33 @@ public interface HttpHeaders public static final String X_CORRUPT = "X-wibble"; /** - * The HTTP Header that specifies the error code information. + * The HTTP Header that specifies the error code information. */ public static final String X_ERROR_CODE = "X-Error-Code"; - + /** * The user agent. */ public static final String USER_AGENT = "User-Agent"; - + /** * The Slug header. */ public static final String SLUG = "Slug"; - + /** * Submission created */ public static final int CREATED = HttpServletResponse.SC_CREATED; - + /** * Submission accepted. */ - public static final int ACCEPTED = HttpServletResponse.SC_ACCEPTED; - + public static final int ACCEPTED = HttpServletResponse.SC_ACCEPTED; + /** * The HTTP Header that specifies the content disposition item. This is - * used by the SWORD profile to identify the name for the deposit. + * used by the SWORD profile to identify the name for the deposit. */ public static final String CONTENT_DISPOSITION = "Content-Disposition"; } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/Namespaces.java b/dspace-sword/src/main/java/org/purl/sword/base/Namespaces.java index e88beedf1e..9a76f3527b 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/Namespaces.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/Namespaces.java @@ -8,54 +8,53 @@ package org.purl.sword.base; /** - * List of the namespaces that are used by SWORD. - * + * List of the namespaces that are used by SWORD. + * * Last updated on: $Date$ - * + * * @author Neil Taylor * @version $Revision$ - * */ public interface Namespaces { - /** - * Atom Publishing Protocol (APP) Namespace. - */ - public static final String NS_APP = "http://www.w3.org/2007/app"; - - /** - * APP Prefix. - */ - public static final String PREFIX_APP = "app"; - - /** - * ATOM Namespace. - */ - public static final String NS_ATOM = "http://www.w3.org/2005/Atom"; - - /** - * ATOM Prefix. - */ - public static final String PREFIX_ATOM = "atom"; - - /** - * Sword Namespace. - */ - public static final String NS_SWORD = "http://purl.org/net/sword/"; - - /** - * SWORD Prefix. - */ - public static final String PREFIX_SWORD = "sword"; - - /** - * DC Terms Namespace. - */ - public static final String NS_DC_TERMS = "http://purl.org/dc/terms/"; - - /** - * DC Terms Prefix. - */ - public static final String PREFIX_DC_TERMS = "dcterms"; - + /** + * Atom Publishing Protocol (APP) Namespace. + */ + public static final String NS_APP = "http://www.w3.org/2007/app"; + + /** + * APP Prefix. + */ + public static final String PREFIX_APP = "app"; + + /** + * ATOM Namespace. + */ + public static final String NS_ATOM = "http://www.w3.org/2005/Atom"; + + /** + * ATOM Prefix. + */ + public static final String PREFIX_ATOM = "atom"; + + /** + * Sword Namespace. + */ + public static final String NS_SWORD = "http://purl.org/net/sword/"; + + /** + * SWORD Prefix. + */ + public static final String PREFIX_SWORD = "sword"; + + /** + * DC Terms Namespace. + */ + public static final String NS_DC_TERMS = "http://purl.org/dc/terms/"; + + /** + * DC Terms Prefix. + */ + public static final String PREFIX_DC_TERMS = "dcterms"; + } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/QualityValue.java b/dspace-sword/src/main/java/org/purl/sword/base/QualityValue.java index ef68378748..ed993942e8 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/QualityValue.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/QualityValue.java @@ -10,83 +10,79 @@ package org.purl.sword.base; /** * A representation of a quality value. - * + * * The quality value must be between 0 and 1, with no more than three digits * after the decimal place. - * + * * @author Stuart Lewis */ public class QualityValue { - - /** The quality value. */ + + /** + * The quality value. + */ private float quality; - + /** * Create a quality value defaulting to 1 - * + * * @throws NumberFormatException thrown if the quality value is invalid according to the SWORD specification */ - public QualityValue() throws NumberFormatException - { + public QualityValue() throws NumberFormatException { // As per the spec, default to value 1 setQualityValue(1f); } - + /** * Create a quality value - * + * * @param q The quality value * @throws NumberFormatException thrown if the quality value is invalid according to the SWORD specification */ - public QualityValue(float q) throws NumberFormatException - { + public QualityValue(float q) throws NumberFormatException { setQualityValue(q); } - + /** * Set the quality value. - * + * * @param q The quality value * @throws NumberFormatException thrown if the quality value is invalid according to the SWORD specification */ - public final void setQualityValue(float q) throws NumberFormatException - { + public final void setQualityValue(float q) throws NumberFormatException { // Check the float is in range - if ((q < 0) || (q > 1)) - { + if ((q < 0) || (q > 1)) { throw new NumberFormatException("Invalid value - must be between 0 and 1"); } - + // Check there are no more than three digits after the decimal point String qStr = "" + q; int pos = qStr.indexOf('.'); - if (qStr.substring(pos + 1).length() > 3) - { - throw new NumberFormatException("Invalid value - no more than three digits after the decimal point: " + qStr); + if (qStr.substring(pos + 1).length() > 3) { + throw new NumberFormatException( + "Invalid value - no more than three digits after the decimal point: " + qStr); } quality = q; } - + /** * Get the quality value - * + * * @return the quality value */ - public final float getQualityValue() - { + public final float getQualityValue() { return quality; } - + /** * Get a String representation of this quality value - * + * * @return The String representation of the quality value */ - public String toString() - { + public String toString() { return Float.toString(quality); } - + /** * A main method with rudimentary tests to check the class */ @@ -94,7 +90,7 @@ public class QualityValue { public static void main(String[] args) { // Test the class - + // Fail - under 0 try { @@ -106,7 +102,7 @@ public class QualityValue { System.out.print("1) Pass: -0.01 failed as expected "); System.out.println(nfe); } - + // Fail - over 1 try { @@ -118,7 +114,7 @@ public class QualityValue { System.out.print("2) Pass: 1.01 failed as expected "); System.out.println(nfe); } - + // Fail - to many decimal points try { @@ -130,7 +126,7 @@ public class QualityValue { System.out.print("3) Pass: 0.1234 failed as expected "); System.out.println(nfe); } - + // Pass - no decimal places 0 try { @@ -141,7 +137,7 @@ public class QualityValue { { System.out.println("4) Fail: 0 failed unexpectedly"); } - + // Pass - no decimal places 1 try { @@ -164,7 +160,7 @@ public class QualityValue { { System.out.println("6) Fail: 0.123 failed unexpectedly"); } - + // Pass - No value given try { diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SWORDAuthenticationException.java b/dspace-sword/src/main/java/org/purl/sword/base/SWORDAuthenticationException.java index d353f5a5dc..c024124db1 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SWORDAuthenticationException.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SWORDAuthenticationException.java @@ -10,32 +10,29 @@ package org.purl.sword.base; /** * Represents a SWORD exception to be thrown if bad authentication credentials * are passed to a repository. - * + * * @author Stuart Lewis * @author Neil Taylor */ -public class SWORDAuthenticationException extends Exception -{ +public class SWORDAuthenticationException extends Exception { /** - * Create a new instance and store the specified message and source data. - * - * @param message The message for the exception. + * Create a new instance and store the specified message and source data. + * + * @param message The message for the exception. * @param source The original exception that lead to this exception. This - * can be null. + * can be null. */ - public SWORDAuthenticationException(String message, Exception source) - { - super(message, source); + public SWORDAuthenticationException(String message, Exception source) { + super(message, source); } - + /** - * Create a new instance and store the specified message. - * - * @param message The message for the exception. + * Create a new instance and store the specified message. + * + * @param message The message for the exception. */ - public SWORDAuthenticationException(String message) - { + public SWORDAuthenticationException(String message) { super(message); } - + } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SWORDEntry.java b/dspace-sword/src/main/java/org/purl/sword/base/SWORDEntry.java index 23da5f4d03..4cc569a97c 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SWORDEntry.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SWORDEntry.java @@ -8,21 +8,20 @@ package org.purl.sword.base; import java.util.Properties; + import nu.xom.Element; import nu.xom.Elements; - import org.purl.sword.atom.Entry; /** - * Extension of the ATOM Entry class. This adds support for the additional - * SWORD elements. These elements reside inside the ATOM Entry object, - * created in org.w3.atom.Entry class. - * + * Extension of the ATOM Entry class. This adds support for the additional + * SWORD elements. These elements reside inside the ATOM Entry object, + * created in org.w3.atom.Entry class. + * * @author Neil Taylor */ -public class SWORDEntry extends Entry -{ +public class SWORDEntry extends Entry { /** * Specifies whether the document was run in noOp mode, i.e. @@ -30,58 +29,54 @@ public class SWORDEntry extends Entry * the deposit other than to generate a response. */ protected SwordNoOp swordNoOp; - + /** - * Used to supply a verbose description. + * Used to supply a verbose description. */ protected SwordVerboseDescription swordVerboseDescription; - + /** * Used for a human readable statement about what treatment * the deposited resource has received. Include either a * text description or a URI. */ protected SwordTreatment swordTreatment; - + /** * The user agent */ protected SwordUserAgent swordUserAgent; - - /** + + /** * The packaging information */ private SwordPackaging swordPackaging; - + /** * Create a new SWORDEntry with the given namespace and element. This method is * not normally used, instead the default constructor should be used as this will * set the namespace and element correctly. - * - * @param namespace The namespace of the element - * @param element The element name + * + * @param namespace The namespace of the element + * @param element The element name * @param namespaceUri The namespace URI. */ - public SWORDEntry(String namespace, String element, String namespaceUri) - { + public SWORDEntry(String namespace, String element, String namespaceUri) { super(namespace, element, namespaceUri); } - + /** * A default constructor. */ - public SWORDEntry() - { + public SWORDEntry() { super(); } - - public SWORDEntry(XmlName name) - { - super(name); + + public SWORDEntry(XmlName name) { + super(name); } - - protected void initialise() - { + + protected void initialise() { super.initialise(); swordNoOp = null; swordPackaging = null; @@ -89,437 +84,381 @@ public class SWORDEntry extends Entry swordTreatment = null; swordUserAgent = null; } - + /** - * Get the current value of NoOp. - * - * @return True if the value is set, false otherwise. + * Get the current value of NoOp. + * + * @return True if the value is set, false otherwise. */ - public boolean isNoOp() - { - if ( swordNoOp == null ) - { + public boolean isNoOp() { + if (swordNoOp == null) { return false; } return swordNoOp.getContent(); } - + /** - * Call this method to set noOp. It should be called even by internal - * methods so that the object can determine if the value has been set - * or whether it just holds the default value. - * - * @param noOp True if the NoOp header should be used. + * Call this method to set noOp. It should be called even by internal + * methods so that the object can determine if the value has been set + * or whether it just holds the default value. + * + * @param noOp True if the NoOp header should be used. */ - public void setNoOp(boolean noOp) - { - swordNoOp = new SwordNoOp(noOp); + public void setNoOp(boolean noOp) { + swordNoOp = new SwordNoOp(noOp); } - + /** - * Determine if the noOp value has been set. This should be called - * if you want to know whether false for noOp means that it is the + * Determine if the noOp value has been set. This should be called + * if you want to know whether false for noOp means that it is the * default value (i.e. no code has set it) or it is a value that - * has been actively set. - * - * @return True if the value has been set. Otherwise, false. + * has been actively set. + * + * @return True if the value has been set. Otherwise, false. */ - public boolean isNoOpSet() - { - if ( swordNoOp == null ) - { - return false; + public boolean isNoOpSet() { + if (swordNoOp == null) { + return false; } return swordNoOp.isSet(); } - + /** - * Get the Verbose Description for this entry. - * - * @return The description. + * Get the Verbose Description for this entry. + * + * @return The description. */ - public String getVerboseDescription() - { - if ( swordVerboseDescription == null ) - { + public String getVerboseDescription() { + if (swordVerboseDescription == null) { return null; } return swordVerboseDescription.getContent(); } - + /** - * Set the verbose description. - * - * @param verboseDescription The description. + * Set the verbose description. + * + * @param verboseDescription The description. */ - public void setVerboseDescription(String verboseDescription) - { + public void setVerboseDescription(String verboseDescription) { swordVerboseDescription = new SwordVerboseDescription(verboseDescription); } - + /** - * Get the treatment value. - * - * @return The treatment. + * Get the treatment value. + * + * @return The treatment. */ - public String getTreatment() - { - if ( swordTreatment == null ) - { + public String getTreatment() { + if (swordTreatment == null) { return null; } return swordTreatment.getContent(); } - + /** - * Set the treatment value. - * - * @param treatment The treatment. + * Set the treatment value. + * + * @param treatment The treatment. */ - public void setTreatment(String treatment) - { + public void setTreatment(String treatment) { swordTreatment = new SwordTreatment(treatment); } - + /** * Get the user agent - * + * * @return the user agent */ - public String getUserAgent() - { - if ( swordUserAgent == null ) - { + public String getUserAgent() { + if (swordUserAgent == null) { return null; } return swordUserAgent.getContent(); } - + /** * Set the user agent - * + * * @param userAgent the user agent */ - public void setUserAgent(String userAgent) - { + public void setUserAgent(String userAgent) { swordUserAgent = new SwordUserAgent(userAgent); } - + /** * Get the packaging format - * + * * @return the packaging format */ - public String getPackaging() - { - if ( swordPackaging == null ) - { + public String getPackaging() { + if (swordPackaging == null) { return null; } return swordPackaging.getContent(); } - + /** * Set the packaging format - * + * * @param packaging the packaging format */ - public void setPackaging(String packaging) - { + public void setPackaging(String packaging) { this.swordPackaging = new SwordPackaging(packaging); } - - protected void marshallElements(Element entry) - { + + protected void marshallElements(Element entry) { super.marshallElements(entry); - - if ( swordTreatment != null ) - { + + if (swordTreatment != null) { entry.appendChild(swordTreatment.marshall()); } - - if ( swordVerboseDescription != null ) - { + + if (swordVerboseDescription != null) { entry.appendChild(swordVerboseDescription.marshall()); } - - if (swordNoOp != null) - { + + if (swordNoOp != null) { entry.appendChild(swordNoOp.marshall()); } - - if ( swordUserAgent != null ) - { + + if (swordUserAgent != null) { entry.appendChild(swordUserAgent.marshall()); } - - if ( swordPackaging != null ) - { - entry.appendChild(swordPackaging.marshall()); + + if (swordPackaging != null) { + entry.appendChild(swordPackaging.marshall()); } - + } - + /** - * Overrides the unmarshall method in the parent Entry. This will + * Overrides the unmarshall method in the parent Entry. This will * call the parent method to parse the general Atom elements and * attributes. This method will then parse the remaining sword - * extensions that exist in the element. - * - * @param entry The entry to parse. + * extensions that exist in the element. + * + * @param entry The entry to parse. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info - * @throws UnmarshallException If the entry is not an atom:entry - * or if there is an exception extracting the data. + * @throws UnmarshallException If the entry is not an atom:entry + * or if there is an exception extracting the data. */ public SwordValidationInfo unmarshallWithValidation(Element entry, Properties validationProperties) - throws UnmarshallException - { + throws UnmarshallException { SwordValidationInfo result = super.unmarshallWithoutValidate(entry, validationProperties); - + processUnexpectedAttributes(entry, result); - + // retrieve all of the sub-elements Elements elements = entry.getChildElements(); - Element element = null; + Element element = null; int length = elements.size(); - - for (int i = 0; i < length; i++ ) - { + + for (int i = 0; i < length; i++) { element = elements.get(i); - - if (isInstanceOf(element, SwordTreatment.elementName())) - { - if ( swordTreatment == null ) - { + + if (isInstanceOf(element, SwordTreatment.elementName())) { + if (swordTreatment == null) { swordTreatment = new SwordTreatment(); result.addUnmarshallElementInfo( swordTreatment.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(SwordTreatment.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (isInstanceOf(element, SwordNoOp.elementName())) - { - if ( swordNoOp == null ) - { - swordNoOp = new SwordNoOp(); - result.addUnmarshallElementInfo(swordNoOp.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(SwordNoOp.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); - info.setContentDescription(element.getValue()); - result.addUnmarshallElementInfo(info); - } - } - else if (isInstanceOf(element, SwordVerboseDescription.elementName())) - { - if ( swordVerboseDescription == null ) - { - swordVerboseDescription = new SwordVerboseDescription(); - result.addUnmarshallElementInfo(swordVerboseDescription.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(SwordVerboseDescription.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); - info.setContentDescription(element.getValue()); - result.addUnmarshallElementInfo(info); - } - } - else if (isInstanceOf(element, SwordUserAgent.elementName())) - { - if ( swordUserAgent == null ) - { - swordUserAgent = new SwordUserAgent(); - result.addUnmarshallElementInfo(swordUserAgent.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(SwordUserAgent.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); - info.setContentDescription(element.getValue()); - result.addUnmarshallElementInfo(info); - } - } - else if (isInstanceOf(element, SwordPackaging.elementName())) - { - if ( swordPackaging == null ) - { + } else if (isInstanceOf(element, SwordNoOp.elementName())) { + if (swordNoOp == null) { + swordNoOp = new SwordNoOp(); + result.addUnmarshallElementInfo(swordNoOp.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(SwordNoOp.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); + info.setContentDescription(element.getValue()); + result.addUnmarshallElementInfo(info); + } + } else if (isInstanceOf(element, SwordVerboseDescription.elementName())) { + if (swordVerboseDescription == null) { + swordVerboseDescription = new SwordVerboseDescription(); + result.addUnmarshallElementInfo(swordVerboseDescription.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(SwordVerboseDescription.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); + info.setContentDescription(element.getValue()); + result.addUnmarshallElementInfo(info); + } + } else if (isInstanceOf(element, SwordUserAgent.elementName())) { + if (swordUserAgent == null) { + swordUserAgent = new SwordUserAgent(); + result.addUnmarshallElementInfo(swordUserAgent.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(SwordUserAgent.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); + info.setContentDescription(element.getValue()); + result.addUnmarshallElementInfo(info); + } + } else if (isInstanceOf(element, SwordPackaging.elementName())) { + if (swordPackaging == null) { swordPackaging = new SwordPackaging(); result.addUnmarshallElementInfo(swordPackaging.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(SwordPackaging.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } - } - else if (validationProperties != null ) - { + } else if (validationProperties != null) { XmlName name = new XmlName(element); - if ( ! isElementChecked(name) ) - { + if (!isElementChecked(name)) { SwordValidationInfo info = new SwordValidationInfo(name, - SwordValidationInfo.UNKNOWN_ELEMENT, - SwordValidationInfoType.INFO); + SwordValidationInfo.UNKNOWN_ELEMENT, + SwordValidationInfoType.INFO); info.setContentDescription(element.getValue()); result.addUnmarshallElementInfo(info); } } - + } // for return result; } - + public SwordValidationInfo unmarshall(Element entry, Properties validationProperties) - throws UnmarshallException - { - + throws UnmarshallException { + SwordValidationInfo result = unmarshallWithValidation(entry, validationProperties); - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(result, validationProperties); } return result; } - + /** - * - * @param elementName - * name of element to check + * @param elementName name of element to check * @return true if element is checked */ - protected boolean isElementChecked(XmlName elementName) - { - if ( elementName == null ) - { + protected boolean isElementChecked(XmlName elementName) { + if (elementName == null) { return false; } - + return elementName.equals(SwordNoOp.elementName()) | - elementName.equals(SwordUserAgent.elementName()) | - elementName.equals(SwordTreatment.elementName()) | - elementName.equals(SwordVerboseDescription.elementName()) | - elementName.equals(SwordPackaging.elementName()) | - super.isElementChecked(elementName); + elementName.equals(SwordUserAgent.elementName()) | + elementName.equals(SwordTreatment.elementName()) | + elementName.equals(SwordVerboseDescription.elementName()) | + elementName.equals(SwordPackaging.elementName()) | + super.isElementChecked(elementName); } - - public SwordValidationInfo validate(Properties validationContext) - { + + public SwordValidationInfo validate(Properties validationContext) { return validate(null, validationContext); } - - protected SwordValidationInfo validate(SwordValidationInfo info, - Properties validationContext) - { + + protected SwordValidationInfo validate(SwordValidationInfo info, + Properties validationContext) { boolean validateAll = (info == null); - + SwordValidationInfo swordEntry = super.validate(info, validationContext); - - if ( swordUserAgent == null ) - { - String agent = validationContext.getProperty(HttpHeaders.USER_AGENT); - - if ( agent != null ) - { - swordEntry.addValidationInfo(new SwordValidationInfo(SwordUserAgent.elementName(), - SwordValidationInfo.MISSING_ELEMENT_WARNING + - " Clients SHOULD provide a User-Agent request-header (as described in [HTTP1.1] section 14.43). If provided, servers SHOULD store the value in the sword:userAgent element.", - SwordValidationInfoType.WARNING)); - } - } - else if ( swordUserAgent != null && validateAll ) - { + + if (swordUserAgent == null) { + String agent = validationContext.getProperty(HttpHeaders.USER_AGENT); + + if (agent != null) { + swordEntry.addValidationInfo(new SwordValidationInfo(SwordUserAgent.elementName(), + SwordValidationInfo.MISSING_ELEMENT_WARNING + + " Clients SHOULD provide a User-Agent " + + "request-header (as described in [HTTP1.1] " + + "section 14.43). If provided, servers SHOULD" + + " store the value in the sword:userAgent " + + "element.", + SwordValidationInfoType.WARNING)); + } + } else if (swordUserAgent != null && validateAll) { info.addValidationInfo(swordUserAgent.validate(validationContext)); } - + // additional rules for sword elements - if ( swordTreatment == null ) - { + if (swordTreatment == null) { swordEntry.addValidationInfo(new SwordValidationInfo(SwordTreatment.elementName(), - SwordValidationInfo.MISSING_ELEMENT_ERROR + " MUST be present and contain either a human-readable statement describing treatment the deposited resource has received or a URI that dereferences to such a description.", - SwordValidationInfoType.ERROR)); - } - else if ( swordTreatment != null && validateAll ) - { + SwordValidationInfo.MISSING_ELEMENT_ERROR + " MUST " + + "be present and contain either a human-readable " + + "statement describing treatment the deposited " + + "resource has received or a URI that " + + "dereferences to such a description.", + SwordValidationInfoType.ERROR)); + } else if (swordTreatment != null && validateAll) { info.addValidationInfo(swordTreatment.validate(validationContext)); } - + // additional rules for sword elements - if ( swordVerboseDescription == null ) - { + if (swordVerboseDescription == null) { String verbose = validationContext.getProperty(HttpHeaders.X_VERBOSE); - if ( verbose != null ) - { + if (verbose != null) { swordEntry.addValidationInfo(new SwordValidationInfo(SwordVerboseDescription.elementName(), - SwordValidationInfo.MISSING_ELEMENT_WARNING + " If the client made the POST request with an X-Verbose:true header, the server SHOULD supply a verbose description of the deposit process.", - SwordValidationInfoType.WARNING)); + SwordValidationInfo.MISSING_ELEMENT_WARNING + " " + + "If the client made the POST request with an" + + " X-Verbose:true header, the server SHOULD " + + "supply a verbose description of the deposit" + + " process.", + SwordValidationInfoType.WARNING)); } - } - else if ( swordVerboseDescription != null && validateAll ) - { + } else if (swordVerboseDescription != null && validateAll) { info.addValidationInfo(swordVerboseDescription.validate(validationContext)); } - - if ( swordNoOp == null ) - { + + if (swordNoOp == null) { String noOp = validationContext.getProperty(HttpHeaders.X_NO_OP); - if ( noOp != null ) - { + if (noOp != null) { swordEntry.addValidationInfo(new SwordValidationInfo(SwordNoOp.elementName(), - SwordValidationInfo.MISSING_ELEMENT_WARNING + " If the client made the POST request with an X-No-Op:true header, the server SHOULD reflect this by including a sword:noOp element with a value of 'true' in the response. See Part A Section 3.1. Servers MAY use a value of 'false' to indicate that the deposit proceeded but MUST NOT use this element to signify an error.", - SwordValidationInfoType.WARNING)); + SwordValidationInfo.MISSING_ELEMENT_WARNING + " " + + "If the client made the POST request with an" + + " X-No-Op:true header, the server SHOULD " + + "reflect this by including a sword:noOp " + + "element with a value of 'true' in the " + + "response. See Part A Section 3.1. Servers " + + "MAY use a value of 'false' to indicate that" + + " the deposit proceeded but MUST NOT use " + + "this element to signify an error.", + SwordValidationInfoType.WARNING)); } - } - else if ( swordNoOp != null && validateAll ) - { + } else if (swordNoOp != null && validateAll) { info.addValidationInfo(swordNoOp.validate(validationContext)); } - - if ( swordPackaging == null ) - { - swordEntry.addValidationInfo(new SwordValidationInfo(SwordPackaging.elementName(), - SwordValidationInfo.MISSING_ELEMENT_WARNING + " If the POST request results in the creation of packaged resource, the server MAY use this element to declare the packaging type. If used it SHOULD take a value from [SWORD-TYPES].", - SwordValidationInfoType.INFO)); - } - else if ( swordPackaging != null && validateAll ) - { + + if (swordPackaging == null) { + swordEntry.addValidationInfo(new SwordValidationInfo(SwordPackaging.elementName(), + SwordValidationInfo.MISSING_ELEMENT_WARNING + " If " + + "the POST request results in the creation of " + + "packaged resource, the server MAY use this " + + "element to declare the packaging type. If used " + + "it SHOULD take a value from [SWORD-TYPES].", + SwordValidationInfoType.INFO)); + } else if (swordPackaging != null && validateAll) { info.addValidationInfo(swordPackaging.validate(validationContext)); } - + return swordEntry; } - + /** - * Overrides the unmarshall method in the parent Entry. This will + * Overrides the unmarshall method in the parent Entry. This will * call the parent method to parse the general Atom elements and * attributes. This method will then parse the remaining sword - * extensions that exist in the element. - * - * @param entry The entry to parse. - * - * @throws UnmarshallException If the entry is not an atom:entry - * or if there is an exception extracting the data. + * extensions that exist in the element. + * + * @param entry The entry to parse. + * @throws UnmarshallException If the entry is not an atom:entry + * or if there is an exception extracting the data. */ @Override public void unmarshall(Element entry) - throws UnmarshallException - { + throws UnmarshallException { unmarshall(entry, null); - } + } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SWORDErrorDocument.java b/dspace-sword/src/main/java/org/purl/sword/base/SWORDErrorDocument.java index ee278a67be..47d1336eb5 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SWORDErrorDocument.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SWORDErrorDocument.java @@ -8,34 +8,34 @@ package org.purl.sword.base; import java.util.Properties; + import nu.xom.Attribute; import nu.xom.Element; /** - * Extension of the SWORD Entry class, specialized for Error Documents. - * + * Extension of the SWORD Entry class, specialized for Error Documents. + * * @author Stuart Lewis (sdl@aber.ac.uk) * @author Neil Taylor (nst@aber.ac.uk) - */ -public class SWORDErrorDocument extends SWORDEntry -{ + */ +public class SWORDErrorDocument extends SWORDEntry { /** - * Local name for the element. - */ + * Local name for the element. + */ @Deprecated public static final String ELEMENT_NAME = "error"; - + private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "error", Namespaces.NS_SWORD); - + new XmlName(Namespaces.PREFIX_SWORD, "error", Namespaces.NS_SWORD); + private static final XmlName ATTRIBUTE_HREF_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "href", Namespaces.NS_SWORD); - + new XmlName(Namespaces.PREFIX_SWORD, "href", Namespaces.NS_SWORD); + /** * The Error URI */ private String errorURI; - + /** * Create the error document (intended to be used when unmarshalling an error document * as this will set the errorURI) @@ -45,34 +45,32 @@ public class SWORDErrorDocument extends SWORDEntry XML_NAME.getLocalName(), XML_NAME.getNamespace()); } - + /** * Create the error document - * + * * @param errorURI The URI of the error */ public SWORDErrorDocument(String errorURI) { this(); this.errorURI = errorURI; } - + /** * Get the element name. * * @return the element name. */ - public static XmlName elementName() - { - return XML_NAME; + public static XmlName elementName() { + return XML_NAME; } - + /** - * Overrides the marshal method in the parent SWORDEntry. This will - * call the parent marshal method and then add the additional - * elements that have been added in this subclass. + * Overrides the marshal method in the parent SWORDEntry. This will + * call the parent marshal method and then add the additional + * elements that have been added in this subclass. */ - public Element marshall() - { + public Element marshall() { Element entry = new Element(getQualifiedName(), Namespaces.NS_SWORD); entry.addNamespaceDeclaration(Namespaces.PREFIX_SWORD, Namespaces.NS_SWORD); entry.addNamespaceDeclaration(Namespaces.PREFIX_ATOM, Namespaces.NS_ATOM); @@ -81,158 +79,142 @@ public class SWORDErrorDocument extends SWORDEntry super.marshallElements(entry); return entry; } - + /** - * Overrides the unmarshal method in the parent SWORDEntry. This will + * Overrides the unmarshal method in the parent SWORDEntry. This will * call the parent method to parse the general Atom elements and * attributes. This method will then parse the remaining sword - * extensions that exist in the element. - * - * @param entry The entry to parse. - * - * @throws UnmarshallException If the entry is not an atom:entry - * or if there is an exception extracting the data. + * extensions that exist in the element. + * + * @param entry The entry to parse. + * @throws UnmarshallException If the entry is not an atom:entry + * or if there is an exception extracting the data. */ - public void unmarshall(Element entry) throws UnmarshallException - { + public void unmarshall(Element entry) throws UnmarshallException { unmarshall(entry, null); } - + /** - * - * @param entry an element to unmarshall. + * @param entry an element to unmarshall. * @param validationProperties FIXME: PLEASE DOCUMENT. * @throws org.purl.sword.base.UnmarshallException passed through. */ public SwordValidationInfo unmarshall(Element entry, Properties validationProperties) - throws UnmarshallException - { - SwordValidationInfo result = super.unmarshall(entry, validationProperties); - result.clearValidationItems(); - - errorURI = entry.getAttributeValue(ATTRIBUTE_HREF_NAME.getLocalName()); - - if ( validationProperties != null ) - { - result = validate(result, validationProperties); - } - - return result; + throws UnmarshallException { + SwordValidationInfo result = super.unmarshall(entry, validationProperties); + result.clearValidationItems(); + + errorURI = entry.getAttributeValue(ATTRIBUTE_HREF_NAME.getLocalName()); + + if (validationProperties != null) { + result = validate(result, validationProperties); + } + + return result; } - + /** * This method overrides the XmlElement definition so that it can allow * the definition of the href attribute. All other attributes are * shown as 'Unknown Attribute' info elements. * * @param element The element that contains the attributes - * @param info The info object that will hold the validation info. + * @param info The info object that will hold the validation info. */ @Override - protected void processUnexpectedAttributes(Element element, SwordValidationInfo info) - { + protected void processUnexpectedAttributes(Element element, SwordValidationInfo info) { int attributeCount = element.getAttributeCount(); Attribute attribute = null; - - for ( int i = 0; i < attributeCount; i++ ) - { - attribute = element.getAttribute(i); - if ( ! ATTRIBUTE_HREF_NAME.getLocalName().equals(attribute.getQualifiedName()) ) - { - + + for (int i = 0; i < attributeCount; i++) { + attribute = element.getAttribute(i); + if (!ATTRIBUTE_HREF_NAME.getLocalName().equals(attribute.getQualifiedName())) { + XmlName attributeName = new XmlName(attribute.getNamespacePrefix(), - attribute.getLocalName(), - attribute.getNamespaceURI()); - + attribute.getLocalName(), + attribute.getNamespaceURI()); + SwordValidationInfo item = new SwordValidationInfo(xmlName, attributeName, - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO); + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); item.setContentDescription(attribute.getValue()); info.addUnmarshallAttributeInfo(item); - } + } } } - + /** - * * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info */ - public SwordValidationInfo validate(Properties validationContext) - { + public SwordValidationInfo validate(Properties validationContext) { return validate(null, validationContext); } - + /** - * - * @param info add results to this. + * @param info add results to this. * @param validationContext unused. * @return SWORD validation info */ protected SwordValidationInfo validate(SwordValidationInfo info, - Properties validationContext) - { - - if ( errorURI == null ) - { - info.addValidationInfo(new SwordValidationInfo(xmlName, ATTRIBUTE_HREF_NAME, - SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, - SwordValidationInfoType.WARNING)); - } - else - { - boolean validUri = true; - if (errorURI.startsWith("http://purl.org/net/sword/error/")) - { - // check that the list of codes - if ( ! (errorURI.equals(ErrorCodes.ERROR_CONTENT) || - errorURI.equals(ErrorCodes.ERROR_CHECKSUM_MISMATCH) || - errorURI.equals(ErrorCodes.ERROR_BAD_REQUEST) || - errorURI.equals(ErrorCodes.TARGET_OWNER_UKNOWN) || - errorURI.equals(ErrorCodes.MEDIATION_NOT_ALLOWED)) ) - { - info.addValidationInfo(new SwordValidationInfo(xmlName, - ATTRIBUTE_HREF_NAME, - "Errors in the SWORD namespace are reserved and legal values are enumerated in the SWORD 1.3 specification. Implementations MAY define their own errors, but MUST use a different namespace to do so.", - SwordValidationInfoType.ERROR)); - validUri = false; - } - } - - if ( validUri ) - { - SwordValidationInfo item = new SwordValidationInfo(xmlName, ATTRIBUTE_HREF_NAME); - item.setContentDescription(errorURI); - info.addAttributeValidationInfo(item); - } - } - return info; + Properties validationContext) { + + if (errorURI == null) { + info.addValidationInfo(new SwordValidationInfo(xmlName, ATTRIBUTE_HREF_NAME, + SwordValidationInfo.MISSING_ATTRIBUTE_WARNING, + SwordValidationInfoType.WARNING)); + } else { + boolean validUri = true; + if (errorURI.startsWith("http://purl.org/net/sword/error/")) { + // check that the list of codes + if (!(errorURI.equals(ErrorCodes.ERROR_CONTENT) || + errorURI.equals(ErrorCodes.ERROR_CHECKSUM_MISMATCH) || + errorURI.equals(ErrorCodes.ERROR_BAD_REQUEST) || + errorURI.equals(ErrorCodes.TARGET_OWNER_UKNOWN) || + errorURI.equals(ErrorCodes.MEDIATION_NOT_ALLOWED))) { + info.addValidationInfo(new SwordValidationInfo(xmlName, + ATTRIBUTE_HREF_NAME, + "Errors in the SWORD namespace are reserved and " + + "legal values are enumerated in the SWORD 1.3 " + + "specification. Implementations MAY define " + + "their own errors, but MUST use a different " + + "namespace to do so.", + SwordValidationInfoType.ERROR)); + validUri = false; + } + } + + if (validUri) { + SwordValidationInfo item = new SwordValidationInfo(xmlName, ATTRIBUTE_HREF_NAME); + item.setContentDescription(errorURI); + info.addAttributeValidationInfo(item); + } + } + return info; } - - + + /** * Get the error URI - * + * * @return the error URI */ - public String getErrorURI() - { + public String getErrorURI() { return errorURI; } - + /** * set the error URI - * + * * @param error the error URI */ - public void setErrorURI(String error) - { + public void setErrorURI(String error) { errorURI = error; } - + /** * Main method to perform a brief test of the class - * + * * @param args the command line arguments given */ /*public static void main(String[] args) @@ -248,7 +230,7 @@ public class SWORDErrorDocument extends SWORDEntry a.setName("Lewis, Stuart"); a.setEmail("stuart@example.com"); sed.addAuthors(a); - + System.out.println(sed.marshall().toXML()); } */ diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SWORDErrorException.java b/dspace-sword/src/main/java/org/purl/sword/base/SWORDErrorException.java index 8287eed11b..c6472f48ce 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SWORDErrorException.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SWORDErrorException.java @@ -10,40 +10,52 @@ package org.purl.sword.base; /** * Represents a generic SWORD exception. If this thrown by a repository, * it would result in a SWORD Error Document being thrown. - * + * * @author Stuart Lewis */ -public class SWORDErrorException extends Exception -{ - /** The error URI (defined in ErrorCodes class) */ - private String errorURI; - - /** The HTTP error code (defined in HTTPServletResponse class) */ - private int status; - - /** The error message given by the repository */ - private String description; - - +public class SWORDErrorException extends Exception { /** - * Create a new instance and store the specified data. - * - * @param errorURI The errorURI of the exception being thrown - * @param description A description of the error thrown. + * The error URI (defined in ErrorCodes class) */ - public SWORDErrorException(String errorURI, String description) - { - super(description); - this.errorURI = errorURI; - this.description = description; - - if (errorURI.equals(ErrorCodes.ERROR_BAD_REQUEST)) { status = 400; } - else if (errorURI.equals(ErrorCodes.ERROR_CHECKSUM_MISMATCH)) { status = 412; } - else if (errorURI.equals(ErrorCodes.ERROR_CONTENT)) { status = 415; } - else if (errorURI.equals(ErrorCodes.MAX_UPLOAD_SIZE_EXCEEDED)) { status = 413; } - else if (errorURI.equals(ErrorCodes.MEDIATION_NOT_ALLOWED)) { status = 412; } - else if (errorURI.equals(ErrorCodes.TARGET_OWNER_UKNOWN)) { status = 401; } - else { status = 400; } + private String errorURI; + + /** + * The HTTP error code (defined in HTTPServletResponse class) + */ + private int status; + + /** + * The error message given by the repository + */ + private String description; + + + /** + * Create a new instance and store the specified data. + * + * @param errorURI The errorURI of the exception being thrown + * @param description A description of the error thrown. + */ + public SWORDErrorException(String errorURI, String description) { + super(description); + this.errorURI = errorURI; + this.description = description; + + if (errorURI.equals(ErrorCodes.ERROR_BAD_REQUEST)) { + status = 400; + } else if (errorURI.equals(ErrorCodes.ERROR_CHECKSUM_MISMATCH)) { + status = 412; + } else if (errorURI.equals(ErrorCodes.ERROR_CONTENT)) { + status = 415; + } else if (errorURI.equals(ErrorCodes.MAX_UPLOAD_SIZE_EXCEEDED)) { + status = 413; + } else if (errorURI.equals(ErrorCodes.MEDIATION_NOT_ALLOWED)) { + status = 412; + } else if (errorURI.equals(ErrorCodes.TARGET_OWNER_UKNOWN)) { + status = 401; + } else { + status = 400; + } } @@ -60,10 +72,10 @@ public class SWORDErrorException extends Exception public int getStatus() { return status; } - + /** * Set the status - * + * * @param status The HTTP status code */ public void setStatus(int status) { @@ -75,5 +87,5 @@ public class SWORDErrorException extends Exception */ public String getDescription() { return description; - } + } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SWORDException.java b/dspace-sword/src/main/java/org/purl/sword/base/SWORDException.java index 88ddc64685..e315c63f75 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SWORDException.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SWORDException.java @@ -10,56 +10,52 @@ package org.purl.sword.base; /** * Represents a generic SWORD exception. If this thrown by a repository, * it would result in a HTTP 500 message being returned to the user. - * + * * @author Stuart Lewis * @author Neil Taylor */ -public class SWORDException extends Exception -{ - private String errorCode; - - /** - * Create a new instance and store the specified message and source data. - * - * @param message The message for the exception. +public class SWORDException extends Exception { + private String errorCode; + + /** + * Create a new instance and store the specified message and source data. + * + * @param message The message for the exception. * @param source The original exception that lead to this exception. This * can be null. */ - public SWORDException(String message, Exception source) - { - super(message, source); + public SWORDException(String message, Exception source) { + super(message, source); } - + /** - * Create a new instance and store the specified message and source data. - * - * @param message The message for the exception. - * @param source The original exception that lead to this exception. This - * can be null. + * Create a new instance and store the specified message and source data. + * + * @param message The message for the exception. + * @param source The original exception that lead to this exception. This + * can be null. * @param errorCode The error code to sed back with the request */ - public SWORDException(String message, Exception source, String errorCode) - { - super(message, source); - this.errorCode = errorCode; + public SWORDException(String message, Exception source, String errorCode) { + super(message, source); + this.errorCode = errorCode; } - + /** - * Create a new instance and store the specified message. - * - * @param message The message for the exception. + * Create a new instance and store the specified message. + * + * @param message The message for the exception. */ - public SWORDException(String message) - { - super(message); + public SWORDException(String message) { + super(message); } - + /** * Get the error code - * + * * @return The error code */ public String getErrorCode() { - return errorCode; + return errorCode; } } \ No newline at end of file diff --git a/dspace-sword/src/main/java/org/purl/sword/base/Service.java b/dspace-sword/src/main/java/org/purl/sword/base/Service.java index 0ce9a124ca..c335aecf75 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/Service.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/Service.java @@ -10,597 +10,513 @@ package org.purl.sword.base; import java.util.ArrayList; import java.util.Iterator; import java.util.List; - import java.util.Properties; + import nu.xom.Element; import nu.xom.Elements; - import org.apache.log4j.Logger; import org.purl.sword.atom.Generator; /** - * Represents an Atom Publishing Protocol Service element, with - * SWORD extensions. - * + * Represents an Atom Publishing Protocol Service element, with + * SWORD extensions. + * * @author Neil Taylor */ -public class Service extends XmlElement implements SwordElementInterface -{ +public class Service extends XmlElement implements SwordElementInterface { private SwordVersion swordVersion; - + private SwordNoOp swordNoOp; - + private SwordVerbose swordVerbose; - + private SwordMaxUploadSize swordMaxUploadSize; - + /** * The details of the server software that generated the service document. */ private Generator generator; - + /** - * List of Workspaces. + * List of Workspaces. + */ + private List workspaces; + + /** + * Logger */ - private List workspaces; - - /** Logger */ private static Logger log = Logger.getLogger(Service.class); - + /** * MaxUploadSize */ @Deprecated public static final String ELEMENT_GENERATOR = "generator"; - + /** - * Name for this element. + * Name for this element. */ @Deprecated public static final String ELEMENT_NAME = "service"; - + /** * The XML NAME (prefix, local name and namespace) for this element. */ private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_APP, "service", Namespaces.NS_APP); - - + new XmlName(Namespaces.PREFIX_APP, "service", Namespaces.NS_APP); + + /** - * Create a new instance. + * Create a new instance. */ - public Service() - { + public Service() { super(XML_NAME); initialise(); } - + /** - * Create a new instance. - * - * @param version The service compliance level. + * Create a new instance. + * + * @param version The service compliance level. */ - public Service(String version) - { + public Service(String version) { this(); setVersion(version); } - + /** - * Create a new instance with the specified compliance level, noOp and - * verbose values. - * - * @param version The service compliance level. - * @param noOp The noOp. - * @param verbose The verbose element. + * Create a new instance with the specified compliance level, noOp and + * verbose values. + * + * @param version The service compliance level. + * @param noOp The noOp. + * @param verbose The verbose element. */ - public Service(String version, boolean noOp, boolean verbose) - { + public Service(String version, boolean noOp, boolean verbose) { this(); setVersion(version); setNoOp(noOp); setVerbose(verbose); } - - public static XmlName elementName() - { - return XML_NAME; + + public static XmlName elementName() { + return XML_NAME; } + /** * Initialise the data structures in this tool. */ - private void initialise() - { + private void initialise() { workspaces = new ArrayList(); swordVersion = null; - swordNoOp = null; - swordVerbose = null; + swordNoOp = null; + swordVerbose = null; swordMaxUploadSize = null; generator = null; } - - + + /** - * Get the SWORD version. - * - * @return The version. + * Get the SWORD version. + * + * @return The version. */ - public final String getVersion() - { - if ( swordVersion == null ) - { + public final String getVersion() { + if (swordVersion == null) { return null; } return swordVersion.getContent(); } - + /** - * Set the SWORD version. - * - * @param version The version. + * Set the SWORD version. + * + * @param version The version. */ - public final void setVersion(String version) - { - if ( version == null ) - { - // clear the value + public final void setVersion(String version) { + if (version == null) { + // clear the value swordVersion = null; - return; + return; } - + swordVersion = new SwordVersion(version); } - + /** - * Get the NoOp value. - * - * @return The value. + * Get the NoOp value. + * + * @return The value. */ - public final boolean isNoOp() - { - if ( swordNoOp == null ) - { + public final boolean isNoOp() { + if (swordNoOp == null) { return false; } - + return swordNoOp.getContent(); } - + /** - * Set the NoOp value. - * - * @param noOp The value. + * Set the NoOp value. + * + * @param noOp The value. */ - public final void setNoOp(boolean noOp) - { + public final void setNoOp(boolean noOp) { swordNoOp = new SwordNoOp(noOp); } - + /** - * Determine if the NoOp value has been set. This should be called to + * Determine if the NoOp value has been set. This should be called to * check if an item has been programmatically set and does not have a - * default value. - * - * @return True if it has been set programmatically. Otherwise, false. + * default value. + * + * @return True if it has been set programmatically. Otherwise, false. */ - public final boolean isNoOpSet() - { - if ( swordNoOp == null ) - { + public final boolean isNoOpSet() { + if (swordNoOp == null) { return false; } - + return swordNoOp.isSet(); } - + /** - * Get the Verbose setting. - * - * @return The value. + * Get the Verbose setting. + * + * @return The value. */ - public final boolean isVerbose() - { - if ( swordVerbose == null ) - { + public final boolean isVerbose() { + if (swordVerbose == null) { return false; } - + return swordVerbose.getContent(); } - + /** - * Set the Verbose value. - * - * @param verbose The value. + * Set the Verbose value. + * + * @param verbose The value. */ - public final void setVerbose(boolean verbose) - { + public final void setVerbose(boolean verbose) { swordVerbose = new SwordVerbose(verbose); } - + /** - * Determine if the Verbose value has been set. This should be called to + * Determine if the Verbose value has been set. This should be called to * check if an item has been programmatically set and does not have a - * default value. - * - * @return True if it has been set programmatically. Otherwise, false. + * default value. + * + * @return True if it has been set programmatically. Otherwise, false. */ - public final boolean isVerboseSet() - { - if ( swordVerbose == null ) - { + public final boolean isVerboseSet() { + if (swordVerbose == null) { return false; } - + return swordVerbose.isSet(); } - + /** * Set the maximum file upload size in kB - * + * * @param maxUploadSize Max upload file size in kB */ - public final void setMaxUploadSize(int maxUploadSize) - { + public final void setMaxUploadSize(int maxUploadSize) { swordMaxUploadSize = new SwordMaxUploadSize(maxUploadSize); } - + /** * Get the maximum upload file size (in kB) * * @return the maximum file upload size. If no value has been set, this will - * be equal to Integer.MIN_VALUE. + * be equal to Integer.MIN_VALUE. */ - public final int getMaxUploadSize() - { - if ( swordMaxUploadSize == null ) - { + public final int getMaxUploadSize() { + if (swordMaxUploadSize == null) { return Integer.MIN_VALUE; } return swordMaxUploadSize.getContent(); } - - public final Generator getGenerator() - { + + public final Generator getGenerator() { return generator; } - - public final void setGenerator(Generator generator) - { - this.generator = generator; + + public final void setGenerator(Generator generator) { + this.generator = generator; } - + /** - * Get an Iterator over the workspaces. - * - * @return The workspace. + * Get an Iterator over the workspaces. + * + * @return The workspace. */ - public final Iterator getWorkspaces() - { + public final Iterator getWorkspaces() { return workspaces.iterator(); } - + /** * Get a List of workspaces - * + * * @return The workspaces in a List */ - public final List getWorkspacesList() - { + public final List getWorkspacesList() { return workspaces; } - + /** - * Add a workspace. - * - * @param workspace The workspace. + * Add a workspace. + * + * @param workspace The workspace. */ - public final void addWorkspace(Workspace workspace) - { + public final void addWorkspace(Workspace workspace) { this.workspaces.add(workspace); } - + /** - * Clear the list of workspaces. + * Clear the list of workspaces. */ - public final void clearWorkspaces() - { + public final void clearWorkspaces() { this.workspaces.clear(); } - + /** - * Marshal the data in this object to an Element object. - * - * @return A XOM Element that holds the data for this Content element. + * Marshal the data in this object to an Element object. + * + * @return A XOM Element that holds the data for this Content element. */ - public final Element marshall( ) - { + public final Element marshall() { Element service = new Element(getQualifiedName(), Namespaces.NS_APP); service.addNamespaceDeclaration(Namespaces.PREFIX_ATOM, Namespaces.NS_ATOM); service.addNamespaceDeclaration(Namespaces.PREFIX_DC_TERMS, Namespaces.NS_DC_TERMS); service.addNamespaceDeclaration(Namespaces.PREFIX_SWORD, Namespaces.NS_SWORD); - - if ( swordVersion != null ) - { + + if (swordVersion != null) { service.appendChild(swordVersion.marshall()); } - - if ( swordVerbose != null ) - { - service.appendChild(swordVerbose.marshall()); + + if (swordVerbose != null) { + service.appendChild(swordVerbose.marshall()); } - - if ( swordNoOp != null ) - { + + if (swordNoOp != null) { service.appendChild(swordNoOp.marshall()); } - - if ( swordMaxUploadSize != null ) - { - service.appendChild(swordMaxUploadSize.marshall()); + + if (swordMaxUploadSize != null) { + service.appendChild(swordMaxUploadSize.marshall()); } - - if ( generator != null ) - { + + if (generator != null) { service.appendChild(generator.marshall()); } - - for (Workspace item : workspaces) - { + + for (Workspace item : workspaces) { service.appendChild(item.marshall()); } - - return service; + + return service; } - + /** - * Unmarshal the content element into the data in this object. - * + * Unmarshal the content element into the data in this object. + * * @throws UnmarshallException If the element does not contain a - * content element or if there are problems - * accessing the data. + * content element or if there are problems + * accessing the data. */ - public final void unmarshall( Element service ) - throws UnmarshallException - { + public final void unmarshall(Element service) + throws UnmarshallException { unmarshall(service, null); } - + /** - * - * @param service - * element to unmarshall - * @param validationProperties - * FIXME: PLEASE DOCUMENT. + * @param service element to unmarshall + * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info * @throws UnmarshallException If the element does not contain a - * content element or if there are problems - * accessing the data. + * content element or if there are problems + * accessing the data. */ public final SwordValidationInfo unmarshall(Element service, Properties validationProperties) - throws UnmarshallException - { - if (!isInstanceOf(service, xmlName)) - { + throws UnmarshallException { + if (!isInstanceOf(service, xmlName)) { return handleIncorrectElement(service, validationProperties); } - + ArrayList validationItems = - new ArrayList(); - - try - { - initialise(); - + new ArrayList(); + + try { + initialise(); + // Retrieve all of the sub-elements Elements elements = service.getChildElements(); Element element = null; int length = elements.size(); - - for (int i = 0; i < length; i++ ) - { + + for (int i = 0; i < length; i++) { element = elements.get(i); - - if (isInstanceOf(element, SwordVersion.elementName() ) ) - { + + if (isInstanceOf(element, SwordVersion.elementName())) { //validationItems.add(unmarshallVersion(element, validate)); - if ( swordVersion == null ) - { + if (swordVersion == null) { swordVersion = new SwordVersion(); validationItems.add(swordVersion.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(SwordVersion.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); validationItems.add(info); } - } - else if (isInstanceOf(element, SwordVerbose.elementName())) - { - if ( swordVerbose == null ) - { + } else if (isInstanceOf(element, SwordVerbose.elementName())) { + if (swordVerbose == null) { swordVerbose = new SwordVerbose(); validationItems.add(swordVerbose.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(SwordVerbose.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); validationItems.add(info); } - } - else if (isInstanceOf(element, SwordNoOp.elementName()) ) - { - if ( swordNoOp == null ) - { + } else if (isInstanceOf(element, SwordNoOp.elementName())) { + if (swordNoOp == null) { swordNoOp = new SwordNoOp(); validationItems.add(swordNoOp.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { SwordValidationInfo info = new SwordValidationInfo(SwordNoOp.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); validationItems.add(info); } - } - else if (isInstanceOf(element, SwordMaxUploadSize.elementName())) - { - if ( swordMaxUploadSize == null ) - { + } else if (isInstanceOf(element, SwordMaxUploadSize.elementName())) { + if (swordMaxUploadSize == null) { swordMaxUploadSize = new SwordMaxUploadSize(); validationItems.add(swordMaxUploadSize.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(SwordNoOp.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); - info.setContentDescription(element.getValue()); - validationItems.add(info); - } - } - else if (isInstanceOf(element, Generator.elementName())) - { - if ( generator == null ) - { - generator = new Generator(); - validationItems.add(generator.unmarshall(element, validationProperties)); - } - else if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo(Generator.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(SwordNoOp.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); validationItems.add(info); } - } - else if (isInstanceOf(element, Workspace.elementName() )) - { - Workspace workspace = new Workspace( ); + } else if (isInstanceOf(element, Generator.elementName())) { + if (generator == null) { + generator = new Generator(); + validationItems.add(generator.unmarshall(element, validationProperties)); + } else if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo(Generator.elementName(), + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); + info.setContentDescription(element.getValue()); + validationItems.add(info); + } + } else if (isInstanceOf(element, Workspace.elementName())) { + Workspace workspace = new Workspace(); validationItems.add(workspace.unmarshall(element, validationProperties)); workspaces.add(workspace); - } - else if ( validationProperties != null ) - { + } else if (validationProperties != null) { // report on any additional items. They are permitted because of - // the Atom/APP specification. Report the items for information - XmlName name = new XmlName(element.getNamespacePrefix(), - element.getLocalName(), + // the Atom/APP specification. Report the items for information + XmlName name = new XmlName(element.getNamespacePrefix(), + element.getLocalName(), element.getNamespaceURI()); - + validationItems.add(new SwordValidationInfo(name, - SwordValidationInfo.UNKNOWN_ELEMENT, - SwordValidationInfoType.INFO)); + SwordValidationInfo.UNKNOWN_ELEMENT, + SwordValidationInfoType.INFO)); } } - } - catch ( Exception ex ) - { + } catch (Exception ex) { log.error("Unable to parse an element in Service: " + ex.getMessage()); ex.printStackTrace(); throw new UnmarshallException("Unable to parse element in Service", ex); } - + // now process the validation information SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(validationItems, validationProperties); } return result; - + } - - - public SwordValidationInfo validate(Properties validationContext) - { + + + public SwordValidationInfo validate(Properties validationContext) { return validate(null, validationContext); } - + /** - * - * @param existing add results to this. + * @param existing add results to this. * @param validationContext FIXME: PLEASE DOCUMENT. * @return validation information */ protected SwordValidationInfo validate(List existing, - Properties validationContext) - { + Properties validationContext) { boolean validateAll = (existing != null); - + SwordValidationInfo result = new SwordValidationInfo(xmlName); - + // process the basic rules - if ( swordVersion == null ) - { + if (swordVersion == null) { SwordValidationInfo info = new SwordValidationInfo(SwordVersion.elementName(), - SwordValidationInfo.MISSING_ELEMENT_WARNING, - SwordValidationInfoType.WARNING); + SwordValidationInfo.MISSING_ELEMENT_WARNING, + SwordValidationInfoType.WARNING); result.addValidationInfo(info); } - - if ( generator == null ) - { + + if (generator == null) { SwordValidationInfo info = new SwordValidationInfo(Generator.elementName(), - SwordValidationInfo.MISSING_ELEMENT_WARNING, - SwordValidationInfoType.WARNING); + SwordValidationInfo.MISSING_ELEMENT_WARNING, + SwordValidationInfoType.WARNING); result.addValidationInfo(info); } - - - if ( workspaces == null || workspaces.size() == 0 ) - { + + + if (workspaces == null || workspaces.size() == 0) { SwordValidationInfo info = new SwordValidationInfo(Workspace.elementName(), - "This element SHOULD be included unless the authenticated user does not have permission to deposit.", - SwordValidationInfoType.WARNING); + "This element SHOULD be included unless the " + + "authenticated user does not have permission to " + + "deposit.", + SwordValidationInfoType.WARNING); result.addValidationInfo(info); } - - if ( validateAll ) - { - if ( swordVersion != null ) - { + + if (validateAll) { + if (swordVersion != null) { result.addValidationInfo(swordVersion.validate(validationContext)); } - - if ( swordNoOp != null ) - { + + if (swordNoOp != null) { result.addValidationInfo(swordNoOp.validate(validationContext)); } - - if ( swordVerbose != null ) - { + + if (swordVerbose != null) { result.addValidationInfo(swordVerbose.validate(validationContext)); } - - if ( swordMaxUploadSize != null ) - { + + if (swordMaxUploadSize != null) { result.addValidationInfo(swordMaxUploadSize.validate(validationContext)); } - - if ( generator != null ) - { + + if (generator != null) { result.addValidationInfo(generator.validate(validationContext)); } - + Iterator iterator = workspaces.iterator(); - while ( iterator.hasNext() ) - { + while (iterator.hasNext()) { result.addValidationInfo(iterator.next().validate(validationContext)); } } - + result.addUnmarshallValidationInfo(existing, null); - return result; + return result; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/ServiceDocument.java b/dspace-sword/src/main/java/org/purl/sword/base/ServiceDocument.java index 498cf606ad..b88787c825 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/ServiceDocument.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/ServiceDocument.java @@ -9,8 +9,8 @@ package org.purl.sword.base; import java.io.ByteArrayOutputStream; import java.io.IOException; - import java.util.Properties; + import nu.xom.Builder; import nu.xom.Document; import nu.xom.Element; @@ -19,9 +19,9 @@ import nu.xom.Serializer; /** * A representation of a SWORD Service Document. - * + * * http://www.ukoln.ac.uk/repositories/digirep/index/SWORD_APP_Profile_0.5 - * + * * @author Stuart Lewis * @author Neil Taylor */ @@ -35,14 +35,13 @@ public class ServiceDocument { * Create a new instance and set the initial service level to Zero. */ public ServiceDocument() { - + } /** * Create a new instance and set the specified service level. - * - * @param version - * The SWORD version. + * + * @param version The SWORD version. */ public ServiceDocument(String version) { service = new Service(version); @@ -50,9 +49,8 @@ public class ServiceDocument { /** * Create a new instance and store the specified Service document. - * - * @param service - * The Service object. + * + * @param service The Service object. */ public ServiceDocument(Service service) { this.service = service; @@ -60,9 +58,8 @@ public class ServiceDocument { /** * Set the service object associated with this document. - * - * @param service - * The new Service object. + * + * @param service The new Service object. */ public void setService(Service service) { this.service = service; @@ -70,7 +67,7 @@ public class ServiceDocument { /** * Retrieve the Service object associated with this document. - * + * * @return The Service object. */ public Service getService() { @@ -79,7 +76,7 @@ public class ServiceDocument { /** * Return the Service Document in its XML form. - * + * * @return The ServiceDocument */ public String toString() { @@ -89,9 +86,9 @@ public class ServiceDocument { /** * Marshall the data in the Service element and generate a String * representation. The returned string is UTF-8 format. - * + * * @return A string of XML, or null if there was an error - * marshalling the data. + * marshalling the data. */ public String marshall() { try { @@ -115,17 +112,14 @@ public class ServiceDocument { * Convert the specified XML string into a set of objects used within the * service. A new Service object will be created and stored. This will * dispose of any previous Service object associated with this object. - * - * @param xml - * The XML string. - * @throws UnmarshallException - * If there was a problem unmarshalling the data. This might be - * as a result of an error in parsing the XML string, extracting - * information. + * + * @param xml The XML string. + * @throws UnmarshallException If there was a problem unmarshalling the data. This might be + * as a result of an error in parsing the XML string, extracting + * information. */ - public void unmarshall(String xml) throws UnmarshallException - { - unmarshall(xml, null); + public void unmarshall(String xml) throws UnmarshallException { + unmarshall(xml, null); } /** @@ -133,17 +127,15 @@ public class ServiceDocument { * service. A new Service object will be created and stored. This will * dispose of any previous Service object associated with this object. * - * @param xml The XML string. + * @param xml The XML string. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info - * @throws UnmarshallException - * If there was a problem unmarshalling the data. This might be - * as a result of an error in parsing the XML string, extracting - * information. + * @throws UnmarshallException If there was a problem unmarshalling the data. This might be + * as a result of an error in parsing the XML string, extracting + * information. */ public SwordValidationInfo unmarshall(String xml, Properties validationProperties) - throws UnmarshallException - { + throws UnmarshallException { try { Builder builder = new Builder(); Document doc = builder.build(xml, Namespaces.PREFIX_APP); @@ -161,36 +153,29 @@ public class ServiceDocument { * Unmarshall the specified element. This version does not generate any * validation information. * - * @param element - * element to unmarshall - * @throws UnmarshallException - * If there was a problem unmarshalling the data. This might be - * as a result of an error in parsing the XML string, extracting - * information. + * @param element element to unmarshall + * @throws UnmarshallException If there was a problem unmarshalling the data. This might be + * as a result of an error in parsing the XML string, extracting + * information. */ public void unmarshall(Element element) - throws UnmarshallException - { - unmarshall(element, null); + throws UnmarshallException { + unmarshall(element, null); } /** * Unmarshall the specified element, and return the generated validation * information. - * - * @param element - * element to unmarshall. - * @param validationProperties - * FIXME: PLEASE DOCUMENT. + * + * @param element element to unmarshall. + * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info - * @throws UnmarshallException - * If there was a problem unmarshalling the data. This might be - * as a result of an error in parsing the XML string, extracting - * information. + * @throws UnmarshallException If there was a problem unmarshalling the data. This might be + * as a result of an error in parsing the XML string, extracting + * information. */ public SwordValidationInfo unmarshall(Element element, Properties validationProperties) - throws UnmarshallException - { + throws UnmarshallException { service = new Service(); try { return service.unmarshall(element, validationProperties); @@ -200,19 +185,15 @@ public class ServiceDocument { } - public SwordValidationInfo validate() - { - if ( service == null ) - { + public SwordValidationInfo validate() { + if (service == null) { return null; } return service.validate(new Properties()); } - public SwordValidationInfo validate(Properties validationContext) - { - if ( service == null) - { + public SwordValidationInfo validate(Properties validationContext) { + if (service == null) { return null; } return service.validate(validationContext); diff --git a/dspace-sword/src/main/java/org/purl/sword/base/ServiceDocumentRequest.java b/dspace-sword/src/main/java/org/purl/sword/base/ServiceDocumentRequest.java index b3c10238fb..0935f8e174 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/ServiceDocumentRequest.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/ServiceDocumentRequest.java @@ -8,117 +8,125 @@ package org.purl.sword.base; /** - * Represents a ServiceDocumentRequest. - * - * @author Stuart Lewis - * + * Represents a ServiceDocumentRequest. + * + * @author Stuart Lewis */ -public class ServiceDocumentRequest -{ - /** The username */ - private String username; - - /** The password */ - private String password; - - /** The onBehalf of name */ - private String onBehalfOf; - - /** The IP address */ - private String IPAddress; - - /** The location */ - private String location; - +public class ServiceDocumentRequest { + /** + * The username + */ + private String username; - /** - * Retrieve the username. - * - * @return the authenticatedUserName - */ - public String getUsername() { - return username; - } + /** + * The password + */ + private String password; - /** - * Set the username. - * - * @param username the authenticated UserName to set - */ - public void setUsername(String username) { - this.username = username; - } + /** + * The onBehalf of name + */ + private String onBehalfOf; - /** - * Get the password. - * - * @return the authenticatedUserPassword - */ - public String getPassword() { - return password; - } + /** + * The IP address + */ + private String IPAddress; - /** - * Set the password. - * - * @param password the password to set - */ - public void setPassword(String password) { - this.password = password; - } + /** + * The location + */ + private String location; - /** - * Get the onBehalfOf name. - * - * @return the onBehalfOf - */ - public String getOnBehalfOf() { - return onBehalfOf; - } - /** - * Set the onBehalfOf name. - * - * @param onBehalfOf the onBehalfOf to set - */ - public void setOnBehalfOf(String onBehalfOf) { - this.onBehalfOf = onBehalfOf; - } - - /** - * Get the IP address of the user - * - * @return the the IP address - */ - public String getIPAddress() { - return IPAddress; - } - - /** - * Set the IP address of the user - * - * @param IPAddress the IP address - */ - public void setIPAddress(String IPAddress) { - this.IPAddress = IPAddress; - } - - /** - * Get the location of the service document - * - * @return the location of the service document - */ - public String getLocation() { - return location; - } - - /** - * Set the location of the service document - * - * @param location the location - */ - public void setLocation(String location) { - this.location = location; - } + /** + * Retrieve the username. + * + * @return the authenticatedUserName + */ + public String getUsername() { + return username; + } + + /** + * Set the username. + * + * @param username the authenticated UserName to set + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Get the password. + * + * @return the authenticatedUserPassword + */ + public String getPassword() { + return password; + } + + /** + * Set the password. + * + * @param password the password to set + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Get the onBehalfOf name. + * + * @return the onBehalfOf + */ + public String getOnBehalfOf() { + return onBehalfOf; + } + + /** + * Set the onBehalfOf name. + * + * @param onBehalfOf the onBehalfOf to set + */ + public void setOnBehalfOf(String onBehalfOf) { + this.onBehalfOf = onBehalfOf; + } + + /** + * Get the IP address of the user + * + * @return the the IP address + */ + public String getIPAddress() { + return IPAddress; + } + + /** + * Set the IP address of the user + * + * @param IPAddress the IP address + */ + public void setIPAddress(String IPAddress) { + this.IPAddress = IPAddress; + } + + /** + * Get the location of the service document + * + * @return the location of the service document + */ + public String getLocation() { + return location; + } + + /** + * Set the location of the service document + * + * @param location the location + */ + public void setLocation(String location) { + this.location = location; + } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordAcceptPackaging.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordAcceptPackaging.java index 98c5122d1e..6d063c6c7e 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordAcceptPackaging.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordAcceptPackaging.java @@ -10,291 +10,255 @@ package org.purl.sword.base; import java.util.ArrayList; import java.util.List; import java.util.Properties; + import nu.xom.Attribute; import nu.xom.Element; - import org.apache.log4j.Logger; /** - * Represents a text construct in the ATOM elements. This is a superclass of - * several elements within this implementation. - * + * Represents a text construct in the ATOM elements. This is a superclass of + * several elements within this implementation. + * * @author Neil Taylor */ public class SwordAcceptPackaging extends XmlElement -implements SwordElementInterface -{ + implements SwordElementInterface { /** - * The content in the element. - */ - private String content; - - /** - * The type of the element. - */ - private QualityValue qualityValue; - - /** - * The log. - */ - private static Logger log = Logger.getLogger(SwordAcceptPackaging.class); - - /** */ - public static final String ELEMENT_NAME = "acceptPackaging"; - - protected static final XmlName ATTRIBUTE_Q_NAME = new XmlName(Namespaces.PREFIX_SWORD, - "q", - Namespaces.NS_SWORD); - - private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, ELEMENT_NAME, Namespaces.NS_SWORD); - - public SwordAcceptPackaging() - { - this(null, new QualityValue()); - } - - public SwordAcceptPackaging(String name, float value) - { - this(name, new QualityValue(value)); - } - - public SwordAcceptPackaging(String name, QualityValue value) - { + * The content in the element. + */ + private String content; + + /** + * The type of the element. + */ + private QualityValue qualityValue; + + /** + * The log. + */ + private static Logger log = Logger.getLogger(SwordAcceptPackaging.class); + + /** */ + public static final String ELEMENT_NAME = "acceptPackaging"; + + protected static final XmlName ATTRIBUTE_Q_NAME = new XmlName(Namespaces.PREFIX_SWORD, + "q", + Namespaces.NS_SWORD); + + private static final XmlName XML_NAME = + new XmlName(Namespaces.PREFIX_SWORD, ELEMENT_NAME, Namespaces.NS_SWORD); + + public SwordAcceptPackaging() { + this(null, new QualityValue()); + } + + public SwordAcceptPackaging(String name, float value) { + this(name, new QualityValue(value)); + } + + public SwordAcceptPackaging(String name, QualityValue value) { super(XML_NAME.getPrefix(), XML_NAME.getLocalName(), XML_NAME.getNamespace()); initialise(); setContent(name); - setQualityValue(value); - } - - public static XmlName elementName() - { - return XML_NAME; - } - - protected final void initialise() - { - qualityValue = null; - content = null; - } - - /** - * Marshal the data in this object to an Element object. - * - * @return The data expressed in an Element. - */ - public Element marshall() - { + setQualityValue(value); + } + + public static XmlName elementName() { + return XML_NAME; + } + + protected final void initialise() { + qualityValue = null; + content = null; + } + + /** + * Marshal the data in this object to an Element object. + * + * @return The data expressed in an Element. + */ + public Element marshall() { Element element = new Element(getQualifiedName(), xmlName.getNamespace()); - if ( qualityValue != null ) - { + if (qualityValue != null) { Attribute qualityValueAttribute = new Attribute(ATTRIBUTE_Q_NAME.getLocalName(), qualityValue.toString()); element.addAttribute(qualityValueAttribute); } - - if ( content != null ) - { + + if (content != null) { element.appendChild(content); } return element; } - + /** * Unmarshal the text element into this object. - * - * This unmarshaller only handles plain text content, although it can + * + * This unmarshaller only handles plain text content, although it can * recognise the three different type elements of text, html and xhtml. This - * is an area that can be improved in a future implementation, if necessary. - * - * @param acceptPackaging The text element. + * is an area that can be improved in a future implementation, if necessary. + * + * @param acceptPackaging The text element. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return SWORD validation info - * * @throws UnmarshallException If the specified element is not of * the correct type, where the localname is used - * to specify the valid name. Also thrown - * if there is an issue accessing the data. + * to specify the valid name. Also thrown + * if there is an issue accessing the data. */ public SwordValidationInfo unmarshall(Element acceptPackaging, - Properties validationProperties) throws UnmarshallException - { - if ( ! isInstanceOf(acceptPackaging, xmlName) ) - { + Properties validationProperties) throws UnmarshallException { + if (!isInstanceOf(acceptPackaging, xmlName)) { handleIncorrectElement(acceptPackaging, validationProperties); } - + ArrayList validationItems = new ArrayList(); ArrayList attributeItems = new ArrayList(); - - try - { + + try { // get the attributes int attributeCount = acceptPackaging.getAttributeCount(); Attribute attribute = null; float qv = -1; - - for ( int i = 0; i < attributeCount; i++ ) - { + + for (int i = 0; i < attributeCount; i++) { attribute = acceptPackaging.getAttribute(i); - if ( ATTRIBUTE_Q_NAME.getLocalName().equals(attribute.getQualifiedName())) - { - try - { - qv = Float.parseFloat(attribute.getValue()); - qualityValue = new QualityValue(qv); - - SwordValidationInfo attr = new SwordValidationInfo(xmlName, ATTRIBUTE_Q_NAME); - attr.setContentDescription("" + qv); - attributeItems.add(attr); + if (ATTRIBUTE_Q_NAME.getLocalName().equals(attribute.getQualifiedName())) { + try { + qv = Float.parseFloat(attribute.getValue()); + qualityValue = new QualityValue(qv); + + SwordValidationInfo attr = new SwordValidationInfo(xmlName, ATTRIBUTE_Q_NAME); + attr.setContentDescription("" + qv); + attributeItems.add(attr); + } catch (NumberFormatException nfe) { + SwordValidationInfo attr = new SwordValidationInfo(xmlName, ATTRIBUTE_Q_NAME, + nfe.getMessage(), + SwordValidationInfoType.ERROR); + attr.setContentDescription(attribute.getValue()); + attributeItems.add(attr); } - catch (NumberFormatException nfe ) - { - SwordValidationInfo attr = new SwordValidationInfo(xmlName, ATTRIBUTE_Q_NAME, - nfe.getMessage(), SwordValidationInfoType.ERROR); - attr.setContentDescription(attribute.getValue()); - attributeItems.add(attr); - } - - } - else - { + + } else { SwordValidationInfo attr = new SwordValidationInfo(xmlName, - new XmlName(attribute), - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO ); + new XmlName(attribute), + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); attr.setContentDescription(attribute.getValue()); - + attributeItems.add(attr); } } - + int length = acceptPackaging.getChildCount(); - if ( length > 0 ) - { - try - { - content = unmarshallString(acceptPackaging); - } - catch ( UnmarshallException ume ) - { - log.error("Error accessing the content of the acceptPackaging element"); - validationItems.add(new SwordValidationInfo(xmlName, - "Error unmarshalling element: " + ume.getMessage(), - SwordValidationInfoType.ERROR)); + if (length > 0) { + try { + content = unmarshallString(acceptPackaging); + } catch (UnmarshallException ume) { + log.error("Error accessing the content of the acceptPackaging element"); + validationItems.add(new SwordValidationInfo(xmlName, + "Error unmarshalling element: " + ume.getMessage(), + SwordValidationInfoType.ERROR)); } } - - } - catch ( Exception ex ) - { + + } catch (Exception ex) { log.error("Unable to parse an element in " + getQualifiedName() + ": " + ex.getMessage()); throw new UnmarshallException("Unable to parse an element in " + getQualifiedName(), ex); } - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(validationItems, attributeItems, validationProperties); } return result; } - + public void unmarshall(Element element) - throws UnmarshallException - { + throws UnmarshallException { unmarshall(element, null); } - + @Override - public SwordValidationInfo validate(Properties validationContext) - { + public SwordValidationInfo validate(Properties validationContext) { return validate(null, null, validationContext); } - + /** - * - * @param existing add results to this. - * @param attributeItems FIXME: PLEASE DOCUMENT. + * @param existing add results to this. + * @param attributeItems FIXME: PLEASE DOCUMENT. * @param validationContext FIXME: PLEASE DOCUMENT. * @return SWORD validation info */ protected SwordValidationInfo validate(List existing, - List attributeItems, - Properties validationContext) - { - SwordValidationInfo result = new SwordValidationInfo(xmlName); + List attributeItems, + Properties validationContext) { + SwordValidationInfo result = new SwordValidationInfo(xmlName); result.setContentDescription(content); - + // item specific rules - if ( content == null ) - { + if (content == null) { result.addValidationInfo( new SwordValidationInfo(xmlName, - SwordValidationInfo.MISSING_CONTENT, - SwordValidationInfoType.WARNING)); - } - else - { + SwordValidationInfo.MISSING_CONTENT, + SwordValidationInfoType.WARNING)); + } else { // check that the content is one of the Sword types - if ( ! SwordContentPackageTypes.instance().isValidType(content) ) - { + if (!SwordContentPackageTypes.instance().isValidType(content)) { result.addValidationInfo(new SwordValidationInfo(xmlName, - "The URI is not one of the types specified in http://purl.org/NET/sword-types", SwordValidationInfoType.WARNING)); + "The URI is not one of the types specified in " + + "http://purl.org/NET/sword-types", + SwordValidationInfoType.WARNING)); } } - + result.addUnmarshallValidationInfo(existing, attributeItems); return result; } - - + + /** - * Get the content in this TextConstruct. - * - * @return The content, expressed as a string. + * Get the content in this TextConstruct. + * + * @return The content, expressed as a string. */ public final String getContent() { return content; } - + /** - * Set the content. This only supports text content. - * - * @param content The content. + * Set the content. This only supports text content. + * + * @param content The content. */ - public final void setContent(String content) - { + public final void setContent(String content) { this.content = content; } - + /** - * Get the type. - * - * @return The type. + * Get the type. + * + * @return The type. */ - public final QualityValue getQualityValue() - { + public final QualityValue getQualityValue() { return qualityValue; } - + /** - * Set the type. - * + * Set the type. + * * @param value The type. */ - public final void setQualityValue(QualityValue value) - { + public final void setQualityValue(QualityValue value) { this.qualityValue = value; } - - /** - * Get a string representation. - * - * @return The string. + + /** + * Get a string representation. + * + * @return The string. */ @Override - public String toString() - { + public String toString() { return "Summary - content: " + getContent() + " value: " + getQualityValue(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordCollectionPolicy.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordCollectionPolicy.java index 2416cc5212..c6e5b94805 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordCollectionPolicy.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordCollectionPolicy.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordCollectionPolicy extends BasicStringContentElement -{ +public class SwordCollectionPolicy extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "collectionPolicy", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "collectionPolicy", Namespaces.NS_SWORD); - public SwordCollectionPolicy() - { + public SwordCollectionPolicy() { super(XML_NAME); } - public SwordCollectionPolicy(String version) - { + public SwordCollectionPolicy(String version) { this(); - setContent(version); + setContent(version); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordContentPackageTypes.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordContentPackageTypes.java index c26cd57e34..814c91bb39 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordContentPackageTypes.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordContentPackageTypes.java @@ -7,7 +7,6 @@ */ package org.purl.sword.base; - import java.io.InputStream; import java.util.Enumeration; import java.util.Properties; @@ -15,7 +14,6 @@ import java.util.Properties; import org.apache.log4j.Logger; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ public class SwordContentPackageTypes { @@ -24,56 +22,45 @@ public class SwordContentPackageTypes { private static Properties types; - static - { + static { // static constructor to attempt to load the properties file - try - { + try { types = new Properties(); - InputStream stream = SwordContentPackageTypes.class.getClassLoader().getResourceAsStream("swordContentPackageTypes.properties"); - if ( stream != null ) - { + InputStream stream = SwordContentPackageTypes.class.getClassLoader().getResourceAsStream( + "swordContentPackageTypes.properties"); + if (stream != null) { types.loadFromXML(stream); } - } - catch (Exception ex) - { + } catch (Exception ex) { log.error("Unable to load sword types property file: " + ex.getMessage()); } } - public SwordContentPackageTypes() - { + public SwordContentPackageTypes() { } private static SwordContentPackageTypes instance; - public static SwordContentPackageTypes instance() - { - if ( instance == null ) - { - instance = new SwordContentPackageTypes(); - } - return instance; + public static SwordContentPackageTypes instance() { + if (instance == null) { + instance = new SwordContentPackageTypes(); + } + return instance; } - public boolean isValidType(String uri) - { + public boolean isValidType(String uri) { return types.containsKey(uri); } - public boolean isEmpty() - { + public boolean isEmpty() { return types.isEmpty(); } - public Enumeration elements() - { + public Enumeration elements() { return types.elements(); } - - public Enumeration keys() - { + + public Enumeration keys() { return types.keys(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordElementInterface.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordElementInterface.java index bbbe2a3a09..044c7a7bb9 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordElementInterface.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordElementInterface.java @@ -11,27 +11,26 @@ import nu.xom.Element; /** * Common methods that should be supported by all classes that - * represent data in the SWORD api. - * + * represent data in the SWORD api. + * * @author Neil Taylor */ -public interface SwordElementInterface -{ - /** - * Marshall the data in the object to the XOM Element. - * - * @return The Element. - */ - public Element marshall( ); - - /** - * Unmarshall the data in the specified element and store it - * in the object. - * - * @param element The data to unmarshall. - * @throws UnmarshallException If the element is not of the - * correct type, or if there is an error unmarshalling the data. - */ - public void unmarshall( Element element ) - throws UnmarshallException; +public interface SwordElementInterface { + /** + * Marshall the data in the object to the XOM Element. + * + * @return The Element. + */ + public Element marshall(); + + /** + * Unmarshall the data in the specified element and store it + * in the object. + * + * @param element The data to unmarshall. + * @throws UnmarshallException If the element is not of the + * correct type, or if there is an error unmarshalling the data. + */ + public void unmarshall(Element element) + throws UnmarshallException; } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordMaxUploadSize.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordMaxUploadSize.java index 941b3af8cf..fb4aa8253a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordMaxUploadSize.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordMaxUploadSize.java @@ -13,27 +13,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordMaxUploadSize extends BasicIntegerContentElement -{ +public class SwordMaxUploadSize extends BasicIntegerContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "maxUploadSize", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "maxUploadSize", Namespaces.NS_SWORD); - public SwordMaxUploadSize() - { + public SwordMaxUploadSize() { super(XML_NAME); } - public SwordMaxUploadSize(int value) - { + public SwordMaxUploadSize(int value) { this(); setContent(value); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordMediation.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordMediation.java index 0c2830a8a0..8007bd362a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordMediation.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordMediation.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordMediation extends BasicBooleanContentElement -{ +public class SwordMediation extends BasicBooleanContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "mediation", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "mediation", Namespaces.NS_SWORD); - public SwordMediation() - { + public SwordMediation() { super(XML_NAME.getPrefix(), XML_NAME.getLocalName(), XML_NAME.getNamespace()); } - public SwordMediation(boolean value) - { + public SwordMediation(boolean value) { this(); setContent(value); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordNoOp.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordNoOp.java index e0bae1da89..ef2a5026db 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordNoOp.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordNoOp.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordNoOp extends BasicBooleanContentElement -{ +public class SwordNoOp extends BasicBooleanContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "noOp", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "noOp", Namespaces.NS_SWORD); - public SwordNoOp() - { + public SwordNoOp() { super(XML_NAME.getPrefix(), XML_NAME.getLocalName(), XML_NAME.getNamespace()); } - public SwordNoOp(boolean value) - { + public SwordNoOp(boolean value) { this(); setContent(value); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordPackaging.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordPackaging.java index 80b2e2c9e5..884c5a1c25 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordPackaging.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordPackaging.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordPackaging extends BasicStringContentElement -{ +public class SwordPackaging extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "packaging", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "packaging", Namespaces.NS_SWORD); - public SwordPackaging() - { + public SwordPackaging() { super(XML_NAME); } - public SwordPackaging(String version) - { + public SwordPackaging(String version) { this(); - setContent(version); + setContent(version); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordService.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordService.java index 88503027cc..2c0be83219 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordService.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordService.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordService extends BasicStringContentElement -{ +public class SwordService extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "service", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "service", Namespaces.NS_SWORD); - public SwordService() - { + public SwordService() { super(XML_NAME); } - public SwordService(String version) - { + public SwordService(String version) { this(); - setContent(version); + setContent(version); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordTreatment.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordTreatment.java index 12ba5a3a8e..4270cbdab2 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordTreatment.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordTreatment.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordTreatment extends BasicStringContentElement -{ +public class SwordTreatment extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "treatment", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "treatment", Namespaces.NS_SWORD); - public SwordTreatment() - { + public SwordTreatment() { super(XML_NAME); } - public SwordTreatment(String version) - { + public SwordTreatment(String version) { this(); - setContent(version); + setContent(version); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordUserAgent.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordUserAgent.java index 887a880d7d..fbc827a6ea 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordUserAgent.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordUserAgent.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordUserAgent extends BasicStringContentElement -{ +public class SwordUserAgent extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "userAgent", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "userAgent", Namespaces.NS_SWORD); - public SwordUserAgent() - { + public SwordUserAgent() { super(XML_NAME); } - public SwordUserAgent(String version) - { + public SwordUserAgent(String version) { this(); - setContent(version); + setContent(version); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordValidationInfo.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordValidationInfo.java index 1570b34951..adf45a8c29 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordValidationInfo.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordValidationInfo.java @@ -14,13 +14,13 @@ import java.util.List; /** * Represents an validation information item about * the elements/attributes. - * + * * @author Neil Taylor (nst@aber.ac.uk) */ public class SwordValidationInfo { /** - * Name of the element. + * Name of the element. */ private XmlName elementName; @@ -31,17 +31,23 @@ public class SwordValidationInfo { private XmlName attributeName; /** - * Optional description of the content of the element or attribute. + * Optional description of the content of the element or attribute. */ private String contentDescription; - /** The information message. This holds the actual error/warning message */ + /** + * The information message. This holds the actual error/warning message + */ private String message; - /** The type of validation information */ + /** + * The type of validation information + */ private SwordValidationInfoType type; - /** List of nested validation info items */ + /** + * List of nested validation info items + */ private List elementInfo; private List attributeInfo; @@ -58,29 +64,33 @@ public class SwordValidationInfo { */ private List unmarshallAttributeInfo; - public static final String UNKNOWN_ELEMENT = "This element is present, but it is not used as part of the SWORD profile"; + public static final String UNKNOWN_ELEMENT = "This element is present, but it is not used as part of the SWORD " + + "profile"; - public static final String UNKNOWN_ATTRIBUTE = "This attribute is present, but it is not used as part of the SWORD profile"; + public static final String UNKNOWN_ATTRIBUTE = "This attribute is present, but it is not used as part of the " + + "SWORD profile"; public static final String MISSING_ELEMENT_WARNING = "This element is not present, but it SHOULD be included."; public static final String MISSING_ATTRIBUTE_WARNING = "This attribute is not present, but it SHOULD be included."; - public static final String DUPLICATE_ELEMENT = "This element has already been included earlier in this document. This element is ignored."; + public static final String DUPLICATE_ELEMENT = "This element has already been included earlier in this document. " + + "This element is ignored."; public static final String MISSING_CONTENT = "No content is defined. This element should have content."; - public static final String MISSING_ELEMENT_ERROR = "This element is not present, but at least one MUST be included."; + public static final String MISSING_ELEMENT_ERROR = "This element is not present, but at least one MUST be " + + "included."; public static final String ERROR_WITH_CONTENT = "There is an error with the value."; + /** * Create a new information object for the specified element. Sets the * default type to be VALID. * * @param element The element. */ - public SwordValidationInfo(XmlName element) - { + public SwordValidationInfo(XmlName element) { this(element, null, "", SwordValidationInfoType.VALID); } @@ -89,10 +99,9 @@ public class SwordValidationInfo { * attribute. Sets the default type to be VALID. * * @param element the element. - * @param attribute the attribute. + * @param attribute the attribute. */ - public SwordValidationInfo(XmlName element, XmlName attribute) - { + public SwordValidationInfo(XmlName element, XmlName attribute) { this(element, attribute, "", SwordValidationInfoType.VALID); } @@ -100,14 +109,13 @@ public class SwordValidationInfo { * Create a new instance of a validation information object that * reports on an element. * - * @param element The element. + * @param element The element. * @param theMessage The information message. * @param theType The type of message. */ - public SwordValidationInfo(XmlName element, + public SwordValidationInfo(XmlName element, String theMessage, - SwordValidationInfoType theType) - { + SwordValidationInfoType theType) { this(element, null, theMessage, theType); } @@ -115,24 +123,23 @@ public class SwordValidationInfo { * Create a new instance of a validation information object that * reports on an attribute in the specified element. * - * @param element The local name for the element. - * @param attribute The attribute. - * @param theMessage The information message. - * @param theType The type of message. + * @param element The local name for the element. + * @param attribute The attribute. + * @param theMessage The information message. + * @param theType The type of message. */ public SwordValidationInfo(XmlName element, XmlName attribute, String theMessage, - SwordValidationInfoType theType) - { + SwordValidationInfoType theType) { this.elementName = element; this.attributeName = attribute; - + message = theMessage; type = theType; elementInfo = new ArrayList(); attributeInfo = new ArrayList(); unmarshallElementInfo = new ArrayList(); - unmarshallAttributeInfo = new ArrayList(); + unmarshallAttributeInfo = new ArrayList(); } /** @@ -146,7 +153,7 @@ public class SwordValidationInfo { /** * Set the information message. - * + * * @param message the message to set */ public void setMessage(String message) { @@ -200,7 +207,7 @@ public class SwordValidationInfo { /** * Set the attribute that this information describes. - * + * * @param attribute the attribute to set */ public void setAttribute(XmlName attribute) { @@ -209,58 +216,48 @@ public class SwordValidationInfo { /** * Add a related information item to this resource. - * + * * @param item The information item to store. */ - public void addValidationInfo(SwordValidationInfo item) - { - - if ( type.compareTo(item.getType()) < 0 ) - { + public void addValidationInfo(SwordValidationInfo item) { + + if (type.compareTo(item.getType()) < 0) { type = item.getType(); } - + elementInfo.add(item); } - public void addAttributeValidationInfo(SwordValidationInfo attribute) - { - if ( type.compareTo(attribute.getType()) < 0 ) - { + public void addAttributeValidationInfo(SwordValidationInfo attribute) { + if (type.compareTo(attribute.getType()) < 0) { type = attribute.getType(); } - attributeInfo.add(attribute); + attributeInfo.add(attribute); } - public void addUnmarshallElementInfo(SwordValidationInfo unmarshallElement) - { - if ( unmarshallElement == null ) - { + public void addUnmarshallElementInfo(SwordValidationInfo unmarshallElement) { + if (unmarshallElement == null) { // not part of the validation process - end here return; } - - if ( type.compareTo(unmarshallElement.getType()) < 0 ) - { + + if (type.compareTo(unmarshallElement.getType()) < 0) { type = unmarshallElement.getType(); } unmarshallElementInfo.add(unmarshallElement); } - public void addUnmarshallAttributeInfo(SwordValidationInfo unmarshallAttribute) - { - if ( type.compareTo(unmarshallAttribute.getType()) < 0 ) - { + public void addUnmarshallAttributeInfo(SwordValidationInfo unmarshallAttribute) { + if (type.compareTo(unmarshallAttribute.getType()) < 0) { type = unmarshallAttribute.getType(); } unmarshallAttributeInfo.add(unmarshallAttribute); } /** - * Clear the list of validation info items. + * Clear the list of validation info items. */ - public void clearValidationItems() - { + public void clearValidationItems() { elementInfo.clear(); attributeInfo.clear(); resetType(); @@ -269,31 +266,26 @@ public class SwordValidationInfo { /** * Clear the list of unmarshalled info items. */ - public void clearUnmarshallItems() - { + public void clearUnmarshallItems() { unmarshallElementInfo.clear(); unmarshallAttributeInfo.clear(); - resetType(); + resetType(); } - protected void resetType() - { + protected void resetType() { type = SwordValidationInfoType.VALID; - + resetType(getValidationElementInfoIterator()); resetType(getValidationAttributeInfoIterator()); resetType(getUnmarshallElementInfoIterator()); resetType(getUnmarshallAttributeInfoIterator()); } - protected void resetType(Iterator iterator) - { + protected void resetType(Iterator iterator) { SwordValidationInfo item = null; - while ( iterator.hasNext() ) - { + while (iterator.hasNext()) { item = iterator.next(); - if ( item != null && type.compareTo(item.getType()) < 0 ) - { + if (item != null && type.compareTo(item.getType()) < 0) { type = item.getType(); } } @@ -303,37 +295,30 @@ public class SwordValidationInfo { /** * Return an iterator to view the nested validation info objects. * - * @return Iterator for the nested objects. + * @return Iterator for the nested objects. */ - public Iterator getValidationElementInfoIterator() - { + public Iterator getValidationElementInfoIterator() { return elementInfo.iterator(); } /** - * * @return the iterator. */ - public Iterator getValidationAttributeInfoIterator() - { + public Iterator getValidationAttributeInfoIterator() { return attributeInfo.iterator(); } /** - * * @return the iterator. */ - public Iterator getUnmarshallElementInfoIterator() - { + public Iterator getUnmarshallElementInfoIterator() { return unmarshallElementInfo.iterator(); } /** - * * @return the iterator. */ - public Iterator getUnmarshallAttributeInfoIterator() - { + public Iterator getUnmarshallAttributeInfoIterator() { return unmarshallAttributeInfo.iterator(); } @@ -352,47 +337,39 @@ public class SwordValidationInfo { } /** - * - * @param elementItems FIXME: PLEASE DOCUMENT. + * @param elementItems FIXME: PLEASE DOCUMENT. * @param attributeItems FIXME: PLEASE DOCUMENT. */ public void addUnmarshallValidationInfo( - List elementItems, - List attributeItems) - { - if ( elementItems != null ) - { + List elementItems, + List attributeItems) { + if (elementItems != null) { Iterator items = elementItems.iterator(); - while ( items.hasNext() ) - { - addUnmarshallElementInfo(items.next()); + while (items.hasNext()) { + addUnmarshallElementInfo(items.next()); } } - if ( attributeItems != null ) - { + if (attributeItems != null) { Iterator attributes = attributeItems.iterator(); - - while ( attributes.hasNext() ) - { + + while (attributes.hasNext()) { addUnmarshallAttributeInfo(attributes.next()); } } } - public void addUnmarshallValidationInfo(SwordValidationInfo other) - { + public void addUnmarshallValidationInfo(SwordValidationInfo other) { addUnmarshallValidationInfo(other.elementInfo, other.attributeInfo); } @Override - public String toString() - { + public String toString() { return "" + getType(); } - /** + /** * Utility method that will recursively print out the list of items * for the specified validation info object. * @@ -400,8 +377,7 @@ public class SwordValidationInfo { * @param buffer string buffer to append to * @param indent The level of indent, expressed as a number of space characters. */ - public void createString(SwordValidationInfo info, StringBuffer buffer, String indent) - { + public void createString(SwordValidationInfo info, StringBuffer buffer, String indent) { String prefix = info.getElement().getPrefix(); buffer.append(indent); @@ -409,8 +385,7 @@ public class SwordValidationInfo { buffer.append(info.getType()); buffer.append("]"); - if ( prefix != null && prefix.trim().length() > 0 ) - { + if (prefix != null && prefix.trim().length() > 0) { buffer.append(prefix); buffer.append(":"); } @@ -420,48 +395,40 @@ public class SwordValidationInfo { if (info.getAttribute() != null) { buffer.append(info.getAttribute().getLocalName()); buffer.append("=\""); - if ( info.getContentDescription() != null ) - { + if (info.getContentDescription() != null) { buffer.append(info.getContentDescription()); } buffer.append("\""); - } - else - { - if ( info.getContentDescription() != null ) - { + } else { + if (info.getContentDescription() != null) { buffer.append(" Value: '"); buffer.append(info.getContentDescription()); buffer.append("'"); } } - buffer.append("\n" + indent + "message: " ); + buffer.append("\n" + indent + "message: "); buffer.append(info.getMessage()); buffer.append("\n"); - + // process the list of attributes first Iterator iterator = info.getValidationAttributeInfoIterator(); - while ( iterator.hasNext()) - { + while (iterator.hasNext()) { createString(iterator.next(), buffer, " " + indent); } iterator = info.getUnmarshallAttributeInfoIterator(); - while ( iterator.hasNext()) - { + while (iterator.hasNext()) { createString(iterator.next(), buffer, " " + indent); } // next, process the element messages iterator = info.getValidationElementInfoIterator(); - while ( iterator.hasNext()) - { + while (iterator.hasNext()) { createString(iterator.next(), buffer, " " + indent); } iterator = info.getUnmarshallElementInfoIterator(); - while ( iterator.hasNext()) - { + while (iterator.hasNext()) { createString(iterator.next(), buffer, " " + indent); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordValidationInfoType.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordValidationInfoType.java index 67007b8bd3..2d41a117b7 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordValidationInfoType.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordValidationInfoType.java @@ -8,13 +8,12 @@ package org.purl.sword.base; /** - * * @author Neil Taylor */ public enum SwordValidationInfoType { - VALID, - INFO, - WARNING, - ERROR; + VALID, + INFO, + WARNING, + ERROR; } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordVerbose.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordVerbose.java index e74ee9b695..360f50633a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordVerbose.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordVerbose.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordVerbose extends BasicBooleanContentElement -{ +public class SwordVerbose extends BasicBooleanContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "verbose", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "verbose", Namespaces.NS_SWORD); - public SwordVerbose() - { + public SwordVerbose() { super(XML_NAME); } - public SwordVerbose(boolean value) - { + public SwordVerbose(boolean value) { this(); setContent(value); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordVerboseDescription.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordVerboseDescription.java index f2d5b1706a..d748eaa7f6 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordVerboseDescription.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordVerboseDescription.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordVerboseDescription extends BasicStringContentElement -{ +public class SwordVerboseDescription extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "verboseDescription", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "verboseDescription", Namespaces.NS_SWORD); - public SwordVerboseDescription() - { + public SwordVerboseDescription() { super(XML_NAME); } - public SwordVerboseDescription(String version) - { + public SwordVerboseDescription(String version) { this(); - setContent(version); + setContent(version); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/SwordVersion.java b/dspace-sword/src/main/java/org/purl/sword/base/SwordVersion.java index 02cf3a3b9a..ad6ec9445d 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/SwordVersion.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/SwordVersion.java @@ -8,27 +8,22 @@ package org.purl.sword.base; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ -public class SwordVersion extends BasicStringContentElement -{ +public class SwordVersion extends BasicStringContentElement { private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_SWORD, "version", Namespaces.NS_SWORD); + new XmlName(Namespaces.PREFIX_SWORD, "version", Namespaces.NS_SWORD); - public SwordVersion() - { + public SwordVersion() { super(XML_NAME); } - public SwordVersion(String version) - { + public SwordVersion(String version) { this(); - setContent(version); + setContent(version); } - public static XmlName elementName() - { + public static XmlName elementName() { return XML_NAME; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/UnmarshallException.java b/dspace-sword/src/main/java/org/purl/sword/base/UnmarshallException.java index 7409491f06..64c0834987 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/UnmarshallException.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/UnmarshallException.java @@ -9,32 +9,29 @@ package org.purl.sword.base; /** * Represents information about an exception that is generated during - * the Unmarshall process. - * + * the Unmarshall process. + * * @author Neil Taylor */ -public class UnmarshallException extends Exception -{ +public class UnmarshallException extends Exception { /** - * Create a new instance and store the specified message and source data. - * - * @param message The message for the exception. + * Create a new instance and store the specified message and source data. + * + * @param message The message for the exception. * @param source The original exception that lead to this exception. This - * can be null. + * can be null. */ - public UnmarshallException(String message, Exception source) - { - super(message, source); + public UnmarshallException(String message, Exception source) { + super(message, source); } - + /** - * Create a new instance and store the specified message. - * - * @param message The message for the exception. + * Create a new instance and store the specified message. + * + * @param message The message for the exception. */ - public UnmarshallException(String message) - { + public UnmarshallException(String message) { super(message); } - + } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/Workspace.java b/dspace-sword/src/main/java/org/purl/sword/base/Workspace.java index de27b15366..81964152ba 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/Workspace.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/Workspace.java @@ -10,305 +10,263 @@ package org.purl.sword.base; import java.util.ArrayList; import java.util.Iterator; import java.util.List; - import java.util.Properties; + import nu.xom.Element; import nu.xom.Elements; - import org.apache.log4j.Logger; import org.purl.sword.atom.ContentType; import org.purl.sword.atom.Title; /** - * Represents an Atom Publishing Protocol Workspace element. - * + * Represents an Atom Publishing Protocol Workspace element. + * * @author Neil Taylor */ -public class Workspace extends XmlElement implements SwordElementInterface -{ +public class Workspace extends XmlElement implements SwordElementInterface { /** - * The title for the workspace. + * The title for the workspace. */ - private Title title; - + private Title title; + /** - * A list of collections associated with this workspace. + * A list of collections associated with this workspace. */ - private List collections; - + private List collections; + /** - * The logger. + * The logger. */ private static Logger log = Logger.getLogger(Workspace.class); - + /** * Local name part of this element. */ @Deprecated public static final String ELEMENT_NAME = "workspace"; - - private static final XmlName XML_NAME = - new XmlName(Namespaces.PREFIX_APP, "workspace", Namespaces.NS_APP); - + + private static final XmlName XML_NAME = + new XmlName(Namespaces.PREFIX_APP, "workspace", Namespaces.NS_APP); + /** - * Create a new instance of the workspace, with no title. + * Create a new instance of the workspace, with no title. */ - public Workspace( ) - { + public Workspace() { super(XML_NAME); initialise(); } - - public static XmlName elementName() - { + + public static XmlName elementName() { return XML_NAME; } - + /** - * Create a new instance of the workspace with the specified title. - * - * @param title The title. + * Create a new instance of the workspace with the specified title. + * + * @param title The title. */ - public Workspace( String title ) - { + public Workspace(String title) { this(); - + setTitle(title); } - + /** * Initialise the object, ready for use. */ - protected final void initialise() - { + protected final void initialise() { collections = new ArrayList(); - title = null; + title = null; } - + /** - * Set the title. The type for the title will be set to + * Set the title. The type for the title will be set to * ContentType.TEXT - * - * @param title The title. + * + * @param title The title. */ - public final void setTitle( String title ) - { - if ( this.title == null) - { + public final void setTitle(String title) { + if (this.title == null) { this.title = new Title(); } this.title.setContent(title); this.title.setType(ContentType.TEXT); } - + /** - * Get the content of the Title element. - * - * @return The title. + * Get the content of the Title element. + * + * @return The title. */ - public final String getTitle( ) - { - if ( title == null ) - { + public final String getTitle() { + if (title == null) { return null; } - - return title.getContent(); + + return title.getContent(); } - + /** - * Add a collection to the Workspace. - * - * @param collection The collection. + * Add a collection to the Workspace. + * + * @param collection The collection. */ - public void addCollection( Collection collection ) - { + public void addCollection(Collection collection) { collections.add(collection); } - + /** - * Get an Iterator over the collections. - * - * @return An iterator. + * Get an Iterator over the collections. + * + * @return An iterator. */ - public Iterator collectionIterator( ) - { + public Iterator collectionIterator() { return collections.iterator(); } - + /** * Get a list of the collections - * + * * @return A list. */ - public List getCollections( ) - { + public List getCollections() { return collections; } - + /** - * Marshal the data in this element to an Element. - * - * @return An element that contains the data in this object. + * Marshal the data in this element to an Element. + * + * @return An element that contains the data in this object. */ - public Element marshall( ) - { - // convert data into XOM elements and return the 'root', i.e. the one - // that represents the collection. + public Element marshall() { + // convert data into XOM elements and return the 'root', i.e. the one + // that represents the collection. Element workspace = new Element(xmlName.getQualifiedName(), xmlName.getNamespace()); - - if ( title != null ) - { + + if (title != null) { workspace.appendChild(title.marshall()); } - - for ( Collection item : collections ) - { + + for (Collection item : collections) { workspace.appendChild(item.marshall()); } - - return workspace; + + return workspace; } - + /** - * Unmarshal the workspace element into the data in this object. - * + * Unmarshal the workspace element into the data in this object. + * * @throws UnmarshallException If the element does not contain a * workspace element or if there are problems - * accessing the data. + * accessing the data. */ - public void unmarshall( Element workspace ) - throws UnmarshallException - { + public void unmarshall(Element workspace) + throws UnmarshallException { unmarshall(workspace, null); } - + /** - * - * @param workspace the element to unmarshall. + * @param workspace the element to unmarshall. * @param validationProperties FIXME: PLEASE DOCUMENT. * @return FIXME: PLEASE DOCUMENT. * @throws UnmarshallException If the element does not contain a * workspace element or if there are problems - * accessing the data. + * accessing the data. */ - public SwordValidationInfo unmarshall( Element workspace, Properties validationProperties ) - throws UnmarshallException - { - if ( ! isInstanceOf(workspace, xmlName)) - { + public SwordValidationInfo unmarshall(Element workspace, Properties validationProperties) + throws UnmarshallException { + if (!isInstanceOf(workspace, xmlName)) { return handleIncorrectElement(workspace, validationProperties); } - + ArrayList validationItems = new ArrayList(); - - try - { + + try { initialise(); - - // FIXME - process the attributes - + + // FIXME - process the attributes + // retrieve all of the sub-elements Elements elements = workspace.getChildElements(); Element element = null; int length = elements.size(); - - for (int i = 0; i < length; i++ ) - { + + for (int i = 0; i < length; i++) { element = elements.get(i); - if ( isInstanceOf(element, Title.elementName() ) ) - { - if ( title == null ) - { + if (isInstanceOf(element, Title.elementName())) { + if (title == null) { title = new Title(); validationItems.add(title.unmarshall(element, validationProperties)); - } - else - { + } else { SwordValidationInfo info = new SwordValidationInfo(Title.elementName(), - SwordValidationInfo.DUPLICATE_ELEMENT, - SwordValidationInfoType.WARNING); + SwordValidationInfo.DUPLICATE_ELEMENT, + SwordValidationInfoType.WARNING); info.setContentDescription(element.getValue()); validationItems.add(info); } - } - else if ( isInstanceOf(element, Collection.elementName() )) - { - Collection collection = new Collection( ); - validationItems.add(collection.unmarshall(element, validationProperties)); - collections.add(collection); - } - else if ( validationProperties != null ) - { + } else if (isInstanceOf(element, Collection.elementName())) { + Collection collection = new Collection(); + validationItems.add(collection.unmarshall(element, validationProperties)); + collections.add(collection); + } else if (validationProperties != null) { validationItems.add(new SwordValidationInfo(new XmlName(element), - SwordValidationInfo.UNKNOWN_ELEMENT, - SwordValidationInfoType.INFO)); + SwordValidationInfo.UNKNOWN_ELEMENT, + SwordValidationInfoType.INFO)); } } - } - catch ( Exception ex ) - { + } catch (Exception ex) { log.error("Unable to parse an element in workspace: " + ex.getMessage()); throw new UnmarshallException("Unable to parse element in workspace.", ex); } - + SwordValidationInfo result = null; - if ( validationProperties != null ) - { + if (validationProperties != null) { result = validate(validationItems, validationProperties); } - return result; + return result; } - + /** - * * @return A validation object that specifies the status of this object. */ @Override - public SwordValidationInfo validate(Properties validationContext) - { + public SwordValidationInfo validate(Properties validationContext) { return validate(null, validationContext); } - + /** - * - * @param existing add results to this. + * @param existing add results to this. * @param validationContext FIXME: PLEASE DOCUMENT. * @return FIXME: PLEASE DOCUMENT. */ protected SwordValidationInfo validate(List existing, - Properties validationContext) - { - boolean validateAll = (existing == null ); - + Properties validationContext) { + boolean validateAll = (existing == null); + SwordValidationInfo result = new SwordValidationInfo(xmlName); - - if ( collections == null || collections.size() == 0 ) - { + + if (collections == null || collections.size() == 0) { result.addValidationInfo(new SwordValidationInfo(Collection.elementName(), - SwordValidationInfo.MISSING_ELEMENT_WARNING, - SwordValidationInfoType.WARNING )); + SwordValidationInfo.MISSING_ELEMENT_WARNING, + SwordValidationInfoType.WARNING)); } - - if ( validateAll ) - { - if ( title != null ) - { + + if (validateAll) { + if (title != null) { result.addValidationInfo(title.validate(validationContext)); } - - if ( collections.size() > 0 ) - { + + if (collections.size() > 0) { Iterator iterator = collections.iterator(); - while ( iterator.hasNext() ) - { + while (iterator.hasNext()) { result.addValidationInfo(iterator.next().validate(validationContext)); } } } - + result.addUnmarshallValidationInfo(existing, null); - return result; + return result; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/XmlElement.java b/dspace-sword/src/main/java/org/purl/sword/base/XmlElement.java index b2824634fb..6249c4290a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/XmlElement.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/XmlElement.java @@ -9,6 +9,7 @@ package org.purl.sword.base; import java.util.List; import java.util.Properties; + import nu.xom.Attribute; import nu.xom.Element; import nu.xom.Node; @@ -16,95 +17,89 @@ import org.apache.log4j.Logger; /** * Parent class for all classes that represent an XML element. This provides - * some common utility methods that are useful for marshalling and - * unmarshalling data. - * + * some common utility methods that are useful for marshalling and + * unmarshalling data. + * * @author Neil Taylor */ -public abstract class XmlElement -{ +public abstract class XmlElement { - /** Logger */ + /** + * Logger + */ private static Logger log = Logger.getLogger(XmlElement.class); - - + + /** * */ protected XmlName xmlName; - - - public XmlName getXmlName() - { + + + public XmlName getXmlName() { // FIXME - should this be a clone? - return xmlName; + return xmlName; } - + /** - * The name to use for the prefix. E.g. atom:title, atom is the prefix. + * The name to use for the prefix. E.g. atom:title, atom is the prefix. */ //protected String prefix; - + /** - * The local name of the element. E.g. atom:title, title is the local name. + * The local name of the element. E.g. atom:title, title is the local name. */ //protected String localName; - + /** - * Create a new instance. Set the local name that will be used. - * - * @param localName The local name for the element. + * Create a new instance. Set the local name that will be used. + * + * @param localName The local name for the element. */ - public XmlElement(String localName) - { + public XmlElement(String localName) { this("", localName); } - + /** - * Create a new instance. Set the prefix and local name. - * - * @param prefix The prefix for the element. - * @param localName The local name for the element. + * Create a new instance. Set the prefix and local name. + * + * @param prefix The prefix for the element. + * @param localName The local name for the element. */ - public XmlElement(String prefix, String localName) - { + public XmlElement(String prefix, String localName) { this.xmlName = new XmlName(prefix, localName, ""); } - + /** * Create a new insatnce. Set the prefix, local name and the namespace URI. * * @param prefix The prefix. - * @param localName The element's local name. + * @param localName The element's local name. * @param namespaceUri The namespace URI. */ - public XmlElement(String prefix, String localName, String namespaceUri) - { + public XmlElement(String prefix, String localName, String namespaceUri) { this.xmlName = new XmlName(prefix, localName, namespaceUri); } - + /** * Set the name of this XML element. - * - * @param name - * name to set + * + * @param name name to set */ - public XmlElement(XmlName name) - { - xmlName = name; + public XmlElement(XmlName name) { + xmlName = name; } - + /** - * The Date format that is used to parse dates to and from the ISO format - * in the XML data. + * The Date format that is used to parse dates to and from the ISO format + * in the XML data. */ protected static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - + /** - * Array of possible date formats that are permitted for date elements. + * Array of possible date formats that are permitted for date elements. */ - protected static final String[] DATE_FORMATS = - { + protected static final String[] DATE_FORMATS = { "yyyy-MM-dd'T'HH:mm:ss'Z'", "yyyy-MM-dd'T'HH:mm:ss.SZ", "yyyy-MM-dd'T'HH:mm:ss.Sz", @@ -122,262 +117,222 @@ public abstract class XmlElement "yyyy-MM", "yyyy" }; - + /** - * Extract a boolean value from the specified element. The boolean value + * Extract a boolean value from the specified element. The boolean value * is represented as the string 'true' or 'false' as the only child - * of the specified element. - * - * @param element The element that contains the boolean value. - * @return True or false, based on the string in the element's content. + * of the specified element. + * + * @param element The element that contains the boolean value. + * @return True or false, based on the string in the element's content. * @throws UnmarshallException If the element does not contain a single child, or if - * the child does not contain the value 'true' or 'false'. + * the child does not contain the value 'true' or 'false'. */ - protected boolean unmarshallBoolean( Element element ) - throws UnmarshallException - { - if ( element.getChildCount() != 1 ) - { + protected boolean unmarshallBoolean(Element element) + throws UnmarshallException { + if (element.getChildCount() != 1) { throw new UnmarshallException("Missing Boolean Value", null); } - + // ok to get the single child element. This should be a text element. - try - { + try { Node child = element.getChild(0); String value = child.getValue(); - if ( "true".equals(value) ) - { + if ("true".equals(value)) { return true; - } - else if ( "false".equals(value)) - { + } else if ("false".equals(value)) { return false; - } - else - { + } else { throw new UnmarshallException("Illegal Value"); } - } - catch ( IndexOutOfBoundsException ex ) - { + } catch (IndexOutOfBoundsException ex) { throw new UnmarshallException("Error accessing Boolean element", ex); } } - + /** - * Extract a string value from the specified element. The value - * is the only child of the specified element. - * - * @param element The element that contains the string value. - * @return The string. - * @throws UnmarshallException If the element does not contain a single child. + * Extract a string value from the specified element. The value + * is the only child of the specified element. + * + * @param element The element that contains the string value. + * @return The string. + * @throws UnmarshallException If the element does not contain a single child. */ - protected String unmarshallString( Element element ) - throws UnmarshallException - { - if ( element.getChildCount() != 1 ) - { - throw new UnmarshallException("Missing String Value", null); + protected String unmarshallString(Element element) + throws UnmarshallException { + if (element.getChildCount() != 1) { + throw new UnmarshallException("Missing String Value", null); } - + // ok to get the single child element. This should be a text element. - try - { - Node child = element.getChild(0); - return child.getValue(); + try { + Node child = element.getChild(0); + return child.getValue(); + } catch (IndexOutOfBoundsException ex) { + throw new UnmarshallException("Error accessing String element", ex); } - catch ( IndexOutOfBoundsException ex ) - { - throw new UnmarshallException("Error accessing String element", ex); - } } - + /** - * Extract an integer value from the specified element. The integer value + * Extract an integer value from the specified element. The integer value * is represented as a string in the only child - * of the specified element. - * - * @param element The element that contains the integer. - * @return The integer. + * of the specified element. + * + * @param element The element that contains the integer. + * @return The integer. * @throws UnmarshallException If the element does not contain a single child, or if - * the child does not contain the valid integer. + * the child does not contain the valid integer. */ - protected int unmarshallInteger( Element element ) - throws UnmarshallException - { - if ( element.getChildCount() != 1 ) - { - throw new UnmarshallException("Missing Integer Value", null); + protected int unmarshallInteger(Element element) + throws UnmarshallException { + if (element.getChildCount() != 1) { + throw new UnmarshallException("Missing Integer Value", null); } - + // ok to get the single child element. This should be a text element. - try - { - Node child = element.getChild(0); - return Integer.parseInt( child.getValue() ); - } - catch ( IndexOutOfBoundsException ex ) - { - throw new UnmarshallException("Error accessing Integer", ex); - } - catch ( NumberFormatException nfex ) - { - throw new UnmarshallException("Error formatting the number", nfex); + try { + Node child = element.getChild(0); + return Integer.parseInt(child.getValue()); + } catch (IndexOutOfBoundsException ex) { + throw new UnmarshallException("Error accessing Integer", ex); + } catch (NumberFormatException nfex) { + throw new UnmarshallException("Error formatting the number", nfex); } } - + /** - * Determines if the specified element is an instance of the element name. If + * Determines if the specified element is an instance of the element name. If * you are checking the name title in the ATOM namespace, then the local name - * should be 'title' and the namespaceURI is the URI for the ATOM namespace. - * - * @param element The specified element. - * @param localName The local name for the element. - * @param namespaceURI The namespace for the element. - * @return True if the element matches the localname and namespace URI. Otherwise, false. + * should be 'title' and the namespaceURI is the URI for the ATOM namespace. + * + * @param element The specified element. + * @param localName The local name for the element. + * @param namespaceURI The namespace for the element. + * @return True if the element matches the localname and namespace URI. Otherwise, false. */ - protected boolean isInstanceOf(Element element, String localName, String namespaceURI ) - { - return (localName.equals(element.getLocalName()) && - namespaceURI.equals(element.getNamespaceURI()) ); + protected boolean isInstanceOf(Element element, String localName, String namespaceURI) { + return (localName.equals(element.getLocalName()) && + namespaceURI.equals(element.getNamespaceURI())); } - + /** * Checks XML element local name and namespace URI. - * - * @param element - * XML element to check - * @param xmlName - * XML element name - * @return True if the element matches the localname and namespace URI. Otherwise, false. + * + * @param element XML element to check + * @param xmlName XML element name + * @return True if the element matches the localname and namespace URI. Otherwise, false. */ - protected boolean isInstanceOf(Element element, XmlName xmlName) - { + protected boolean isInstanceOf(Element element, XmlName xmlName) { return (xmlName.getLocalName().equals(element.getLocalName()) && - xmlName.getNamespace().equals(element.getNamespaceURI())); + xmlName.getNamespace().equals(element.getNamespaceURI())); } - + /** * Retrieve the qualified name for this object. This uses the - * prefix and local name stored in this object. - * + * prefix and local name stored in this object. + * * @return A string of the format 'prefix:localName' */ - public String getQualifiedName() - { + public String getQualifiedName() { return getQualifiedName(xmlName.getLocalName()); } - + /** - * Retrieve the qualified name. The prefix for this object is prepended - * onto the specified local name. - * - * @param name the specified local name. + * Retrieve the qualified name. The prefix for this object is prepended + * onto the specified local name. + * + * @param name the specified local name. * @return A string of the format 'prefix:name' */ - public String getQualifiedName(String name) - { + public String getQualifiedName(String name) { return xmlName.getQualifiedName(); } - + /** * Get the qualified name for the given prefix and name - * + * * @param prefix the prefix - * @param name the name + * @param name the name * @return the qualified name */ - public String getQualifiedNameWithPrefix(String prefix, String name) - { + public String getQualifiedNameWithPrefix(String prefix, String name) { return prefix + ":" + name; } - - + + public abstract SwordValidationInfo validate(Properties validationContext); - - protected void processUnexpectedAttributes(Element element, List attributeItems) - { + + protected void processUnexpectedAttributes(Element element, List attributeItems) { int attributeCount = element.getAttributeCount(); Attribute attribute = null; - - for ( int i = 0; i < attributeCount; i++ ) - { - attribute = element.getAttribute(i); - XmlName attributeName = new XmlName(attribute.getNamespacePrefix(), - attribute.getLocalName(), - attribute.getNamespaceURI()); - - SwordValidationInfo info = new SwordValidationInfo(xmlName, attributeName, - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO); - info.setContentDescription(attribute.getValue()); - attributeItems.add(info); + + for (int i = 0; i < attributeCount; i++) { + attribute = element.getAttribute(i); + XmlName attributeName = new XmlName(attribute.getNamespacePrefix(), + attribute.getLocalName(), + attribute.getNamespaceURI()); + + SwordValidationInfo info = new SwordValidationInfo(xmlName, attributeName, + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); + info.setContentDescription(attribute.getValue()); + attributeItems.add(info); } } - + /** * Add the information to the unmarshall attribute section of the specified * info object. - * - * @param element - * XML element to process - * @param info - * validation information item about elements/attributes + * + * @param element XML element to process + * @param info validation information item about elements/attributes */ - protected void processUnexpectedAttributes(Element element, SwordValidationInfo info) - { + protected void processUnexpectedAttributes(Element element, SwordValidationInfo info) { int attributeCount = element.getAttributeCount(); Attribute attribute = null; - - for ( int i = 0; i < attributeCount; i++ ) - { - attribute = element.getAttribute(i); - XmlName attributeName = new XmlName(attribute.getNamespacePrefix(), - attribute.getLocalName(), - attribute.getNamespaceURI()); - - SwordValidationInfo item = new SwordValidationInfo(xmlName, attributeName, - SwordValidationInfo.UNKNOWN_ATTRIBUTE, - SwordValidationInfoType.INFO); - item.setContentDescription(attribute.getValue()); - info.addUnmarshallAttributeInfo(item); + + for (int i = 0; i < attributeCount; i++) { + attribute = element.getAttribute(i); + XmlName attributeName = new XmlName(attribute.getNamespacePrefix(), + attribute.getLocalName(), + attribute.getNamespaceURI()); + + SwordValidationInfo item = new SwordValidationInfo(xmlName, attributeName, + SwordValidationInfo.UNKNOWN_ATTRIBUTE, + SwordValidationInfoType.INFO); + item.setContentDescription(attribute.getValue()); + info.addUnmarshallAttributeInfo(item); } } - + protected SwordValidationInfo handleIncorrectElement(Element element, Properties validationProperties) - throws UnmarshallException - { + throws UnmarshallException { log.error( - "Unexpected element. Expected: " + getQualifiedName() +". Got: " + - ((element != null) ? element.getQualifiedName() : "null" )); - - if ( validationProperties != null ) - { - SwordValidationInfo info = new SwordValidationInfo( - new XmlName(element.getNamespacePrefix(), element.getLocalName(), - element.getNamespaceURI()), - "This is not the expected element. Received: " + - element.getQualifiedName() + " for namespaceUri: " + - element.getNamespaceURI(), SwordValidationInfoType.ERROR - ); - return info; - } - else - { - throw new UnmarshallException( "Not a " + getQualifiedName() + " element" ); + "Unexpected element. Expected: " + getQualifiedName() + ". Got: " + + ((element != null) ? element.getQualifiedName() : "null")); + + if (validationProperties != null) { + SwordValidationInfo info = new SwordValidationInfo( + new XmlName(element.getNamespacePrefix(), element.getLocalName(), + element.getNamespaceURI()), + "This is not the expected element. Received: " + + element.getQualifiedName() + " for namespaceUri: " + + element.getNamespaceURI(), SwordValidationInfoType.ERROR + ); + return info; + } else { + throw new UnmarshallException("Not a " + getQualifiedName() + " element"); } } - - protected SwordValidationInfo createValidAttributeInfo(String name, String content) - { + + protected SwordValidationInfo createValidAttributeInfo(String name, String content) { XmlName attributeName = new XmlName(xmlName.getPrefix(), - name, - xmlName.getNamespace()); - + name, + xmlName.getNamespace()); + SwordValidationInfo item = new SwordValidationInfo(xmlName, attributeName); item.setContentDescription(content); //attributeItems.add(item); - return item; + return item; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/base/XmlName.java b/dspace-sword/src/main/java/org/purl/sword/base/XmlName.java index 9bd3be20c6..b6dff75281 100644 --- a/dspace-sword/src/main/java/org/purl/sword/base/XmlName.java +++ b/dspace-sword/src/main/java/org/purl/sword/base/XmlName.java @@ -13,44 +13,46 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.HashCodeBuilder; /** - * * @author Neil Taylor (nst@aber.ac.uk) */ public class XmlName { - /** Prefix for the name */ + /** + * Prefix for the name + */ private String prefix; - /** Local name */ + /** + * Local name + */ private String localName; - /** The namespace for the element */ + /** + * The namespace for the element + */ private String namespace; - + /** * Create a new instance with the specified prefix and local name. * - * @param prefix The namespace prefix. - * @param localName The element's local name. - * @param namespace The element's namespace. + * @param prefix The namespace prefix. + * @param localName The element's local name. + * @param namespace The element's namespace. */ - public XmlName(String prefix, String localName, String namespace) - { + public XmlName(String prefix, String localName, String namespace) { this.prefix = prefix; this.localName = localName; this.namespace = namespace; } - public XmlName(Element element) - { + public XmlName(Element element) { this.prefix = element.getNamespacePrefix(); this.localName = element.getLocalName(); this.namespace = element.getNamespaceURI(); } - public XmlName(Attribute attribute) - { + public XmlName(Attribute attribute) { this.prefix = attribute.getNamespacePrefix(); this.localName = attribute.getLocalName(); this.namespace = attribute.getNamespaceURI(); @@ -85,7 +87,7 @@ public class XmlName { /** * Set the local name. - * + * * @param localName the localName to set */ public void setLocalName(String localName) { @@ -94,7 +96,7 @@ public class XmlName { /** * Get the current namespace value. - * + * * @return the namespace */ public String getNamespace() { @@ -110,34 +112,29 @@ public class XmlName { this.namespace = namespace; } - public String getQualifiedName() - { + public String getQualifiedName() { String qName = ""; - if ( prefix != null && prefix.trim().length() > 0 ) - { - qName = prefix + ":"; + if (prefix != null && prefix.trim().length() > 0) { + qName = prefix + ":"; } qName += localName; return qName; } @Override - public boolean equals(Object other) - { + public boolean equals(Object other) { - if ( other instanceof XmlName ) - { + if (other instanceof XmlName) { XmlName otherName = (XmlName) other; return StringUtils.equals(this.namespace, otherName.namespace) && - StringUtils.equals(this.localName, otherName.localName); + StringUtils.equals(this.localName, otherName.localName); } return false; } @Override - public int hashCode() - { + public int hashCode() { return new HashCodeBuilder().append(namespace).append(localName).hashCode(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/Client.java b/dspace-sword/src/main/java/org/purl/sword/client/Client.java index d49682b687..4b4899e4f9 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/Client.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/Client.java @@ -7,12 +7,17 @@ */ package org.purl.sword.client; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.security.NoSuchAlgorithmException; - import java.util.Properties; + import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; @@ -38,7 +43,7 @@ import org.purl.sword.base.UnmarshallException; * This is an example Client implementation to demonstrate how to connect to a * SWORD server. The client supports BASIC HTTP Authentication. This can be * initialised by setting a username and password. - * + * * @author Neil Taylor */ public class Client implements SWORDClient { @@ -100,8 +105,9 @@ public class Client implements SWORDClient { client = new DefaultHttpClient(); HttpParams params = client.getParams(); params.setParameter("http.socket.timeout", - Integer.valueOf(DEFAULT_TIMEOUT)); - HttpHost proxyHost = (HttpHost) params.getParameter(ConnRoutePNames.DEFAULT_PROXY); // XXX does this really work? + Integer.valueOf(DEFAULT_TIMEOUT)); + HttpHost proxyHost = (HttpHost) params + .getParameter(ConnRoutePNames.DEFAULT_PROXY); // XXX does this really work? log.debug("proxy host: " + proxyHost.getHostName()); log.debug("proxy port: " + proxyHost.getPort()); doAuthentication = false; @@ -109,11 +115,9 @@ public class Client implements SWORDClient { /** * Initialise the server that will be used to send the network access. - * - * @param server - * server address/hostname - * @param port - * server port + * + * @param server server address/hostname + * @param port server port */ public void setServer(String server, int port) { this.server = server; @@ -123,11 +127,9 @@ public class Client implements SWORDClient { /** * Set the user credentials that will be used when making the access to the * server. - * - * @param username - * The username. - * @param password - * The password. + * + * @param username The username. + * @param password The password. */ public void setCredentials(String username, String password) { this.username = username; @@ -138,26 +140,23 @@ public class Client implements SWORDClient { /** * Set the basic credentials. You must have previously set the server and * port using setServer. - * - * @param username - * The username. - * @param password - * The password. + * + * @param username The username. + * @param password The password. */ private void setBasicCredentials(String username, String password) { log.debug("server: " + server + " port: " + port + " u: '" + username - + "' p '" + password + "'"); + + "' p '" + password + "'"); client.getCredentialsProvider().setCredentials(new AuthScope(server, port), - new UsernamePasswordCredentials(username, password)); + new UsernamePasswordCredentials(username, password)); } /** * Set a proxy that should be used by the client when trying to access the * server. If this is not set, the client will attempt to make a direct * direct connection to the server. The port is set to 80. - * - * @param host - * The hostname. + * + * @param host The hostname. */ public void setProxy(String host) { setProxy(host, 80); @@ -167,15 +166,13 @@ public class Client implements SWORDClient { * Set a proxy that should be used by the client when trying to access the * server. If this is not set, the client will attempt to make a direct * direct connection to the server. - * - * @param host - * The name of the host. - * @param port - * The port. + * + * @param host The name of the host. + * @param port The port. */ public void setProxy(String host, int port) { client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, - new HttpHost(host, port)); // XXX does this really work? + new HttpHost(host, port)); // XXX does this really work? } /** @@ -193,51 +190,45 @@ public class Client implements SWORDClient { doAuthentication = false; } - public void setUserAgent(String userAgent){ + public void setUserAgent(String userAgent) { this.userAgent = userAgent; } + /** * Set the connection timeout for the socket. - * - * @param milliseconds - * The time, expressed as a number of milliseconds. + * + * @param milliseconds The time, expressed as a number of milliseconds. */ public void setSocketTimeout(int milliseconds) { client.getParams().setParameter("http.socket.timeout", - Integer.valueOf(milliseconds)); + Integer.valueOf(milliseconds)); } /** * Retrieve the service document. The service document is located at the * specified URL. This calls getServiceDocument(url,onBehalfOf). - * - * @param url - * The location of the service document. + * + * @param url The location of the service document. * @return The ServiceDocument, or null if there was a - * problem accessing the document. e.g. invalid access. - * - * @throws SWORDClientException - * If there is an error accessing the resource. + * problem accessing the document. e.g. invalid access. + * @throws SWORDClientException If there is an error accessing the resource. */ public ServiceDocument getServiceDocument(String url) - throws SWORDClientException { + throws SWORDClientException { return getServiceDocument(url, null); } /** * Retrieve the service document. The service document is located at the * specified URL. This calls getServiceDocument(url,onBehalfOf). - * - * @param url - * The location of the service document. + * + * @param url The location of the service document. * @return The ServiceDocument, or null if there was a - * problem accessing the document. e.g. invalid access. - * - * @throws SWORDClientException - * If there is an error accessing the resource. + * problem accessing the document. e.g. invalid access. + * @throws SWORDClientException If there is an error accessing the resource. */ public ServiceDocument getServiceDocument(String url, String onBehalfOf) - throws SWORDClientException { + throws SWORDClientException { URL serviceDocURL = null; try { serviceDocURL = new URL(url); @@ -250,12 +241,12 @@ public class Client implements SWORDClient { } catch (MalformedURLException e1) { // No dice, can't even form base URL... throw new SWORDClientException(url + " is not a valid URL (" - + e1.getMessage() - + "), and could not form a relative one from: " - + baseURL + " / " + url, e1); + + e1.getMessage() + + "), and could not form a relative one from: " + + baseURL + " / " + url, e1); } } - + HttpGet httpget = new HttpGet(serviceDocURL.toExternalForm()); if (doAuthentication) { // this does not perform any check on the username password. It @@ -266,7 +257,8 @@ public class Client implements SWORDClient { Properties properties = new Properties(); if (containsValue(onBehalfOf)) { - log.debug("Setting on-behalf-of: " + onBehalfOf);httpget.addHeader(url, url); + log.debug("Setting on-behalf-of: " + onBehalfOf); + httpget.addHeader(url, url); httpget.addHeader(HttpHeaders.X_ON_BEHALF_OF, onBehalfOf); properties.put(HttpHeaders.X_ON_BEHALF_OF, onBehalfOf); } @@ -293,8 +285,8 @@ public class Client implements SWORDClient { lastUnmarshallInfo = doc.unmarshall(message, properties); } else { throw new SWORDClientException( - "Received error from service document request: " - + status); + "Received error from service document request: " + + status); } } catch (IOException ioex) { throw new SWORDClientException(ioex.getMessage(), ioex); @@ -312,23 +304,19 @@ public class Client implements SWORDClient { /** * @return SWORD validation info */ - public SwordValidationInfo getLastUnmarshallInfo() - { + public SwordValidationInfo getLastUnmarshallInfo() { return lastUnmarshallInfo; } /** * Post a file to the server. The different elements of the post are encoded * in the specified message. - * - * @param message - * The message that contains the post information. - * - * @throws SWORDClientException - * if there is an error during the post operation. + * + * @param message The message that contains the post information. + * @throws SWORDClientException if there is an error during the post operation. */ public DepositResponse postFile(PostMessage message) - throws SWORDClientException { + throws SWORDClientException { if (message == null) { throw new SWORDClientException("Message cannot be null."); } @@ -342,7 +330,7 @@ public class Client implements SWORDClient { DepositResponse response = null; String messageBody = ""; - + try { if (message.isUseMD5()) { String md5 = ChecksumUtils.generateMD5(message.getFilepath()); @@ -356,17 +344,16 @@ public class Client implements SWORDClient { } String filename = message.getFilename(); - if (! "".equals(filename)) { + if (!"".equals(filename)) { httppost.addHeader(HttpHeaders.CONTENT_DISPOSITION, - " filename=" + filename); + " filename=" + filename); } if (containsValue(message.getSlug())) { httppost.addHeader(HttpHeaders.SLUG, message.getSlug()); } - if (message.getCorruptRequest()) - { + if (message.getCorruptRequest()) { // insert a header with an invalid boolean value httppost.addHeader(HttpHeaders.X_NO_OP, "Wibble"); } else { @@ -374,7 +361,7 @@ public class Client implements SWORDClient { .toString(message.isNoOp())); } httppost.addHeader(HttpHeaders.X_VERBOSE, Boolean - .toString(message.isVerbose())); + .toString(message.isVerbose())); String packaging = message.getPackaging(); if (packaging != null && packaging.length() > 0) { @@ -385,7 +372,7 @@ public class Client implements SWORDClient { if (containsValue(onBehalfOf)) { httppost.addHeader(HttpHeaders.X_ON_BEHALF_OF, onBehalfOf); } - + String userAgent = message.getUserAgent(); if (containsValue(userAgent)) { httppost.addHeader(HttpHeaders.USER_AGENT, userAgent); @@ -393,8 +380,8 @@ public class Client implements SWORDClient { FileEntity requestEntity = new FileEntity( - new File(message.getFilepath()), - ContentType.create(message.getFiletype())); + new File(message.getFilepath()), + ContentType.create(message.getFiletype())); httppost.setEntity(requestEntity); HttpResponse httpResponse = client.execute(httppost); @@ -405,14 +392,13 @@ public class Client implements SWORDClient { log.info("Checking the status code: " + status.getCode()); if (status.getCode() == HttpStatus.SC_ACCEPTED - || status.getCode() == HttpStatus.SC_CREATED) { + || status.getCode() == HttpStatus.SC_CREATED) { messageBody = readResponse(httpResponse.getEntity().getContent()); - response = new DepositResponse(status.getCode()); + response = new DepositResponse(status.getCode()); response.setLocation(httpResponse.getFirstHeader("Location").getValue()); // added call for the status code. lastUnmarshallInfo = response.unmarshall(messageBody, new Properties()); - } - else { + } else { messageBody = readResponse(httpResponse.getEntity().getContent()); response = new DepositResponse(status.getCode()); response.unmarshallErrorDocument(messageBody); @@ -421,7 +407,7 @@ public class Client implements SWORDClient { } catch (NoSuchAlgorithmException nex) { throw new SWORDClientException("Unable to use MD5. " - + nex.getMessage(), nex); + + nex.getMessage(), nex); } catch (IOException ioex) { throw new SWORDClientException(ioex.getMessage(), ioex); } catch (UnmarshallException uex) { @@ -433,19 +419,17 @@ public class Client implements SWORDClient { /** * Read a response from the stream and return it as a string. - * - * @param stream - * The stream that contains the response. + * + * @param stream The stream that contains the response. * @return The string extracted from the screen. - * * @throws UnsupportedEncodingException - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O + * operations. */ private String readResponse(InputStream stream) - throws UnsupportedEncodingException, IOException { + throws UnsupportedEncodingException, IOException { BufferedReader reader = new BufferedReader(new InputStreamReader( - stream, "UTF-8")); + stream, "UTF-8")); String line = null; StringBuffer buffer = new StringBuffer(); while ((line = reader.readLine()) != null) { @@ -458,7 +442,7 @@ public class Client implements SWORDClient { /** * Return the status information that was returned from the most recent * request sent to the server. - * + * * @return The status code returned from the most recent access. */ public Status getStatus() { @@ -467,12 +451,11 @@ public class Client implements SWORDClient { /** * Check to see if the specified item contains a non-empty string. - * - * @param item - * The string to check. + * + * @param item The string to check. * @return True if the string is not null and has a length greater than 0 - * after any whitespace is trimmed from the start and end. - * Otherwise, false. + * after any whitespace is trimmed from the start and end. + * Otherwise, false. */ private boolean containsValue(String item) { return ((item != null) && (item.trim().length() > 0)); diff --git a/dspace-sword/src/main/java/org/purl/sword/client/ClientConstants.java b/dspace-sword/src/main/java/org/purl/sword/client/ClientConstants.java index aec80e9412..124ed38d33 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/ClientConstants.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/ClientConstants.java @@ -8,29 +8,33 @@ package org.purl.sword.client; /** - * Hold general constants for the client. - * + * Hold general constants for the client. + * * @author Neil Taylor */ -public class ClientConstants -{ - /** - * Current software version. - */ - public static final String CLIENT_VERSION = "1.1"; +public class ClientConstants { + /** + * Current software version. + */ + public static final String CLIENT_VERSION = "1.1"; - /** - * the name of this application - */ - public static final String SERVICE_NAME = "CASIS Test Client"; + /** + * the name of this application + */ + public static final String SERVICE_NAME = "CASIS Test Client"; - /** - * the name of this application - */ - public static final String NOT_DEFINED_TEXT = "Not defined"; + /** + * the name of this application + */ + public static final String NOT_DEFINED_TEXT = "Not defined"; - /** - * The logging property file. - */ - public static final String LOGGING_PROPERTY_FILE = "log4j.properties"; + /** + * The logging property file. + */ + public static final String LOGGING_PROPERTY_FILE = "log4j.properties"; + + /** + * Default constructor + */ + private ClientConstants() { } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/ClientFactory.java b/dspace-sword/src/main/java/org/purl/sword/client/ClientFactory.java index 687ec330fd..0ae5cb3f26 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/ClientFactory.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/ClientFactory.java @@ -12,7 +12,7 @@ import org.apache.log4j.PropertyConfigurator; /** * Entry point for the SWORD Demonstration Client. This will parse the list of * command line options and load either a Command Line client or a GUI client. - * + * * @author Neil Taylor */ public class ClientFactory { @@ -25,13 +25,13 @@ public class ClientFactory { // reload these properties if it is set to capture the output and // display it in a panel. PropertyConfigurator.configure(this.getClass().getClassLoader() - .getResource(ClientConstants.LOGGING_PROPERTY_FILE)); + .getResource(ClientConstants.LOGGING_PROPERTY_FILE)); } /** * Generate a string that specifies the command line options for this * program. - * + * * @return A list of the options for this program. */ public static String usage() { @@ -101,10 +101,8 @@ public class ClientFactory { /** * Create a client. If GUI mode is set, a GUI client is created. Otherwise, * a command line client is created. - * - * @param options - * The list of options extracted from the command line. - * + * + * @param options The list of options extracted from the command line. * @return A new client. */ public ClientType createClient(ClientOptions options) { @@ -115,7 +113,7 @@ public class ClientFactory { * Start the application and determine which client should be loaded. The * application currently has two modes: GUI and client. The GUI mode is the * default option. - * + * * @param args the command line arguments given */ public static void main(String[] args) { diff --git a/dspace-sword/src/main/java/org/purl/sword/client/ClientOptions.java b/dspace-sword/src/main/java/org/purl/sword/client/ClientOptions.java index 4747b22305..2f3c73d1e5 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/ClientOptions.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/ClientOptions.java @@ -16,610 +16,589 @@ import java.util.regex.Pattern; import org.apache.log4j.Logger; /** - * List of options that are parsed from the command line. + * List of options that are parsed from the command line. + * * @author Neil Taylor */ -public class ClientOptions -{ +public class ClientOptions { /** - * Label for the service operation. + * Label for the service operation. */ public static final String TYPE_SERVICE = "service"; - + /** - * Label for the post operation. + * Label for the post operation. */ public static final String TYPE_POST = "post"; - + /** - * Label for the multipost operation. + * Label for the multipost operation. */ public static final String TYPE_MULTI_POST = "multipost"; - + /** - * The access type. + * The access type. */ - private String accessType = null; - - /** - * Proxy host name. + private String accessType = null; + + /** + * Proxy host name. */ private String proxyHost = null; - + /** - * Proxy host port. + * Proxy host port. */ - private int proxyPort = 8080; - - /** - * Username to access the service/post server. + private int proxyPort = 8080; + + /** + * Username to access the service/post server. */ private String username = null; - + /** * Password to access the service/post server. */ - private String password = null; - + private String password = null; + /** - * HREF of the server to access. + * HREF of the server to access. */ private String href = null; - - /** - * Filename to post. - */ - private String filename = null; - + /** - * Filetype. + * Filename to post. + */ + private String filename = null; + + /** + * Filetype. */ private String filetype = null; - + /** - * Specifies that the output streams are not to be captured by the GUI client. + * Specifies that the output streams are not to be captured by the GUI client. */ - private boolean noCapture = false; - - + private boolean noCapture = false; + + /** * SLUG Header field. */ - private String slug = null; - + private String slug = null; + /** - * NoOp, used to indicate an operation on the server that does not - * require the file to be stored. + * NoOp, used to indicate an operation on the server that does not + * require the file to be stored. */ - private boolean noOp = false; - + private boolean noOp = false; + /** - * Request verbose output from the server. + * Request verbose output from the server. */ - private boolean verbose = false; - - /** - * OnBehalfOf user id. - */ - private String onBehalfOf = null; - + private boolean verbose = false; + /** - * Format namespace to be used for the posted file. + * OnBehalfOf user id. */ - private String formatNamespace = null; - + private String onBehalfOf = null; + /** - * Introduce a checksum error. This is used to simulate an error with the - * MD5 value. + * Format namespace to be used for the posted file. + */ + private String formatNamespace = null; + + /** + * Introduce a checksum error. This is used to simulate an error with the + * MD5 value. */ private boolean checksumError = false; - + /** - * Logger. + * Logger. */ private static Logger log = Logger.getLogger(ClientOptions.class); - + /** - * List of multiple destination items. Used if the mode is set to multipost. + * List of multiple destination items. Used if the mode is set to multipost. */ private List multiPost = new ArrayList(); - + /** - * Pattern string to extract the data from a destination parameter in multipost mode. + * Pattern string to extract the data from a destination parameter in multipost mode. */ private static final Pattern multiPattern = Pattern.compile("(.*?)(\\[(.*?)\\]) {0,1}(:(.*)) {0,1}@(http://.*)"); - + /** - * Flag that indicates if the GUI mode has been set. This is - * true by default. + * Flag that indicates if the GUI mode has been set. This is + * true by default. */ - private boolean guiMode = true; - + private boolean guiMode = true; + /** * Flat that indicates if the MD5 option has been selected. This - * is true by default. + * is true by default. */ - private boolean md5 = false; - + private boolean md5 = false; + /** - * Parse the list of options contained in the specified array. - * - * @param args The array of options. - * - * @return True if the options were parsed successfully. + * Parse the list of options contained in the specified array. + * + * @param args The array of options. + * @return True if the options were parsed successfully. */ - public boolean parseOptions( String[] args ) - { - try - { - // iterate over the args - for ( int i = 0; i < args.length; i++ ) - { - if ( "-md5".equals(args[i])) - { - md5 = true; - } - - if ( "-noOp".equals(args[i])) - { - noOp = true; - } - - if ( "-verbose".equals(args[i])) - { - verbose = true; - } - - if ( "-cmd".equals(args[i]) ) - { - guiMode = false; - } - - if ( "-gui".equals(args[i]) ) - { - guiMode = true; - } - - if ( "-host".equals(args[i]) ) - { - i++; - proxyHost = args[i]; - } - - if ( "-port".equals(args[i]) ) - { - i++; - proxyPort = Integer.parseInt(args[i]); - } - - if ( "-u".equals(args[i]) ) - { - i++; - username = args[i]; - } - - if ( "-p".equals(args[i])) - { - i++; - password = args[i]; - } - - if ( "-href".equals(args[i])) - { - i++; - href = args[i]; - } - - if ( "-help".equals(args[i]) ) - { - // force the calling code to display the usage information - return false; - } - - if ( "-t".equals(args[i])) - { - i++; - accessType = args[i]; - } - - if ( "-file".equals(args[i])) - { - i++; - filename = args[i]; - } - - if ( "-filetype".equals(args[i])) - { - i++; - filetype = args[i]; - } - - if ( "-slug".equals(args[i])) - { - i++; - slug = args[i]; - } - - if ( "-onBehalfOf".equals(args[i])) - { - i++; - onBehalfOf = args[i]; - } - - if ( "-formatNamespace".equals(args[i])) - { - i++; - formatNamespace = args[i]; - } - - if ( "-checksumError".equals(args[i])) - { - i++; - checksumError = true; - } - - if ( "-dest".equals(args[i])) - { - i++; - Matcher m = multiPattern.matcher(args[i]); - if ( ! m.matches() ) - { - log.debug("Error with dest parameter. Ignoring value: " + args[i]); - } - else - { - int numGroups = m.groupCount(); - for ( int g = 0; g <= numGroups; g++ ) - { - log.debug("Group (" + g + ") is: " + m.group(g)); - } - - String username = m.group(1); - String onBehalfOf = m.group(3); - String password = m.group(5); - String url = m.group(6); - PostDestination destination = new PostDestination(url, username, password, onBehalfOf); - - multiPost.add(destination); - } - } - - if ( "-nocapture".equals(args[i]) ) - { - i++; - noCapture = true; - } - } - - // apply any settings - if ( href == null && "service".equals(accessType) ) - { - log.error( "No href specified."); - return false; - } - - if ( multiPost.size() == 0 && "multipost".equals(accessType)) - { - log.error("No destinations specified"); - return false; - } - - if ( accessType == null && ! guiMode ) - { - log.error("No access type specified"); - return false; - } - - if ( ( username == null && password != null ) || (username != null && password == null)) - { - log.error("The username and/or password are not specified. If one is specified, the other must also be specified."); - return false; - } - } - catch ( ArrayIndexOutOfBoundsException ex ) - { + public boolean parseOptions(String[] args) { + try { + // iterate over the args + for (int i = 0; i < args.length; i++) { + if ("-md5".equals(args[i])) { + md5 = true; + } + + if ("-noOp".equals(args[i])) { + noOp = true; + } + + if ("-verbose".equals(args[i])) { + verbose = true; + } + + if ("-cmd".equals(args[i])) { + guiMode = false; + } + + if ("-gui".equals(args[i])) { + guiMode = true; + } + + if ("-host".equals(args[i])) { + i++; + proxyHost = args[i]; + } + + if ("-port".equals(args[i])) { + i++; + proxyPort = Integer.parseInt(args[i]); + } + + if ("-u".equals(args[i])) { + i++; + username = args[i]; + } + + if ("-p".equals(args[i])) { + i++; + password = args[i]; + } + + if ("-href".equals(args[i])) { + i++; + href = args[i]; + } + + if ("-help".equals(args[i])) { + // force the calling code to display the usage information + return false; + } + + if ("-t".equals(args[i])) { + i++; + accessType = args[i]; + } + + if ("-file".equals(args[i])) { + i++; + filename = args[i]; + } + + if ("-filetype".equals(args[i])) { + i++; + filetype = args[i]; + } + + if ("-slug".equals(args[i])) { + i++; + slug = args[i]; + } + + if ("-onBehalfOf".equals(args[i])) { + i++; + onBehalfOf = args[i]; + } + + if ("-formatNamespace".equals(args[i])) { + i++; + formatNamespace = args[i]; + } + + if ("-checksumError".equals(args[i])) { + i++; + checksumError = true; + } + + if ("-dest".equals(args[i])) { + i++; + Matcher m = multiPattern.matcher(args[i]); + if (!m.matches()) { + log.debug("Error with dest parameter. Ignoring value: " + args[i]); + } else { + int numGroups = m.groupCount(); + for (int g = 0; g <= numGroups; g++) { + log.debug("Group (" + g + ") is: " + m.group(g)); + } + + String username = m.group(1); + String onBehalfOf = m.group(3); + String password = m.group(5); + String url = m.group(6); + PostDestination destination = new PostDestination(url, username, password, onBehalfOf); + + multiPost.add(destination); + } + } + + if ("-nocapture".equals(args[i])) { + i++; + noCapture = true; + } + } + + // apply any settings + if (href == null && "service".equals(accessType)) { + log.error("No href specified."); + return false; + } + + if (multiPost.size() == 0 && "multipost".equals(accessType)) { + log.error("No destinations specified"); + return false; + } + + if (accessType == null && !guiMode) { + log.error("No access type specified"); + return false; + } + + if ((username == null && password != null) || (username != null && password == null)) { + log.error( + "The username and/or password are not specified. If one is specified, the other must also be " + + "specified."); + return false; + } + } catch (ArrayIndexOutOfBoundsException ex) { log.error("Error with parameters."); return false; } - + return true; } - - /** - * Get the access type. - * @return The value, or null if the value is not set. - */ - public String getAccessType() - { + + /** + * Get the access type. + * + * @return The value, or null if the value is not set. + */ + public String getAccessType() { return accessType; } - - /** - * Set the access type. - * @param accessType The value, or null to clear the value. + + /** + * Set the access type. + * + * @param accessType The value, or null to clear the value. */ - public void setAccessType(String accessType) - { + public void setAccessType(String accessType) { this.accessType = accessType; } - - /** - * Get the proxy host. - * @return The value, or null if the value is not set. + + /** + * Get the proxy host. + * + * @return The value, or null if the value is not set. */ - public String getProxyHost() - { + public String getProxyHost() { return proxyHost; } - + /** * Set the proxy host. - * @param proxyHost The value, or null to clear the value. + * + * @param proxyHost The value, or null to clear the value. */ - public void setProxyHost(String proxyHost) - { + public void setProxyHost(String proxyHost) { this.proxyHost = proxyHost; } - + /** - * Get the proxy port. + * Get the proxy port. + * * @return The proxy port. Default value is 80. */ - public int getProxyPort() - { + public int getProxyPort() { return proxyPort; } - + /** - * Set the proxy port. - * @param proxyPort The proxy port. + * Set the proxy port. + * + * @param proxyPort The proxy port. */ - public void setProxyPort(int proxyPort) - { + public void setProxyPort(int proxyPort) { this.proxyPort = proxyPort; } - - /** - * Get the username. - * @return The value, or null if the value is not set. + + /** + * Get the username. + * + * @return The value, or null if the value is not set. */ - public String getUsername() - { + public String getUsername() { return username; } - + /** - * Set the username. - * @param username The value, or null to clear the value. + * Set the username. + * + * @param username The value, or null to clear the value. */ - public void setUsername(String username) - { + public void setUsername(String username) { this.username = username; } - + /** - * Get the password. - * @return The value, or null if the value is not set. + * Get the password. + * + * @return The value, or null if the value is not set. */ - public String getPassword() - { + public String getPassword() { return password; } - + /** - * Set the password. - * @param password The value, or null to clear the value. + * Set the password. + * + * @param password The value, or null to clear the value. */ - public void setPassword(String password) - { + public void setPassword(String password) { this.password = password; } - + /** - * Get the HREF of the service to access. - * @return The value, or null if the value is not set. + * Get the HREF of the service to access. + * + * @return The value, or null if the value is not set. */ - public String getHref() - { + public String getHref() { return href; } - + /** - * Set the HREF of the service to access. - * @param href The value, or null to clear the value. + * Set the HREF of the service to access. + * + * @param href The value, or null to clear the value. */ - public void setHref(String href) - { + public void setHref(String href) { this.href = href; } - + /** - * Get the name of the file to post. - * @return The value, or null if the value is not set. + * Get the name of the file to post. + * + * @return The value, or null if the value is not set. */ - public String getFilename() - { + public String getFilename() { return filename; } - - /** - * Set the name of the file to post. - * @param filename The value, or null to clear the value. + + /** + * Set the name of the file to post. + * + * @param filename The value, or null to clear the value. */ - public void setFilename(String filename) - { + public void setFilename(String filename) { this.filename = filename; } - - /** - * Get the type of the file to post. - * @return The filetype, or null if the value is not set. + + /** + * Get the type of the file to post. + * + * @return The filetype, or null if the value is not set. */ - public String getFiletype() - { + public String getFiletype() { return filetype; } - + /** - * Set the type of the file to post. - * @param filetype The value, or null to clear the value. + * Set the type of the file to post. + * + * @param filetype The value, or null to clear the value. */ - public void setFiletype(String filetype) - { + public void setFiletype(String filetype) { this.filetype = filetype; } - + /** - * Determine if the tool is to be run in GUI mode. - * @return True if the tool is set for GUI mode. + * Determine if the tool is to be run in GUI mode. + * + * @return True if the tool is set for GUI mode. */ - public boolean isGuiMode() - { + public boolean isGuiMode() { return guiMode; } - + /** - * Set the tool to run in GUI mode. - * @param guiMode True if the tool is to run in gui mode. + * Set the tool to run in GUI mode. + * + * @param guiMode True if the tool is to run in gui mode. */ - public void setGuiMode(boolean guiMode) - { - this.guiMode = guiMode; + public void setGuiMode(boolean guiMode) { + this.guiMode = guiMode; } - + /** - * Get the MD5 setting. True if the tool is to use MD5 for post operations. - * @return The MD5 setting. + * Get the MD5 setting. True if the tool is to use MD5 for post operations. + * + * @return The MD5 setting. */ public boolean isMd5() { return md5; } - + /** - * Set the MD5 setting. - * @param md5 True if the tool should use MD5 for post operations. + * Set the MD5 setting. + * + * @param md5 True if the tool should use MD5 for post operations. */ public void setMd5(boolean md5) { this.md5 = md5; } - + /** - * Determine if the NoOp header should be sent. - * @return True if the header should be sent. + * Determine if the NoOp header should be sent. + * + * @return True if the header should be sent. */ public boolean isNoOp() { return noOp; } - + /** - * Set the NoOp setting. - * @param noOp True if the NoOp header should be used. + * Set the NoOp setting. + * + * @param noOp True if the NoOp header should be used. */ public void setNoOp(boolean noOp) { this.noOp = noOp; } - + /** - * Determine if the verbose option is set. - * @return True if verbose option is set. + * Determine if the verbose option is set. + * + * @return True if verbose option is set. */ public boolean isVerbose() { return verbose; } - + /** - * Set the verbose option. - * @param verbose True if verbose should be set. + * Set the verbose option. + * + * @param verbose True if verbose should be set. */ public void setVerbose(boolean verbose) { this.verbose = verbose; } - + /** - * Get the onBehalfOf value. - * @return The value, or null to clear the value. + * Get the onBehalfOf value. + * + * @return The value, or null to clear the value. */ public String getOnBehalfOf() { return onBehalfOf; } - + /** - * Set the onBehalf of Value. - * @param onBehalfOf The value, or null to clear the value. + * Set the onBehalf of Value. + * + * @param onBehalfOf The value, or null to clear the value. */ public void setOnBehalfOf(String onBehalfOf) { this.onBehalfOf = onBehalfOf; } - + /** - * Get the format namespace value. - * @return The value, or null if the value is not set. + * Get the format namespace value. + * + * @return The value, or null if the value is not set. */ public String getFormatNamespace() { return formatNamespace; } - + /** - * Set the format namespace value. - * @param formatNamespace The value, or null to clear the value. + * Set the format namespace value. + * + * @param formatNamespace The value, or null to clear the value. */ public void setFormatNamespace(String formatNamespace) { this.formatNamespace = formatNamespace; } - + /** - * Get the checksum error value. - * @return True if an error should be introduced into the checksum. + * Get the checksum error value. + * + * @return True if an error should be introduced into the checksum. */ public boolean getChecksumError() { return checksumError; } - + /** - * Set the checksum error value. - * @param checksumError True if the error should be introduced. + * Set the checksum error value. + * + * @param checksumError True if the error should be introduced. */ public void setChecksumError(boolean checksumError) { this.checksumError = checksumError; } - + /** * Get the current slug header. - * @return The slug value, or null if the value is not set. + * + * @return The slug value, or null if the value is not set. */ - public String getSlug( ) - { + public String getSlug() { return this.slug; } - + /** * Set the text that is to be used for the slug header. - * @param slug The value, or null to clear the value. + * + * @param slug The value, or null to clear the value. */ - public void setSlug(String slug) - { + public void setSlug(String slug) { this.slug = slug; } - + /** - * Get the list of post destinations. - * @return An iterator over the list of PostDestination objects. + * Get the list of post destinations. + * + * @return An iterator over the list of PostDestination objects. */ - public Iterator getMultiPost() - { + public Iterator getMultiPost() { return multiPost.iterator(); } - - + + /** - * Determine if the noCapture option is set. This indicates that the code - * should not attempt to redirect stdout and stderr to a different output - * destination. Intended for use in a GUI client. - * - * @return The noCapture setting. True if set. + * Determine if the noCapture option is set. This indicates that the code + * should not attempt to redirect stdout and stderr to a different output + * destination. Intended for use in a GUI client. + * + * @return The noCapture setting. True if set. */ - public boolean isNoCapture() - { + public boolean isNoCapture() { return noCapture; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/ClientType.java b/dspace-sword/src/main/java/org/purl/sword/client/ClientType.java index a25cb00f70..11474782c1 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/ClientType.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/ClientType.java @@ -8,17 +8,16 @@ package org.purl.sword.client; /** - * Interface for a client. This contains a single method that allows the factory - * to pass a set of command line options to the client. + * Interface for a client. This contains a single method that allows the factory + * to pass a set of command line options to the client. * * @author Neil Taylor */ -public interface ClientType -{ - /** - * Run the client, processing the specified options. - * - * @param options The options extracted from the command line. - */ - public void run( ClientOptions options ); +public interface ClientType { + /** + * Run the client, processing the specified options. + * + * @param options The options extracted from the command line. + */ + public void run(ClientOptions options); } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/CmdClient.java b/dspace-sword/src/main/java/org/purl/sword/client/CmdClient.java index fb48a91542..f1f224fe8b 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/CmdClient.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/CmdClient.java @@ -13,8 +13,8 @@ import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; - import java.util.List; + import org.apache.log4j.Logger; import org.purl.sword.atom.Author; import org.purl.sword.atom.Content; @@ -28,97 +28,81 @@ import org.purl.sword.base.Collection; import org.purl.sword.base.DepositResponse; import org.purl.sword.base.SWORDEntry; import org.purl.sword.base.ServiceDocument; -import org.purl.sword.base.Workspace; import org.purl.sword.base.SwordAcceptPackaging; +import org.purl.sword.base.Workspace; /** - * Example implementation of a command line client. This can send out service - * document requests and print out the results and process posting a file to - * either a single or multiple destinations. The command line options are - * initialised prior to calling the class. The options are passed into the - * run(ClientOptions) method. - * + * Example implementation of a command line client. This can send out service + * document requests and print out the results and process posting a file to + * either a single or multiple destinations. The command line options are + * initialised prior to calling the class. The options are passed into the + * run(ClientOptions) method. + * * @author Neil Taylor */ -public class CmdClient implements ClientType -{ +public class CmdClient implements ClientType { /** - * The client that is used to process the service and post requests. + * The client that is used to process the service and post requests. */ - private SWORDClient client; + private SWORDClient client; /** * List of the options that can be specified on the command line. */ - private ClientOptions options; - + private ClientOptions options; + /** * The logger. */ private static Logger log = Logger.getLogger(CmdClient.class); - - /** - * Create a new instance of the class and create an instance of the - * client. - */ - public CmdClient( ) - { - client = new Client( ); - } /** - * Process the options that have been initialised from the command line. - * This will call one of service(), post() or multiPost(). + * Create a new instance of the class and create an instance of the + * client. */ - public void process() - { - if (options.getProxyHost() != null) - { + public CmdClient() { + client = new Client(); + } + + /** + * Process the options that have been initialised from the command line. + * This will call one of service(), post() or multiPost(). + */ + public void process() { + if (options.getProxyHost() != null) { client.setProxy(options.getProxyHost(), options.getProxyPort()); } - try - { + try { String accessType = options.getAccessType(); - if (ClientOptions.TYPE_SERVICE.equals(accessType)) - { + if (ClientOptions.TYPE_SERVICE.equals(accessType)) { service(); - } - else if (ClientOptions.TYPE_POST.equals(accessType)) - { + } else if (ClientOptions.TYPE_POST.equals(accessType)) { post(); - } - else if (ClientOptions.TYPE_MULTI_POST.equals(accessType) ) - { + } else if (ClientOptions.TYPE_MULTI_POST.equals(accessType)) { System.out.println("checking multi-post"); multiPost(); - } - else - { + } else { System.out.println("Access type not recognised."); } - } - catch ( MalformedURLException mex ) - { - System.out.println("The specified href was not valid: " + options.getHref() + " message: " + mex.getMessage()); - } - catch (SWORDClientException ex) - { + } catch (MalformedURLException mex) { + System.out + .println("The specified href was not valid: " + options.getHref() + " message: " + mex.getMessage()); + } catch (SWORDClientException ex) { System.out.println("Exception: " + ex.getMessage()); log.error("Unable to process request", ex); } } /** - * Process the service operation. Output the results of the service request. - * - * @throws SWORDClientException if there is an error processing the service request. - * @throws MalformedURLException if there is an error with the URL for the service request. + * Process the service operation. Output the results of the service request. + * + * @throws SWORDClientException if there is an error processing the service request. + * @throws MalformedURLException if there is an error with the URL for the service request. */ private void service() - throws SWORDClientException, MalformedURLException - { + throws SWORDClientException, MalformedURLException { String href = options.getHref(); initialiseServer(href, options.getUsername(), options.getPassword()); @@ -126,104 +110,93 @@ public class CmdClient implements ClientType Status status = client.getStatus(); System.out.println("The status is: " + status); - if (status.getCode() == 200) - { + if (status.getCode() == 200) { log.debug("message is: " + document.marshall()); - + System.out.println("\nThe following Details were retrieved: "); System.out.println("SWORD Version: " - + document.getService().getVersion()); + + document.getService().getVersion()); System.out.println("Supports NoOp? " + document.getService().isNoOp()); System.out.println("Supports Verbose? " - + document.getService().isVerbose()); + + document.getService().isVerbose()); System.out.println("Max Upload File Size " - + document.getService().getMaxUploadSize() +" kB"); + + document.getService().getMaxUploadSize() + " kB"); Iterator workspaces = document.getService().getWorkspaces(); - for (; workspaces.hasNext();) - { + for (; workspaces.hasNext(); ) { Workspace workspace = workspaces.next(); System.out.println("\nWorkspace Title: '" - + workspace.getTitle() + "'"); + + workspace.getTitle() + "'"); System.out.println("\n+ Collections ---"); // process the collections Iterator collections = workspace - .collectionIterator(); - for (; collections.hasNext();) - { + .collectionIterator(); + for (; collections.hasNext(); ) { Collection collection = collections.next(); System.out.println("\nCollection location: " - + collection.getLocation()); + + collection.getLocation()); System.out.println("Collection title: " - + collection.getTitle()); + + collection.getTitle()); System.out - .println("Abstract: " + collection.getAbstract()); + .println("Abstract: " + collection.getAbstract()); System.out.println("Collection Policy: " - + collection.getCollectionPolicy()); + + collection.getCollectionPolicy()); System.out.println("Treatment: " - + collection.getTreatment()); + + collection.getTreatment()); System.out.println("Mediation: " - + collection.getMediation()); + + collection.getMediation()); String[] accepts = collection.getAccepts(); - if ( accepts != null && accepts.length == 0 ) - { + if (accepts != null && accepts.length == 0) { System.out.println("Accepts: none specified"); - } - else - { - for (String s : accepts) - { + } else { + for (String s : accepts) { System.out.println("Accepts: " + s); } } - List acceptsPackaging = collection.getAcceptPackaging(); + List acceptsPackaging = collection.getAcceptPackaging(); - StringBuilder acceptPackagingList = new StringBuilder(); - for (Iterator i = acceptsPackaging.iterator();i.hasNext();) - { + StringBuilder acceptPackagingList = new StringBuilder(); + for (Iterator i = acceptsPackaging.iterator(); i.hasNext(); ) { SwordAcceptPackaging accept = (SwordAcceptPackaging) i.next(); - acceptPackagingList.append(accept.getContent()).append(" (").append(accept.getQualityValue()).append("), ").toString(); - } + acceptPackagingList.append(accept.getContent()).append(" (").append(accept.getQualityValue()) + .append("), ").toString(); + } - System.out.println("Accepts Packaging: "+ acceptPackagingList.toString()); + System.out.println("Accepts Packaging: " + acceptPackagingList.toString()); } System.out.println("+ End of Collections ---"); } } } - + /** - * Perform a post. If any of the destination URL, the filename and the - * filetype are missing, the user will be prompted to enter the values. - * - * @throws SWORDClientException if there is an error processing the post for a requested - * destination. - * @throws MalformedURLException if there is an error with the URL for the post. + * Perform a post. If any of the destination URL, the filename and the + * filetype are missing, the user will be prompted to enter the values. + * + * @throws SWORDClientException if there is an error processing the post for a requested + * destination. + * @throws MalformedURLException if there is an error with the URL for the post. */ private void post() - throws SWORDClientException, MalformedURLException - { + throws SWORDClientException, MalformedURLException { String url = options.getHref(); - if ( url == null ) - { + if (url == null) { url = readLine("Please enter the URL for the deposit: "); } initialiseServer(url, options.getUsername(), options.getPassword()); String file = options.getFilename(); - if ( file == null ) - { + if (file == null) { file = readLine("Please enter the filename to deposit: "); } - String type = options.getFiletype(); - if ( type == null ) - { + String type = options.getFiletype(); + if (type == null) { type = readLine("Please enter the file type, e.g. application/zip: "); } - PostMessage message = new PostMessage(); + PostMessage message = new PostMessage(); message.setFilepath(file); message.setDestination(url); message.setFiletype(type); @@ -234,72 +207,65 @@ public class CmdClient implements ClientType message.setOnBehalfOf(options.getOnBehalfOf()); message.setChecksumError(options.getChecksumError()); message.setUserAgent(ClientConstants.SERVICE_NAME); - + processPost(message); } /** - * Perform a multi-post. Iterate over the list of -dest arguments in the command line - * options. For each -dest argument, attempt to post the file to the server. - * - * @throws SWORDClientException if there is an error processing the post for a requested - * destination. - * @throws MalformedURLException if there is an error with the URL for the post. + * Perform a multi-post. Iterate over the list of -dest arguments in the command line + * options. For each -dest argument, attempt to post the file to the server. + * + * @throws SWORDClientException if there is an error processing the post for a requested + * destination. + * @throws MalformedURLException if there is an error with the URL for the post. */ private void multiPost() - throws SWORDClientException, MalformedURLException - { - // request the common information + throws SWORDClientException, MalformedURLException { + // request the common information String file = options.getFilename(); - if ( file == null ) - { + if (file == null) { file = readLine("Please enter the filename to deposit: "); } - String type = options.getFiletype(); - if ( type == null ) - { + String type = options.getFiletype(); + if (type == null) { type = readLine("Please enter the file type, e.g. application/zip: "); } - + // process this information for each of the specified destinations PostDestination destination; - String url = null; - + String url = null; + Iterator iterator = options.getMultiPost(); - while ( iterator.hasNext() ) - { - destination = iterator.next(); - url = destination.getUrl(); - initialiseServer(url, destination.getUsername(), destination.getPassword()); - - String onBehalfOf = destination.getOnBehalfOf(); - if ( onBehalfOf == null ) - { - onBehalfOf = ""; - } - else - { - onBehalfOf = " on behalf of: " + onBehalfOf; - } - - System.out.println("Sending file to: " + url + " for: " + destination.getUsername() + - onBehalfOf ); - PostMessage message = new PostMessage(); - message.setFilepath(file); - message.setDestination(url); - message.setFiletype(type); - message.setUseMD5(options.isMd5()); - message.setVerbose(options.isVerbose()); - message.setNoOp(options.isNoOp()); - message.setFormatNamespace(options.getFormatNamespace()); - message.setOnBehalfOf(destination.getOnBehalfOf()); - message.setChecksumError(options.getChecksumError()); - message.setUserAgent(ClientConstants.SERVICE_NAME); - - processPost(message); + while (iterator.hasNext()) { + destination = iterator.next(); + url = destination.getUrl(); + initialiseServer(url, destination.getUsername(), destination.getPassword()); + + String onBehalfOf = destination.getOnBehalfOf(); + if (onBehalfOf == null) { + onBehalfOf = ""; + } else { + onBehalfOf = " on behalf of: " + onBehalfOf; + } + + System.out.println("Sending file to: " + url + " for: " + destination.getUsername() + + onBehalfOf); + PostMessage message = new PostMessage(); + message.setFilepath(file); + message.setDestination(url); + message.setFiletype(type); + message.setUseMD5(options.isMd5()); + message.setVerbose(options.isVerbose()); + message.setNoOp(options.isNoOp()); + message.setFormatNamespace(options.getFormatNamespace()); + message.setOnBehalfOf(destination.getOnBehalfOf()); + message.setChecksumError(options.getChecksumError()); + message.setUserAgent(ClientConstants.SERVICE_NAME); + + processPost(message); } - + } /** @@ -308,165 +274,133 @@ public class CmdClient implements ClientType * response. * * @param message The post options. - * * @throws SWORDClientException if there is an error accessing the - * post response. + * post response. */ protected void processPost(PostMessage message) - throws SWORDClientException - { + throws SWORDClientException { DepositResponse response = client.postFile(message); System.out.println("The status is: " + client.getStatus()); - - if ( response != null) - { + + if (response != null) { log.debug("message is: " + response.marshall()); - - // iterate over the data and output it - SWORDEntry entry = response.getEntry(); - + + // iterate over the data and output it + SWORDEntry entry = response.getEntry(); + System.out.println("Id: " + entry.getId()); - Title title = entry.getTitle(); - if ( title != null ) - { - System.out.print("Title: " + title.getContent() + " type: " ); - if ( title.getType() != null ) - { + Title title = entry.getTitle(); + if (title != null) { + System.out.print("Title: " + title.getContent() + " type: "); + if (title.getType() != null) { System.out.println(title.getType().toString()); - } - else - { + } else { System.out.println("Not specified."); } } // process the authors Iterator authors = entry.getAuthors(); - while ( authors.hasNext() ) - { - Author author = authors.next(); - System.out.println("Author - " + author.toString() ); + while (authors.hasNext()) { + Author author = authors.next(); + System.out.println("Author - " + author.toString()); } - + Iterator categories = entry.getCategories(); - while ( categories.hasNext() ) - { - System.out.println("Category: " + categories.next()); + while (categories.hasNext()) { + System.out.println("Category: " + categories.next()); } - + Iterator contributors = entry.getContributors(); - while ( contributors.hasNext() ) - { - Contributor contributor = contributors.next(); - System.out.println("Contributor - " + contributor.toString()); + while (contributors.hasNext()) { + Contributor contributor = contributors.next(); + System.out.println("Contributor - " + contributor.toString()); } - + Iterator links = entry.getLinks(); - while ( links.hasNext() ) - { - Link link = links.next(); - System.out.println(link.toString()); + while (links.hasNext()) { + Link link = links.next(); + System.out.println(link.toString()); } Generator generator = entry.getGenerator(); - if ( generator != null ) - { + if (generator != null) { System.out.println("Generator - " + generator.toString()); - } - else - { + } else { System.out.println("There is no generator"); } - System.out.println( "Published: " + entry.getPublished()); - + System.out.println("Published: " + entry.getPublished()); + Content content = entry.getContent(); - if ( content != null ) - { - System.out.println(content.toString()); + if (content != null) { + System.out.println(content.toString()); + } else { + System.out.println("There is no content element."); } - else - { - System.out.println("There is no content element."); - } - + Rights right = entry.getRights(); - if ( right != null ) - { - System.out.println(right.toString()); + if (right != null) { + System.out.println(right.toString()); + } else { + System.out.println("There is no right element."); } - else - { - System.out.println("There is no right element."); - } - + Summary summary = entry.getSummary(); - if ( summary != null ) - { - - System.out.println(summary.toString()); + if (summary != null) { + + System.out.println(summary.toString()); + } else { + System.out.println("There is no summary element."); } - else - { - System.out.println("There is no summary element."); - } - - System.out.println("Update: " + entry.getUpdated() ); + + System.out.println("Update: " + entry.getUpdated()); System.out.println("Published: " + entry.getPublished()); System.out.println("Verbose Description: " + entry.getVerboseDescription()); System.out.println("Treatment: " + entry.getTreatment()); System.out.println("Packaging: " + entry.getPackaging()); - if ( entry.isNoOpSet() ) - { + if (entry.isNoOpSet()) { System.out.println("NoOp: " + entry.isNoOp()); } - } - else - { + } else { System.out.println("No valid Entry document was received from the server"); - } + } } - + /** - * Initialise the server. Set the server that will be connected to and - * initialise any username and password. If the username and password are - * either null or contain empty strings, the user credentials will be cleared. - * - * @param location The location to connect to. This is a URL, of the format, - * http://a.host.com:port/. The host name and port number will - * be extracted. If the port is not specified, a default port of - * 80 will be used. - * @param username The username. If this is null or an empty string, the basic - * credentials will be cleared. - * @param password The password. If this is null or an empty string, the basic - * credentials will be cleared. - * - * @throws MalformedURLException if there is an error processing the URL. + * Initialise the server. Set the server that will be connected to and + * initialise any username and password. If the username and password are + * either null or contain empty strings, the user credentials will be cleared. + * + * @param location The location to connect to. This is a URL, of the format, + * http://a.host.com:port/. The host name and port number will + * be extracted. If the port is not specified, a default port of + * 80 will be used. + * @param username The username. If this is null or an empty string, the basic + * credentials will be cleared. + * @param password The password. If this is null or an empty string, the basic + * credentials will be cleared. + * @throws MalformedURLException if there is an error processing the URL. */ private void initialiseServer(String location, String username, String password) - throws MalformedURLException - { + throws MalformedURLException { URL url = new URL(location); int port = url.getPort(); - if ( port == -1 ) - { + if (port == -1) { port = 80; } client.setServer(url.getHost(), port); - if (username != null && username.length() > 0 && - password != null && password.length() > 0 ) - { + if (username != null && username.length() > 0 && + password != null && password.length() > 0) { log.info("Setting the username/password: " + username + " " - + password); + + password); client.setCredentials(username, password); - } - else - { + } else { client.clearCredentials(); } } @@ -474,22 +408,19 @@ public class CmdClient implements ClientType /** * Read a line of text from System.in. If there is an error reading * from the input, the prompt will be redisplayed and the user asked - * to try again. - * - * @param prompt The prompt to display before the prompt. + * to try again. + * + * @param prompt The prompt to display before the prompt. * @return The string that is read from the line. */ - private String readLine( String prompt ) - { + private String readLine(String prompt) { BufferedReader reader = new BufferedReader(new InputStreamReader( - System.in)); + System.in)); String result = null; boolean ok = false; - while (!ok) - { - try - { + while (!ok) { + try { System.out.print(prompt); System.out.flush(); result = reader.readLine(); @@ -502,14 +433,13 @@ public class CmdClient implements ClientType return result; } - /** - * Run the client and process the specified options. - * - * @param options The command line options. - */ - public void run( ClientOptions options ) - { - this.options = options; - process( ); + /** + * Run the client and process the specified options. + * + * @param options The command line options. + */ + public void run(ClientOptions options) { + this.options = options; + process(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/DebugOutputStream.java b/dspace-sword/src/main/java/org/purl/sword/client/DebugOutputStream.java index 1a66df46f2..dfd8b6c60f 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/DebugOutputStream.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/DebugOutputStream.java @@ -11,38 +11,34 @@ import java.io.IOException; import java.io.OutputStream; /** - * A stream that will write any output to the specified panel. - * + * A stream that will write any output to the specified panel. + * * @author Neil Taylor */ -public class DebugOutputStream extends OutputStream -{ +public class DebugOutputStream extends OutputStream { /** - * Panel that will display the messages. + * Panel that will display the messages. */ - private MessageOutputPanel panel; - + private MessageOutputPanel panel; + /** - * Create a new instance and specify the panel that will receive the output. - * - * @param panel The panel. + * Create a new instance and specify the panel that will receive the output. + * + * @param panel The panel. */ - public DebugOutputStream(MessageOutputPanel panel) - { - this.panel = panel; + public DebugOutputStream(MessageOutputPanel panel) { + this.panel = panel; } - + /** - * Override the write method from OutputStream. Capture the char and - * send it to the panel. - * - * @param arg0 The output character, expressed as an integer. - * + * Override the write method from OutputStream. Capture the char and + * send it to the panel. + * + * @param arg0 The output character, expressed as an integer. * @see java.io.OutputStream#write(int) */ - public void write(int arg0) throws IOException - { - panel.addCharacter(Character.valueOf((char)arg0)); + public void write(int arg0) throws IOException { + panel.addCharacter(Character.valueOf((char) arg0)); } - + } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/MessageOutputPanel.java b/dspace-sword/src/main/java/org/purl/sword/client/MessageOutputPanel.java index 51145772dc..e703f79ccc 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/MessageOutputPanel.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/MessageOutputPanel.java @@ -5,40 +5,41 @@ * * http://www.dspace.org/license/ */ + /** * Copyright (c) 2007, Aberystwyth University * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * + * 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 + * + * - 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 + * + * - 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 of the Centre for Advanced Software and - * Intelligent Systems (CASIS) nor the names of its - * contributors may be used to endorse or promote products derived + * + * - Neither the name of the Centre for Advanced Software and + * Intelligent Systems (CASIS) 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 - * OWNER 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER 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. */ package org.purl.sword.client; @@ -48,45 +49,42 @@ import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; - import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; /** - * Panel to display output messages. Text or characters can be sent to the - * panel for display. The panel also includes a button to clear any - * text that is currently displayed. - * + * Panel to display output messages. Text or characters can be sent to the + * panel for display. The panel also includes a button to clear any + * text that is currently displayed. + * * @author Neil Taylor */ public class MessageOutputPanel extends JPanel -implements ActionListener -{ - + implements ActionListener { + /** - * The text area that displays the messages. + * The text area that displays the messages. */ - private JTextArea messages = null; - + private JTextArea messages = null; + /** * Create a new instance and initialise the panel. */ - public MessageOutputPanel() - { + public MessageOutputPanel() { super(); - + setLayout(new GridBagLayout()); - + messages = new JTextArea(); - - JScrollPane detailsPane = new JScrollPane(messages, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + JScrollPane detailsPane = new JScrollPane(messages, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); JButton clearButton = new JButton("Clear"); clearButton.addActionListener(this); - + //add components and set constraints //dpc = details pane constraint GridBagConstraints dpc = new GridBagConstraints(); @@ -96,48 +94,45 @@ implements ActionListener dpc.weightx = 0.75; dpc.weighty = 0.45; dpc.gridwidth = 2; - dpc.insets = new Insets(5,5,5,5); - add(detailsPane,dpc); - + dpc.insets = new Insets(5, 5, 5, 5); + add(detailsPane, dpc); + //cbc = clear button constraint GridBagConstraints cbc = new GridBagConstraints(); cbc.gridx = 1; cbc.gridy = 1; - cbc.insets = new Insets(0,0,5,5); + cbc.insets = new Insets(0, 0, 5, 5); cbc.anchor = GridBagConstraints.LINE_END; - add(clearButton,cbc); - + add(clearButton, cbc); + } - + /** - * Add a message to the text area. The message will be added with a carriage return. - * - * @param message The message. + * Add a message to the text area. The message will be added with a carriage return. + * + * @param message The message. */ - public void addMessage(String message) - { + public void addMessage(String message) { messages.insert(message + "\n", messages.getDocument().getLength()); } - + /** - * Add a single character to the text area. - * - * @param character The character. + * Add a single character to the text area. + * + * @param character The character. */ - public void addCharacter(Character character) - { + public void addCharacter(Character character) { messages.insert(character.toString(), messages.getDocument().getLength()); } - + /** - * Clear the text from the display. - * - * @param arg0 The action event. - * + * Clear the text from the display. + * + * @param arg0 The action event. + * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ - public void actionPerformed(ActionEvent arg0) - { + public void actionPerformed(ActionEvent arg0) { messages.setText(""); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/PostDestination.java b/dspace-sword/src/main/java/org/purl/sword/client/PostDestination.java index ae25b818d1..3124f02b45 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/PostDestination.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/PostDestination.java @@ -8,147 +8,133 @@ package org.purl.sword.client; /** - * Details for a destination. This is used to represent a destination. If - * expressed as a string, the destination looks like: + * Details for a destination. This is used to represent a destination. If + * expressed as a string, the destination looks like: *
      * <user>[<onBehalfOf>]:<password>@<url>
      * 
    - * + * * @author Neil Taylor */ -public class PostDestination -{ +public class PostDestination { /** - * URL for the post destination. + * URL for the post destination. */ - private String url; - - /** - * The username. + private String url; + + /** + * The username. */ private String username; - + /** - * The password. + * The password. */ private String password; - + /** - * The onBehalfOf ID. + * The onBehalfOf ID. */ private String onBehalfOf; - + /** - * Create a new instance. + * Create a new instance. */ - public PostDestination() - { - // No-Op + public PostDestination() { + // No-Op } - + /** - * Create a new instance. - * - * @param url The url. - * @param username The username. - * @param password The password. - * @param onBehalfOf The onBehalfOf id. + * Create a new instance. + * + * @param url The url. + * @param username The username. + * @param password The password. + * @param onBehalfOf The onBehalfOf id. */ - public PostDestination(String url, String username, String password, String onBehalfOf) - { - this.url = url; - this.username = username; - this.password = password; - this.onBehalfOf = onBehalfOf; + public PostDestination(String url, String username, String password, String onBehalfOf) { + this.url = url; + this.username = username; + this.password = password; + this.onBehalfOf = onBehalfOf; } - + /** * @return the url */ - public String getUrl() - { - return url; + public String getUrl() { + return url; } - + /** * @param url the url to set */ - public void setUrl(String url) - { - this.url = url; + public void setUrl(String url) { + this.url = url; } - + /** * @return the username */ - public String getUsername() - { - return username; + public String getUsername() { + return username; } - + /** * @param username the username to set */ - public void setUsername(String username) - { - this.username = username; + public void setUsername(String username) { + this.username = username; } - + /** * @return the password */ - public String getPassword() - { - return password; + public String getPassword() { + return password; } - + /** * @param password the password to set */ - public void setPassword(String password) - { - this.password = password; + public void setPassword(String password) { + this.password = password; } - + /** * @return the onBehalfOf */ - public String getOnBehalfOf() - { - return onBehalfOf; + public String getOnBehalfOf() { + return onBehalfOf; } - + /** * @param onBehalfOf the onBehalfOf to set */ - public void setOnBehalfOf(String onBehalfOf) - { - this.onBehalfOf = onBehalfOf; + public void setOnBehalfOf(String onBehalfOf) { + this.onBehalfOf = onBehalfOf; } - - /** - * Create a string representation of this object. - * - * @return The string. + + /** + * Create a string representation of this object. + * + * @return The string. */ - public String toString() - { - StringBuffer buffer = new StringBuffer(); - buffer.append(username); - if ( onBehalfOf != null ) - { - buffer.append("["); - buffer.append(onBehalfOf); - buffer.append("]"); - } - - if ( password != null ) - { - buffer.append(":******"); - } - buffer.append("@"); - buffer.append(url); - - return buffer.toString(); + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(username); + if (onBehalfOf != null) { + buffer.append("["); + buffer.append(onBehalfOf); + buffer.append("]"); + } + + if (password != null) { + buffer.append(":******"); + } + buffer.append("@"); + buffer.append(url); + + return buffer.toString(); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/PostDialog.java b/dspace-sword/src/main/java/org/purl/sword/client/PostDialog.java index f10a42c912..84815b327e 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/PostDialog.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/PostDialog.java @@ -5,40 +5,41 @@ * * http://www.dspace.org/license/ */ + /** * Copyright (c) 2007, Aberystwyth University * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * + * 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 + * + * - 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 + * + * - 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 of the Centre for Advanced Software and - * Intelligent Systems (CASIS) nor the names of its - * contributors may be used to endorse or promote products derived + * + * - Neither the name of the Centre for Advanced Software and + * Intelligent Systems (CASIS) 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 - * OWNER 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER 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. */ package org.purl.sword.client; @@ -47,7 +48,6 @@ import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; - import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -63,587 +63,536 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** - * Dialog for users to enter details of post destinations. - * + * Dialog for users to enter details of post destinations. + * * @author Neil Taylor */ -public class PostDialog -implements ActionListener, ChangeListener -{ +public class PostDialog + implements ActionListener, ChangeListener { /** - * label for the browse command. + * label for the browse command. */ - protected static final String BROWSE = "browse"; - + protected static final String BROWSE = "browse"; + /** - * label for the add command. + * label for the add command. */ protected static final String ADD = "add"; - + /** - * label for the edit command. + * label for the edit command. */ protected static final String EDIT = "edit"; - + /** - * label for the delete command. + * label for the delete command. */ protected static final String DELETE = "delete"; - + /** - * label for the clear command. + * label for the clear command. */ protected static final String CLEAR = "clear"; - + /** - * Username combo box. + * Username combo box. */ private SWORDComboBox username; - + /** - * Post Location combo box. + * Post Location combo box. */ private SWORDComboBox postLocation; - + /** - * Password field. + * Password field. */ private JPasswordField password; - + /** - * The file combo box. + * The file combo box. */ private SWORDComboBox file; - + /** - * The filetype combo box. + * The filetype combo box. */ private SWORDComboBox fileType; - + /** - * The onBehalfOf combo box. + * The onBehalfOf combo box. */ private SWORDComboBox onBehalfOf; - + /** - * The md5 checkbox. + * The md5 checkbox. */ private JCheckBox useMD5; - + /** * The corruptMD5 checkbox. */ private JCheckBox corruptMD5; - + /** * The corruptRequest checkbox. */ private JCheckBox corruptRequest; - + /** - * The useNoOp checkbox. + * The useNoOp checkbox. */ private JCheckBox useNoOp; - + /** - * The verbose checkbox. + * The verbose checkbox. */ private JCheckBox useVerbose; - + /** - * The format namespace combo box. + * The format namespace combo box. */ private SWORDComboBox formatNamespace; - + /** - * The list of post destinations. + * The list of post destinations. */ private JList list; - + /** * The parent frame for the dialog that is displayed. */ - private JFrame parentFrame = null; - + private JFrame parentFrame = null; + /** * Array that lists the labels for the buttons on the panel. */ - private static Object[] options = {"Post File", "Cancel" }; - + private static Object[] options = {"Post File", "Cancel"}; + /** - * The panel that holds the controls to show. + * The panel that holds the controls to show. */ - private JPanel controls = null; - + private JPanel controls = null; + /** - * + * * @param parentFrame the parent of this dialog. */ - public PostDialog(JFrame parentFrame) - { - this.parentFrame = parentFrame; - controls = createControls(); + public PostDialog(JFrame parentFrame) { + this.parentFrame = parentFrame; + controls = createControls(); } - + /** - * Show the dialog with ok and cancel options. - * @return The return value from displaying JOptionPane. Either + * Show the dialog with ok and cancel options. + * @return The return value from displaying JOptionPane. Either * JOptionPane.OK_OPTION or JOptionPane.CANCEL_OPTION. */ - public int show( ) - { - int result = JOptionPane.showOptionDialog(parentFrame, - controls, - "Post Document", - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE, - null, - options, - null); - - if ( result == JOptionPane.OK_OPTION ) - { - // update the combo boxes with the values - username.updateList(); - file.updateList(); - fileType.updateList(); - onBehalfOf.updateList(); - formatNamespace.updateList(); - } - - return result; + public int show() { + int result = JOptionPane.showOptionDialog(parentFrame, + controls, + "Post Document", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.PLAIN_MESSAGE, + null, + options, + null); + + if (result == JOptionPane.OK_OPTION) { + // update the combo boxes with the values + username.updateList(); + file.updateList(); + fileType.updateList(); + onBehalfOf.updateList(); + formatNamespace.updateList(); + } + + return result; } - + /** - * Create the controls for the main panel. - * - * @return The panel. + * Create the controls for the main panel. + * + * @return The panel. */ - protected final JPanel createControls( ) - { - file = new SWORDComboBox(); - JPanel filePanel = new JPanel(new BorderLayout()); - filePanel.add(file, BorderLayout.CENTER); - JButton browse = new JButton("Browse..."); - browse.setActionCommand(BROWSE); - browse.addActionListener(this); - - filePanel.add(browse, BorderLayout.SOUTH); - - fileType = new SWORDComboBox(); - String type = "application/zip"; - fileType.addItem(type); - fileType.setSelectedItem(type); - - // controls that will be used in the second dialog - postLocation = new SWORDComboBox(); - username = new SWORDComboBox(); - password = new JPasswordField(); - onBehalfOf = new SWORDComboBox(); - - - useMD5 = new JCheckBox(); - useMD5.addChangeListener(this); - corruptMD5 = new JCheckBox(); - corruptRequest = new JCheckBox(); - useNoOp = new JCheckBox(); - useVerbose = new JCheckBox(); - formatNamespace = new SWORDComboBox(); - - JLabel fileLabel = new JLabel("File:", JLabel.TRAILING); - JLabel fileTypeLabel = new JLabel("File Type:", JLabel.TRAILING); - JLabel useMD5Label = new JLabel("Use MD5:", JLabel.TRAILING); - JLabel corruptMD5Label = new JLabel("Corrupt MD5:", JLabel.TRAILING); - JLabel corruptRequestLabel = new JLabel("Corrupt Request:", JLabel.TRAILING); - //JLabel corruptMD5Label = new JLabel("Corrupt MD5:", JLabel.TRAILING); - JLabel useNoOpLabel = new JLabel("Use noOp:", JLabel.TRAILING); - JLabel useVerboseLabel = new JLabel("Use verbose:", JLabel.TRAILING); - JLabel formatNamespaceLabel = new JLabel("X-Packaging:", JLabel.TRAILING); - JLabel userAgentLabel = new JLabel("User Agent:", JLabel.TRAILING); - JLabel userAgentNameLabel = new JLabel(ClientConstants.SERVICE_NAME, JLabel.LEADING); - - SWORDFormPanel panel = new SWORDFormPanel(); - panel.addFirstRow(new JLabel("Please enter the details for the post operation")); - - JPanel destinations = createDestinationsPanel(); - - panel.addRow(new JLabel("Destinations:"), destinations); - panel.addRow(fileLabel, filePanel); - panel.addRow(fileTypeLabel, fileType); - panel.addRow(useMD5Label, useMD5); - panel.addRow(corruptMD5Label, corruptMD5); - panel.addRow(corruptRequestLabel, corruptRequest); - panel.addRow(useNoOpLabel, useNoOp); - panel.addRow(useVerboseLabel, useVerbose); - panel.addRow(formatNamespaceLabel, formatNamespace); - panel.addRow(userAgentLabel, userAgentNameLabel); - - return panel; + protected final JPanel createControls() { + file = new SWORDComboBox(); + JPanel filePanel = new JPanel(new BorderLayout()); + filePanel.add(file, BorderLayout.CENTER); + JButton browse = new JButton("Browse..."); + browse.setActionCommand(BROWSE); + browse.addActionListener(this); + + filePanel.add(browse, BorderLayout.SOUTH); + + fileType = new SWORDComboBox(); + String type = "application/zip"; + fileType.addItem(type); + fileType.setSelectedItem(type); + + // controls that will be used in the second dialog + postLocation = new SWORDComboBox(); + username = new SWORDComboBox(); + password = new JPasswordField(); + onBehalfOf = new SWORDComboBox(); + + + useMD5 = new JCheckBox(); + useMD5.addChangeListener(this); + corruptMD5 = new JCheckBox(); + corruptRequest = new JCheckBox(); + useNoOp = new JCheckBox(); + useVerbose = new JCheckBox(); + formatNamespace = new SWORDComboBox(); + + JLabel fileLabel = new JLabel("File:", JLabel.TRAILING); + JLabel fileTypeLabel = new JLabel("File Type:", JLabel.TRAILING); + JLabel useMD5Label = new JLabel("Use MD5:", JLabel.TRAILING); + JLabel corruptMD5Label = new JLabel("Corrupt MD5:", JLabel.TRAILING); + JLabel corruptRequestLabel = new JLabel("Corrupt Request:", JLabel.TRAILING); + //JLabel corruptMD5Label = new JLabel("Corrupt MD5:", JLabel.TRAILING); + JLabel useNoOpLabel = new JLabel("Use noOp:", JLabel.TRAILING); + JLabel useVerboseLabel = new JLabel("Use verbose:", JLabel.TRAILING); + JLabel formatNamespaceLabel = new JLabel("X-Packaging:", JLabel.TRAILING); + JLabel userAgentLabel = new JLabel("User Agent:", JLabel.TRAILING); + JLabel userAgentNameLabel = new JLabel(ClientConstants.SERVICE_NAME, JLabel.LEADING); + + SWORDFormPanel panel = new SWORDFormPanel(); + panel.addFirstRow(new JLabel("Please enter the details for the post operation")); + + JPanel destinations = createDestinationsPanel(); + + panel.addRow(new JLabel("Destinations:"), destinations); + panel.addRow(fileLabel, filePanel); + panel.addRow(fileTypeLabel, fileType); + panel.addRow(useMD5Label, useMD5); + panel.addRow(corruptMD5Label, corruptMD5); + panel.addRow(corruptRequestLabel, corruptRequest); + panel.addRow(useNoOpLabel, useNoOp); + panel.addRow(useVerboseLabel, useVerbose); + panel.addRow(formatNamespaceLabel, formatNamespace); + panel.addRow(userAgentLabel, userAgentNameLabel); + + return panel; } - + /** * Create the destinations panel. This contains a list and four buttons - * to operate on values in the list. - * - * @return The panel containing the controls. + * to operate on values in the list. + * + * @return The panel containing the controls. */ - protected JPanel createDestinationsPanel() - { - DefaultListModel model = new DefaultListModel(); - list = new JList(model); - JScrollPane jsp = new JScrollPane(list); - - JPanel destinations = new JPanel(new BorderLayout()); - destinations.add(jsp, BorderLayout.CENTER); - JPanel destinationButtons = new JPanel(); - - JButton addButton = new JButton("Add"); - addButton.setActionCommand(ADD); - addButton.addActionListener(this); - - JButton editButton = new JButton("Edit"); - editButton.setActionCommand(EDIT); - editButton.addActionListener(this); - - JButton deleteButton = new JButton("Delete"); - deleteButton.setActionCommand(DELETE); - deleteButton.addActionListener(this); - - JButton clearButton = new JButton("Clear"); - clearButton.setActionCommand(CLEAR); - clearButton.addActionListener(this); - - destinationButtons.add(addButton); - destinationButtons.add(editButton); - destinationButtons.add(deleteButton); - destinationButtons.add(clearButton); - - destinations.add(destinationButtons, BorderLayout.SOUTH); - - return destinations; + protected JPanel createDestinationsPanel() { + DefaultListModel model = new DefaultListModel(); + list = new JList(model); + JScrollPane jsp = new JScrollPane(list); + + JPanel destinations = new JPanel(new BorderLayout()); + destinations.add(jsp, BorderLayout.CENTER); + JPanel destinationButtons = new JPanel(); + + JButton addButton = new JButton("Add"); + addButton.setActionCommand(ADD); + addButton.addActionListener(this); + + JButton editButton = new JButton("Edit"); + editButton.setActionCommand(EDIT); + editButton.addActionListener(this); + + JButton deleteButton = new JButton("Delete"); + deleteButton.setActionCommand(DELETE); + deleteButton.addActionListener(this); + + JButton clearButton = new JButton("Clear"); + clearButton.setActionCommand(CLEAR); + clearButton.addActionListener(this); + + destinationButtons.add(addButton); + destinationButtons.add(editButton); + destinationButtons.add(deleteButton); + destinationButtons.add(clearButton); + + destinations.add(destinationButtons, BorderLayout.SOUTH); + + return destinations; } - + /** - * Handle the button click to select a file to upload. + * Handle the button click to select a file to upload. */ - public void actionPerformed(ActionEvent evt) - { - String cmd = evt.getActionCommand(); - - if ( BROWSE.equals(cmd) ) - { - JFileChooser chooser = new JFileChooser(); - chooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); - int returnVal = chooser.showOpenDialog(parentFrame); - if (returnVal == JFileChooser.APPROVE_OPTION) { - file.setSelectedItem(chooser.getSelectedFile().getAbsolutePath()); - } - } - else if ( ADD.equals(cmd)) - { - PostDestination dest = showDestinationDialog(null); - if ( dest != null ) - { - ((DefaultListModel)list.getModel()).addElement(dest); - } - } - else if ( EDIT.equals(cmd)) - { - PostDestination dest = (PostDestination)list.getSelectedValue(); - if ( dest != null ) - { - showDestinationDialog(dest); - list.repaint(); - } - } - else if ( DELETE.equals(cmd)) - { - if ( list.getSelectedIndex() != -1 ) - { - ((DefaultListModel)list.getModel()).removeElementAt(list.getSelectedIndex()); - } - } - else if ( CLEAR.equals(cmd)) - { - ((DefaultListModel)list.getModel()).clear(); - } + public void actionPerformed(ActionEvent evt) { + String cmd = evt.getActionCommand(); + + if (BROWSE.equals(cmd)) { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); + int returnVal = chooser.showOpenDialog(parentFrame); + if (returnVal == JFileChooser.APPROVE_OPTION) { + file.setSelectedItem(chooser.getSelectedFile().getAbsolutePath()); + } + } else if (ADD.equals(cmd)) { + PostDestination dest = showDestinationDialog(null); + if (dest != null) { + ((DefaultListModel) list.getModel()).addElement(dest); + } + } else if (EDIT.equals(cmd)) { + PostDestination dest = (PostDestination) list.getSelectedValue(); + if (dest != null) { + showDestinationDialog(dest); + list.repaint(); + } + } else if (DELETE.equals(cmd)) { + if (list.getSelectedIndex() != -1) { + ((DefaultListModel) list.getModel()).removeElementAt(list.getSelectedIndex()); + } + } else if (CLEAR.equals(cmd)) { + ((DefaultListModel) list.getModel()).clear(); + } } - + /** - * Show the destination dialog. This is used to enter the URL, - * username, password and onBehalfOf name for a destination. - * + * Show the destination dialog. This is used to enter the URL, + * username, password and onBehalfOf name for a destination. + * * @param destination The post destination. If this is not null, the values - * in the object are used to set the current values - * in the dialog controls. - * @return The post destination value. + * in the object are used to set the current values + * in the dialog controls. + * @return The post destination value. */ - public PostDestination showDestinationDialog( PostDestination destination ) - { - SWORDFormPanel panel = new SWORDFormPanel(); - panel.addFirstRow(new JLabel("Please enter the details for the post operation")); - - JLabel postLabel = new JLabel("Post Location:", JLabel.TRAILING); - JLabel userLabel = new JLabel("Username:", JLabel.TRAILING); - JLabel passwordLabel = new JLabel("Password:", JLabel.TRAILING); - JLabel onBehalfOfLabel = new JLabel("On Behalf Of:", JLabel.TRAILING); - - panel.addRow(postLabel, postLocation); - panel.addRow(userLabel, username); - panel.addRow(passwordLabel, password); - panel.addRow(onBehalfOfLabel, onBehalfOf); - - if ( destination != null ) - { - postLocation.insertItem(destination.getUrl()); - username.insertItem(destination.getUsername()); - password.setText(destination.getPassword()); - onBehalfOf.insertItem(destination.getOnBehalfOf()); - } - else - { - String s = ""; - postLocation.insertItem(s); - //postLocation.setSelectedItem(s); - username.insertItem(s); - username.setSelectedItem(s); - password.setText(s); - onBehalfOf.insertItem(s); - onBehalfOf.setSelectedItem(s); - } - - int result = JOptionPane.showOptionDialog(null, - panel, - "Destination", - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE, - null, - new String[] { "OK", "Cancel" }, - null); - - if ( result == JOptionPane.OK_OPTION ) - { - postLocation.updateList(); - username.updateList(); - onBehalfOf.updateList(); - - if ( destination == null ) - { - destination = new PostDestination(); - } - - destination.setUrl(postLocation.getText()); - destination.setUsername(username.getText()); - String pass = new String(password.getPassword()); - if ( pass.length() > 0 ) - { - destination.setPassword(pass); - } - else - { - destination.setPassword(null); - } - - String obo = onBehalfOf.getText(); - if ( obo.length() > 0 ) - { - destination.setOnBehalfOf(onBehalfOf.getText()); - } - else - { - destination.setOnBehalfOf(null); - } - - } - - return destination; + public PostDestination showDestinationDialog(PostDestination destination) { + SWORDFormPanel panel = new SWORDFormPanel(); + panel.addFirstRow(new JLabel("Please enter the details for the post operation")); + + JLabel postLabel = new JLabel("Post Location:", JLabel.TRAILING); + JLabel userLabel = new JLabel("Username:", JLabel.TRAILING); + JLabel passwordLabel = new JLabel("Password:", JLabel.TRAILING); + JLabel onBehalfOfLabel = new JLabel("On Behalf Of:", JLabel.TRAILING); + + panel.addRow(postLabel, postLocation); + panel.addRow(userLabel, username); + panel.addRow(passwordLabel, password); + panel.addRow(onBehalfOfLabel, onBehalfOf); + + if (destination != null) { + postLocation.insertItem(destination.getUrl()); + username.insertItem(destination.getUsername()); + password.setText(destination.getPassword()); + onBehalfOf.insertItem(destination.getOnBehalfOf()); + } else { + String s = ""; + postLocation.insertItem(s); + //postLocation.setSelectedItem(s); + username.insertItem(s); + username.setSelectedItem(s); + password.setText(s); + onBehalfOf.insertItem(s); + onBehalfOf.setSelectedItem(s); + } + + int result = JOptionPane.showOptionDialog(null, + panel, + "Destination", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.PLAIN_MESSAGE, + null, + new String[] {"OK", "Cancel"}, + null); + + if (result == JOptionPane.OK_OPTION) { + postLocation.updateList(); + username.updateList(); + onBehalfOf.updateList(); + + if (destination == null) { + destination = new PostDestination(); + } + + destination.setUrl(postLocation.getText()); + destination.setUsername(username.getText()); + String pass = new String(password.getPassword()); + if (pass.length() > 0) { + destination.setPassword(pass); + } else { + destination.setPassword(null); + } + + String obo = onBehalfOf.getText(); + if (obo.length() > 0) { + destination.setOnBehalfOf(onBehalfOf.getText()); + } else { + destination.setOnBehalfOf(null); + } + + } + + return destination; } - + /** - * Get the list of Post Destinations. - * @return The destinations. + * Get the list of Post Destinations. + * @return The destinations. */ - public PostDestination[] getDestinations() - { - DefaultListModel model = (DefaultListModel)list.getModel(); - PostDestination[] destinations = new PostDestination[model.size()]; - for ( int i = 0; i < model.size(); i++) - { - destinations[i] = (PostDestination)model.get(i); - } - return destinations; + public PostDestination[] getDestinations() { + DefaultListModel model = (DefaultListModel) list.getModel(); + PostDestination[] destinations = new PostDestination[model.size()]; + for (int i = 0; i < model.size(); i++) { + destinations[i] = (PostDestination) model.get(i); + } + return destinations; } - + /** - * Get the file details. - * @return The value. + * Get the file details. + * @return The value. */ - public String getFile( ) - { + public String getFile() { return file.getText(); } - + /** - * Get the filetype value. - * @return The value. + * Get the filetype value. + * @return The value. */ - public String getFileType() - { + public String getFileType() { return fileType.getText(); } - + /** - * Get the onBehalfOf value. - * @return The value. + * Get the onBehalfOf value. + * @return The value. */ - public String getOnBehalfOf() - { + public String getOnBehalfOf() { return onBehalfOf.getText(); } - + /** - * Get the format namespace value. - * @return The value. + * Get the format namespace value. + * @return The value. */ - public String getFormatNamespace() - { + public String getFormatNamespace() { return formatNamespace.getText(); } - + /** - * Determine if the MD5 checkbox is selected. - * - * @return True if the MD5 checkbox is selected. + * Determine if the MD5 checkbox is selected. + * + * @return True if the MD5 checkbox is selected. */ - public boolean useMd5() - { + public boolean useMd5() { return useMD5.isSelected(); } - + /** - * Determine if the noOp checkbox is selected. - * - * @return True if the checkbox is selected. + * Determine if the noOp checkbox is selected. + * + * @return True if the checkbox is selected. */ - public boolean useNoOp() - { + public boolean useNoOp() { return useNoOp.isSelected(); } - + /** * Determine if the verbose checkbox is selected. - * - * @return True if the checkbox is selected. + * + * @return True if the checkbox is selected. */ - public boolean useVerbose() - { + public boolean useVerbose() { return useVerbose.isSelected(); } - + /** - * Get the post location. - * @return The post location. + * Get the post location. + * @return The post location. */ - public String getPostLocation() - { + public String getPostLocation() { return postLocation.getText(); } - + /** * Determine if the MD5 hash should be corrupted. * @return True if the corrupt MD5 checkbox is selected. The MD5 checkbox * must also be selected. */ - public boolean corruptMD5() - { + public boolean corruptMD5() { return (corruptMD5.isEnabled() && corruptMD5.isSelected()); } - + /** * Determine if the POST request should be corrupted. * @return True if the corrupt request checkbox is selected. */ - public boolean corruptRequest() - { + public boolean corruptRequest() { return (corruptRequest.isSelected()); } - + /** - * Detect a state change event for the checkbox. - * - * @param evt The event. + * Detect a state change event for the checkbox. + * + * @param evt The event. */ - public void stateChanged(ChangeEvent evt) - { - corruptMD5.setEnabled(useMD5.isSelected()); + public void stateChanged(ChangeEvent evt) { + corruptMD5.setEnabled(useMD5.isSelected()); } - + /** - * Add a list of user ids. - * - * @param users The user ids. + * Add a list of user ids. + * + * @param users The user ids. */ - public void addUserIds(String[] users) - { + public void addUserIds(String[] users) { username.insertItems(users); } - + /** * Add a list of deposit URLs. - * - * @param deposits The URLs. + * + * @param deposits The URLs. */ - public void addDepositUrls(String[] deposits) - { + public void addDepositUrls(String[] deposits) { postLocation.insertItems(deposits); } - + /** - * Add a list of onBehalfOf names. - * - * @param users The names. + * Add a list of onBehalfOf names. + * + * @param users The names. */ - public void addOnBehalfOf(String[] users) - { + public void addOnBehalfOf(String[] users) { onBehalfOf.insertItems(users); } - + /** - * Add the list of formatNamespace strings. - * - * @param namespaces list of strings. + * Add the list of formatNamespace strings. + * + * @param namespaces list of strings. */ - public void addFormatNamespaces(String[] namespaces) - { + public void addFormatNamespaces(String[] namespaces) { formatNamespace.insertItems(namespaces); } - + /** - * Add a list of file types. - * - * @param types The file types. + * Add a list of file types. + * + * @param types The file types. */ - public void addFileTypes(String[] types) - { + public void addFileTypes(String[] types) { fileType.insertItems(types); } - + /** - * Add a list of file names. - * @param files The list of files. + * Add a list of file names. + * @param files The list of files. */ - public void addFiles(String[] files) - { + public void addFiles(String[] files) { file.insertItems(files); } - + /** - * Set the deposit location. - * - * @param location The location. + * Set the deposit location. + * + * @param location The location. */ - public void setDepositLocation(String location) - { + public void setDepositLocation(String location) { postLocation.insertItem(location); postLocation.setSelectedItem(location); } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/PostMessage.java b/dspace-sword/src/main/java/org/purl/sword/client/PostMessage.java index 417cad0dd5..a44f21ce2b 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/PostMessage.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/PostMessage.java @@ -5,40 +5,41 @@ * * http://www.dspace.org/license/ */ + /** * Copyright (c) 2007, Aberystwyth University * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * + * 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 + * + * - 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 + * + * - 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 of the Centre for Advanced Software and - * Intelligent Systems (CASIS) nor the names of its - * contributors may be used to endorse or promote products derived + * + * - Neither the name of the Centre for Advanced Software and + * Intelligent Systems (CASIS) 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 - * OWNER 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER 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. */ package org.purl.sword.client; @@ -47,306 +48,282 @@ import java.io.File; /** * Represents the details of a post to a server. The message holds all of the possible values - * that are to be sent from the client to the server. Not all elements of the message - * must be filled in. Any required fields are defined in the current SWORD specification. - * + * that are to be sent from the client to the server. Not all elements of the message + * must be filled in. Any required fields are defined in the current SWORD specification. + * * @author Neil Taylor */ -public class PostMessage -{ +public class PostMessage { /** - * The local filepath for the file to upload/deposit. + * The local filepath for the file to upload/deposit. */ private String filepath; - + /** - * The URL of the destination server. + * The URL of the destination server. */ - private String destination; - + private String destination; + /** - * The filetype of the package that is to be uploaded. + * The filetype of the package that is to be uploaded. */ private String filetype; - + /** - * The string with the username if the deposit is on behalf of another user. + * The string with the username if the deposit is on behalf of another user. */ - private String onBehalfOf; - + private String onBehalfOf; + /** - * True if an MD5 checksum should be sent with the deposit. + * True if an MD5 checksum should be sent with the deposit. */ private boolean useMD5; - + /** - * True if the deposit is a test and should not result in an actual deposit. + * True if the deposit is a test and should not result in an actual deposit. */ private boolean noOp; - + /** - * True if the verbose operation is requested. + * True if the verbose operation is requested. */ - private boolean verbose; - + private boolean verbose; + /** * The packaging format for the deposit. */ private String packaging; - + /** * True if the deposit should simulate a checksum error. The client should check this * field to determine if a correct MD5 checksum should be sent or whether the checksum should * be modified so that it generates an error at the server. */ private boolean checksumError; - + /** * True if the deposit should corrupt the POST header. The client should check this * field to determine if a correct header should be sent or whether the header should * be modified so that it generates an error at the server. */ private boolean corruptRequest; - - /** - * The Slug header value. + + /** + * The Slug header value. */ - private String slug; - + private String slug; + /** * The user agent name */ private String userAgent; - + /** - * Get the filepath. - * - * @return The filepath. + * Get the filepath. + * + * @return The filepath. */ - public String getFilepath() - { + public String getFilepath() { return filepath; } - + /** - * Get the filename. This is the last element of the filepath - * that has been set in this class. + * Get the filename. This is the last element of the filepath + * that has been set in this class. * * @return filename */ - public String getFilename() - { + public String getFilename() { File file = new File(filepath); - return file.getName(); + return file.getName(); } - - /** - * Set the filepath. - * - * @param filepath The filepath. + + /** + * Set the filepath. + * + * @param filepath The filepath. */ - public void setFilepath(String filepath) - { + public void setFilepath(String filepath) { this.filepath = filepath; } - + /** - * Get the destination collection. - * - * @return The collection. + * Get the destination collection. + * + * @return The collection. */ - public String getDestination() - { + public String getDestination() { return destination; } - + /** - * Set the destination collection. - * - * @param destination The destination. + * Set the destination collection. + * + * @param destination The destination. */ - public void setDestination(String destination) - { + public void setDestination(String destination) { this.destination = destination; } - + /** - * Get the filetype. - * @return The filetype. + * Get the filetype. + * @return The filetype. */ - public String getFiletype() - { + public String getFiletype() { return filetype; } - + /** - * Set the filetype. - * - * @param filetype The filetype. + * Set the filetype. + * + * @param filetype The filetype. */ - public void setFiletype(String filetype) - { + public void setFiletype(String filetype) { this.filetype = filetype; } - - /** - * Get the onBehalfOf value. - * - * @return The value. - */ - public String getOnBehalfOf() - { - return onBehalfOf; - } - + /** - * Set the onBehalfOf value. - * - * @param onBehalfOf The value. - */ - public void setOnBehalfOf(String onBehalfOf) - { - this.onBehalfOf = onBehalfOf; - } - - /** - * Get the MD5 status. - * @return The value. - */ - public boolean isUseMD5() - { - return useMD5; - } - - /** - * Set the md5 state. - * - * @param useMD5 True if the message should use an MD5 checksum. - */ - public void setUseMD5(boolean useMD5) - { - this.useMD5 = useMD5; - } - - /** - * Get the no-op state. - * - * @return The value. - */ - public boolean isNoOp() - { - return noOp; - } - - /** - * Set the no-op state. - * - * @param noOp The no-op. - */ - public void setNoOp(boolean noOp) - { - this.noOp = noOp; - } - - /** - * Get the verbose value. - * - * @return The value. - */ - public boolean isVerbose() - { - return verbose; - } - - /** - * Set the verbose state. - * - * @param verbose True if the post message should send a - * verbose header. - */ - public void setVerbose(boolean verbose) - { - this.verbose = verbose; - } - - /** - * Get the packaging format. - * + * Get the onBehalfOf value. + * * @return The value. */ - public String getPackaging() - { + public String getOnBehalfOf() { + return onBehalfOf; + } + + /** + * Set the onBehalfOf value. + * + * @param onBehalfOf The value. + */ + public void setOnBehalfOf(String onBehalfOf) { + this.onBehalfOf = onBehalfOf; + } + + /** + * Get the MD5 status. + * @return The value. + */ + public boolean isUseMD5() { + return useMD5; + } + + /** + * Set the md5 state. + * + * @param useMD5 True if the message should use an MD5 checksum. + */ + public void setUseMD5(boolean useMD5) { + this.useMD5 = useMD5; + } + + /** + * Get the no-op state. + * + * @return The value. + */ + public boolean isNoOp() { + return noOp; + } + + /** + * Set the no-op state. + * + * @param noOp The no-op. + */ + public void setNoOp(boolean noOp) { + this.noOp = noOp; + } + + /** + * Get the verbose value. + * + * @return The value. + */ + public boolean isVerbose() { + return verbose; + } + + /** + * Set the verbose state. + * + * @param verbose True if the post message should send a + * verbose header. + */ + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + /** + * Get the packaging format. + * + * @return The value. + */ + public String getPackaging() { return packaging; } - + /** - * Set the packaging format. - * - * @param packaging The packaging format. + * Set the packaging format. + * + * @param packaging The packaging format. */ - public void setFormatNamespace(String packaging) - { + public void setFormatNamespace(String packaging) { this.packaging = packaging; } - + /** - * Get the status of the checksum error. - * - * @return True if the client should simulate a checksum error. + * Get the status of the checksum error. + * + * @return True if the client should simulate a checksum error. */ - public boolean getChecksumError() - { + public boolean getChecksumError() { return checksumError; } - + /** - * Set the state of the checksum error. - * - * @param checksumError True if the item should include a checksum error. + * Set the state of the checksum error. + * + * @param checksumError True if the item should include a checksum error. */ - public void setChecksumError(boolean checksumError) - { + public void setChecksumError(boolean checksumError) { this.checksumError = checksumError; } - + /** * Get the status of the corrupt request flag. - * + * * @return True if the client should corrupt the POST header. */ - public boolean getCorruptRequest() - { + public boolean getCorruptRequest() { return corruptRequest; } - + /** * Set the state of the corrupt request flag. - * + * * @param corruptRequest True if the item should corrupt the POST header. */ - public void setCorruptRequest(boolean corruptRequest) - { + public void setCorruptRequest(boolean corruptRequest) { this.corruptRequest = corruptRequest; } - + /** - * Set the Slug value. - * - * @param slug The value. + * Set the Slug value. + * + * @param slug The value. */ - public void setSlug(String slug) - { + public void setSlug(String slug) { this.slug = slug; } - + /** - * Get the Slug value. - * - * @return The Slug. + * Get the Slug value. + * + * @return The Slug. */ - public String getSlug() - { - return this.slug; + public String getSlug() { + return this.slug; } /** @@ -355,10 +332,10 @@ public class PostMessage public String getUserAgent() { return userAgent; } - + /** * Set the user agent - * + * * @param userAgent the userAgent to set */ public void setUserAgent(String userAgent) { diff --git a/dspace-sword/src/main/java/org/purl/sword/client/PropertiesDialog.java b/dspace-sword/src/main/java/org/purl/sword/client/PropertiesDialog.java index 03c5327533..6d43cb68ef 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/PropertiesDialog.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/PropertiesDialog.java @@ -10,7 +10,6 @@ package org.purl.sword.client; import java.awt.BorderLayout; import java.util.Enumeration; import java.util.Properties; - import javax.swing.DefaultCellEditor; import javax.swing.JFrame; import javax.swing.JOptionPane; @@ -21,244 +20,221 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellEditor; /** - * Dialog that is used to edit the collection of properties. - * + * Dialog that is used to edit the collection of properties. + * * @author Neil Taylor, Suzana Barreto */ -public class PropertiesDialog -{ +public class PropertiesDialog { /** * The parent frame for the dialog that is displayed. */ - private JFrame parentFrame = null; - + private JFrame parentFrame = null; + /** * Array that lists the labels for the buttons on the panel. */ - private static Object[] options = {"OK", "Cancel" }; - + private static Object[] options = {"OK", "Cancel"}; + /** - * The panel that holds the controls to show. + * The panel that holds the controls to show. */ - private JPanel controls = null; - + private JPanel controls = null; + /** * The configuration properties */ private Properties properties = null; - + /** - * Table that is used to display the list of properties. + * Table that is used to display the list of properties. */ private JTable propertiesTable; - + /** - * Create a new instance. - * - * @param parentFrame The parent frame for the dialog. - * @param props The properties lisst to display + * Create a new instance. + * + * @param parentFrame The parent frame for the dialog. + * @param props The properties lisst to display */ - public PropertiesDialog(JFrame parentFrame, Properties props) - { - this.parentFrame = parentFrame; - properties = props; - controls = createControls(); + public PropertiesDialog(JFrame parentFrame, Properties props) { + this.parentFrame = parentFrame; + properties = props; + controls = createControls(); } - + /** - * Create the controls that are to be displayed in the system. - * - * @return A panel that contains the controls. + * Create the controls that are to be displayed in the system. + * + * @return A panel that contains the controls. */ - protected final JPanel createControls( ) - { - JPanel panel = new JPanel(new BorderLayout()); - propertiesTable = new JTable(new PropertiesModel()); - ((DefaultCellEditor)propertiesTable.getDefaultEditor(String.class)).setClickCountToStart(1); - JScrollPane scrollpane = new JScrollPane(propertiesTable,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); - panel.add(scrollpane, BorderLayout.CENTER); - return panel; + protected final JPanel createControls() { + JPanel panel = new JPanel(new BorderLayout()); + propertiesTable = new JTable(new PropertiesModel()); + ((DefaultCellEditor) propertiesTable.getDefaultEditor(String.class)).setClickCountToStart(1); + JScrollPane scrollpane = new JScrollPane(propertiesTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + panel.add(scrollpane, BorderLayout.CENTER); + return panel; } - - + + /** - * Show the dialog and return the status code. - * - * @return The status code returned from the dialog. + * Show the dialog and return the status code. + * + * @return The status code returned from the dialog. */ - public int show( ) - { - int result = JOptionPane.showOptionDialog(parentFrame, - controls, - "Edit Properties", - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE, - null, - options, - null); - - // cancel any edit in the table. If there is a cell editing, the getEditingColumn will - // return a non-negative column number. This can be used to retreive the cell editor. - // The code then gets the default editor and calls the stopCellEditing. If custom - // editors are used, an additional check must be made to get the cell editor - // for a specific cell. - int column = propertiesTable.getEditingColumn(); - - if ( column > -1 ) - { - TableCellEditor editor = propertiesTable.getDefaultEditor( propertiesTable.getColumnClass(column)); - if ( editor != null ) - { - editor.stopCellEditing(); - } - } - - return result; + public int show() { + int result = JOptionPane.showOptionDialog(parentFrame, + controls, + "Edit Properties", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.PLAIN_MESSAGE, + null, + options, + null); + + // cancel any edit in the table. If there is a cell editing, the getEditingColumn will + // return a non-negative column number. This can be used to retreive the cell editor. + // The code then gets the default editor and calls the stopCellEditing. If custom + // editors are used, an additional check must be made to get the cell editor + // for a specific cell. + int column = propertiesTable.getEditingColumn(); + + if (column > -1) { + TableCellEditor editor = propertiesTable.getDefaultEditor(propertiesTable.getColumnClass(column)); + if (editor != null) { + editor.stopCellEditing(); + } + } + + return result; } - - + + /** - * A table model that is used to show the properties. The model links directly - * to the underlying properties object. As changes are made in the table, the - * corresponding changes are made in the properties object. The user can only - * edit the value column in the table. + * A table model that is used to show the properties. The model links directly + * to the underlying properties object. As changes are made in the table, the + * corresponding changes are made in the properties object. The user can only + * edit the value column in the table. */ - public class PropertiesModel extends AbstractTableModel - { - /** - * Column names. - */ - private String columns[] = {"Property Name","Value"}; - + public class PropertiesModel extends AbstractTableModel { /** - * Create a new instance of the model. If no properties object exists, + * Column names. + */ + private String columns[] = {"Property Name", "Value"}; + + /** + * Create a new instance of the model. If no properties object exists, * a default model is created. Note, this will allow the table to * continue editing, although this value will not be passed back to - * the calling window. + * the calling window. */ - public PropertiesModel() - { + public PropertiesModel() { super(); - if (properties == null) - { + if (properties == null) { properties = new Properties(); } } - + /** - * Get the number of columns. - * - * @return The number of columns. + * Get the number of columns. + * + * @return The number of columns. */ - public int getColumnCount() - { + public int getColumnCount() { return columns.length; } - + /** - * Get the number of rows. - * - * @return The number of rows. + * Get the number of rows. + * + * @return The number of rows. */ - public int getRowCount() - { + public int getRowCount() { return properties.size(); } - + /** - * Get the value that is at the specified cell. - * - * @param row The row for the cell. - * @param col The column for the cell. - * - * @return The data value from the properties. + * Get the value that is at the specified cell. + * + * @param row The row for the cell. + * @param col The column for the cell. + * @return The data value from the properties. */ - public Object getValueAt(int row, int col) - { - if (col == 0) - { + public Object getValueAt(int row, int col) { + if (col == 0) { return getKeyValue(row); - } - else - { + } else { String key = getKeyValue(row); return properties.get(key); } } - + /** - * Retrieve the column name for the specified column. - * - * @param col The column number. - * - * @return The column name. + * Retrieve the column name for the specified column. + * + * @param col The column number. + * @return The column name. */ - public String getColumnName(int col){ + public String getColumnName(int col) { return columns[col]; } - - /** - * Retrieve the column class. - * - * @param col The column number. - * - * @return The class for the object found at the column position. - */ - public Class getColumnClass(int col) - { - return getValueAt(0, col).getClass(); - } /** - * Determine if the cell can be edited. This model will only - * allow the second column to be edited. - * - * @param row The cell row. - * @param col The cell column. - * - * @return True if the cell can be edited. Otherwise, false. + * Retrieve the column class. + * + * @param col The column number. + * @return The class for the object found at the column position. */ - public boolean isCellEditable(int row, int col) - { - if (col == 1) - { - return true; - } - return false; + public Class getColumnClass(int col) { + return getValueAt(0, col).getClass(); } /** - * Set the value for the specified cell. - * - * @param value The value to set. - * @param row The row for the cell. - * @param col The column. + * Determine if the cell can be edited. This model will only + * allow the second column to be edited. + * + * @param row The cell row. + * @param col The cell column. + * @return True if the cell can be edited. Otherwise, false. */ - public void setValueAt(Object value, int row, int col) - { - String key = getKeyValue(row); - properties.setProperty(key, ((String) value)); - fireTableCellUpdated(row, col); + public boolean isCellEditable(int row, int col) { + if (col == 1) { + return true; + } + return false; } - /** - * Get the Key value for the specified row. - * @param row The row. - * @return A string that shows the key value. + /** + * Set the value for the specified cell. + * + * @param value The value to set. + * @param row The row for the cell. + * @param col The column. */ - public String getKeyValue(int row) - { - int count = 0; - Enumeration k = properties.keys(); - while (k.hasMoreElements()) { - String key = (String) k.nextElement(); - if (count == row){ - return key; - } - count++; - } - return null; + public void setValueAt(Object value, int row, int col) { + String key = getKeyValue(row); + properties.setProperty(key, ((String) value)); + fireTableCellUpdated(row, col); } - } + + /** + * Get the Key value for the specified row. + * + * @param row The row. + * @return A string that shows the key value. + */ + public String getKeyValue(int row) { + int count = 0; + Enumeration k = properties.keys(); + while (k.hasMoreElements()) { + String key = (String) k.nextElement(); + if (count == row) { + return key; + } + count++; + } + return null; + } + } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/SWORDClient.java b/dspace-sword/src/main/java/org/purl/sword/client/SWORDClient.java index 41fe686fce..0df7fd5310 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/SWORDClient.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/SWORDClient.java @@ -11,80 +11,75 @@ import org.purl.sword.base.DepositResponse; import org.purl.sword.base.ServiceDocument; /** - * Interface for any SWORD client implementation. + * Interface for any SWORD client implementation. */ -public interface SWORDClient -{ +public interface SWORDClient { /** - * Set the server that is to be contacted on the next access. - * + * Set the server that is to be contacted on the next access. + * * @param server The name of the server, e.g. www.aber.ac.uk - * @param port The port number, e.g. 80. + * @param port The port number, e.g. 80. */ - public void setServer( String server, int port ); - - /** - * Set the user credentials that are to be used for subsequent accesses. - * - * @param username The username. - * @param password The password. - */ - public void setCredentials( String username, String password ); + public void setServer(String server, int port); /** - * Clear the credentials settings on the client. - */ + * Set the user credentials that are to be used for subsequent accesses. + * + * @param username The username. + * @param password The password. + */ + public void setCredentials(String username, String password); + + /** + * Clear the credentials settings on the client. + */ public void clearCredentials(); /** - * Set the proxy that is to be used for subsequent accesses. - * - * @param host The host name, e.g. cache.host.com. - * @param port The port, e.g. 8080. + * Set the proxy that is to be used for subsequent accesses. + * + * @param host The host name, e.g. cache.host.com. + * @param port The port, e.g. 8080. */ - public void setProxy( String host, int port ); - + public void setProxy(String host, int port); + /** - * Get the status result returned from the most recent network test. - * - * @return The status code and message. + * Get the status result returned from the most recent network test. + * + * @return The status code and message. */ - public Status getStatus( ); - + public Status getStatus(); + /** - * Get a service document, specified in the URL. - * - * @param url The URL to connect to. - * @return A ServiceDocument that contains the Service details that were - * obained from the specified URL. - * - * @throws SWORDClientException If there is an error accessing the - * URL. + * Get a service document, specified in the URL. + * + * @param url The URL to connect to. + * @return A ServiceDocument that contains the Service details that were + * obained from the specified URL. + * @throws SWORDClientException If there is an error accessing the + * URL. */ - public ServiceDocument getServiceDocument( String url ) throws SWORDClientException; - + public ServiceDocument getServiceDocument(String url) throws SWORDClientException; + /** * Get a service document, specified in the URL. The document is accessed on - * behalf of the specified user. - * - * @param url The URL to connect to. - * @param onBehalfOf The username for the onBehalfOf access. - * @return A ServiceDocument that contains the Service details that were - * obtained from the specified URL. - * + * behalf of the specified user. + * + * @param url The URL to connect to. + * @param onBehalfOf The username for the onBehalfOf access. + * @return A ServiceDocument that contains the Service details that were + * obtained from the specified URL. * @throws SWORDClientException If there is an error accessing the URL. */ - public ServiceDocument getServiceDocument(String url, String onBehalfOf ) throws SWORDClientException; - + public ServiceDocument getServiceDocument(String url, String onBehalfOf) throws SWORDClientException; + /** - * Post a file to the specified destination URL. - * - * @param message The message that defines the requirements for the operation. - * - * @return A DespoitResponse if the response is successful. If there was an error, - * null should be returned. - * - * @throws SWORDClientException If there is an error accessing the URL. + * Post a file to the specified destination URL. + * + * @param message The message that defines the requirements for the operation. + * @return A DespoitResponse if the response is successful. If there was an error, + * null should be returned. + * @throws SWORDClientException If there is an error accessing the URL. */ - public DepositResponse postFile( PostMessage message ) throws SWORDClientException; + public DepositResponse postFile(PostMessage message) throws SWORDClientException; } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/SWORDClientException.java b/dspace-sword/src/main/java/org/purl/sword/client/SWORDClientException.java index 073678d2ab..1355b9d4ab 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/SWORDClientException.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/SWORDClientException.java @@ -7,40 +7,36 @@ */ package org.purl.sword.client; -/** - * Represents an exception thrown by the SWORD Client. - * +/** + * Represents an exception thrown by the SWORD Client. + * * @author Neil Taylor */ -public class SWORDClientException extends Exception -{ +public class SWORDClientException extends Exception { /** - * Create a new exception, without a message. + * Create a new exception, without a message. */ - public SWORDClientException() - { - super(); + public SWORDClientException() { + super(); } - + /** - * Create a new exception with the specified message. - * - * @param message The message. + * Create a new exception with the specified message. + * + * @param message The message. */ - public SWORDClientException( String message) - { - super(message); + public SWORDClientException(String message) { + super(message); } - - /** + + /** * Create a new exception with the specified message and set - * the exception that generated this error. - * - * @param message The message. - * @param cause The original exception. + * the exception that generated this error. + * + * @param message The message. + * @param cause The original exception. */ - public SWORDClientException( String message, Exception cause) - { - super(message, cause); + public SWORDClientException(String message, Exception cause) { + super(message, cause); } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/SWORDComboBox.java b/dspace-sword/src/main/java/org/purl/sword/client/SWORDComboBox.java index 39117f17ba..0afa6cbde3 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/SWORDComboBox.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/SWORDComboBox.java @@ -5,40 +5,41 @@ * * http://www.dspace.org/license/ */ + /** * Copyright (c) 2007, Aberystwyth University * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * + * 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 + * + * - 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 + * + * - 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 of the Centre for Advanced Software and - * Intelligent Systems (CASIS) nor the names of its - * contributors may be used to endorse or promote products derived + * + * - Neither the name of the Centre for Advanced Software and + * Intelligent Systems (CASIS) 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 - * OWNER 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER 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. */ package org.purl.sword.client; @@ -46,95 +47,83 @@ package org.purl.sword.client; import javax.swing.JComboBox; /** - * An extension of the JComboBox class. This adds a method that + * An extension of the JComboBox class. This adds a method that * can update the list of items with the item. The update will only - * work on combo boxes that are set to editable. - * + * work on combo boxes that are set to editable. + * * @author Neil Taylor */ -public class SWORDComboBox extends JComboBox -{ +public class SWORDComboBox extends JComboBox { /** - * Create an instance of the SWORD Combo box. + * Create an instance of the SWORD Combo box. */ - public SWORDComboBox() - { + public SWORDComboBox() { super(); setEditable(true); } - + /** * Update the list for the Combo box with the currently selected - * item. This will only add an item to the list if: i) the control + * item. This will only add an item to the list if: i) the control * is editable, ii) the selected item is not empty and iii) the - * item is not already in the list. + * item is not already in the list. */ - public void updateList() - { + public void updateList() { Object s = getSelectedItem(); - - if ( ! isEditable() || s == null || (s != null && ((String)s).trim().length() == 0 ) ) - { + + if (!isEditable() || s == null || (s != null && ((String) s).trim().length() == 0)) { // don't update with an empty item or if the combo box is not editable. - return; + return; } - + insertItem(s); } - + /** * Insert an item into the combo box. This will only be added - * if the item is not already present in the combo box. - * - * @param newItem The item to insert. + * if the item is not already present in the combo box. + * + * @param newItem The item to insert. */ - public void insertItem(Object newItem) - { - int count = getItemCount(); - - boolean found = false; - - for ( int i = 0; i < count && ! found; i++ ) - { + public void insertItem(Object newItem) { + int count = getItemCount(); + + boolean found = false; + + for (int i = 0; i < count && !found; i++) { Object item = getItemAt(i); - if ( item != null && item.equals(newItem) ) - { - found = true; + if (item != null && item.equals(newItem)) { + found = true; } } - - if ( ! found ) - { + + if (!found) { addItem(newItem); - } - } - - /** - * Insert multiple items into the combo box. - * - * @param items The array of items. - */ - public void insertItems(String[] items) - { - for ( String item : items ) - { - insertItem(item); } } - + + /** + * Insert multiple items into the combo box. + * + * @param items The array of items. + */ + public void insertItems(String[] items) { + for (String item : items) { + insertItem(item); + } + } + /** * Get the text of the currently selected item in the combo box. - * @return The text. null is returned if no item - * is selected. + * @return The text. null is returned if no item + * is selected. */ - public String getText() - { - Object o = getSelectedItem(); - if ( o != null ) - { + public String getText() { + Object o = getSelectedItem(); + if (o != null) { return o.toString().trim(); } - + return null; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/SWORDFormPanel.java b/dspace-sword/src/main/java/org/purl/sword/client/SWORDFormPanel.java index bfda746e93..81de59ae68 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/SWORDFormPanel.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/SWORDFormPanel.java @@ -11,143 +11,134 @@ import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; - import javax.swing.JPanel; /** - * Utility class. Creates a two column form. The left column is used to show - * the label for the row. The right column is used to show the control, e.g. - * text box, combo box or checkbox, for the row. - * + * Utility class. Creates a two column form. The left column is used to show + * the label for the row. The right column is used to show the control, e.g. + * text box, combo box or checkbox, for the row. + * * @author Neil Taylor */ -public class SWORDFormPanel extends JPanel -{ +public class SWORDFormPanel extends JPanel { /** - * Constraints used to control the layout on the panel. + * Constraints used to control the layout on the panel. */ - private GridBagConstraints labelConstraints; - + private GridBagConstraints labelConstraints; + /** - * Constraints used to control the layout of the input controls on the panel. + * Constraints used to control the layout of the input controls on the panel. */ - private GridBagConstraints controlConstraints; - - /** + private GridBagConstraints controlConstraints; + + /** * Index to the next row. */ - private int rowIndex = 0; - + private int rowIndex = 0; + /** - * Insets for the top row of the label column. + * Insets for the top row of the label column. */ private Insets labelTop = new Insets(10, 10, 0, 0); - + /** - * Insets for the top row of the control column. + * Insets for the top row of the control column. */ private Insets controlTop = new Insets(10, 4, 0, 10); - + /** - * Insets for a general row in the label column. + * Insets for a general row in the label column. */ private Insets labelGeneral = new Insets(3, 10, 0, 0); - + /** - * Insets for a general row in the control column. + * Insets for a general row in the control column. */ - private Insets controlGeneral = new Insets(3, 4, 0, 10); - + private Insets controlGeneral = new Insets(3, 4, 0, 10); + /** - * Create a new instance of the class. + * Create a new instance of the class. */ - public SWORDFormPanel() - { - super(); + public SWORDFormPanel() { + super(); setLayout(new GridBagLayout()); - + labelConstraints = new GridBagConstraints(); labelConstraints.fill = GridBagConstraints.NONE; labelConstraints.anchor = GridBagConstraints.LINE_END; labelConstraints.weightx = 0.1; - + controlConstraints = new GridBagConstraints(); controlConstraints.fill = GridBagConstraints.HORIZONTAL; controlConstraints.weightx = 0.9; } - + /** - * Add the specified component as the first row. It will occupy two - * columns. - * + * Add the specified component as the first row. It will occupy two + * columns. + * * @param one The control to add. */ - public void addFirstRow(Component one) - { + public void addFirstRow(Component one) { addRow(one, null, labelTop, controlTop); } - + /** - * Add the specified components as the first row in the form. - * @param one The label component. - * @param two The control component. + * Add the specified components as the first row in the form. + * + * @param one The label component. + * @param two The control component. */ - public void addFirstRow(Component one, Component two) - { + public void addFirstRow(Component one, Component two) { addRow(one, two, labelTop, controlTop); } - + /** - * Add a component to the general row. This will be added in the label column. - * @param one The component. + * Add a component to the general row. This will be added in the label column. + * + * @param one The component. */ - public void addRow(Component one) - { + public void addRow(Component one) { addRow(one, null); } - + /** - * Add a component to the general row. - * @param one The component to add to the label column. - * @param two The component to add to the control column. + * Add a component to the general row. + * + * @param one The component to add to the label column. + * @param two The component to add to the control column. */ - public void addRow(Component one, Component two) - { + public void addRow(Component one, Component two) { addRow(one, two, labelGeneral, controlGeneral); } - + /** - * Add a row to the table. - * - * @param one The component to display in the label column. - * @param two The component to display in the control column. - * @param labels The insets for the label column. - * @param controls The insets for the controls column. + * Add a row to the table. + * + * @param one The component to display in the label column. + * @param two The component to display in the control column. + * @param labels The insets for the label column. + * @param controls The insets for the controls column. */ - protected void addRow(Component one, Component two, Insets labels, Insets controls ) - { - labelConstraints.insets = labels; + protected void addRow(Component one, Component two, Insets labels, Insets controls) { + labelConstraints.insets = labels; labelConstraints.gridx = 0; labelConstraints.gridy = rowIndex; - if ( two == null ) - { + if (two == null) { labelConstraints.gridwidth = 2; - } - else - { + } else { labelConstraints.gridwidth = 1; } - + add(one, labelConstraints); - - if ( two != null ) - { - controlConstraints.insets = controls; + + if (two != null) { + controlConstraints.insets = controls; controlConstraints.gridx = 1; controlConstraints.gridy = rowIndex; add(two, controlConstraints); } - - rowIndex++; + + rowIndex++; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/ServiceDialog.java b/dspace-sword/src/main/java/org/purl/sword/client/ServiceDialog.java index b8592224b9..03489f0d2e 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/ServiceDialog.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/ServiceDialog.java @@ -5,40 +5,41 @@ * * http://www.dspace.org/license/ */ + /** * Copyright (c) 2007, Aberystwyth University * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * + * 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 + * + * - 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 + * + * - 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 of the Centre for Advanced Software and - * Intelligent Systems (CASIS) nor the names of its - * contributors may be used to endorse or promote products derived + * + * - Neither the name of the Centre for Advanced Software and + * Intelligent Systems (CASIS) 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 - * OWNER 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER 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. */ package org.purl.sword.client; @@ -50,190 +51,177 @@ import javax.swing.JPanel; import javax.swing.JPasswordField; /** - * Dialog that prompts the user to enter the details for a service - * document location. - * + * Dialog that prompts the user to enter the details for a service + * document location. + * * @author Neil Taylor */ -public class ServiceDialog -{ +public class ServiceDialog { /** - * The username. + * The username. */ private SWORDComboBox username; - + /** * The password. */ private JPasswordField password; - + /** - * Holds the URL for the collection. + * Holds the URL for the collection. */ private SWORDComboBox location; - + /** - * The combo box that shows the list of onBehalfOf items. + * The combo box that shows the list of onBehalfOf items. */ private SWORDComboBox onBehalfOf; - + /** - * Parent frame for the dialog. + * Parent frame for the dialog. */ - private JFrame parentFrame = null; - + private JFrame parentFrame = null; + /** - * The panel that holds the controls. + * The panel that holds the controls. */ private JPanel controls = null; - + /** - * List of buttons. + * List of buttons. */ - private static Object[] options = {"Get Service Document", "Cancel" }; - + private static Object[] options = {"Get Service Document", "Cancel"}; + /** - * Create a new instance. - * - * @param parentFrame The parent frame. The dialog will be shown over the - * centre of this frame. + * Create a new instance. + * + * @param parentFrame The parent frame. The dialog will be shown over the + * centre of this frame. */ - public ServiceDialog(JFrame parentFrame) - { - this.parentFrame = parentFrame; - controls = createControls(); + public ServiceDialog(JFrame parentFrame) { + this.parentFrame = parentFrame; + controls = createControls(); } - + /** - * Show the dialog. - * - * @return The close option. This is one of the dialog options from - * JOptionPane. + * Show the dialog. + * + * @return The close option. This is one of the dialog options from + * JOptionPane. */ - public int show( ) - { - int result = JOptionPane.showOptionDialog(parentFrame, - controls, - "Get Service Document", - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE, - null, - options, - options[1]); - - if ( result == JOptionPane.OK_OPTION ) - { - // update the combo boxes with the values - username.updateList(); - location.updateList(); - onBehalfOf.updateList(); + public int show() { + int result = JOptionPane.showOptionDialog(parentFrame, + controls, + "Get Service Document", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.PLAIN_MESSAGE, + null, + options, + options[1]); + + if (result == JOptionPane.OK_OPTION) { + // update the combo boxes with the values + username.updateList(); + location.updateList(); + onBehalfOf.updateList(); } - - return result; + + return result; } - + /** - * Create the controls that are displayed in the dialog. - * - * @return The panel that contains the controls. + * Create the controls that are displayed in the dialog. + * + * @return The panel that contains the controls. */ - protected final JPanel createControls( ) - { - username = new SWORDComboBox(); - username.setEditable(true); - password = new JPasswordField(); - location = new SWORDComboBox(); - location.setEditable(true); - onBehalfOf = new SWORDComboBox(); - onBehalfOf.setEditable(true); - - JLabel userLabel = new JLabel("Username:", JLabel.TRAILING); - JLabel passwordLabel = new JLabel("Password:", JLabel.TRAILING); - JLabel locationLabel = new JLabel("Location:", JLabel.TRAILING); - JLabel onBehalfOfLabel = new JLabel("On Behalf Of:", JLabel.TRAILING); - - SWORDFormPanel panel = new SWORDFormPanel(); - panel.addFirstRow(userLabel, username); - panel.addRow(passwordLabel, password); - panel.addRow(locationLabel, location); - panel.addRow(onBehalfOfLabel, onBehalfOf); - - return panel; + protected final JPanel createControls() { + username = new SWORDComboBox(); + username.setEditable(true); + password = new JPasswordField(); + location = new SWORDComboBox(); + location.setEditable(true); + onBehalfOf = new SWORDComboBox(); + onBehalfOf.setEditable(true); + + JLabel userLabel = new JLabel("Username:", JLabel.TRAILING); + JLabel passwordLabel = new JLabel("Password:", JLabel.TRAILING); + JLabel locationLabel = new JLabel("Location:", JLabel.TRAILING); + JLabel onBehalfOfLabel = new JLabel("On Behalf Of:", JLabel.TRAILING); + + SWORDFormPanel panel = new SWORDFormPanel(); + panel.addFirstRow(userLabel, username); + panel.addRow(passwordLabel, password); + panel.addRow(locationLabel, location); + panel.addRow(onBehalfOfLabel, onBehalfOf); + + return panel; } - + /** - * Get the username from the controls on the dialog. - * - * @return The username. + * Get the username from the controls on the dialog. + * + * @return The username. */ - public String getUsername() - { - return username.getText(); + public String getUsername() { + return username.getText(); } - + /** - * Get the password from the dialog. - * - * @return The password. + * Get the password from the dialog. + * + * @return The password. */ - public String getPassword() - { - return new String(password.getPassword()); + public String getPassword() { + return new String(password.getPassword()); } - + /** - * The location from the dialog. - * - * @return The location. + * The location from the dialog. + * + * @return The location. */ - public String getLocation() - { - return location.getText(); + public String getLocation() { + return location.getText(); } - + /** - * The onBehalfOf value from the dialog. - * - * @return The onBehalfOf value. + * The onBehalfOf value from the dialog. + * + * @return The onBehalfOf value. */ - public String getOnBehalfOf() - { - String text = onBehalfOf.getText().trim(); - if ( text.length() == 0 ) - { - return null; - } - return text; + public String getOnBehalfOf() { + String text = onBehalfOf.getText().trim(); + if (text.length() == 0) { + return null; + } + return text; } - + /** - * Add the list of user ids to the dialog. - * - * @param users The list of user ids. + * Add the list of user ids to the dialog. + * + * @param users The list of user ids. */ - public void addUserIds(String[] users) - { + public void addUserIds(String[] users) { username.insertItems(users); } - - /** - * Add the list of service URLs. - * - * @param services The service URLs. + + /** + * Add the list of service URLs. + * + * @param services The service URLs. */ - public void addServiceUrls(String[] services) - { + public void addServiceUrls(String[] services) { location.insertItems(services); } - + /** - * Add a list of onBehalfOf names. - * - * @param users The list of onBehalfOf items. + * Add a list of onBehalfOf names. + * + * @param users The list of onBehalfOf items. */ - public void addOnBehalfOf(String[] users) - { + public void addOnBehalfOf(String[] users) { onBehalfOf.insertItems(users); } - + } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/ServicePanel.java b/dspace-sword/src/main/java/org/purl/sword/client/ServicePanel.java index 8ac00c7a80..bc3031c333 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/ServicePanel.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/ServicePanel.java @@ -5,48 +5,51 @@ * * http://www.dspace.org/license/ */ + /** * Copyright (c) 2007, Aberystwyth University * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * + * 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 + * + * - 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 + * + * - 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 of the Centre for Advanced Software and - * Intelligent Systems (CASIS) nor the names of its - * contributors may be used to endorse or promote products derived + * + * - Neither the name of the Centre for Advanced Software and + * Intelligent Systems (CASIS) 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 - * OWNER 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER 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. */ package org.purl.sword.client; import java.awt.BorderLayout; import java.awt.Component; -import java.util.*; - +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; @@ -74,401 +77,357 @@ import org.purl.sword.base.DepositResponse; import org.purl.sword.base.SWORDEntry; import org.purl.sword.base.Service; import org.purl.sword.base.ServiceDocument; -import org.purl.sword.base.Workspace; import org.purl.sword.base.SwordAcceptPackaging; +import org.purl.sword.base.Workspace; /** - * The main panel for the GUI client. This contains the top-two sub-panels: the - * tree and the text area to show the details of the selected node. - * + * The main panel for the GUI client. This contains the top-two sub-panels: the + * tree and the text area to show the details of the selected node. + * * @author Neil Taylor */ public class ServicePanel extends JPanel -implements TreeSelectionListener -{ + implements TreeSelectionListener { /** - * The top level item in the tree that lists services. + * The top level item in the tree that lists services. */ DefaultMutableTreeNode top; - + /** - * The tree model used to display the items. + * The tree model used to display the items. */ - DefaultTreeModel treeModel = null; - + DefaultTreeModel treeModel = null; + /** - * Tree that holds the list of services. + * Tree that holds the list of services. */ - private JTree services; - + private JTree services; + /** - * The panel that shows an HTML table with any details for the selected - * node in the services tree. + * The panel that shows an HTML table with any details for the selected + * node in the services tree. */ private JEditorPane details; - + /** - * A registered listener. This listener will be notified when there is a - * different node selected in the service tree. + * A registered listener. This listener will be notified when there is a + * different node selected in the service tree. */ - private ServiceSelectedListener listener; - + private ServiceSelectedListener listener; + /** - * Create a new instance of the panel. + * Create a new instance of the panel. */ - public ServicePanel() - { - super(); + public ServicePanel() { + super(); setLayout(new BorderLayout()); - + top = new DefaultMutableTreeNode("Services & Posted Files"); treeModel = new DefaultTreeModel(top); - - services = new JTree(treeModel); + + services = new JTree(treeModel); services.setCellRenderer(new ServicePostTreeRenderer()); - - JScrollPane servicesPane = new JScrollPane(services, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); - + + JScrollPane servicesPane = new JScrollPane(services, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + details = new JEditorPane("text/html", - "

    Details

    This panel will show the details for the currently selected item in the tree.

    "); - - JScrollPane detailsPane = new JScrollPane(details, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); - + "

    Details

    This panel will show the details for the currently " + + "selected item in the tree.

    "); + + JScrollPane detailsPane = new JScrollPane(details, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, - servicesPane, - detailsPane); + servicesPane, + detailsPane); splitPane.setOneTouchExpandable(true); splitPane.setResizeWeight(0.5); splitPane.setDividerLocation(200); - + services.addTreeSelectionListener(this); ToolTipManager.sharedInstance().registerComponent(services); - + add(splitPane, BorderLayout.CENTER); } - + /** - * Renderer that displays the icons for the tree nodes. - * + * Renderer that displays the icons for the tree nodes. + * * @author Neil Taylor */ - static class ServicePostTreeRenderer extends DefaultTreeCellRenderer - { - Icon workspaceIcon; - Icon serviceIcon; - Icon collectionIcon; - Icon fileIcon; - - /** - * Initialise the renderer. Load the icons. - */ - public ServicePostTreeRenderer() - { - ClassLoader loader = this.getClass().getClassLoader(); - workspaceIcon = new ImageIcon(loader.getResource("images/WorkspaceNodeImage.gif")); - serviceIcon = new ImageIcon(loader.getResource("images/ServiceNodeImage.gif")); - collectionIcon = new ImageIcon(loader.getResource("images/CollectionNodeImage.gif")); - fileIcon = new ImageIcon(loader.getResource("images/ServiceNodeImage.gif")); - } - - /** - * Return the cell renderer. This will be the default tree cell renderer - * with a different icon depending upon the type of data in the node. - * - * @param tree The JTree control. - * @param value The value to display. - * @param sel True if the node is selected. - * @param expanded True if the node is expanded. - * @param leaf True if the node is a leaf. - * @param row The row. - * @param hasFocus True if the node has focus. - */ - public Component getTreeCellRendererComponent( - JTree tree, - Object value, - boolean sel, - boolean expanded, - boolean leaf, - int row, - boolean hasFocus) { - - JComponent comp = (JComponent)super.getTreeCellRendererComponent( - tree, value, sel, - expanded, leaf, row, - hasFocus); - - DefaultMutableTreeNode node = - (DefaultMutableTreeNode)value; - - Object o = node.getUserObject(); - if ( o instanceof TreeNodeWrapper ) - { - TreeNodeWrapper wrapper = (TreeNodeWrapper)o; - comp.setToolTipText(wrapper.toString()); - Object data = wrapper.getData(); - if ( data instanceof Service ) - { - setIcon(serviceIcon); - } - else if ( data instanceof Workspace ) - { - setIcon(workspaceIcon); - } - else if ( data instanceof Collection ) - { - setIcon(collectionIcon); - } - else if ( data instanceof SWORDEntry ) - { - setIcon(fileIcon); - } - } - else - { - comp.setToolTipText(null); - } - return comp; + static class ServicePostTreeRenderer extends DefaultTreeCellRenderer { + Icon workspaceIcon; + Icon serviceIcon; + Icon collectionIcon; + Icon fileIcon; + + /** + * Initialise the renderer. Load the icons. + */ + public ServicePostTreeRenderer() { + ClassLoader loader = this.getClass().getClassLoader(); + workspaceIcon = new ImageIcon(loader.getResource("images/WorkspaceNodeImage.gif")); + serviceIcon = new ImageIcon(loader.getResource("images/ServiceNodeImage.gif")); + collectionIcon = new ImageIcon(loader.getResource("images/CollectionNodeImage.gif")); + fileIcon = new ImageIcon(loader.getResource("images/ServiceNodeImage.gif")); } - - - } - - /** - * Set the service selected listener. This listener will be notified when - * there is a selection change in the tree. - * - * @param listener The listener. - */ - public void setServiceSelectedListener(ServiceSelectedListener listener) - { - this.listener = listener; + + /** + * Return the cell renderer. This will be the default tree cell renderer + * with a different icon depending upon the type of data in the node. + * + * @param tree The JTree control. + * @param value The value to display. + * @param sel True if the node is selected. + * @param expanded True if the node is expanded. + * @param leaf True if the node is a leaf. + * @param row The row. + * @param hasFocus True if the node has focus. + */ + public Component getTreeCellRendererComponent( + JTree tree, + Object value, + boolean sel, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { + + JComponent comp = (JComponent) super.getTreeCellRendererComponent( + tree, value, sel, + expanded, leaf, row, + hasFocus); + + DefaultMutableTreeNode node = + (DefaultMutableTreeNode) value; + + Object o = node.getUserObject(); + if (o instanceof TreeNodeWrapper) { + TreeNodeWrapper wrapper = (TreeNodeWrapper) o; + comp.setToolTipText(wrapper.toString()); + Object data = wrapper.getData(); + if (data instanceof Service) { + setIcon(serviceIcon); + } else if (data instanceof Workspace) { + setIcon(workspaceIcon); + } else if (data instanceof Collection) { + setIcon(collectionIcon); + } else if (data instanceof SWORDEntry) { + setIcon(fileIcon); + } + } else { + comp.setToolTipText(null); + } + return comp; + } + + } - + + /** + * Set the service selected listener. This listener will be notified when + * there is a selection change in the tree. + * + * @param listener The listener. + */ + public void setServiceSelectedListener(ServiceSelectedListener listener) { + this.listener = listener; + } + /** * Process the specified service document. Add the details as a new child of the - * root of the tree. - * - * @param url The url used to access the service document. - * @param doc The service document. + * root of the tree. + * + * @param url The url used to access the service document. + * @param doc The service document. */ - public void processServiceDocument(String url, - ServiceDocument doc) - { - TreeNodeWrapper wrapper = null; - + public void processServiceDocument(String url, + ServiceDocument doc) { + TreeNodeWrapper wrapper = null; + Service service = doc.getService(); wrapper = new TreeNodeWrapper(url, service); DefaultMutableTreeNode serviceNode = new DefaultMutableTreeNode(wrapper); treeModel.insertNodeInto(serviceNode, top, top.getChildCount()); services.scrollPathToVisible(new TreePath(serviceNode.getPath())); - + // process the workspaces - DefaultMutableTreeNode workspaceNode = null; - + DefaultMutableTreeNode workspaceNode = null; + Iterator workspaces = service.getWorkspaces(); - for (; workspaces.hasNext();) - { + for (; workspaces.hasNext(); ) { Workspace workspace = workspaces.next(); wrapper = new TreeNodeWrapper(workspace.getTitle(), workspace); workspaceNode = new DefaultMutableTreeNode(wrapper); treeModel.insertNodeInto(workspaceNode, serviceNode, serviceNode.getChildCount()); services.scrollPathToVisible(new TreePath(workspaceNode.getPath())); - - DefaultMutableTreeNode collectionNode = null; + + DefaultMutableTreeNode collectionNode = null; Iterator collections = workspace.collectionIterator(); - for ( ; collections.hasNext(); ) - { + for (; collections.hasNext(); ) { Collection collection = collections.next(); wrapper = new TreeNodeWrapper(collection.getTitle(), collection); collectionNode = new DefaultMutableTreeNode(wrapper); treeModel.insertNodeInto(collectionNode, workspaceNode, workspaceNode.getChildCount()); services.scrollPathToVisible(new TreePath(collectionNode.getPath())); } - } // for - } - + } // for + } + /** * Holds the data for a tree node. It specifies the name that will be displayed - * in the node, and stores associated data. - * + * in the node, and stores associated data. + * * @author Neil Taylor */ - static class TreeNodeWrapper - { + static class TreeNodeWrapper { /** - * The node name. + * The node name. */ private String name; - + /** - * The user data. + * The user data. */ - private Object userObject; - - /** - * Create a new instance. - * - * @param name The name of the node. - * @param data The data in the node. + private Object userObject; + + /** + * Create a new instance. + * + * @param name The name of the node. + * @param data The data in the node. */ - public TreeNodeWrapper(String name, Object data) - { - this.name = name; - this.userObject = data; + public TreeNodeWrapper(String name, Object data) { + this.name = name; + this.userObject = data; } - + /** - * Retrieve the data that is stored in this node. - * - * @return The data. + * Retrieve the data that is stored in this node. + * + * @return The data. */ - public Object getData() - { - return userObject; + public Object getData() { + return userObject; } - + /** - * Get a string description for this node. + * Get a string description for this node. */ - public String toString() - { - if ( name == null || name.trim().equals("") ) - { + public String toString() { + if (name == null || name.trim().equals("")) { return "Unspecified"; } - + return name; } } - + /** - * Respond to a changed tree selection event. Update the details panel to - * show an appropriate message for the newly selected node. Also, - * alert the selection listener for this panel. The listener will receive - * a path, if a collection has been selected. Otherwise, the listener - * will receive null. + * Respond to a changed tree selection event. Update the details panel to + * show an appropriate message for the newly selected node. Also, + * alert the selection listener for this panel. The listener will receive + * a path, if a collection has been selected. Otherwise, the listener + * will receive null. */ - public void valueChanged(TreeSelectionEvent evt) - { + public void valueChanged(TreeSelectionEvent evt) { // Get all nodes whose selection status has changed TreePath[] paths = evt.getPaths(); - - for (int i=0; iunknown"); alertListener(null); } - } - catch ( Exception e ) - { - details.setText("An error occurred. The message was: " + e.getMessage() + ""); + } catch (Exception e) { + details.setText( + "An error occurred. The message was: " + e.getMessage() + ""); alertListener(null); e.printStackTrace(); } - } - else - { + } else { details.setText("please select one of the other nodes"); alertListener(null); } - } - + } + } } - + /** - * Notify the listener that there has been a change to the currently selected - * item in the tree. - * - * @param value The value to send to the listener. + * Notify the listener that there has been a change to the currently selected + * item in the tree. + * + * @param value The value to send to the listener. */ - private void alertListener(String value) - { - if ( listener != null ) - { + private void alertListener(String value) { + if (listener != null) { listener.selected(value); } } - + /** * Add a new HTML table row to the specified StringBuffer. The label is displayed in - * the left column and the value is displayed in the right column. - * - * @param buffer The destination string buffer. - * @param label The label to add. - * @param value The corresponding value to add. + * the left column and the value is displayed in the right column. + * + * @param buffer The destination string buffer. + * @param label The label to add. + * @param value The corresponding value to add. */ - private void addTableRow(StringBuffer buffer, String label, Object value) - { + private void addTableRow(StringBuffer buffer, String label, Object value) { buffer.append(""); buffer.append(label); buffer.append(""); buffer.append(displayableValue(value)); buffer.append(""); } - + /** - * Show the specified service data in the details panel. - * - * @param service The service node to display. + * Show the specified service data in the details panel. + * + * @param service The service node to display. */ - private void showService(Service service) - { + private void showService(Service service) { StringBuffer buffer = new StringBuffer(); buffer.append(""); buffer.append(""); - + buffer.append(""); buffer.append(""); addTableRow(buffer, "SWORD Version", service.getVersion()); addTableRow(buffer, "NoOp Support ", service.isNoOp()); addTableRow(buffer, "Verbose Support ", service.isVerbose()); - + String maxSize = ""; - + // Commented out the following code as the client code is out of step with the // Sword 'base' library and wont compile. - Robin Taylor. //if ( service.maxUploadIsDefined() ) @@ -477,84 +436,78 @@ implements TreeSelectionListener //} //else //{ - maxSize = "undefined"; + maxSize = "undefined"; //} - + addTableRow(buffer, "Max File Upload Size ", maxSize); - + buffer.append("
    Service Summary
    "); - + buffer.append(""); buffer.append(""); details.setText(buffer.toString()); } - + /** - * Display the workspace data in the details panel. - * - * @param workspace The workspace. + * Display the workspace data in the details panel. + * + * @param workspace The workspace. */ - private void showWorkspace(Workspace workspace) - { + private void showWorkspace(Workspace workspace) { StringBuffer buffer = new StringBuffer(); buffer.append(""); buffer.append(""); - + buffer.append(""); - buffer.append(""); + buffer + .append(""); addTableRow(buffer, "Workspace Title", workspace.getTitle()); buffer.append("
    Workspace Summary
    Workspace Summary
    "); - + buffer.append(""); buffer.append(""); details.setText(buffer.toString()); } - + /** * Return the parameter unmodified if set, or the not defined text if null * @param s * @return s or ClientConstants.NOT_DEFINED_TEXT */ - private Object displayableValue(Object s) - { - if (null == s) - { + private Object displayableValue(Object s) { + if (null == s) { return ClientConstants.NOT_DEFINED_TEXT; } else { return s; } } - - /** - * Add a string within paragraph tags. - * - * @param buffer The buffer to add the message to. - * @param message The message to add. - */ - private void addPara(StringBuffer buffer, String message) - { - buffer.append("

    " + message + "

    "); - } - + /** - * Show the specified collection data in the details panel. - * - * @param collection The collection data. + * Add a string within paragraph tags. + * + * @param buffer The buffer to add the message to. + * @param message The message to add. */ - private void showCollection(Collection collection) - { + private void addPara(StringBuffer buffer, String message) { + buffer.append("

    " + message + "

    "); + } + + /** + * Show the specified collection data in the details panel. + * + * @param collection The collection data. + */ + private void showCollection(Collection collection) { StringBuffer buffer = new StringBuffer(); buffer.append(""); buffer.append(""); - - if ( collection == null ) - { + + if (collection == null) { addPara(buffer, "Invalid Collection object. Unable to display details."); - } - else - { + } else { buffer.append(""); - buffer.append(""); + buffer.append( + ""); addTableRow(buffer, "Collection location", collection.getLocation()); addTableRow(buffer, "Collection title", collection.getTitle()); addTableRow(buffer, "Abstract", collection.getAbstract()); @@ -562,250 +515,222 @@ implements TreeSelectionListener addTableRow(buffer, "Treatment", collection.getTreatment()); addTableRow(buffer, "Mediation", collection.getMediation()); addTableRow(buffer, "Nested Service Document", collection.getService()); - + String[] accepts = collection.getAccepts(); StringBuilder acceptList = new StringBuilder(); - if ( accepts != null && accepts.length == 0 ) - { + if (accepts != null && accepts.length == 0) { acceptList.append("None specified"); - } - else - { - for (String s : accepts) - { + } else { + for (String s : accepts) { acceptList.append(s).append("
    "); } } addTableRow(buffer, "Accepts", acceptList.toString()); - + List acceptsPackaging = collection.getAcceptPackaging(); - + StringBuilder acceptPackagingList = new StringBuilder(); - for (Iterator i = acceptsPackaging.iterator(); i.hasNext();) { + for (Iterator i = acceptsPackaging.iterator(); i.hasNext(); ) { SwordAcceptPackaging accept = (SwordAcceptPackaging) i.next(); - acceptPackagingList.append(accept.getContent()).append(" (").append(accept.getQualityValue()).append(")"); - - // add a , separator if there are any more items in the list - if ( i.hasNext() ) { + acceptPackagingList.append(accept.getContent()).append(" (").append(accept.getQualityValue()) + .append(")"); + + // add a , separator if there are any more items in the list + if (i.hasNext()) { acceptPackagingList.append(", "); } } - + addTableRow(buffer, "Accepts Packaging", acceptPackagingList.toString()); - + buffer.append("
    Collection Summary
    Collection Summary
    "); } - + buffer.append(""); buffer.append(""); details.setText(buffer.toString()); } - + /** - * Display the contents of a Post entry in the display panel. - * - * @param entry The entry to display. + * Display the contents of a Post entry in the display panel. + * + * @param entry The entry to display. */ - private void showEntry(SWORDEntry entry) - { - StringBuffer buffer = new StringBuffer(); - buffer.append(""); - buffer.append(""); - - if ( entry == null ) - { - addPara(buffer, "Invalid Entry object. Unable to display details."); - } - else - { - buffer.append(""); - buffer.append(""); - - // process atom:title - String titleString = getTextConstructDetails(entry.getSummary()); - addTableRow(buffer, "Title", titleString); - - // process id - addTableRow(buffer, "ID", entry.getId()); - - // process updated - addTableRow(buffer, "Date Updated", entry.getUpdated()); - - String authorString = getAuthorDetails(entry.getAuthors()); - addTableRow(buffer, "Authors", authorString); - - // process summary - String summaryString = getTextConstructDetails(entry.getSummary()); - addTableRow(buffer, "Summary", summaryString); - - // process content - Content content = entry.getContent(); - String contentString = ""; - if ( content == null ) - { - contentString = "Not defined."; - } - else - { - contentString += "Source: '" + content.getSource() + "', Type: '" + - content.getType() + "'"; - } - addTableRow(buffer, "Content", contentString); - - // process links - Iterator links = entry.getLinks(); - StringBuffer linkBuffer = new StringBuffer(); - for ( ; links.hasNext(); ) - { - Link link = links.next(); - linkBuffer.append("href: '"); - linkBuffer.append(link.getHref()); - linkBuffer.append("', href lang: '"); - linkBuffer.append(link.getHreflang()); - linkBuffer.append("', rel: '"); - linkBuffer.append(link.getRel()); - linkBuffer.append("')
    "); - } - if ( linkBuffer.length() == 0 ) - { - linkBuffer.append("Not defined"); - } - addTableRow(buffer, "Links", linkBuffer.toString()); - - // process contributors - String contributorString = getContributorDetails(entry.getContributors()); - addTableRow(buffer, "Contributors", contributorString); - - // process source - String sourceString=""; - Generator generator = entry.getGenerator(); - if ( generator != null ) - { - sourceString += "Content: '" + generator.getContent() + "'
    '"; - sourceString += "Version: '" + generator.getVersion() + "'
    '"; - sourceString += "Uri: '" + generator.getUri() + "'"; - } - else - { - sourceString += "No generator defined."; - } - - addTableRow(buffer, "Generator", sourceString); - - // process treatment - addTableRow(buffer, "Treatment", entry.getTreatment()); - - // process verboseDescription - addTableRow(buffer, "Verbose Description", entry.getVerboseDescription()); - - // process noOp - addTableRow(buffer, "NoOp", entry.isNoOp()); - - // process formatNamespace - addTableRow(buffer, "Packaging", entry.getPackaging()); - - // process userAgent - addTableRow(buffer, "User Agent", entry.getUserAgent()); - - - buffer.append("
    Entry Summary
    "); - } - - buffer.append(""); - buffer.append(""); - details.setText(buffer.toString()); + private void showEntry(SWORDEntry entry) { + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + buffer.append(""); + + if (entry == null) { + addPara(buffer, "Invalid Entry object. Unable to display details."); + } else { + buffer.append(""); + buffer + .append(""); + + // process atom:title + String titleString = getTextConstructDetails(entry.getSummary()); + addTableRow(buffer, "Title", titleString); + + // process id + addTableRow(buffer, "ID", entry.getId()); + + // process updated + addTableRow(buffer, "Date Updated", entry.getUpdated()); + + String authorString = getAuthorDetails(entry.getAuthors()); + addTableRow(buffer, "Authors", authorString); + + // process summary + String summaryString = getTextConstructDetails(entry.getSummary()); + addTableRow(buffer, "Summary", summaryString); + + // process content + Content content = entry.getContent(); + String contentString = ""; + if (content == null) { + contentString = "Not defined."; + } else { + contentString += "Source: '" + content.getSource() + "', Type: '" + + content.getType() + "'"; + } + addTableRow(buffer, "Content", contentString); + + // process links + Iterator links = entry.getLinks(); + StringBuffer linkBuffer = new StringBuffer(); + for (; links.hasNext(); ) { + Link link = links.next(); + linkBuffer.append("href: '"); + linkBuffer.append(link.getHref()); + linkBuffer.append("', href lang: '"); + linkBuffer.append(link.getHreflang()); + linkBuffer.append("', rel: '"); + linkBuffer.append(link.getRel()); + linkBuffer.append("')
    "); + } + if (linkBuffer.length() == 0) { + linkBuffer.append("Not defined"); + } + addTableRow(buffer, "Links", linkBuffer.toString()); + + // process contributors + String contributorString = getContributorDetails(entry.getContributors()); + addTableRow(buffer, "Contributors", contributorString); + + // process source + String sourceString = ""; + Generator generator = entry.getGenerator(); + if (generator != null) { + sourceString += "Content: '" + generator.getContent() + "'
    '"; + sourceString += "Version: '" + generator.getVersion() + "'
    '"; + sourceString += "Uri: '" + generator.getUri() + "'"; + } else { + sourceString += "No generator defined."; + } + + addTableRow(buffer, "Generator", sourceString); + + // process treatment + addTableRow(buffer, "Treatment", entry.getTreatment()); + + // process verboseDescription + addTableRow(buffer, "Verbose Description", entry.getVerboseDescription()); + + // process noOp + addTableRow(buffer, "NoOp", entry.isNoOp()); + + // process formatNamespace + addTableRow(buffer, "Packaging", entry.getPackaging()); + + // process userAgent + addTableRow(buffer, "User Agent", entry.getUserAgent()); + + + buffer.append("
    Entry Summary
    "); + } + + buffer.append(""); + buffer.append(""); + details.setText(buffer.toString()); } - + /** * Retrieve the details for a TextConstruct object. - * - * @param data The text construct object to display. - * - * @return Either 'Not defined' if the data is null, or - * details of the text content element. + * + * @param data The text construct object to display. + * + * @return Either 'Not defined' if the data is null, or + * details of the text content element. */ - private String getTextConstructDetails(TextConstruct data) - { + private String getTextConstructDetails(TextConstruct data) { String summaryStr = ""; - if ( data == null ) - { + if (data == null) { summaryStr = "Not defined"; - } - else - { - summaryStr = "Content: '" + data.getContent() + "', Type: "; - if ( data.getType() != null ) - { + } else { + summaryStr = "Content: '" + data.getContent() + "', Type: "; + if (data.getType() != null) { summaryStr += "'" + data.getType().toString() + "'"; - } - else - { + } else { summaryStr += "undefined."; } } - + return summaryStr; } - + /** - * Get the author details and insert them into a string. - * - * @param authors the list of authors to process. - * - * @return A string containing the list of authors. + * Get the author details and insert them into a string. + * + * @param authors the list of authors to process. + * + * @return A string containing the list of authors. */ - private String getAuthorDetails(Iterator authors) - { + private String getAuthorDetails(Iterator authors) { // process author - StringBuffer authorBuffer = new StringBuffer(); - for ( ; authors.hasNext(); ) - { - Author a = authors.next(); + StringBuffer authorBuffer = new StringBuffer(); + for (; authors.hasNext(); ) { + Author a = authors.next(); authorBuffer.append(getAuthorDetails(a)); } - - if ( authorBuffer.length() == 0 ) - { + + if (authorBuffer.length() == 0) { authorBuffer.append("Not defined"); } - + return authorBuffer.toString(); } - + /** * Get the contributor details and insert them into a string. - * - * @param contributors The contributors. - * - * @return The string that lists the details of the contributors. + * + * @param contributors The contributors. + * + * @return The string that lists the details of the contributors. */ - private String getContributorDetails(Iterator contributors) - { + private String getContributorDetails(Iterator contributors) { // process author - StringBuffer authorBuffer = new StringBuffer(); - for ( ; contributors.hasNext(); ) - { - Contributor c = contributors.next(); + StringBuffer authorBuffer = new StringBuffer(); + for (; contributors.hasNext(); ) { + Contributor c = contributors.next(); authorBuffer.append(getAuthorDetails(c)); } - - if ( authorBuffer.length() == 0 ) - { + + if (authorBuffer.length() == 0) { authorBuffer.append("Not defined"); } - + return authorBuffer.toString(); } - + /** - * Build a string that describes the specified author. - * - * @param author The author. - * - * @return The string description. + * Build a string that describes the specified author. + * + * @param author The author. + * + * @return The string description. */ - private String getAuthorDetails(Author author) - { + private String getAuthorDetails(Author author) { // process author StringBuffer authorBuffer = new StringBuffer(); authorBuffer.append(author.getName()); @@ -814,122 +739,105 @@ implements TreeSelectionListener authorBuffer.append("', uri: '"); authorBuffer.append(author.getUri()); authorBuffer.append("')
    "); - + return authorBuffer.toString(); } - + /** - * Process the deposit response and insert the details into the tree. If the url + * Process the deposit response and insert the details into the tree. If the url * matches one of the collections in the tree, the deposit is added as a child - * node. Otherwise, the node is added as a child of the root. - * + * node. Otherwise, the node is added as a child of the root. + * * @param url The url of the collection that the file was posted to. - * - * @param response The details of the deposit. + * + * @param response The details of the deposit. */ - public void processDepositResponse(String url, - DepositResponse response) - { + public void processDepositResponse(String url, + DepositResponse response) { SWORDEntry entry = response.getEntry(); - Object title = entry.getTitle(); - if ( title == null ) - { + Object title = entry.getTitle(); + if (title == null) { title = "Undefined"; - } - else - { + } else { title = entry.getTitle().getContent(); } - + TreeNodeWrapper wrapper = new TreeNodeWrapper(title.toString(), entry); DefaultMutableTreeNode entryNode = new DefaultMutableTreeNode(wrapper); - - DefaultMutableTreeNode newParentNode = top; + + DefaultMutableTreeNode newParentNode = top; List nodes = getCollectionNodes(); - for ( DefaultMutableTreeNode node : nodes ) - { + for (DefaultMutableTreeNode node : nodes) { Object o = node.getUserObject(); - if ( o instanceof TreeNodeWrapper ) - { - TreeNodeWrapper collectionWrapper = (TreeNodeWrapper)o; + if (o instanceof TreeNodeWrapper) { + TreeNodeWrapper collectionWrapper = (TreeNodeWrapper) o; Object data = collectionWrapper.getData(); - if ( data instanceof Collection ) - { - Collection col = (Collection)data; + if (data instanceof Collection) { + Collection col = (Collection) data; String location = col.getLocation(); - if ( location != null && location.equals(url)) - { - newParentNode = node; + if (location != null && location.equals(url)) { + newParentNode = node; break; } } - } + } } - + treeModel.insertNodeInto(entryNode, newParentNode, newParentNode.getChildCount()); services.scrollPathToVisible(new TreePath(entryNode.getPath())); } - + /** * Get a list of all current collections displayed in the tree. - * - * @return An array of the URLs for the collections. + * + * @return An array of the URLs for the collections. */ - public String[] getCollectionLocations() - { + public String[] getCollectionLocations() { List nodes = getCollectionNodes(); String[] locations = new String[nodes.size()]; - + DefaultMutableTreeNode node; - for ( int i = 0; i < nodes.size(); i++ ) - { + for (int i = 0; i < nodes.size(); i++) { node = nodes.get(i); Object o = node.getUserObject(); - if ( o instanceof TreeNodeWrapper ) - { - TreeNodeWrapper collectionWrapper = (TreeNodeWrapper)o; + if (o instanceof TreeNodeWrapper) { + TreeNodeWrapper collectionWrapper = (TreeNodeWrapper) o; Object data = collectionWrapper.getData(); - if ( data instanceof Collection ) - { - Collection col = (Collection)data; + if (data instanceof Collection) { + Collection col = (Collection) data; String location = col.getLocation(); - if ( location != null ) - { - locations[i] = location; + if (location != null) { + locations[i] = location; } } - } + } } return locations; } - + /** - * Get a list of nodes that contain collections. - * - * @return A vector of the collection nodes. + * Get a list of nodes that contain collections. + * + * @return A vector of the collection nodes. */ - private List getCollectionNodes() - { + private List getCollectionNodes() { List nodes = new ArrayList(); - + DefaultMutableTreeNode node; - Enumeration treeNodes = top.depthFirstEnumeration(); - - while ( treeNodes.hasMoreElements() ) - { - node = (DefaultMutableTreeNode)treeNodes.nextElement(); + Enumeration treeNodes = top.depthFirstEnumeration(); + + while (treeNodes.hasMoreElements()) { + node = (DefaultMutableTreeNode) treeNodes.nextElement(); Object o = node.getUserObject(); - if ( o instanceof TreeNodeWrapper ) - { - TreeNodeWrapper wrapper = (TreeNodeWrapper)o; + if (o instanceof TreeNodeWrapper) { + TreeNodeWrapper wrapper = (TreeNodeWrapper) o; Object data = wrapper.getData(); - if ( data instanceof Collection ) - { + if (data instanceof Collection) { nodes.add(node); } } } - + return nodes; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/ServiceSelectedListener.java b/dspace-sword/src/main/java/org/purl/sword/client/ServiceSelectedListener.java index 1a4020885f..fa97549fd9 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/ServiceSelectedListener.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/ServiceSelectedListener.java @@ -8,18 +8,16 @@ package org.purl.sword.client; /** - * Listener for any objects that want to be notified when a collection has been selected in the - * ServicePanel. - * - * @author Neil Taylor + * Listener for any objects that want to be notified when a collection has been selected in the + * ServicePanel. * + * @author Neil Taylor */ -public interface ServiceSelectedListener -{ - /** - * Called to provide an update on whether the selected node is a Collection. - * - * @param collection The location of the collection. null, otherwise. - */ - public void selected(String collection); +public interface ServiceSelectedListener { + /** + * Called to provide an update on whether the selected node is a Collection. + * + * @param collection The location of the collection. null, otherwise. + */ + public void selected(String collection); } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/ServletClient.java b/dspace-sword/src/main/java/org/purl/sword/client/ServletClient.java index a721950699..963e9637dd 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/ServletClient.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/ServletClient.java @@ -5,38 +5,39 @@ * * http://www.dspace.org/license/ */ + /** * Copyright (c) 2008, Aberystwyth University * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * 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 + * + * - 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 + * + * - 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 of the Centre for Advanced Software and - * Intelligent Systems (CASIS) nor the names of its - * contributors may be used to endorse or promote products derived + * + * - Neither the name of the Centre for Advanced Software and + * Intelligent Systems (CASIS) 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 - * OWNER 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 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER 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. */ @@ -47,7 +48,6 @@ import java.io.IOException; import java.net.URL; import java.util.Iterator; import java.util.List; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -63,7 +63,7 @@ import org.purl.sword.base.ServiceDocument; /** * Example client that runs as a Servlet. - * + * * @author Stuart Lewis */ public class ServletClient extends HttpServlet { @@ -71,9 +71,10 @@ public class ServletClient extends HttpServlet { /** * The user agent name of this library */ - public static final String userAgent = "SWORDAPP Java Client: SWORD version 1.3 compatible (http://sourceforge.net/projects/sword-app/)"; - - /** + public static final String userAgent = "SWORDAPP Java Client: SWORD version 1.3 compatible (http://sourceforge" + + ".net/projects/sword-app/)"; + + /** * Temporary directory. */ private String tempDirectory; @@ -106,17 +107,17 @@ public class ServletClient extends HttpServlet { */ public void init() { tempDirectory = getServletContext().getInitParameter( - "upload-temp-directory"); + "upload-temp-directory"); if ((tempDirectory == null) || (tempDirectory.equals(""))) { tempDirectory = System.getProperty("java.io.tmpdir"); } String lots = getServletContext().getInitParameter("client-urls"); urls = lots.split(","); - + pHost = getServletContext().getInitParameter("proxy-host"); String pPortstr = getServletContext().getInitParameter("proxy-port"); if (((pHost != null) && (!pHost.equals(""))) - && ((pPortstr != null) && (!pPortstr.equals("")))) { + && ((pPortstr != null) && (!pPortstr.equals("")))) { try { pPort = Integer.parseInt(pPortstr); useProxy = true; @@ -128,10 +129,10 @@ public class ServletClient extends HttpServlet { /** * Handle a get request. Simply show the default form (form.jsp) - * + * * @param request The request details * @param response The response to write to. - * + * * @throws ServletException * An exception that provides information on a database access error or other errors. * @throws IOException @@ -147,10 +148,10 @@ public class ServletClient extends HttpServlet { /** * Process the post. Determine if the request is for a post or service * document. Then, dispatch the request to the appropriate handler. - * + * * @param request The request details. * @param response The response to write to. - * + * * @throws ServletException * An exception that provides information on a database access error or other errors. * @throws IOException @@ -182,13 +183,13 @@ public class ServletClient extends HttpServlet { } } - /** + /** * Process the request for a service document. - * + * * @param request The request details. * @param response The response to write to. * - * @throws ServletException + * @throws ServletException * An exception that provides information on a database access error or other errors. * @throws IOException * A general class of exceptions produced by failed or interrupted I/O operations. @@ -201,9 +202,9 @@ public class ServletClient extends HttpServlet { // Which URL do we want? URL url = new URL(request.getParameter("url")); String theUrl = request.getParameter("url"); - + if ((request.getParameter("ownurl") != null) - && (!request.getParameter("ownurl").equals(""))) { + && (!request.getParameter("ownurl").equals(""))) { url = new URL(request.getParameter("ownurl")); theUrl = request.getParameter("ownurl"); } @@ -222,9 +223,9 @@ public class ServletClient extends HttpServlet { try { ServiceDocument sd = client.getServiceDocument(theUrl, - request.getParameter("obo")); + request.getParameter("obo")); - // Set the status + // Set the status Status status = client.getStatus(); request.setAttribute("status", status.toString()); if (status.getCode() == 200) { @@ -238,11 +239,11 @@ public class ServletClient extends HttpServlet { validateXml = validateXml.replaceAll("\"", """); validateXml = validateXml.replaceAll("'", "'"); request.setAttribute("xmlValidate", validateXml); // for passing to validation - + xml = xml.replaceAll("<", "<"); xml = xml.replaceAll(">", ">"); request.setAttribute("xml", xml); - + // Set the ServiceDocument and associated values request.setAttribute("sd", sd); request.setAttribute("sdURL", theUrl); @@ -250,14 +251,14 @@ public class ServletClient extends HttpServlet { request.setAttribute("p", request.getParameter("p")); request.setAttribute("sdOBO", request.getParameter("obo")); request.getRequestDispatcher("servicedocument.jsp").forward( - request, response); + request, response); return; } else { request.setAttribute("error", status.getCode() + " " - + status.getMessage()); + + status.getMessage()); request.setAttribute("urls", urls); request.getRequestDispatcher("form.jsp").forward(request, - response); + response); return; } } catch (SWORDClientException e) { @@ -270,10 +271,10 @@ public class ServletClient extends HttpServlet { /** * Process a deposit. - * + * * @param request The request details. * @param response The response to output to. - * + * * @throws ServletException * An exception that provides information on a database access error or other errors. * @throws IOException @@ -286,13 +287,13 @@ public class ServletClient extends HttpServlet { try { PostMessage message = new PostMessage(); message.setUserAgent(ClientConstants.SERVICE_NAME); - + // Get the file FileItemFactory factory = new DiskFileItemFactory(); - + // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); - + // Parse the request List items = upload.parseRequest(request); Iterator iter = items.iterator(); @@ -350,8 +351,8 @@ public class ServletClient extends HttpServlet { } request.setAttribute(name, value); } else { - String fname = tempDirectory + File.separator + - "ServletClient-" + counter++; + String fname = tempDirectory + File.separator + + "ServletClient-" + counter++; if ((contentDisposition != null) && (!contentDisposition.equals(""))) { fname = tempDirectory + File.separator + contentDisposition; } @@ -416,7 +417,7 @@ public class ServletClient extends HttpServlet { request.setAttribute("packaging", se.getPackaging()); request.setAttribute("links", se.getLinks()); request.setAttribute("location", resp.getLocation()); - + // Set the ServiceDocument and associated values request.getRequestDispatcher("deposit.jsp").forward(request, response); return; @@ -424,18 +425,18 @@ public class ServletClient extends HttpServlet { String error = status.getCode() + " " + status.getMessage() + " - "; try { error += resp.getEntry().getSummary().getContent(); - } catch (Exception e) { + } catch (Exception e) { // Do nothing - we have default error message e.printStackTrace(); } request.setAttribute("error", error); - + // Try and get an error document in xml String xml = resp.marshall(); xml = xml.replaceAll("<", "<"); xml = xml.replaceAll(">", ">"); request.setAttribute("xml", xml); - + request.getRequestDispatcher("depositform.jsp").forward(request, response); return; } diff --git a/dspace-sword/src/main/java/org/purl/sword/client/Status.java b/dspace-sword/src/main/java/org/purl/sword/client/Status.java index 84ba359cc1..ff80fa6e52 100644 --- a/dspace-sword/src/main/java/org/purl/sword/client/Status.java +++ b/dspace-sword/src/main/java/org/purl/sword/client/Status.java @@ -8,59 +8,54 @@ package org.purl.sword.client; /** - * Representation of the status code and message. - * + * Representation of the status code and message. + * * @author Neil Taylor */ -public class Status -{ +public class Status { /** - * The status code. + * The status code. */ - private int code; - + private int code; + /** - * The status message. + * The status message. */ - private String message; - + private String message; + /** - * Create a new status message. - * - * @param code The code. - * @param message The message. + * Create a new status message. + * + * @param code The code. + * @param message The message. */ - public Status( int code, String message) - { + public Status(int code, String message) { this.code = code; this.message = message; } - + /** - * Retrieve the code. - * - * @return The code. + * Retrieve the code. + * + * @return The code. */ - public int getCode( ) - { - return code; + public int getCode() { + return code; } - + /** * Get the message. - * - * @return The message. + * + * @return The message. */ - public String getMessage() - { - return message; + public String getMessage() { + return message; } - + /** - * Get a string representation of the status. + * Get a string representation of the status. */ - public String toString() - { - return "Code: " + code + ", Message: '" + message + "'"; + public String toString() { + return "Code: " + code + ", Message: '" + message + "'"; } } diff --git a/dspace-sword/src/main/java/org/purl/sword/server/AtomDocumentServlet.java b/dspace-sword/src/main/java/org/purl/sword/server/AtomDocumentServlet.java index c7a6b8fbc7..adf049c10a 100644 --- a/dspace-sword/src/main/java/org/purl/sword/server/AtomDocumentServlet.java +++ b/dspace-sword/src/main/java/org/purl/sword/server/AtomDocumentServlet.java @@ -9,7 +9,6 @@ package org.purl.sword.server; import java.io.IOException; import java.io.PrintWriter; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -29,8 +28,7 @@ import org.purl.sword.base.SWORDException; public class AtomDocumentServlet extends DepositServlet { public AtomDocumentServlet() - throws ServletException - { + throws ServletException { super(); } @@ -39,27 +37,21 @@ public class AtomDocumentServlet extends DepositServlet { */ @Override protected void doGet(HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException - { - try - { + HttpServletResponse response) + throws ServletException, IOException { + try { // Create the atom document request object AtomDocumentRequest adr = new AtomDocumentRequest(); // Are there any authentication details? String usernamePassword = getUsernamePassword(request); - if ((usernamePassword != null) && (!usernamePassword.equals(""))) - { + if ((usernamePassword != null) && (!usernamePassword.equals(""))) { int p = usernamePassword.indexOf(':'); - if (p != -1) - { + if (p != -1) { adr.setUsername(usernamePassword.substring(0, p)); adr.setPassword(usernamePassword.substring(p + 1)); } - } - else if (authenticateWithBasic()) - { + } else if (authenticateWithBasic()) { String s = "Basic realm=\"SWORD\""; response.setHeader("WWW-Authenticate", s); response.setStatus(401); @@ -81,26 +73,20 @@ public class AtomDocumentServlet extends DepositServlet { PrintWriter out = response.getWriter(); out.write(dr.marshall()); out.flush(); - } - catch (SWORDAuthenticationException sae) - { + } catch (SWORDAuthenticationException sae) { // Ask for credentials again String s = "Basic realm=\"SWORD\""; response.setHeader("WWW-Authenticate", s); response.setStatus(401); - } - catch (SWORDException se) - { + } catch (SWORDException se) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - catch (SWORDErrorException see) - { + } catch (SWORDErrorException see) { // Get the details and send the right SWORD error document super.makeErrorDocument(see.getErrorURI(), - see.getStatus(), - see.getDescription(), - request, - response); + see.getStatus(), + see.getDescription(), + request, + response); } } } diff --git a/dspace-sword/src/main/java/org/purl/sword/server/DepositServlet.java b/dspace-sword/src/main/java/org/purl/sword/server/DepositServlet.java index db0248d204..51b7bd2bcb 100644 --- a/dspace-sword/src/main/java/org/purl/sword/server/DepositServlet.java +++ b/dspace-sword/src/main/java/org/purl/sword/server/DepositServlet.java @@ -19,7 +19,6 @@ import java.util.Calendar; import java.util.Date; import java.util.StringTokenizer; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -36,32 +35,44 @@ import org.purl.sword.base.ErrorCodes; import org.purl.sword.base.HttpHeaders; import org.purl.sword.base.SWORDAuthenticationException; import org.purl.sword.base.SWORDErrorDocument; -import org.purl.sword.base.SWORDException; import org.purl.sword.base.SWORDErrorException; +import org.purl.sword.base.SWORDException; /** * DepositServlet - * + * * @author Stuart Lewis */ public class DepositServlet extends HttpServlet { - /** Sword repository */ + /** + * Sword repository + */ protected transient SWORDServer myRepository; - /** Authentication type */ + /** + * Authentication type + */ private String authN; - - /** Maximum file upload size in kB **/ + + /** + * Maximum file upload size in kB + **/ private int maxUploadSize; - /** Temp directory */ + /** + * Temp directory + */ private String tempDirectory; - /** Counter */ + /** + * Counter + */ private static final AtomicInteger counter = new AtomicInteger(0); - /** Logger */ + /** + * Logger + */ private static final Logger log = Logger.getLogger(DepositServlet.class); /** @@ -81,14 +92,14 @@ public class DepositServlet extends HttpServlet { try { myRepository = (SWORDServer) Class.forName(className) - .newInstance(); + .newInstance(); log.info("Using " + className + " as the SWORDServer"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { log.fatal("Unable to instantiate class from 'sword-server-class': " - + className); + + className); throw new ServletException( - "Unable to instantiate class from 'sword-server-class': " - + className, e); + "Unable to instantiate class from 'sword-server-class': " + + className, e); } authN = getServletContext().getInitParameter("authentication-method"); @@ -98,8 +109,8 @@ public class DepositServlet extends HttpServlet { log.info("Authentication type set to: " + authN); String maxUploadSizeStr = getServletContext().getInitParameter("maxUploadSize"); - if ((maxUploadSizeStr == null) || - (maxUploadSizeStr.equals("")) || + if ((maxUploadSizeStr == null) || + (maxUploadSizeStr.equals("")) || (maxUploadSizeStr.equals("-1"))) { maxUploadSize = -1; log.warn("No maxUploadSize set, so setting max file upload size to unlimited."); @@ -114,65 +125,66 @@ public class DepositServlet extends HttpServlet { } tempDirectory = getServletContext().getInitParameter( - "upload-temp-directory"); + "upload-temp-directory"); if ((tempDirectory == null) || (tempDirectory.equals(""))) { tempDirectory = System.getProperty("java.io.tmpdir"); } - if (!tempDirectory.endsWith(System.getProperty("file.separator"))) - { + if (!tempDirectory.endsWith(System.getProperty("file.separator"))) { tempDirectory += System.getProperty("file.separator"); } File tempDir = new File(tempDirectory); log.info("Upload temporary directory set to: " + tempDir); if (!tempDir.exists() && !tempDir.mkdirs()) { throw new ServletException( - "Upload directory did not exist and I can't create it. " - + tempDir); + "Upload directory did not exist and I can't create it. " + + tempDir); } if (!tempDir.isDirectory()) { log.fatal("Upload temporary directory is not a directory: " - + tempDir); + + tempDir); throw new ServletException( - "Upload temporary directory is not a directory: " + tempDir); + "Upload temporary directory is not a directory: " + tempDir); } if (!tempDir.canWrite()) { log.fatal("Upload temporary directory cannot be written to: " - + tempDir); + + tempDir); throw new ServletException( - "Upload temporary directory cannot be written to: " - + tempDir); + "Upload temporary directory cannot be written to: " + + tempDir); } } /** * Process the Get request. This will return an unimplemented response. - * @param request the request. + * + * @param request the request. * @param response the response. * @throws javax.servlet.ServletException passed through. - * @throws java.io.IOException passed through. + * @throws java.io.IOException passed through. */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { // Send a '501 Not Implemented' response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); } /** * Process a post request. - * @param request the request. + * + * @param request the request. * @param response the response. * @throws javax.servlet.ServletException passed through. - * @throws java.io.IOException passed through. + * @throws java.io.IOException passed through. */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { // Create the Deposit request Deposit d = new Deposit(); Date date = new Date(); log.debug("Starting deposit processing at " + date.toString() + " by " - + request.getRemoteAddr()); + + request.getRemoteAddr()); // Are there any authentication details? String usernamePassword = getUsernamePassword(request); @@ -188,29 +200,25 @@ public class DepositServlet extends HttpServlet { response.setStatus(401); return; } - + // Set up some variables String filename = null; - + // Do the processing try { // Write the file to the temp directory filename = tempDirectory + "SWORD-" - + request.getRemoteAddr() + "-" + counter.addAndGet(1); + + request.getRemoteAddr() + "-" + counter.addAndGet(1); log.debug("Package temporarily stored as: " + filename); InputStream inputstream = request.getInputStream(); OutputStream outputstream = new FileOutputStream(new File(filename)); - try - { + try { byte[] buf = new byte[1024]; int len; - while ((len = inputstream.read(buf)) > 0) - { + while ((len = inputstream.read(buf)) > 0) { outputstream.write(buf, 0, len); } - } - finally - { + } finally { inputstream.close(); outputstream.close(); } @@ -219,16 +227,17 @@ public class DepositServlet extends HttpServlet { File file = new File(filename); long fLength = file.length() / 1024; if ((maxUploadSize != -1) && (fLength > maxUploadSize)) { - this.makeErrorDocument(ErrorCodes.MAX_UPLOAD_SIZE_EXCEEDED, - HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, - "The uploaded file exceeded the maximum file size this server will accept (the file is " + - fLength + "kB but the server will only accept files as large as " + - maxUploadSize + "kB)", + this.makeErrorDocument(ErrorCodes.MAX_UPLOAD_SIZE_EXCEEDED, + HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, + "The uploaded file exceeded the maximum file size this server will accept (the" + + " file is " + + fLength + "kB but the server will only accept files as large as " + + maxUploadSize + "kB)", request, response); return; } - + // Check the MD5 hash String receivedMD5 = ChecksumUtils.generateMD5(filename); log.debug("Received filechecksum: " + receivedMD5); @@ -237,9 +246,10 @@ public class DepositServlet extends HttpServlet { log.debug("Received file checksum header: " + md5); if ((md5 != null) && (!md5.equals(receivedMD5))) { // Return an error document - this.makeErrorDocument(ErrorCodes.ERROR_CHECKSUM_MISMATCH, + this.makeErrorDocument(ErrorCodes.ERROR_CHECKSUM_MISMATCH, HttpServletResponse.SC_PRECONDITION_FAILED, - "The received MD5 checksum for the deposited file did not match the checksum sent by the deposit client", + "The received MD5 checksum for the deposited file did not match the checksum " + + "sent by the deposit client", request, response); log.debug("Bad MD5 for file. Aborting with appropriate error message"); @@ -252,7 +262,7 @@ public class DepositServlet extends HttpServlet { String onBehalfOf = request.getHeader(HttpHeaders.X_ON_BEHALF_OF); if ((onBehalfOf != null) && (onBehalfOf.equals("reject"))) { // user name is "reject", so throw a not know error to allow the client to be tested - throw new SWORDErrorException(ErrorCodes.TARGET_OWNER_UKNOWN,"unknown user \"reject\""); + throw new SWORDErrorException(ErrorCodes.TARGET_OWNER_UKNOWN, "unknown user \"reject\""); } else { d.setOnBehalfOf(onBehalfOf); } @@ -270,7 +280,7 @@ public class DepositServlet extends HttpServlet { } else if (noop == null) { d.setNoOp(false); } else { - throw new SWORDErrorException(ErrorCodes.ERROR_BAD_REQUEST,"Bad no-op"); + throw new SWORDErrorException(ErrorCodes.ERROR_BAD_REQUEST, "Bad no-op"); } // Set the X-Verbose header @@ -282,7 +292,7 @@ public class DepositServlet extends HttpServlet { } else if (verbose == null) { d.setVerbose(false); } else { - throw new SWORDErrorException(ErrorCodes.ERROR_BAD_REQUEST,"Bad verbose"); + throw new SWORDErrorException(ErrorCodes.ERROR_BAD_REQUEST, "Bad verbose"); } // Set the slug @@ -311,21 +321,20 @@ public class DepositServlet extends HttpServlet { // Get the DepositResponse DepositResponse dr = myRepository.doDeposit(d); - + // Echo back the user agent if (request.getHeader(HttpHeaders.USER_AGENT) != null) { dr.getEntry().setUserAgent(request.getHeader(HttpHeaders.USER_AGENT)); } - + // Echo back the packaging format if (request.getHeader(HttpHeaders.X_PACKAGING) != null) { dr.getEntry().setPackaging(request.getHeader(HttpHeaders.X_PACKAGING)); } - + // Print out the Deposit Response response.setStatus(dr.getHttpResponse()); - if ((dr.getLocation() != null) && (!dr.getLocation().equals(""))) - { + if ((dr.getLocation() != null) && (!dr.getLocation().equals(""))) { response.setHeader("Location", dr.getLocation()); } response.setContentType("application/atom+xml; charset=UTF-8"); @@ -343,7 +352,7 @@ public class DepositServlet extends HttpServlet { } catch (SWORDErrorException see) { // Get the details and send the right SWORD error document log.error(see.toString()); - this.makeErrorDocument(see.getErrorURI(), + this.makeErrorDocument(see.getErrorURI(), see.getStatus(), see.getDescription(), request, @@ -355,35 +364,30 @@ public class DepositServlet extends HttpServlet { } catch (NoSuchAlgorithmException nsae) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); log.error(nsae.toString()); - } - - finally { + } finally { // Try deleting the temp file if (filename != null) { File f = new File(filename); - if (f != null && !f.delete()) - { + if (f != null && !f.delete()) { log.error("Unable to delete file: " + filename); } } } } - + /** * Utility method to construct a SWORDErrorDocumentTest - * + * * @param errorURI The error URI to pass - * @param status The HTTP status to return - * @param summary The textual description to give the user - * @param request The HttpServletRequest object + * @param status The HTTP status to return + * @param summary The textual description to give the user + * @param request The HttpServletRequest object * @param response The HttpServletResponse to send the error document to - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ - protected void makeErrorDocument(String errorURI, int status, String summary, - HttpServletRequest request, HttpServletResponse response) - throws IOException - { + protected void makeErrorDocument(String errorURI, int status, String summary, + HttpServletRequest request, HttpServletResponse response) + throws IOException { SWORDErrorDocument sed = new SWORDErrorDocument(errorURI); Title title = new Title(); title.setContent("ERROR"); @@ -409,9 +413,8 @@ public class DepositServlet extends HttpServlet { /** * Utility method to return the username and password (separated by a colon * ':') - * - * @param request - * Servlet's HTTP request object. + * + * @param request Servlet's HTTP request object. * @return The username and password combination */ protected String getUsernamePassword(HttpServletRequest request) { @@ -424,7 +427,7 @@ public class DepositServlet extends HttpServlet { if (basic.equalsIgnoreCase("Basic")) { String credentials = st.nextToken(); String userPass = new String(Base64 - .decodeBase64(credentials.getBytes())); + .decodeBase64(credentials.getBytes())); return userPass; } } @@ -437,7 +440,7 @@ public class DepositServlet extends HttpServlet { /** * Utility method to decide if we are using HTTP Basic authentication - * + * * @return if HTTP Basic authentication is in use or not */ protected boolean authenticateWithBasic() { @@ -446,7 +449,7 @@ public class DepositServlet extends HttpServlet { /** * Utility method to construct the URL called for this Servlet - * + * * @param req The request object * @return The URL */ diff --git a/dspace-sword/src/main/java/org/purl/sword/server/DummyServer.java b/dspace-sword/src/main/java/org/purl/sword/server/DummyServer.java index 5ee17e3c9d..c7c2f49dcc 100644 --- a/dspace-sword/src/main/java/org/purl/sword/server/DummyServer.java +++ b/dspace-sword/src/main/java/org/purl/sword/server/DummyServer.java @@ -15,9 +15,9 @@ import java.util.Date; import java.util.TimeZone; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; - import javax.servlet.http.HttpServletResponse; +import org.apache.log4j.Logger; import org.purl.sword.atom.Author; import org.purl.sword.atom.Content; import org.purl.sword.atom.Contributor; @@ -41,57 +41,58 @@ import org.purl.sword.base.ServiceDocument; import org.purl.sword.base.ServiceDocumentRequest; import org.purl.sword.base.Workspace; -import org.apache.log4j.Logger; - /** * A 'dummy server' which acts as dumb repository which implements the * SWORD ServerInterface. It accepts any type of deposit, and tries to * return appropriate responses. - * + * * It supports authentication: if the username and password match - * (case sensitive) it authenticates the user, if not, the authentication + * (case sensitive) it authenticates the user, if not, the authentication * fails. - * + * * @author Stuart Lewis */ public class DummyServer implements SWORDServer { - /** A counter to count submissions, so the response to a deposit can increment */ + /** + * A counter to count submissions, so the response to a deposit can increment + */ private static int counter = 0; - /** Logger */ + /** + * Logger + */ private static Logger log = Logger.getLogger(ServiceDocumentServlet.class); /** * Provides a dumb but plausible service document - it contains * an anonymous workspace and collection, and one personalised * for the onBehalfOf user. - * + * * @param sdr The request * @throws SWORDAuthenticationException If the credentials are bad - * @throws SWORDErrorException If something goes wrong, such as + * @throws SWORDErrorException If something goes wrong, such as */ public ServiceDocument doServiceDocument(ServiceDocumentRequest sdr) - throws SWORDAuthenticationException, SWORDErrorException, - SWORDException - { + throws SWORDAuthenticationException, SWORDErrorException, + SWORDException { // Authenticate the user String username = sdr.getUsername(); String password = sdr.getPassword(); - if ((username != null) && (password != null) && - (((username.equals("")) && (password.equals(""))) || - (!username.equalsIgnoreCase(password))) ) { - // User not authenticated - throw new SWORDAuthenticationException("Bad credentials"); + if ((username != null) && (password != null) && + (((username.equals("")) && (password.equals(""))) || + (!username.equalsIgnoreCase(password)))) { + // User not authenticated + throw new SWORDAuthenticationException("Bad credentials"); } - + // Allow users to force the throwing of a SWORD error exception by setting // the OBO user to 'error' if ((sdr.getOnBehalfOf() != null) && (sdr.getOnBehalfOf().equals("error"))) { // Throw the error exception throw new SWORDErrorException(ErrorCodes.MEDIATION_NOT_ALLOWED, "Mediated deposits not allowed"); } - + // Create and return a dummy ServiceDocument ServiceDocument document = new ServiceDocument(); Service service = new Service("1.3", true, true); @@ -99,12 +100,13 @@ public class DummyServer implements SWORDServer { log.debug("sdr.getLocation() is: " + sdr.getLocation()); String location = sdr.getLocation().substring(0, sdr.getLocation().length() - 16); log.debug("location is: " + location); - + if (sdr.getLocation().contains("?nested=")) { Workspace workspace = new Workspace(); workspace.setTitle("Nested service document workspace"); Collection collection = new Collection(); - collection.setTitle("Nested collection: " + sdr.getLocation().substring(sdr.getLocation().indexOf('?') + 1)); + collection + .setTitle("Nested collection: " + sdr.getLocation().substring(sdr.getLocation().indexOf('?') + 1)); collection.setLocation(location + "/deposit/nested"); collection.addAcceptPackaging("http://purl.org/net/sword-types/METSDSpaceSIP"); collection.addAcceptPackaging("http://purl.org/net/sword-types/bagit"); @@ -112,13 +114,14 @@ public class DummyServer implements SWORDServer { collection.addAccepts("application/xml"); collection.setAbstract("A nested collection that users can deposit into"); collection.setTreatment("This is a dummy server"); - collection.setCollectionPolicy("No guarantee of service, or that deposits will be retained for any length of time."); + collection.setCollectionPolicy( + "No guarantee of service, or that deposits will be retained for any length of time."); workspace.addCollection(collection); service.addWorkspace(workspace); } else { Workspace workspace = new Workspace(); workspace.setTitle("Anonymous submitters workspace"); - Collection collection = new Collection(); + Collection collection = new Collection(); collection.setTitle("Anonymous submitters collection"); collection.setLocation(location + "/deposit/anon"); collection.addAcceptPackaging("http://purl.org/net/sword-types/METSDSpaceSIP"); @@ -127,10 +130,11 @@ public class DummyServer implements SWORDServer { collection.addAccepts("application/xml"); collection.setAbstract("A collection that anonymous users can deposit into"); collection.setTreatment("This is a dummy server"); - collection.setCollectionPolicy("No guarantee of service, or that deposits will be retained for any length of time."); + collection.setCollectionPolicy( + "No guarantee of service, or that deposits will be retained for any length of time."); collection.setService(location + "/client/servicedocument?nested=anon"); workspace.addCollection(collection); - collection = new Collection(); + collection = new Collection(); collection.setTitle("Anonymous submitters other collection"); collection.setLocation(location + "/deposit/anonymous"); collection.addAcceptPackaging("http://purl.org/net/sword-types/METSDSpaceSIP"); @@ -139,14 +143,15 @@ public class DummyServer implements SWORDServer { collection.addAccepts("application/xml"); collection.setAbstract("Another collection that anonymous users can deposit into"); collection.setTreatment("This is a dummy server"); - collection.setCollectionPolicy("No guarantee of service, or that deposits will be retained for any length of time."); + collection.setCollectionPolicy( + "No guarantee of service, or that deposits will be retained for any length of time."); workspace.addCollection(collection); service.addWorkspace(workspace); - + if (sdr.getUsername() != null) { workspace = new Workspace(); workspace.setTitle("Authenticated workspace for " + username); - collection = new Collection(); + collection = new Collection(); collection.setTitle("Authenticated collection for " + username); collection.setLocation(location + "/deposit/" + username); collection.addAccepts("application/zip"); @@ -155,10 +160,11 @@ public class DummyServer implements SWORDServer { collection.addAcceptPackaging("http://purl.org/net/sword-types/bagit", 0.8f); collection.setAbstract("A collection that " + username + " can deposit into"); collection.setTreatment("This is a dummy server"); - collection.setCollectionPolicy("No guarantee of service, or that deposits will be retained for any length of time."); + collection.setCollectionPolicy( + "No guarantee of service, or that deposits will be retained for any length of time."); collection.setService(location + "/client/servicedocument?nested=authenticated"); workspace.addCollection(collection); - collection = new Collection(); + collection = new Collection(); collection.setTitle("Second authenticated collection for " + username); collection.setLocation(location + "/deposit/" + username + "-2"); collection.addAccepts("application/zip"); @@ -167,17 +173,18 @@ public class DummyServer implements SWORDServer { collection.addAcceptPackaging("http://purl.org/net/sword-types/METSDSpaceSIP"); collection.setAbstract("A collection that " + username + " can deposit into"); collection.setTreatment("This is a dummy server"); - collection.setCollectionPolicy("No guarantee of service, or that deposits will be retained for any length of time."); + collection.setCollectionPolicy( + "No guarantee of service, or that deposits will be retained for any length of time."); workspace.addCollection(collection); } service.addWorkspace(workspace); } - + String onBehalfOf = sdr.getOnBehalfOf(); if ((onBehalfOf != null) && (!onBehalfOf.equals(""))) { Workspace workspace = new Workspace(); workspace.setTitle("Personal workspace for " + onBehalfOf); - Collection collection = new Collection(); + Collection collection = new Collection(); collection.setTitle("Personal collection for " + onBehalfOf); collection.setLocation(location + "/deposit?user=" + onBehalfOf); collection.addAccepts("application/zip"); @@ -191,29 +198,29 @@ public class DummyServer implements SWORDServer { workspace.addCollection(collection); service.addWorkspace(workspace); } - + return document; } - public DepositResponse doDeposit(Deposit deposit) - throws SWORDAuthenticationException, SWORDErrorException, SWORDException { + public DepositResponse doDeposit(Deposit deposit) + throws SWORDAuthenticationException, SWORDErrorException, SWORDException { // Authenticate the user String username = deposit.getUsername(); String password = deposit.getPassword(); - if ((username != null) && (password != null) && - (((username.equals("")) && (password.equals(""))) || - (!username.equalsIgnoreCase(password))) ) { + if ((username != null) && (password != null) && + (((username.equals("")) && (password.equals(""))) || + (!username.equalsIgnoreCase(password)))) { // User not authenticated throw new SWORDAuthenticationException("Bad credentials"); } - + // Check this is a collection that takes obo deposits, else thrown an error - if (((deposit.getOnBehalfOf() != null) && (!deposit.getOnBehalfOf().equals(""))) && + if (((deposit.getOnBehalfOf() != null) && (!deposit.getOnBehalfOf().equals(""))) && (!deposit.getLocation().contains("deposit?user="))) { throw new SWORDErrorException(ErrorCodes.MEDIATION_NOT_ALLOWED, "Mediated deposit not allowed to this collection"); } - + // Get the filenames StringBuffer filenames = new StringBuffer("Deposit file contained: "); if (deposit.getFilename() != null) { @@ -234,44 +241,40 @@ public class DummyServer implements SWORDServer { } catch (IOException ioe) { throw new SWORDException("Failed to open deposited zip file", ioe, ErrorCodes.ERROR_CONTENT); } finally { - if (zip != null) - { - try - { + if (zip != null) { + try { zip.close(); - } - catch (IOException e) - { + } catch (IOException e) { log.error("Unable to close zip stream", e); } } } - + // Handle the deposit if (!deposit.isNoOp()) { counter++; } DepositResponse dr = new DepositResponse(Deposit.CREATED); SWORDEntry se = new SWORDEntry(); - + Title t = new Title(); t.setContent("DummyServer Deposit: #" + counter); se.setTitle(t); - + se.addCategory("Category"); - + if (deposit.getSlug() != null) { se.setId(deposit.getSlug() + " - ID: " + counter); } else { se.setId("ID: " + counter); } - + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); TimeZone utc = TimeZone.getTimeZone("UTC"); - sdf.setTimeZone (utc); + sdf.setTimeZone(utc); String milliFormat = sdf.format(new Date()); se.setUpdated(milliFormat); - + Summary s = new Summary(); s.setContent(filenames.toString()); se.setSummary(s); @@ -282,30 +285,30 @@ public class DummyServer implements SWORDServer { a.setName("unknown"); } se.addAuthors(a); - + Link em = new Link(); em.setRel("edit-media"); em.setHref("http://www.myrepository.ac.uk/sdl/workflow/my deposit"); se.addLink(em); - + Link e = new Link(); e.setRel("edit"); e.setHref("http://www.myrepository.ac.uk/sdl/workflow/my deposit.atom"); se.addLink(e); - + if (deposit.getOnBehalfOf() != null) { Contributor c = new Contributor(); c.setName(deposit.getOnBehalfOf()); c.setEmail(deposit.getOnBehalfOf() + "@myrepository.ac.uk"); se.addContributor(c); } - + Generator generator = new Generator(); generator.setContent("Stuart's Dummy SWORD Server"); generator.setUri("http://dummy-sword-server.example.com/"); generator.setVersion("1.3"); se.setGenerator(generator); - + Content content = new Content(); try { content.setType("application/zip"); @@ -314,34 +317,34 @@ public class DummyServer implements SWORDServer { } content.setSource("http://www.myrepository.ac.uk/sdl/uploads/upload-" + counter + ".zip"); se.setContent(content); - + se.setTreatment("Short back and sides"); - + if (deposit.isVerbose()) { se.setVerboseDescription("I've done a lot of hard work to get this far!"); } - + se.setNoOp(deposit.isNoOp()); - + dr.setEntry(se); - + dr.setLocation("http://www.myrepository.ac.uk/atom/" + counter); - + return dr; } - - public AtomDocumentResponse doAtomDocument(AtomDocumentRequest adr) - throws SWORDAuthenticationException, SWORDErrorException, SWORDException { + + public AtomDocumentResponse doAtomDocument(AtomDocumentRequest adr) + throws SWORDAuthenticationException, SWORDErrorException, SWORDException { // Authenticate the user String username = adr.getUsername(); String password = adr.getPassword(); - if ((username != null) && (password != null) && - (((username.equals("")) && (password.equals(""))) || - (!username.equalsIgnoreCase(password))) ) { + if ((username != null) && (password != null) && + (((username.equals("")) && (password.equals(""))) || + (!username.equalsIgnoreCase(password)))) { // User not authenticated throw new SWORDAuthenticationException("Bad credentials"); } - + return new AtomDocumentResponse(HttpServletResponse.SC_OK); } diff --git a/dspace-sword/src/main/java/org/purl/sword/server/SWORDServer.java b/dspace-sword/src/main/java/org/purl/sword/server/SWORDServer.java index 33010de936..37caad7567 100644 --- a/dspace-sword/src/main/java/org/purl/sword/server/SWORDServer.java +++ b/dspace-sword/src/main/java/org/purl/sword/server/SWORDServer.java @@ -20,58 +20,52 @@ import org.purl.sword.base.ServiceDocumentRequest; /** * An abstract interface to be implemented by repositories wishing to provide * a SWORD compliant service. - * + * * http://www.ukoln.ac.uk/repositories/digirep/index/SWORD - * + * * @author Stuart Lewis */ public interface SWORDServer { - - /** - * Answer a Service Document request sent on behalf of a user - * - * @param sdr The Service Document Request object - * - * @throws SWORDAuthenticationException Thrown if the authentication fails - * @throws SWORDErrorException Thrown if there was an error with the input not matching - * the capabilities of the server - * @throws SWORDException Thrown in an un-handalable Exception occurs. - * This will be dealt with by sending a HTTP 500 Server Exception - * - * @return The ServiceDocument representing the service document - */ - public ServiceDocument doServiceDocument(ServiceDocumentRequest sdr) - throws SWORDAuthenticationException, SWORDErrorException, SWORDException; - - /** - * Answer a SWORD deposit - * - * @param deposit The Deposit object - * - * @throws SWORDAuthenticationException Thrown if the authentication fails - * @throws SWORDErrorException Thrown if there was an error with the input not matching - * the capabilities of the server - * @throws SWORDException Thrown if an un-handalable Exception occurs. - * This will be dealt with by sending a HTTP 500 Server Exception - * - * @return The response to the deposit - */ - public DepositResponse doDeposit(Deposit deposit) - throws SWORDAuthenticationException, SWORDErrorException, SWORDException; - - /** - * Answer a request for an entry document - * - * @param adr The Atom Document Request object - * - * @throws SWORDAuthenticationException Thrown if the authentication fails - * @throws SWORDErrorException Thrown if there was an error with the input not matching - * the capabilities of the server - * @throws SWORDException Thrown if an un-handalable Exception occurs. - * This will be dealt with by sending a HTTP 500 Server Exception - * - * @return The response to the atom document request - */ - public AtomDocumentResponse doAtomDocument(AtomDocumentRequest adr) - throws SWORDAuthenticationException, SWORDErrorException, SWORDException; + + /** + * Answer a Service Document request sent on behalf of a user + * + * @param sdr The Service Document Request object + * @return The ServiceDocument representing the service document + * @throws SWORDAuthenticationException Thrown if the authentication fails + * @throws SWORDErrorException Thrown if there was an error with the input not matching + * the capabilities of the server + * @throws SWORDException Thrown in an un-handalable Exception occurs. + * This will be dealt with by sending a HTTP 500 Server Exception + */ + public ServiceDocument doServiceDocument(ServiceDocumentRequest sdr) + throws SWORDAuthenticationException, SWORDErrorException, SWORDException; + + /** + * Answer a SWORD deposit + * + * @param deposit The Deposit object + * @return The response to the deposit + * @throws SWORDAuthenticationException Thrown if the authentication fails + * @throws SWORDErrorException Thrown if there was an error with the input not matching + * the capabilities of the server + * @throws SWORDException Thrown if an un-handalable Exception occurs. + * This will be dealt with by sending a HTTP 500 Server Exception + */ + public DepositResponse doDeposit(Deposit deposit) + throws SWORDAuthenticationException, SWORDErrorException, SWORDException; + + /** + * Answer a request for an entry document + * + * @param adr The Atom Document Request object + * @return The response to the atom document request + * @throws SWORDAuthenticationException Thrown if the authentication fails + * @throws SWORDErrorException Thrown if there was an error with the input not matching + * the capabilities of the server + * @throws SWORDException Thrown if an un-handalable Exception occurs. + * This will be dealt with by sending a HTTP 500 Server Exception + */ + public AtomDocumentResponse doAtomDocument(AtomDocumentRequest adr) + throws SWORDAuthenticationException, SWORDErrorException, SWORDException; } diff --git a/dspace-sword/src/main/java/org/purl/sword/server/ServiceDocumentServlet.java b/dspace-sword/src/main/java/org/purl/sword/server/ServiceDocumentServlet.java index 79bafbb718..bb43850ef6 100644 --- a/dspace-sword/src/main/java/org/purl/sword/server/ServiceDocumentServlet.java +++ b/dspace-sword/src/main/java/org/purl/sword/server/ServiceDocumentServlet.java @@ -10,7 +10,6 @@ package org.purl.sword.server; import java.io.IOException; import java.io.PrintWriter; import java.util.StringTokenizer; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -32,16 +31,24 @@ import org.purl.sword.base.ServiceDocumentRequest; */ public class ServiceDocumentServlet extends HttpServlet { - /** The repository */ + /** + * The repository + */ private transient SWORDServer myRepository; - /** Authentication type. */ + /** + * Authentication type. + */ private String authN; - /** Maximum file upload size in kB **/ + /** + * Maximum file upload size in kB + **/ private int maxUploadSize; - /** Logger */ + /** + * Logger + */ private static final Logger log = Logger.getLogger(ServiceDocumentServlet.class); /** @@ -57,22 +64,17 @@ public class ServiceDocumentServlet extends HttpServlet { if (className == null) { log.fatal("Unable to read value of 'sword-server-class' from Servlet context"); throw new ServletException("Unable to read value of 'sword-server-class' from Servlet context"); - } - else - { - try - { + } else { + try { myRepository = (SWORDServer) Class.forName(className) - .newInstance(); + .newInstance(); log.info("Using " + className + " as the SWORDServer"); - } - catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) - { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { log.fatal("Unable to instantiate class from 'server-class': " - + className); + + className); throw new ServletException( "Unable to instantiate class from 'server-class': " - + className, e); + + className, e); } } @@ -89,15 +91,11 @@ public class ServiceDocumentServlet extends HttpServlet { (maxUploadSizeStr.equals("-1"))) { maxUploadSize = -1; log.warn("No maxUploadSize set, so setting max file upload size to unlimited."); - } - else - { + } else { try { maxUploadSize = Integer.parseInt(maxUploadSizeStr); log.info("Setting max file upload size to " + maxUploadSize); - } - catch (NumberFormatException nfe) - { + } catch (NumberFormatException nfe) { maxUploadSize = -1; log.warn("maxUploadSize not a number, so setting max file upload size to unlimited."); } @@ -106,14 +104,15 @@ public class ServiceDocumentServlet extends HttpServlet { /** * Process the GET request. - * @param request the request. + * + * @param request the request. * @param response the response. * @throws javax.servlet.ServletException passed through. - * @throws java.io.IOException passed through. + * @throws java.io.IOException passed through. */ @Override protected void doGet(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { + HttpServletResponse response) throws ServletException, IOException { // Create the ServiceDocumentRequest ServiceDocumentRequest sdr = new ServiceDocumentRequest(); @@ -125,9 +124,7 @@ public class ServiceDocumentServlet extends HttpServlet { sdr.setUsername(usernamePassword.substring(0, p)); sdr.setPassword(usernamePassword.substring(p + 1)); } - } - else if (authenticateWithBasic()) - { + } else if (authenticateWithBasic()) { String s = "Basic realm=\"SWORD\""; response.setHeader("WWW-Authenticate", s); response.setStatus(401); @@ -146,8 +143,7 @@ public class ServiceDocumentServlet extends HttpServlet { // Get the ServiceDocument try { ServiceDocument sd = myRepository.doServiceDocument(sdr); - if ((sd.getService().getMaxUploadSize() == -1) && (maxUploadSize != -1)) - { + if ((sd.getService().getMaxUploadSize() == -1) && (maxUploadSize != -1)) { sd.getService().setMaxUploadSize(maxUploadSize); } @@ -156,22 +152,16 @@ public class ServiceDocumentServlet extends HttpServlet { PrintWriter out = response.getWriter(); out.write(sd.marshall()); out.flush(); - } - catch (SWORDAuthenticationException sae) - { + } catch (SWORDAuthenticationException sae) { if (authN.equals("Basic")) { String s = "Basic realm=\"SWORD\""; response.setHeader("WWW-Authenticate", s); response.setStatus(401); } - } - catch (SWORDErrorException see) - { + } catch (SWORDErrorException see) { // Return the relevant HTTP status code response.sendError(see.getStatus(), see.getDescription()); - } - catch (SWORDException se) - { + } catch (SWORDException se) { log.error("Internal error", se); // Throw a HTTP 500 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, se.getMessage()); @@ -180,16 +170,16 @@ public class ServiceDocumentServlet extends HttpServlet { /** * Process the post request. This will return an unimplemented response. - * @param request the request. + * + * @param request the request. * @param response the response. * @throws javax.servlet.ServletException passed through. - * @throws java.io.IOException passed through. + * @throws java.io.IOException passed through. */ @Override protected void doPost(HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException - { + HttpServletResponse response) + throws ServletException, IOException { // Send a '501 Not Implemented' response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); } @@ -202,27 +192,21 @@ public class ServiceDocumentServlet extends HttpServlet { * @return The username and password combination */ private String getUsernamePassword(HttpServletRequest request) { - try - { + try { String authHeader = request.getHeader("Authorization"); - if (authHeader != null) - { + if (authHeader != null) { StringTokenizer st = new StringTokenizer(authHeader); - if (st.hasMoreTokens()) - { + if (st.hasMoreTokens()) { String basic = st.nextToken(); - if (basic.equalsIgnoreCase("Basic")) - { + if (basic.equalsIgnoreCase("Basic")) { String credentials = st.nextToken(); String userPass = new String(Base64 - .decodeBase64(credentials.getBytes())); + .decodeBase64(credentials.getBytes())); return userPass; } } } - } - catch (Exception e) - { + } catch (Exception e) { log.debug(e.toString()); } return null; @@ -233,8 +217,7 @@ public class ServiceDocumentServlet extends HttpServlet { * * @return if HTTP Basic authentication is in use or not */ - private boolean authenticateWithBasic() - { + private boolean authenticateWithBasic() { return (authN.equalsIgnoreCase("Basic")); } @@ -244,13 +227,11 @@ public class ServiceDocumentServlet extends HttpServlet { * @param req The request object * @return The URL */ - private static String getUrl(HttpServletRequest req) - { + private static String getUrl(HttpServletRequest req) { String reqUrl = req.getRequestURL().toString(); String queryString = req.getQueryString(); log.debug("Requested url is: " + reqUrl); - if (queryString != null) - { + if (queryString != null) { reqUrl += "?" + queryString; } log.debug("Requested url with Query String is: " + reqUrl); diff --git a/dspace-sword/src/main/webapp/WEB-INF/web.xml b/dspace-sword/src/main/webapp/WEB-INF/web.xml index 1a2f267bd8..3d721e9744 100644 --- a/dspace-sword/src/main/webapp/WEB-INF/web.xml +++ b/dspace-sword/src/main/webapp/WEB-INF/web.xml @@ -8,81 +8,76 @@ http://www.dspace.org/license/ --> - - + - DSpace SWORD Server + DSpace SWORD Server - dspace.dir - ${dspace.dir} - - The location of the DSpace home directory - + The location of the DSpace home directory + dspace.dir + ${dspace.dir} - - sword-server-class - org.dspace.sword.DSpaceSWORDServer - - The SWORDServer class name - - - - - authentication-method - Basic - - The type of authentication used : [Basic|None] - - - - + + The SWORDServer class name + sword-server-class + org.dspace.sword.DSpaceSWORDServer + + + + The type of authentication used : [Basic|None] + authentication-method + Basic + + + - - org.dspace.app.util.DSpaceContextListener - + + org.dspace.app.util.DSpaceContextListener + - - org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener - - + + org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener + + - - - servicedocument - org.purl.sword.server.ServiceDocumentServlet - + + + servicedocument + org.purl.sword.server.ServiceDocumentServlet + - - deposit - org.purl.sword.server.DepositServlet - + + deposit + org.purl.sword.server.DepositServlet + - - media-link - org.purl.sword.server.AtomDocumentServlet - + + media-link + org.purl.sword.server.AtomDocumentServlet + - + - - servicedocument - /servicedocument/* - - - - deposit - /deposit/* - + + servicedocument + /servicedocument/* + + + + deposit + /deposit/* + + + + media-link + /media-link/* + - - media-link - /media-link/* - - diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 138e9435a3..2d923f69d8 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.dspace dspace-swordv2 @@ -80,7 +81,7 @@ javax.servlet - servlet-api + javax.servlet-api provided @@ -94,6 +95,10 @@ org.apache.abdera abdera-client + + javax.servlet + servlet-api + diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/AbstractSimpleDC.java b/dspace-swordv2/src/main/java/org/dspace/sword2/AbstractSimpleDC.java index 52dae30ac9..5362a08adf 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/AbstractSimpleDC.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/AbstractSimpleDC.java @@ -8,6 +8,10 @@ package org.dspace.sword2; +import java.util.HashMap; +import java.util.List; +import java.util.Properties; + import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; @@ -15,32 +19,23 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; -import java.util.HashMap; -import java.util.List; -import java.util.Properties; - -public class AbstractSimpleDC -{ +public class AbstractSimpleDC { protected HashMap dcMap = null; protected HashMap atomMap = null; protected ItemService itemService = ContentServiceFactory.getInstance() - .getItemService(); + .getItemService(); - protected void loadMetadataMaps() - { - if (this.dcMap == null) - { + protected void loadMetadataMaps() { + if (this.dcMap == null) { // we should load our DC map from configuration this.dcMap = new HashMap<>(); Properties props = ConfigurationManager - .getProperties("swordv2-server"); - for (Object key : props.keySet()) - { + .getProperties("swordv2-server"); + for (Object key : props.keySet()) { String keyString = (String) key; - if (keyString.startsWith("simpledc.")) - { + if (keyString.startsWith("simpledc.")) { String k = keyString.substring("simpledc.".length()); String v = (String) props.get(key); this.dcMap.put(k, v); @@ -48,16 +43,13 @@ public class AbstractSimpleDC } } - if (this.atomMap == null) - { + if (this.atomMap == null) { this.atomMap = new HashMap<>(); Properties props = ConfigurationManager - .getProperties("swordv2-server"); - for (Object key : props.keySet()) - { + .getProperties("swordv2-server"); + for (Object key : props.keySet()) { String keyString = (String) key; - if (keyString.startsWith("atom.")) - { + if (keyString.startsWith("atom.")) { String k = keyString.substring("atom.".length()); String v = (String) props.get(key); this.atomMap.put(k, v); @@ -66,40 +58,33 @@ public class AbstractSimpleDC } } - protected SimpleDCMetadata getMetadata(Item item) - { + protected SimpleDCMetadata getMetadata(Item item) { this.loadMetadataMaps(); SimpleDCMetadata md = new SimpleDCMetadata(); List all = itemService - .getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + .getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue dcv : all) - { + for (MetadataValue dcv : all) { MetadataField field = dcv.getMetadataField(); String valueMatch = field.getMetadataSchema().getName() + "." + - field.getElement(); - if (field.getQualifier() != null) - { + field.getElement(); + if (field.getQualifier() != null) { valueMatch += "." + field.getQualifier(); } // look for the metadata in the dublin core map - for (String key : this.dcMap.keySet()) - { + for (String key : this.dcMap.keySet()) { String value = this.dcMap.get(key); - if (valueMatch.equals(value)) - { + if (valueMatch.equals(value)) { md.addDublinCore(key, dcv.getValue()); } } // look for the metadata in the atom map - for (String key : this.atomMap.keySet()) - { + for (String key : this.atomMap.keySet()) { String value = this.atomMap.get(key); - if (valueMatch.equals(value)) - { + if (valueMatch.equals(value)) { md.addAtom(key, dcv.getValue()); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/AbstractSwordContentIngester.java b/dspace-swordv2/src/main/java/org/dspace/sword2/AbstractSwordContentIngester.java index b31956e32c..9184c5293e 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/AbstractSwordContentIngester.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/AbstractSwordContentIngester.java @@ -7,8 +7,17 @@ */ package org.dspace.sword2; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.StringTokenizer; + import org.apache.log4j.Logger; -import org.dspace.content.*; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.ItemService; @@ -19,14 +28,8 @@ import org.swordapp.server.SwordAuthException; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; -import java.util.StringTokenizer; - public abstract class AbstractSwordContentIngester - implements SwordContentIngester -{ + implements SwordContentIngester { public static final Logger log = Logger.getLogger( AbstractSwordContentIngester.class); @@ -37,67 +40,56 @@ public abstract class AbstractSwordContentIngester ContentServiceFactory.getInstance().getItemService(); public DepositResult ingest(Context context, Deposit deposit, - DSpaceObject dso, VerboseDescription verboseDescription) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + DSpaceObject dso, VerboseDescription verboseDescription) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { return this.ingest(context, deposit, dso, verboseDescription, null); } public DepositResult ingest(Context context, Deposit deposit, - DSpaceObject dso, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - if (dso instanceof Collection) - { + DSpaceObject dso, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + if (dso instanceof Collection) { return this.ingestToCollection(context, deposit, (Collection) dso, - verboseDescription, result); - } - else if (dso instanceof Item) - { + verboseDescription, result); + } else if (dso instanceof Item) { return this.ingestToItem(context, deposit, (Item) dso, - verboseDescription, result); + verboseDescription, result); } return null; } public abstract DepositResult ingestToCollection(Context context, - Deposit deposit, Collection collection, - VerboseDescription verboseDescription, DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException; + Deposit deposit, Collection collection, + VerboseDescription verboseDescription, DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException; public abstract DepositResult ingestToItem(Context context, Deposit deposit, - Item item, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException; + Item item, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException; protected BitstreamFormat getFormat(Context context, String fileName) - throws SQLException - { + throws SQLException { String fext = null; int lastDot = fileName.lastIndexOf("."); - if (lastDot > -1) - { + if (lastDot > -1) { fext = fileName.substring(lastDot + 1); } - if (fext == null) - { + if (fext == null) { return null; } List formats = bitstreamFormatService.findAll(context); - for (BitstreamFormat format : formats) - { + for (BitstreamFormat format : formats) { List extensions = format.getExtensions(); - for (String ext : extensions) - { - if (ext.equals(fext)) - { + for (String ext : extensions) { + if (ext.equals(fext)) { return format; } } @@ -110,38 +102,29 @@ public abstract class AbstractSwordContentIngester * the field in which to store this metadata in the configuration * sword.updated.field * - * @param context - * The relevant DSpace Context. - * @param item - * target item - * @param verboseDescription - * The description. - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @param context The relevant DSpace Context. + * @param item target item + * @param verboseDescription The description. + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ protected void setUpdatedDate(Context context, Item item, - VerboseDescription verboseDescription) - throws DSpaceSwordException - { + VerboseDescription verboseDescription) + throws DSpaceSwordException { String field = ConfigurationManager .getProperty("swordv2-server", "updated.field"); - if (field == null || "".equals(field)) - { + if (field == null || "".equals(field)) { throw new DSpaceSwordException( "No configuration, or configuration is invalid for: sword.updated.field"); } MetadataFieldInfo info = this.configToDC(field, null); - try - { + try { itemService.clearMetadata(context, item, info.schema, info.element, - info.qualifier, Item.ANY); + info.qualifier, Item.ANY); DCDate date = new DCDate(new Date()); itemService.addMetadata(context, item, info.schema, info.element, - info.qualifier, null, date.toString()); - } - catch (SQLException e) - { + info.qualifier, null, date.toString()); + } catch (SQLException e) { log.error("Caught exception trying to set update date", e); throw new DSpaceSwordException(e); } @@ -156,45 +139,34 @@ public abstract class AbstractSwordContentIngester * field in which to store this metadata in the configuration * sword.slug.field * - * @param context - * The relevant DSpace Context. - * @param item - * target item - * @param slugVal - * slug value - * @param verboseDescription - * The description. - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @param context The relevant DSpace Context. + * @param item target item + * @param slugVal slug value + * @param verboseDescription The description. + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ protected void setSlug(Context context, Item item, String slugVal, - VerboseDescription verboseDescription) - throws DSpaceSwordException - { + VerboseDescription verboseDescription) + throws DSpaceSwordException { // if there isn't a slug value, don't set it - if (slugVal == null) - { + if (slugVal == null) { return; } String field = ConfigurationManager .getProperty("swordv2-server", "slug.field"); - if (field == null || "".equals(field)) - { + if (field == null || "".equals(field)) { throw new DSpaceSwordException( "No configuration, or configuration is invalid for: sword.slug.field"); } MetadataFieldInfo info = this.configToDC(field, null); - try - { + try { itemService.clearMetadata(context, item, info.schema, info.element, - info.qualifier, Item.ANY); + info.qualifier, Item.ANY); itemService.addMetadata(context, item, info.schema, info.element, - info.qualifier, null, slugVal); - } - catch (SQLException e) - { + info.qualifier, null, slugVal); + } catch (SQLException e) { log.error("Caught exception trying to set slug", e); throw new DSpaceSwordException(e); } @@ -204,17 +176,16 @@ public abstract class AbstractSwordContentIngester /** * Utility method to turn given metadata fields of the form - schema.element.qualifier into Metadatum objects which can be - used to access metadata in items. + * schema.element.qualifier into Metadatum objects which can be + * used to access metadata in items. * * The def parameter should be null, * or "" depending on how - you intend to use the Metadatum object. + * you intend to use the Metadatum object. * * @param config * @param def */ - private MetadataFieldInfo configToDC(String config, String def) - { + private MetadataFieldInfo configToDC(String config, String def) { MetadataFieldInfo mfi = new MetadataFieldInfo(); mfi.schema = def; mfi.element = def; @@ -223,16 +194,14 @@ public abstract class AbstractSwordContentIngester StringTokenizer stz = new StringTokenizer(config, "."); mfi.schema = stz.nextToken(); mfi.element = stz.nextToken(); - if (stz.hasMoreTokens()) - { + if (stz.hasMoreTokens()) { mfi.qualifier = stz.nextToken(); } return mfi; } - private class MetadataFieldInfo - { + private class MetadataFieldInfo { private String schema; private String element; diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/AtomCollectionGenerator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/AtomCollectionGenerator.java index d0940d4e2c..0be5d00242 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/AtomCollectionGenerator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/AtomCollectionGenerator.java @@ -17,21 +17,16 @@ import org.swordapp.server.SwordCollection; * Define an abstract interface for classes wishing to generate ATOM Collections * for SWORD service documents */ -public interface AtomCollectionGenerator -{ +public interface AtomCollectionGenerator { /** * Build the ATOM Collection which represents the given DSpace Object. * - * @param context - * The relevant DSpace Context. - * @param dso - * target DSpace object - * @param config - * SWORD configuration + * @param context The relevant DSpace Context. + * @param dso target DSpace object + * @param config SWORD configuration * @return ATOM Collection which represents the given DSpace Object - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public SwordCollection buildCollection(Context context, DSpaceObject dso, - SwordConfigurationDSpace config) throws DSpaceSwordException; + SwordConfigurationDSpace config) throws DSpaceSwordException; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/AtomStatementDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/AtomStatementDisseminator.java index c79c8e5160..7c41e3c263 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/AtomStatementDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/AtomStatementDisseminator.java @@ -7,6 +7,8 @@ */ package org.dspace.sword2; +import java.util.List; + import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; @@ -18,27 +20,23 @@ import org.swordapp.server.Statement; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -import java.util.List; - public class AtomStatementDisseminator extends GenericStatementDisseminator - implements SwordStatementDisseminator -{ + implements SwordStatementDisseminator { protected ItemService itemService = ContentServiceFactory.getInstance() - .getItemService(); + .getItemService(); public Statement disseminate(Context context, Item item) - throws DSpaceSwordException, SwordError, SwordServerException - { + throws DSpaceSwordException, SwordError, SwordServerException { SwordUrlManager urlManager = new SwordUrlManager( - new SwordConfigurationDSpace(), context); + new SwordConfigurationDSpace(), context); String feedUri = urlManager.getAtomStatementUri(item); String authorField = ConfigurationManager - .getProperty("swordv2-server", "author.field"); + .getProperty("swordv2-server", "author.field"); String titleField = ConfigurationManager - .getProperty("swordv2-server", "title.field"); + .getProperty("swordv2-server", "title.field"); String updatedField = ConfigurationManager - .getProperty("swordv2-server", "updated.field"); + .getProperty("swordv2-server", "updated.field"); String author = this.stringMetadata(item, authorField); String title = this.stringMetadata(item, titleField); @@ -49,25 +47,20 @@ public class AtomStatementDisseminator extends GenericStatementDisseminator return s; } - private String stringMetadata(Item item, String field) - { - if (field == null) - { + private String stringMetadata(Item item, String field) { + if (field == null) { return null; } List dcvs = itemService - .getMetadataByMetadataString(item, field); - if (dcvs == null || dcvs.isEmpty()) - { + .getMetadataByMetadataString(item, field); + if (dcvs == null || dcvs.isEmpty()) { return null; } StringBuilder md = new StringBuilder(); - for (MetadataValue dcv : dcvs) - { - if (md.length() > 0) - { + for (MetadataValue dcv : dcvs) { + if (md.length() > 0) { md.append(", "); } md.append(dcv.getValue()); diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/BinaryContentIngester.java b/dspace-swordv2/src/main/java/org/dspace/sword2/BinaryContentIngester.java index 9d70abce77..f238ad87e7 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/BinaryContentIngester.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/BinaryContentIngester.java @@ -7,6 +7,10 @@ */ package org.dspace.sword2; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; @@ -25,12 +29,7 @@ import org.swordapp.server.SwordAuthException; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; - -public class BinaryContentIngester extends AbstractSwordContentIngester -{ +public class BinaryContentIngester extends AbstractSwordContentIngester { protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); @@ -41,33 +40,27 @@ public class BinaryContentIngester extends AbstractSwordContentIngester ContentServiceFactory.getInstance().getBitstreamService(); public DepositResult ingestToCollection(Context context, Deposit deposit, - Collection collection, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - try - { + Collection collection, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + try { // decide whether we have a new item or an existing one Item item = null; WorkspaceItem wsi = null; - if (result != null) - { + if (result != null) { item = result.getItem(); - } - else - { + } else { result = new DepositResult(); } - if (item == null) - { + if (item == null) { // simple zip ingester uses the item template, since there is no native metadata wsi = workspaceItemService.create(context, collection, true); item = wsi.getItem(); } Bitstream bs = itemService.createSingleBitstream( - context, deposit.getInputStream(), item); + context, deposit.getInputStream(), item); BitstreamFormat format = this.getFormat( context, deposit.getFilename()); bs.setName(context, deposit.getFilename()); @@ -77,7 +70,7 @@ public class BinaryContentIngester extends AbstractSwordContentIngester // now we have an item in the workspace, and we need to consider adding some metadata to it, // but since the binary file didn't contain anything, what do we do? itemService.addMetadata(context, item, "dc", "title", null, null, - "Untitled: " + deposit.getFilename()); + "Untitled: " + deposit.getFilename()); itemService.addMetadata( context, item, "dc", "description", null, null, "Zip file deposted by SWORD without accompanying metadata"); @@ -107,27 +100,20 @@ public class BinaryContentIngester extends AbstractSwordContentIngester result.setOriginalDeposit(bs); return result; - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); - } - catch (SQLException | IOException e) - { + } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); } } public DepositResult ingestToItem(Context context, Deposit deposit, - Item item, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - try - { - if (result == null) - { + Item item, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + try { + if (result == null) { result = new DepositResult(); } result.setItem(item); @@ -135,23 +121,20 @@ public class BinaryContentIngester extends AbstractSwordContentIngester // get the original bundle List originals = item.getBundles(); Bundle original = null; - for (Bundle bundle : originals) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : originals) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { original = bundle; } } - if (original == null) - { + if (original == null) { original = bundleService - .create(context, item, Constants.CONTENT_BUNDLE_NAME); + .create(context, item, Constants.CONTENT_BUNDLE_NAME); } Bitstream bs = bitstreamService - .create(context, original, deposit.getInputStream()); + .create(context, original, deposit.getInputStream()); BitstreamFormat format = this - .getFormat(context, deposit.getFilename()); + .getFormat(context, deposit.getFilename()); bs.setFormat(context, format); bs.setName(context, deposit.getFilename()); bitstreamService.update(context, bs); @@ -175,13 +158,9 @@ public class BinaryContentIngester extends AbstractSwordContentIngester result.setOriginalDeposit(bs); return result; - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); - } - catch (SQLException | IOException e) - { + } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); } } @@ -191,13 +170,11 @@ public class BinaryContentIngester extends AbstractSwordContentIngester * put the deposit through * * @return human readable description - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ - private String getTreatment() throws DSpaceSwordException - { + private String getTreatment() throws DSpaceSwordException { return "The package has been ingested and unpacked into the item. Template metadata for " + - "the collection has been used, and a default title with the name of the file has " + - "been set"; + "the collection has been used, and a default title with the name of the file has " + + "been set"; } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionCollectionGenerator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionCollectionGenerator.java index 8859cb3c49..f22ebbd60e 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionCollectionGenerator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionCollectionGenerator.java @@ -7,28 +7,25 @@ */ package org.dspace.sword2; +import java.util.List; + import org.apache.abdera.i18n.iri.IRI; import org.apache.commons.lang3.StringUtils; +import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.core.ConfigurationManager; -import org.apache.log4j.Logger; import org.dspace.core.Context; import org.swordapp.server.SwordCollection; -import java.util.Map; -import java.util.List; - /** * Class to generate ATOM Collection Elements which represent * DSpace Collections - * */ -public class CollectionCollectionGenerator implements AtomCollectionGenerator -{ +public class CollectionCollectionGenerator implements AtomCollectionGenerator { private static Logger log = Logger.getLogger( CommunityCollectionGenerator.class); @@ -38,19 +35,16 @@ public class CollectionCollectionGenerator implements AtomCollectionGenerator /** * Build the collection for the given DSpaceObject. In this implementation, * if the object is not a DSpace Collection, it will throw DSpaceSwordException - * @param context - * The relevant DSpace Context. - * @param dso DSpace object + * + * @param context The relevant DSpace Context. + * @param dso DSpace object * @return the SWORD ATOM collection - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public SwordCollection buildCollection(Context context, DSpaceObject dso, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException - { - if (!(dso instanceof org.dspace.content.Collection)) - { + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException { + if (!(dso instanceof org.dspace.content.Collection)) { log.error( "buildCollection passed argument which is not of type Collection"); throw new DSpaceSwordException( @@ -59,7 +53,7 @@ public class CollectionCollectionGenerator implements AtomCollectionGenerator // get the things we need out of the service SwordUrlManager urlManager = swordConfig - .getUrlManager(context, swordConfig); + .getUrlManager(context, swordConfig); Collection col = (Collection) dso; SwordCollection scol = new SwordCollection(); @@ -78,7 +72,7 @@ public class CollectionCollectionGenerator implements AtomCollectionGenerator // abstract is the short description of the collection List dcAbstracts = collectionService - .getMetadataByMetadataString(col, "short_description"); + .getMetadataByMetadataString(col, "short_description"); // we just do support mediation boolean mediation = swordConfig.isMediated(); @@ -87,14 +81,12 @@ public class CollectionCollectionGenerator implements AtomCollectionGenerator scol.setLocation(location); // add the title if it exists - if (StringUtils.isNotBlank(title)) - { + if (StringUtils.isNotBlank(title)) { scol.setTitle(title); } // add the collection policy if it exists - if (StringUtils.isNotBlank(collectionPolicy)) - { + if (StringUtils.isNotBlank(collectionPolicy)) { scol.setCollectionPolicy(collectionPolicy); } @@ -103,11 +95,9 @@ public class CollectionCollectionGenerator implements AtomCollectionGenerator // scol.setTreatment(treatment); // add the abstract if it exists - if (dcAbstracts != null && !dcAbstracts.isEmpty()) - { + if (dcAbstracts != null && !dcAbstracts.isEmpty()) { String firstValue = dcAbstracts.get(0).getValue(); - if (StringUtils.isNotBlank(firstValue)) - { + if (StringUtils.isNotBlank(firstValue)) { scol.setAbstract(firstValue); } } @@ -115,16 +105,14 @@ public class CollectionCollectionGenerator implements AtomCollectionGenerator scol.setMediation(mediation); List accepts = swordConfig.getCollectionAccepts(); - for (String accept : accepts) - { + for (String accept : accepts) { scol.addAccepts(accept); scol.addMultipartAccepts(accept); } // add the accept packaging values List aps = swordConfig.getAcceptPackaging(col); - for (String ap : aps) - { + for (String ap : aps) { scol.addAcceptPackaging(ap); } @@ -132,8 +120,7 @@ public class CollectionCollectionGenerator implements AtomCollectionGenerator // targets? boolean itemService = ConfigurationManager.getBooleanProperty( "sword.expose-items"); - if (itemService) - { + if (itemService) { String subService = urlManager.constructSubServiceUrl(col); scol.addSubService(new IRI(subService)); } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionDepositManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionDepositManagerDSpace.java index a054a57749..a088ce5300 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionDepositManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionDepositManagerDSpace.java @@ -7,35 +7,40 @@ */ package org.dspace.sword2; +import java.io.IOException; +import java.util.Date; + import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.core.Context; import org.dspace.core.LogManager; -import org.swordapp.server.*; - -import java.io.IOException; -import java.util.Date; +import org.swordapp.server.AuthCredentials; +import org.swordapp.server.CollectionDepositManager; +import org.swordapp.server.Deposit; +import org.swordapp.server.DepositReceipt; +import org.swordapp.server.SwordAuthException; +import org.swordapp.server.SwordConfiguration; +import org.swordapp.server.SwordError; +import org.swordapp.server.SwordServerException; public class CollectionDepositManagerDSpace extends DSpaceSwordAPI - implements CollectionDepositManager -{ + implements CollectionDepositManager { /** * logger */ private static Logger log = Logger - .getLogger(CollectionDepositManagerDSpace.class); + .getLogger(CollectionDepositManagerDSpace.class); protected CollectionService collectionService = ContentServiceFactory - .getInstance().getCollectionService(); + .getInstance().getCollectionService(); private VerboseDescription verboseDescription = new VerboseDescription(); public DepositReceipt createNew(String collectionUri, Deposit deposit, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); @@ -45,24 +50,21 @@ public class CollectionDepositManagerDSpace extends DSpaceSwordAPI SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { // first authenticate the request // note: this will build our various DSpace contexts for us sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug( - LogManager.getHeader(context, "sword_create_new", "")); + LogManager.getHeader(context, "sword_create_new", "")); } // get the deposit target Collection collection = this - .getDepositTarget(context, collectionUri, config); - if (collection == null) - { + .getDepositTarget(context, collectionUri, config); + if (collection == null) { throw new SwordError(404); } @@ -73,78 +75,58 @@ public class CollectionDepositManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, collection, this.verboseDescription)) - { + if (!auth.canSubmit(sc, collection, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager - .getHeader(context, "deposit_failed_authorisation", - "user=" + - sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + .getHeader(context, "deposit_failed_authorisation", + "user=" + + sc.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( - "Cannot submit to the given collection with this context"); + "Cannot submit to the given collection with this context"); } // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } DepositResult result = null; - try - { - if (deposit.isBinaryOnly()) - { + try { + if (deposit.isBinaryOnly()) { result = this.createNewFromBinary(sc, collection, deposit, - authCredentials, config); - } - else if (deposit.isEntryOnly()) - { + authCredentials, config); + } else if (deposit.isEntryOnly()) { result = this.createNewFromEntry(sc, collection, deposit, - authCredentials, config); - } - else if (deposit.isMultipart()) - { + authCredentials, config); + } else if (deposit.isMultipart()) { result = this - .createNewFromMultipart(sc, collection, deposit, - authCredentials, config); + .createNewFromMultipart(sc, collection, deposit, + authCredentials, config); } - } - catch (DSpaceSwordException | SwordError e) - { - if (config.isKeepPackageOnFailedIngest()) - { - try - { - if (deposit.isBinaryOnly()) - { + } catch (DSpaceSwordException | SwordError e) { + if (config.isKeepPackageOnFailedIngest()) { + try { + if (deposit.isBinaryOnly()) { this.storePackageAsFile(deposit, authCredentials, - config); - } - else if (deposit.isEntryOnly()) - { + config); + } else if (deposit.isEntryOnly()) { this.storeEntryAsFile(deposit, authCredentials, - config); - } - else if (deposit.isMultipart()) - { + config); + } else if (deposit.isMultipart()) { this.storePackageAsFile(deposit, authCredentials, - config); + config); this.storeEntryAsFile(deposit, authCredentials, - config); + config); } - } - catch (IOException e2) - { + } catch (IOException e2) { log.warn("Unable to store SWORD package as file: " + e); } } @@ -156,13 +138,13 @@ public class CollectionDepositManagerDSpace extends DSpaceSwordAPI ReceiptGenerator genny = new ReceiptGenerator(); DepositReceipt receipt = genny - .createReceipt(context, result, config); + .createReceipt(context, result, config); Date finish = new Date(); long delta = finish.getTime() - start.getTime(); this.verboseDescription - .append("Total time for deposit processing: " + delta + + .append("Total time for deposit processing: " + delta + " ms"); this.addVerboseDescription(receipt, this.verboseDescription); @@ -170,30 +152,24 @@ public class CollectionDepositManagerDSpace extends DSpaceSwordAPI sc.commit(); return receipt; - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( - "There was a problem depositing the item", e); - } - finally - { + "There was a problem depositing the item", e); + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } protected DepositResult createNewFromBinary(SwordContext swordContext, - Collection collection, Deposit deposit, - AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + Collection collection, Deposit deposit, + AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { // get the things out of the service that we need Context context = swordContext.getContext(); // is the content acceptable? If not, this will throw an error @@ -201,56 +177,54 @@ public class CollectionDepositManagerDSpace extends DSpaceSwordAPI // Obtain the relevant ingester from the factory SwordContentIngester si = SwordIngesterFactory - .getContentInstance(context, deposit, collection); + .getContentInstance(context, deposit, collection); this.verboseDescription - .append("Loaded ingester: " + si.getClass().getName()); + .append("Loaded ingester: " + si.getClass().getName()); // do the deposit DepositResult result = si - .ingest(context, deposit, collection, this.verboseDescription); + .ingest(context, deposit, collection, this.verboseDescription); this.verboseDescription.append("Archive ingest completed successfully"); // store the originals (this code deals with the possibility that that's not required) this.storeOriginals(swordConfig, context, this.verboseDescription, - deposit, result); + deposit, result); return result; } protected DepositResult createNewFromEntry(SwordContext swordContext, - Collection collection, Deposit deposit, - AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + Collection collection, Deposit deposit, + AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { // get the things out of the service that we need Context context = swordContext.getContext(); // Obtain the relevant ingester from the factory SwordEntryIngester si = SwordIngesterFactory - .getEntryInstance(context, deposit, collection); + .getEntryInstance(context, deposit, collection); this.verboseDescription - .append("Loaded ingester: " + si.getClass().getName()); + .append("Loaded ingester: " + si.getClass().getName()); // do the deposit DepositResult result = si - .ingest(context, deposit, collection, this.verboseDescription); + .ingest(context, deposit, collection, this.verboseDescription); this.verboseDescription.append("Archive ingest completed successfully"); // store the originals (this code deals with the possibility that that's not required) this.storeOriginals(swordConfig, context, this.verboseDescription, - deposit, result); + deposit, result); return result; } protected DepositResult createNewFromMultipart(SwordContext swordContext, - Collection collection, Deposit deposit, - AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + Collection collection, Deposit deposit, + AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { // get the things out of the service that we need Context context = swordContext.getContext(); @@ -259,67 +233,62 @@ public class CollectionDepositManagerDSpace extends DSpaceSwordAPI // Obtain the relevant content ingester from the factory SwordContentIngester sci = SwordIngesterFactory - .getContentInstance(context, deposit, collection); + .getContentInstance(context, deposit, collection); this.verboseDescription - .append("Loaded content ingester: " + sci.getClass().getName()); + .append("Loaded content ingester: " + sci.getClass().getName()); // obtain the relevant entry intester from the factory SwordEntryIngester sei = SwordIngesterFactory - .getEntryInstance(context, deposit, collection); + .getEntryInstance(context, deposit, collection); this.verboseDescription - .append("Loaded entry ingester: " + sei.getClass().getName()); + .append("Loaded entry ingester: " + sei.getClass().getName()); DepositResult result; - if (swordConfig.isEntryFirst()) - { + if (swordConfig.isEntryFirst()) { // do the entry deposit result = sei.ingest(context, deposit, collection, - this.verboseDescription); + this.verboseDescription); // do the content deposit result = sci.ingest(context, deposit, collection, - this.verboseDescription, result); + this.verboseDescription, result); this.verboseDescription - .append("Archive ingest completed successfully"); - } - else - { + .append("Archive ingest completed successfully"); + } else { // do the content deposit result = sci.ingest(context, deposit, collection, - this.verboseDescription); + this.verboseDescription); // do the entry deposit result = sei.ingest(context, deposit, collection, - this.verboseDescription, result, false); + this.verboseDescription, result, false); this.verboseDescription - .append("Archive ingest completed successfully"); + .append("Archive ingest completed successfully"); } // store the originals (this code deals with the possibility that that's not required) this.storeOriginals(swordConfig, context, this.verboseDescription, - deposit, result); + deposit, result); return result; } protected Collection getDepositTarget(Context context, String depositUrl, - SwordConfigurationDSpace config) - throws DSpaceSwordException, SwordError - { + SwordConfigurationDSpace config) + throws DSpaceSwordException, SwordError { SwordUrlManager urlManager = config.getUrlManager(context, config); // get the target collection Collection collection = urlManager.getCollection(context, depositUrl); - if (collection == null) - { + if (collection == null) { throw new SwordError(404); } this.verboseDescription - .append("Performing deposit using deposit URL: " + depositUrl); + .append("Performing deposit using deposit URL: " + depositUrl); this.verboseDescription - .append("Location resolves to collection with handle: " + + .append("Location resolves to collection with handle: " + collection.getHandle() + " and name: " + collectionService.getName(collection)); diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionListManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionListManagerDSpace.java index f56edb5732..6e1febf9a4 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionListManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionListManagerDSpace.java @@ -7,6 +7,11 @@ */ package org.dspace.sword2; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import org.apache.abdera.Abdera; import org.apache.abdera.i18n.iri.IRI; import org.apache.abdera.model.Entry; @@ -23,29 +28,26 @@ import org.dspace.eperson.EPerson; import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.WorkflowItemService; import org.dspace.workflow.factory.WorkflowServiceFactory; -import org.swordapp.server.*; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import org.swordapp.server.AuthCredentials; +import org.swordapp.server.CollectionListManager; +import org.swordapp.server.SwordAuthException; +import org.swordapp.server.SwordConfiguration; +import org.swordapp.server.SwordError; +import org.swordapp.server.SwordServerException; public class CollectionListManagerDSpace extends DSpaceSwordAPI - implements CollectionListManager -{ + implements CollectionListManager { protected WorkspaceItemService workspaceItemService = ContentServiceFactory - .getInstance().getWorkspaceItemService(); + .getInstance().getWorkspaceItemService(); protected WorkflowItemService workflowItemService = WorkflowServiceFactory - .getInstance().getWorkflowItemService(); + .getInstance().getWorkflowItemService(); public Feed listCollectionContents(IRI colIRI, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordServerException, SwordError, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordServerException, SwordError, SwordAuthException { SwordContext sc = null; - try - { + try { SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; sc = this.doAuth(authCredentials); Context context = sc.getContext(); @@ -53,32 +55,25 @@ public class CollectionListManagerDSpace extends DSpaceSwordAPI Collection collection = urlManager .getCollection(context, colIRI.toString()); - if (collection == null) - { + if (collection == null) { throw new SwordError(404); } List items = this.listItems(sc, collection, swordConfig); return this.itemListToFeed(sc, items, swordConfig); - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { throw new SwordServerException(e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } private Feed itemListToFeed(SwordContext sc, List items, - SwordConfiguration swordConfig) - throws DSpaceSwordException - { + SwordConfiguration swordConfig) + throws DSpaceSwordException { SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; SwordUrlManager urlManager = config.getUrlManager( sc.getContext(), config); @@ -86,8 +81,7 @@ public class CollectionListManagerDSpace extends DSpaceSwordAPI Abdera abdera = new Abdera(); Feed feed = abdera.newFeed(); - for (Item item : items) - { + for (Item item : items) { Entry entry = feed.addEntry(); entry.setId(urlManager.getEditIRI(item).toString()); String title = this.stringMetadata(item, ConfigurationManager @@ -102,11 +96,9 @@ public class CollectionListManagerDSpace extends DSpaceSwordAPI } private List listItems(SwordContext sc, Collection collection, - SwordConfiguration swordConfig) - throws DSpaceSwordException - { - try - { + SwordConfiguration swordConfig) + throws DSpaceSwordException { + try { EPerson person = sc.getOnBehalfOf() != null ? sc.getOnBehalfOf() : sc.getAuthenticated(); @@ -115,14 +107,11 @@ public class CollectionListManagerDSpace extends DSpaceSwordAPI // first get the ones out of the archive Iterator items = itemService .findBySubmitter(sc.getContext(), person); - while (items.hasNext()) - { + while (items.hasNext()) { Item item = items.next(); List cols = item.getCollections(); - for (Collection col : cols) - { - if (col.getID().equals(collection.getID())) - { + for (Collection col : cols) { + if (col.getID().equals(collection.getID())) { collectionItems.add(item); break; } @@ -131,24 +120,20 @@ public class CollectionListManagerDSpace extends DSpaceSwordAPI // now get the ones out of the workspace List wsis = workspaceItemService - .findByEPerson(sc.getContext(), person); - for (WorkspaceItem wsi : wsis) - { + .findByEPerson(sc.getContext(), person); + for (WorkspaceItem wsi : wsis) { Item item = wsi.getItem(); // check for the wsi collection Collection wsCol = wsi.getCollection(); - if (wsCol.getID().equals(collection.getID())) - { + if (wsCol.getID().equals(collection.getID())) { collectionItems.add(item); } // then see if there are any additional associated collections List cols = item.getCollections(); - for (Collection col : cols) - { - if (col.getID().equals(collection.getID())) - { + for (Collection col : cols) { + if (col.getID().equals(collection.getID())) { collectionItems.add(item); break; } @@ -157,27 +142,22 @@ public class CollectionListManagerDSpace extends DSpaceSwordAPI // finally get the ones out of the workflow List wfis = workflowItemService.findBySubmitter(sc.getContext(), - person); - for (Object found : wfis) - { - if (found instanceof WorkflowItem) - { + person); + for (Object found : wfis) { + if (found instanceof WorkflowItem) { WorkflowItem wfi = (WorkflowItem) found; Item item = wfi.getItem(); // check for the wfi collection Collection wfCol = wfi.getCollection(); - if (wfCol.getID().equals(collection.getID())) - { + if (wfCol.getID().equals(collection.getID())) { collectionItems.add(item); } // then see if there are any additional associated collections List cols = item.getCollections(); - for (Collection col : cols) - { - if (col.getID().equals(collection.getID())) - { + for (Collection col : cols) { + if (col.getID().equals(collection.getID())) { collectionItems.add(item); break; } @@ -186,32 +166,25 @@ public class CollectionListManagerDSpace extends DSpaceSwordAPI } return collectionItems; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } - private String stringMetadata(Item item, String field) - { - if (field == null) - { + private String stringMetadata(Item item, String field) { + if (field == null) { return null; } List dcvs = itemService - .getMetadataByMetadataString(item, field); - if (dcvs == null) - { + .getMetadataByMetadataString(item, field); + if (dcvs == null) { return null; } StringBuilder md = new StringBuilder(); - for (MetadataValue dcv : dcvs) - { - if (md.length() > 0) - { + for (MetadataValue dcv : dcvs) { + if (md.length() > 0) { md.append(", "); } md.append(dcv.getValue()); diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/CommunityCollectionGenerator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/CommunityCollectionGenerator.java index 9b51d737c1..5dd4b73208 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/CommunityCollectionGenerator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/CommunityCollectionGenerator.java @@ -7,64 +7,58 @@ */ package org.dspace.sword2; +import java.util.List; + import org.apache.abdera.i18n.iri.IRI; import org.apache.commons.lang.StringUtils; -import org.dspace.content.DSpaceObject; -import org.dspace.content.Community; import org.apache.log4j.Logger; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CommunityService; import org.dspace.core.Context; -import org.dspace.handle.HandleServiceImpl; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; import org.swordapp.server.SwordCollection; -import java.util.List; - -public class CommunityCollectionGenerator implements AtomCollectionGenerator -{ +public class CommunityCollectionGenerator implements AtomCollectionGenerator { private static Logger log = Logger - .getLogger(CommunityCollectionGenerator.class); + .getLogger(CommunityCollectionGenerator.class); protected HandleService handleService = HandleServiceFactory.getInstance() - .getHandleService(); + .getHandleService(); protected CommunityService communityService = ContentServiceFactory - .getInstance().getCommunityService(); + .getInstance().getCommunityService(); public SwordCollection buildCollection(Context context, DSpaceObject dso, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException - { - if (!(dso instanceof Community)) - { + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException { + if (!(dso instanceof Community)) { log.error( - "buildCollection passed something other than a Community object"); + "buildCollection passed something other than a Community object"); throw new DSpaceSwordException( - "Incorrect ATOMCollectionGenerator instantiated"); + "Incorrect ATOMCollectionGenerator instantiated"); } // get the things we need out of the service SwordUrlManager urlManager = swordConfig - .getUrlManager(context, swordConfig); + .getUrlManager(context, swordConfig); Community com = (Community) dso; SwordCollection scol = new SwordCollection(); // prepare the parameters to be put in the sword collection String location = urlManager.getDepositLocation(com); - if (location == null) - { + if (location == null) { location = handleService.getCanonicalForm(com.getHandle()); } scol.setLocation(location); // collection title is just the community name String title = communityService.getName(com); - if (StringUtils.isNotBlank(title)) - { + if (StringUtils.isNotBlank(title)) { scol.setTitle(title); } @@ -74,12 +68,10 @@ public class CommunityCollectionGenerator implements AtomCollectionGenerator // abstract is the short description of the collection List abstracts = communityService - .getMetadataByMetadataString(com, "short_description"); - if (abstracts != null && !abstracts.isEmpty()) - { + .getMetadataByMetadataString(com, "short_description"); + if (abstracts != null && !abstracts.isEmpty()) { String firstValue = abstracts.get(0).getValue(); - if (StringUtils.isNotBlank(firstValue)) - { + if (StringUtils.isNotBlank(firstValue)) { scol.setAbstract(firstValue); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java index 718e7e86f9..92b2b57787 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/ContainerManagerDSpace.java @@ -7,6 +7,13 @@ */ package org.dspace.sword2; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.factory.AuthorizeServiceFactory; @@ -21,18 +28,17 @@ import org.dspace.core.LogManager; import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.WorkflowItemService; import org.dspace.workflow.factory.WorkflowServiceFactory; -import org.swordapp.server.*; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; +import org.swordapp.server.AuthCredentials; +import org.swordapp.server.ContainerManager; +import org.swordapp.server.Deposit; +import org.swordapp.server.DepositReceipt; +import org.swordapp.server.SwordAuthException; +import org.swordapp.server.SwordConfiguration; +import org.swordapp.server.SwordError; +import org.swordapp.server.SwordServerException; public class ContainerManagerDSpace extends DSpaceSwordAPI - implements ContainerManager -{ + implements ContainerManager { private static Logger log = Logger.getLogger(ContainerManagerDSpace.class); protected AuthorizeService authorizeService = @@ -47,67 +53,54 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI private VerboseDescription verboseDescription = new VerboseDescription(); public boolean isStatementRequest(String editIRI, - Map accept, AuthCredentials authCredentials, - SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + Map accept, AuthCredentials authCredentials, + SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { SwordContext sc = null; - try - { + try { sc = this.noAuthContext(); SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; String acceptContentType = this.getHeader(accept, "Accept", null); TreeMap> analysed = this - .analyseAccept(acceptContentType); + .analyseAccept(acceptContentType); // a request is for a statement if the content negotiation asks for a format that the // Statement disseminator supports SwordStatementDisseminator disseminator = null; - try - { + try { SwordDisseminatorFactory - .getStatementInstance(analysed); - } - catch (SwordError swordError) - { + .getStatementInstance(analysed); + } catch (SwordError swordError) { // in this case, it means that no relevant disseminator could be found, which means // this is not a statement request return false; } return true; - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( "There was a problem determining the request type", e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public DepositReceipt getEntry(String editIRI, Map accept, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordServerException, SwordError, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordServerException, SwordError, SwordAuthException { SwordContext sc = null; - try - { + try { SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; sc = this.doAuth(authCredentials); Context context = sc.getContext(); SwordUrlManager urlManager = config.getUrlManager(context, config); Item item = urlManager.getItem(context, editIRI); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -118,29 +111,21 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI DepositReceipt receipt = genny.createReceipt(context, item, config); sc.abort(); return receipt; - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(); - } - catch (SQLException | DSpaceSwordException e) - { + } catch (SQLException | DSpaceSwordException e) { throw new SwordServerException(e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public DepositReceipt replaceMetadata(String editIRI, Deposit deposit, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); @@ -151,20 +136,17 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "sword_replace", "")); } // get the deposit target Item item = this.getDSpaceTarget(context, editIRI, config); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -176,47 +158,37 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager.getHeader( context, "replace_failed_authorisation", "user=" + sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( - "Cannot replace the given item with this context"); + "Cannot replace the given item with this context"); } // make a note of the authentication in the verbose string this.verboseDescription.append( "Authenticated user: " + sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } DepositResult result = null; - try - { + try { result = this.doReplaceMetadata( sc, item, deposit, authCredentials, config); - } - catch (DSpaceSwordException | SwordError e) - { - if (config.isKeepPackageOnFailedIngest()) - { - try - { + } catch (DSpaceSwordException | SwordError e) { + if (config.isKeepPackageOnFailedIngest()) { + try { this.storeEntryAsFile(deposit, authCredentials, config); - } - catch (IOException e2) - { + } catch (IOException e2) { log.warn("Unable to store SWORD entry as file: " + e); } } @@ -241,28 +213,22 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI sc.commit(); return receipt; - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( "There was a problem depositing the item", e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public DepositReceipt replaceMetadataAndMediaResource(String editIRI, - Deposit deposit, AuthCredentials authCredentials, - SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + Deposit deposit, AuthCredentials authCredentials, + SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); @@ -273,23 +239,20 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { // first authenticate the request // note: this will build our various DSpace contexts for us sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader( context, "sword_create_new", "")); } // get the deposit target Item item = this.getDSpaceTarget(context, editIRI, config); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -300,18 +263,16 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager.getHeader(context, - "deposit_failed_authorisation", - "user=" + sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + "deposit_failed_authorisation", + "user=" + sc.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( "Cannot submit to the given collection with this context"); } @@ -319,30 +280,22 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI // make a note of the authentication in the verbose string this.verboseDescription.append( "Authenticated user: " + sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } DepositResult result = null; - try - { + try { result = this.replaceFromMultipart( - sc, item, deposit, authCredentials, config); - } - catch (DSpaceSwordException | SwordError e) - { - if (config.isKeepPackageOnFailedIngest()) - { - try - { + sc, item, deposit, authCredentials, config); + } catch (DSpaceSwordException | SwordError e) { + if (config.isKeepPackageOnFailedIngest()) { + try { this.storePackageAsFile(deposit, authCredentials, - config); + config); this.storeEntryAsFile(deposit, authCredentials, config); - } - catch (IOException e2) - { + } catch (IOException e2) { log.warn("Unable to store SWORD package as file: " + e); } } @@ -367,34 +320,27 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI sc.commit(); return receipt; - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( "There was a problem depositing the item", e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public DepositReceipt addMetadataAndResources(String s, Deposit deposit, - AuthCredentials authCredentials, SwordConfiguration config) - throws SwordError, SwordServerException - { + AuthCredentials authCredentials, SwordConfiguration config) + throws SwordError, SwordServerException { return null; } public DepositReceipt addMetadata(String editIRI, Deposit deposit, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); @@ -405,20 +351,17 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "sword_replace", "")); } // get the deposit target Item item = this.getDSpaceTarget(context, editIRI, config); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -430,47 +373,37 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager.getHeader( context, "replace_failed_authorisation", "user=" + sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( "Cannot replace the given item with this context"); } // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } DepositResult result = null; - try - { + try { result = this.doAddMetadata( sc, item, deposit, authCredentials, config); - } - catch (DSpaceSwordException | SwordError e) - { - if (config.isKeepPackageOnFailedIngest()) - { - try - { + } catch (DSpaceSwordException | SwordError e) { + if (config.isKeepPackageOnFailedIngest()) { + try { this.storeEntryAsFile(deposit, authCredentials, config); - } - catch (IOException e2) - { + } catch (IOException e2) { log.warn("Unable to store SWORD entry as file: " + e); } } @@ -495,34 +428,27 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI sc.commit(); return receipt; - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( "There was a problem depositing the item", e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public DepositReceipt addResources(String s, Deposit deposit, - AuthCredentials authCredentials, SwordConfiguration config) - throws SwordError, SwordServerException - { + AuthCredentials authCredentials, SwordConfiguration config) + throws SwordError, SwordServerException { return null; } public void deleteContainer(String editIRI, AuthCredentials authCredentials, - SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); @@ -532,20 +458,17 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "sword_delete", "")); } // get the deposit target Item item = this.getDSpaceTarget(context, editIRI, config); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -557,29 +480,26 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager.getHeader(context, - "replace_failed_authorisation", - "user=" + sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + "replace_failed_authorisation", + "user=" + sc.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( "Cannot delete the given item with this context"); } // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } this.doContainerDelete(sc, item, authCredentials, config); @@ -592,27 +512,21 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI // if something hasn't killed it already (allowed), then complete the transaction sc.commit(); - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( "There was a problem depositing the item", e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public DepositReceipt useHeaders(String editIRI, Deposit deposit, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); @@ -623,21 +537,18 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader( context, "sword_modify_by_headers", "")); } // get the deposit target Item item = this.getDSpaceTarget(context, editIRI, config); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -649,29 +560,26 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager.getHeader(context, - "modify_failed_authorisation", - "user=" + sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + "modify_failed_authorisation", + "user=" + sc.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( "Cannot modify the given item with this context"); } // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Modifying on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } DepositResult result = new DepositResult(); @@ -695,29 +603,23 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI sc.commit(); return receipt; - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( "There was a problem depositing the item", e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } private DepositResult replaceFromMultipart(SwordContext swordContext, - Item item, Deposit deposit, AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + Item item, Deposit deposit, AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { // get the things out of the service that we need Context context = swordContext.getContext(); @@ -726,9 +628,9 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI // Obtain the relevant content ingester from the factory SwordContentIngester sci = SwordIngesterFactory - .getContentInstance(context, deposit, item); + .getContentInstance(context, deposit, item); this.verboseDescription - .append("Loaded content ingester: " + sci.getClass().getName()); + .append("Loaded content ingester: " + sci.getClass().getName()); // obtain the relevant entry intester from the factory SwordEntryIngester sei = SwordIngesterFactory.getEntryInstance( @@ -736,25 +638,19 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI this.verboseDescription.append( "Loaded entry ingester: " + sei.getClass().getName()); - try - { + try { // delegate the to the version manager to get rid of any existing content and to version // if if necessary VersionManager vm = new VersionManager(); vm.removeBundle(context, item, "ORIGINAL"); - } - catch (SQLException | IOException e) - { + } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); } DepositResult result; - if (swordConfig.isEntryFirst()) - { + if (swordConfig.isEntryFirst()) { // do the entry deposit result = sei.ingest( context, deposit, item, this.verboseDescription, null, true); @@ -764,9 +660,7 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI context, deposit, item, this.verboseDescription, result); this.verboseDescription.append( "Archive ingest completed successfully"); - } - else - { + } else { // do the content deposit result = sci.ingest( context, deposit, item, this.verboseDescription, null); @@ -786,11 +680,10 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI } private DepositResult doReplaceMetadata(SwordContext swordContext, - Item item, Deposit deposit, AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + Item item, Deposit deposit, AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { // get the things out of the service that we need Context context = swordContext.getContext(); @@ -813,23 +706,20 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI } protected DepositResult doAddMetadata(SwordContext swordContext, Item item, - Deposit deposit, AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + Deposit deposit, AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { return this.doAddMetadata( swordContext, item, deposit, authCredentials, swordConfig, null); } protected DepositResult doAddMetadata(SwordContext swordContext, Item item, - Deposit deposit, AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig, DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - if (result == null) - { + Deposit deposit, AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig, DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + if (result == null) { result = new DepositResult(); } @@ -855,50 +745,39 @@ public class ContainerManagerDSpace extends DSpaceSwordAPI } protected void doContainerDelete(SwordContext swordContext, Item item, - AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordAuthException - { - try - { + AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordAuthException { + try { Context context = swordContext.getContext(); // first figure out if there's anything we need to do about the workflow/workspace state WorkflowTools wft = new WorkflowTools(); - if (wft.isItemInWorkspace(swordContext.getContext(), item)) - { + if (wft.isItemInWorkspace(swordContext.getContext(), item)) { WorkspaceItem wsi = wft.getWorkspaceItem(context, item); workspaceItemService.deleteAll(context, wsi); - } - else if (wft.isItemInWorkflow(context, item)) - { + } else if (wft.isItemInWorkflow(context, item)) { WorkflowItem wfi = wft.getWorkflowItem(context, item); workflowItemService.deleteWrapper(context, wfi); } // then delete the item itemService.delete(context, item); - } - catch (SQLException | IOException e) - { + } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); } } private Item getDSpaceTarget(Context context, String editUrl, - SwordConfigurationDSpace config) - throws DSpaceSwordException, SwordError - { + SwordConfigurationDSpace config) + throws DSpaceSwordException, SwordError { SwordUrlManager urlManager = config.getUrlManager(context, config); // get the target collection Item item = urlManager.getItem(context, editUrl); - if (item == null) - { + if (item == null) { throw new SwordError(404); } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceSwordAPI.java b/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceSwordAPI.java index 3385a89255..845d13341b 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceSwordAPI.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceSwordAPI.java @@ -7,35 +7,12 @@ */ package org.dspace.sword2; -import org.apache.log4j.Logger; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Bitstream; -import org.dspace.content.BitstreamFormat; -import org.dspace.content.Bundle; -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.BitstreamFormatService; -import org.dspace.content.service.BitstreamService; -import org.dspace.content.service.BundleService; -import org.dspace.content.service.ItemService; -import org.dspace.core.*; -import org.swordapp.server.AuthCredentials; -import org.swordapp.server.Deposit; -import org.swordapp.server.DepositReceipt; -import org.swordapp.server.SwordAuthException; -import org.swordapp.server.SwordError; -import org.swordapp.server.SwordServerException; -import org.swordapp.server.UriRegistry; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; @@ -50,8 +27,31 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -public class DSpaceSwordAPI -{ +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.BitstreamFormatService; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.BundleService; +import org.dspace.content.service.ItemService; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.core.LogManager; +import org.dspace.core.Utils; +import org.swordapp.server.AuthCredentials; +import org.swordapp.server.Deposit; +import org.swordapp.server.DepositReceipt; +import org.swordapp.server.SwordAuthException; +import org.swordapp.server.SwordError; +import org.swordapp.server.SwordServerException; +import org.swordapp.server.UriRegistry; + +public class DSpaceSwordAPI { private static Logger log = Logger.getLogger(DSpaceSwordAPI.class); protected ItemService itemService = @@ -67,8 +67,7 @@ public class DSpaceSwordAPI ContentServiceFactory.getInstance().getBitstreamFormatService(); public SwordContext noAuthContext() - throws DSpaceSwordException - { + throws DSpaceSwordException { SwordContext sc = new SwordContext(); Context context = new Context(); sc.setContext(context); @@ -76,11 +75,9 @@ public class DSpaceSwordAPI } public SwordContext doAuth(AuthCredentials authCredentials) - throws SwordAuthException, SwordError, DSpaceSwordException - { + throws SwordAuthException, SwordError, DSpaceSwordException { // if there is no supplied username, then we should request a retry - if (authCredentials.getUsername() == null) - { + if (authCredentials.getUsername() == null) { throw new SwordAuthException(true); } @@ -91,33 +88,28 @@ public class DSpaceSwordAPI // log the request String un = authCredentials.getUsername() != null ? - authCredentials.getUsername() : - "NONE"; + authCredentials.getUsername() : + "NONE"; String obo = authCredentials.getOnBehalfOf() != null ? - authCredentials.getOnBehalfOf() : - "NONE"; + authCredentials.getOnBehalfOf() : + "NONE"; log.info(LogManager.getHeader(sc.getContext(), "sword_auth_request", - "username=" + un + ",on_behalf_of=" + obo)); + "username=" + un + ",on_behalf_of=" + obo)); return sc; } - public String getHeader(Map map, String header, String def) - { - for (String key : map.keySet()) - { - if (key.toLowerCase().equals(header.toLowerCase())) - { + public String getHeader(Map map, String header, String def) { + for (String key : map.keySet()) { + if (key.toLowerCase().equals(header.toLowerCase())) { return map.get(key); } } return def; } - public TreeMap> analyseAccept(String acceptHeader) - { - if (acceptHeader == null) - { + public TreeMap> analyseAccept(String acceptHeader) { + if (acceptHeader == null) { return null; } @@ -126,8 +118,7 @@ public class DSpaceSwordAPI List unsorted = new ArrayList(); float highest_q = 0; int counter = 0; - for (String part : parts) - { + for (String part : parts) { counter += 1; // the components of the part can be "type;params;q" "type;params", "type;q" or just "type" @@ -144,42 +135,34 @@ public class DSpaceSwordAPI // There are then 3 possibilities remaining to check for: "type;q", "type;params" and "type;params;q" // ("type" is already handled by the default cases set up above) - if (components.length == 2) - { + if (components.length == 2) { // "type;q" or "type;params" - if (components[1].trim().startsWith("q=")) - { + if (components[1].trim().startsWith("q=")) { // "type;q" //strip the "q=" from the start of the q value - q = Float.parseFloat(components[1].trim().substring( 2)); + q = Float.parseFloat(components[1].trim().substring(2)); // if the q value is the highest one we've seen so far, record it - if (q > highest_q) - { + if (q > highest_q) { highest_q = q; } - } - else - { + } else { // "type;params" params = components[1].trim(); } - } - else if (components.length == 3) - { + } else if (components.length == 3) { // "type;params;q" params = components[1].trim(); q = Float.parseFloat(components[1].trim().substring( - 2)); // strip the "q=" from the start of the q value + 2)); // strip the "q=" from the start of the q value // if the q value is the highest one we've seen so far, record it - if (q > highest_q) - { + if (q > highest_q) { highest_q = q; } } - Object[] res = new Object[] { type, params, q }; + Object[] res = new Object[] {type, params, q}; unsorted.add(res); } @@ -194,43 +177,34 @@ public class DSpaceSwordAPI TreeMap> sorted = new TreeMap>(); // go through the unsorted list - for (Object[] oa : unsorted) - { + for (Object[] oa : unsorted) { String contentType = (String) oa[0]; String p = (String) oa[1]; - if (p != null) - { + if (p != null) { contentType += ";" + p; } Float qv = (Float) oa[2]; - if (qv > 0) - { - // if the q value is greater than 0 it was explicitly assigned in the Accept header and we can just place + if (qv > 0) { + // if the q value is greater than 0 it was explicitly assigned in the Accept header and we can just + // place // it into the sorted dictionary - if (sorted.containsKey(qv)) - { + if (sorted.containsKey(qv)) { sorted.get(qv).add(contentType); - } - else - { + } else { List cts = new ArrayList(); cts.add(contentType); sorted.put(qv, cts); } - } - else - { + } else { // otherwise, we have to calculate the q value using the following equation which creates a q value "qv" - // within "q_range" of 1.0 [the first part of the eqn] based on the fraction of the way through the total + // within "q_range" of 1.0 [the first part of the eqn] based on the fraction of the way through the + // total // accept header list scaled by the q_range [the second part of the eqn] float nq = (1 - q_range) + (((-1 * qv) / counter) * q_range); - if (sorted.containsKey(nq)) - { + if (sorted.containsKey(nq)) { sorted.get(nq).add(contentType); - } - else - { + } else { List cts = new ArrayList(); cts.add(contentType); sorted.put(nq, cts); @@ -242,46 +216,40 @@ public class DSpaceSwordAPI } public void isAcceptable(SwordConfigurationDSpace swordConfig, - Context context, Deposit deposit, DSpaceObject dso) - throws SwordError, DSpaceSwordException - { + Context context, Deposit deposit, DSpaceObject dso) + throws SwordError, DSpaceSwordException { // determine if this is an acceptable file format if (!swordConfig - .isAcceptableContentType(context, deposit.getMimeType(), dso)) - { + .isAcceptableContentType(context, deposit.getMimeType(), dso)) { log.error("Unacceptable content type detected: " + - deposit.getMimeType() + " for object " + dso.getID()); + deposit.getMimeType() + " for object " + dso.getID()); throw new SwordError(UriRegistry.ERROR_CONTENT, - "Unacceptable content type in deposit request: " + - deposit.getMimeType()); + "Unacceptable content type in deposit request: " + + deposit.getMimeType()); } // determine if this is an acceptable packaging type for the deposit // if not, we throw a 415 HTTP error (Unsupported Media Type, ERROR_CONTENT) - if (!swordConfig.isAcceptedPackaging(deposit.getPackaging(), dso)) - { + if (!swordConfig.isAcceptedPackaging(deposit.getPackaging(), dso)) { log.error("Unacceptable packaging type detected: " + - deposit.getPackaging() + " for object " + dso.getID()); + deposit.getPackaging() + " for object " + dso.getID()); throw new SwordError(UriRegistry.ERROR_CONTENT, - "Unacceptable packaging type in deposit request: " + - deposit.getPackaging()); + "Unacceptable packaging type in deposit request: " + + deposit.getPackaging()); } } public void storeOriginals(SwordConfigurationDSpace swordConfig, - Context context, VerboseDescription verboseDescription, - Deposit deposit, DepositResult result) - throws DSpaceSwordException, SwordServerException - { + Context context, VerboseDescription verboseDescription, + Deposit deposit, DepositResult result) + throws DSpaceSwordException, SwordServerException { // if there's an item availalble, and we want to keep the original // then do that - try - { - if (swordConfig.isKeepOriginal()) - { + try { + if (swordConfig.isKeepOriginal()) { verboseDescription.append( "DSpace will store an original copy of the deposit, " + - "as well as ingesting the item into the archive"); + "as well as ingesting the item into the archive"); // in order to be allowed to add the file back to the item, we need to ignore authorisations // for a moment @@ -289,29 +257,24 @@ public class DSpaceSwordAPI String bundleName = ConfigurationManager.getProperty( "swordv2-server", "bundle.name"); - if (bundleName == null || "".equals(bundleName)) - { + if (bundleName == null || "".equals(bundleName)) { bundleName = "SWORD"; } Item item = result.getItem(); List bundles = item.getBundles(); Bundle swordBundle = null; - for (Bundle bundle : bundles) - { - if (bundleName.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (bundleName.equals(bundle.getName())) { swordBundle = bundle; break; } } - if (swordBundle == null) - { + if (swordBundle == null) { swordBundle = bundleService.create( context, item, bundleName); } - if (deposit.isMultipart() || deposit.isEntryOnly()) - { + if (deposit.isMultipart() || deposit.isEntryOnly()) { String entry = deposit.getSwordEntry().toString(); ByteArrayInputStream bais = new ByteArrayInputStream( entry.getBytes()); @@ -321,43 +284,34 @@ public class DSpaceSwordAPI String fn = this.createEntryFilename(context, deposit, true); entryBitstream.setName(context, fn); entryBitstream.setDescription(context, - "Original SWORD entry document"); + "Original SWORD entry document"); BitstreamFormat bf = bitstreamFormatService - .findByMIMEType(context, "application/xml"); - if (bf != null) - { + .findByMIMEType(context, "application/xml"); + if (bf != null) { entryBitstream.setFormat(context, bf); } bitstreamService.update(context, entryBitstream); verboseDescription.append("Original entry stored as " + fn + - ", in item bundle " + swordBundle); + ", in item bundle " + swordBundle); } - if (deposit.isMultipart() || deposit.isBinaryOnly()) - { + if (deposit.isMultipart() || deposit.isBinaryOnly()) { String fn = this.createFilename(context, deposit, true); Bitstream bitstream; InputStream fis = null; - try - { + try { fis = deposit.getInputStream(); bitstream = bitstreamService - .create(context, swordBundle, fis); - } - finally - { - if (fis != null) - { - try - { + .create(context, swordBundle, fis); + } finally { + if (fis != null) { + try { fis.close(); - } - catch (IOException e) - { + } catch (IOException e) { // problem closing input stream; leave it to the garbage collector } } @@ -365,25 +319,23 @@ public class DSpaceSwordAPI bitstream.setName(context, fn); bitstream.setDescription(context, - "Original SWORD deposit file"); + "Original SWORD deposit file"); BitstreamFormat bf = bitstreamFormatService - .findByMIMEType(context, deposit.getMimeType()); - if (bf != null) - { + .findByMIMEType(context, deposit.getMimeType()); + if (bf != null) { bitstream.setFormat(context, bf); } bitstreamService.update(context, bitstream); - if (result.getOriginalDeposit() == null) - { + if (result.getOriginalDeposit() == null) { // it may be that the original deposit is already set, in which case we // shouldn't mess with it result.setOriginalDeposit(bitstream); } verboseDescription.append( "Original deposit stored as " + fn + - ", in item bundle " + swordBundle); + ", in item bundle " + swordBundle); } bundleService.update(context, swordBundle); @@ -392,9 +344,7 @@ public class DSpaceSwordAPI // now reset the context ignore authorisation context.restoreAuthSystemState(); } - } - catch (SQLException | AuthorizeException | IOException e) - { + } catch (SQLException | AuthorizeException | IOException e) { log.error("caught exception: ", e); throw new DSpaceSwordException(e); } @@ -403,63 +353,49 @@ public class DSpaceSwordAPI /** * Construct the most appropriate filename for the incoming deposit. * - * @param context - * The relevant DSpace Context. - * @param deposit - * deposit request - * @param original - * use the ".original" filename suffix? + * @param context The relevant DSpace Context. + * @param deposit deposit request + * @param original use the ".original" filename suffix? * @return filename for deposit - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public String createFilename(Context context, Deposit deposit, - boolean original) - throws DSpaceSwordException - { - try - { + boolean original) + throws DSpaceSwordException { + try { BitstreamFormat bf = bitstreamFormatService - .findByMIMEType(context, deposit.getMimeType()); + .findByMIMEType(context, deposit.getMimeType()); List exts = null; - if (bf != null) - { + if (bf != null) { exts = bf.getExtensions(); } String fn = deposit.getFilename(); - if (fn == null || "".equals(fn)) - { + if (fn == null || "".equals(fn)) { SimpleDateFormat sdf = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss"); + "yyyy-MM-dd'T'HH:mm:ss"); fn = "sword-" + sdf.format(new Date()); - if (original) - { + if (original) { fn = fn + ".original"; } - if (exts != null) - { + if (exts != null) { fn = fn + "." + exts.get(0); } } return fn; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } public String createEntryFilename(Context context, Deposit deposit, - boolean original) - throws DSpaceSwordException - { + boolean original) + throws DSpaceSwordException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); String fn = "sword-" + sdf.format(new Date()); - if (original) - { + if (original) { fn = fn + ".original"; } @@ -470,44 +406,38 @@ public class DSpaceSwordAPI * Store original package on disk and companion file containing SWORD headers as found in the deposit object * Also write companion file with header info from the deposit object. * - * @param deposit - * deposit object to store as package - * @param auth - * authentication credentials - * @param config - * SWORD configuration - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param deposit deposit object to store as package + * @param auth authentication credentials + * @param config SWORD configuration + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ protected void storePackageAsFile(Deposit deposit, AuthCredentials auth, - SwordConfigurationDSpace config) throws IOException - { + SwordConfigurationDSpace config) throws IOException { String path = config.getFailedPackageDir(); File dir = new File(path); - if (!dir.exists() || !dir.isDirectory()) - { + if (!dir.exists() || !dir.isDirectory()) { throw new IOException( "Directory does not exist for writing packages on ingest error."); } String filenameBase = - "sword-" + auth.getUsername() + "-" + (new Date()).getTime(); + "sword-" + auth.getUsername() + "-" + (new Date()).getTime(); File packageFile = new File(path, filenameBase); File headersFile = new File(path, filenameBase + "-headers"); InputStream is = new BufferedInputStream( - new FileInputStream(deposit.getFile())); + new FileInputStream(deposit.getFile())); OutputStream fos = new BufferedOutputStream( - new FileOutputStream(packageFile)); + new FileOutputStream(packageFile)); Utils.copy(is, fos); fos.close(); is.close(); //write companion file with headers PrintWriter pw = new PrintWriter( - new BufferedWriter(new FileWriter(headersFile))); + new BufferedWriter(new FileWriter(headersFile))); pw.println("Filename=" + deposit.getFilename()); pw.println("Content-Type=" + deposit.getMimeType()); @@ -522,29 +452,23 @@ public class DSpaceSwordAPI * Store original package on disk and companion file containing SWORD headers as found in the deposit object * Also write companion file with header info from the deposit object. * - * @param deposit - * deposit object to store as package - * @param auth - * authentication credentials - * @param config - * SWORD configuration - * @throws IOException - * A general class of exceptions produced by failed or interrupted I/O operations. + * @param deposit deposit object to store as package + * @param auth authentication credentials + * @param config SWORD configuration + * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations. */ protected void storeEntryAsFile(Deposit deposit, AuthCredentials auth, - SwordConfigurationDSpace config) throws IOException - { + SwordConfigurationDSpace config) throws IOException { String path = config.getFailedPackageDir(); File dir = new File(path); - if (!dir.exists() || !dir.isDirectory()) - { + if (!dir.exists() || !dir.isDirectory()) { throw new IOException( "Directory does not exist for writing packages on ingest error."); } String filenameBase = - "sword-" + auth.getUsername() + "-" + (new Date()).getTime(); + "sword-" + auth.getUsername() + "-" + (new Date()).getTime(); File packageFile = new File(path, filenameBase); File headersFile = new File(path, filenameBase + "-headers"); @@ -552,14 +476,14 @@ public class DSpaceSwordAPI String entry = deposit.getSwordEntry().toString(); ByteArrayInputStream is = new ByteArrayInputStream(entry.getBytes()); OutputStream fos = new BufferedOutputStream( - new FileOutputStream(packageFile)); + new FileOutputStream(packageFile)); Utils.copy(is, fos); fos.close(); is.close(); //write companion file with headers PrintWriter pw = new PrintWriter( - new BufferedWriter(new FileWriter(headersFile))); + new BufferedWriter(new FileWriter(headersFile))); pw.println("Filename=" + deposit.getFilename()); pw.println("Content-Type=" + deposit.getMimeType()); @@ -571,13 +495,11 @@ public class DSpaceSwordAPI } protected void addVerboseDescription(DepositReceipt receipt, - VerboseDescription verboseDescription) - { + VerboseDescription verboseDescription) { boolean includeVerbose = ConfigurationManager - .getBooleanProperty("swordv2-server", - "verbose-description.receipt.enable"); - if (includeVerbose) - { + .getBooleanProperty("swordv2-server", + "verbose-description.receipt.enable"); + if (includeVerbose) { receipt.setVerboseDescription(verboseDescription.toString()); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceSwordException.java b/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceSwordException.java index b9d671e0f9..dc7ded309b 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceSwordException.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceSwordException.java @@ -7,35 +7,27 @@ */ package org.dspace.sword2; -import org.swordapp.server.SwordServerException; - /** * This Exception class can be thrown by the internals of the * DSpace SWORD implementation * * @author Richard Jones - * */ -public class DSpaceSwordException extends Exception -{ +public class DSpaceSwordException extends Exception { - public DSpaceSwordException() - { + public DSpaceSwordException() { super(); } - public DSpaceSwordException(String arg0, Throwable arg1) - { + public DSpaceSwordException(String arg0, Throwable arg1) { super(arg0, arg1); } - public DSpaceSwordException(String arg0) - { + public DSpaceSwordException(String arg0) { super(arg0); } - public DSpaceSwordException(Throwable arg0) - { + public DSpaceSwordException(Throwable arg0) { super(arg0); } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceUriRegistry.java b/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceUriRegistry.java index 5c13d58aa6..abbc3ae44f 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceUriRegistry.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/DSpaceUriRegistry.java @@ -7,45 +7,65 @@ */ package org.dspace.sword2; -public class DSpaceUriRegistry -{ +public class DSpaceUriRegistry { public static final String DSPACE_SWORD_NS = "http://www.dspace.org/ns/sword/2.0/"; - /** if unpackaging the package fails */ + /** + * if unpackaging the package fails + */ public static final String UNPACKAGE_FAIL = - DSPACE_SWORD_NS + "errors/UnpackageFail"; + DSPACE_SWORD_NS + "errors/UnpackageFail"; - /** if the url of the request does not resolve to something meaningful */ + /** + * if the url of the request does not resolve to something meaningful + */ public static final String BAD_URL = DSPACE_SWORD_NS + "errors/BadUrl"; - /** if the media requested is unavailable */ + /** + * if the media requested is unavailable + */ public static final String MEDIA_UNAVAILABLE = - DSPACE_SWORD_NS + "errors/MediaUnavailable"; + DSPACE_SWORD_NS + "errors/MediaUnavailable"; /* additional codes */ - /** Invalid package */ + /** + * Invalid package + */ public static final String PACKAGE_ERROR = - DSPACE_SWORD_NS + "errors/PackageError"; + DSPACE_SWORD_NS + "errors/PackageError"; - /** Missing resources in package */ + /** + * Missing resources in package + */ public static final String PACKAGE_VALIDATION_ERROR = - DSPACE_SWORD_NS + "errors/PackageValidationError"; + DSPACE_SWORD_NS + "errors/PackageValidationError"; - /** Crosswalk error */ + /** + * Crosswalk error + */ public static final String CROSSWALK_ERROR = - DSPACE_SWORD_NS + "errors/CrosswalkError"; + DSPACE_SWORD_NS + "errors/CrosswalkError"; - /** Invalid collection for linking */ + /** + * Invalid collection for linking + */ public static final String COLLECTION_LINK_ERROR = - DSPACE_SWORD_NS + "errors/CollectionLinkError"; + DSPACE_SWORD_NS + "errors/CollectionLinkError"; - /** Database or IO Error when installing new item */ + /** + * Database or IO Error when installing new item + */ public static final String REPOSITORY_ERROR = - DSPACE_SWORD_NS + "errors/RepositoryError"; + DSPACE_SWORD_NS + "errors/RepositoryError"; // FIXME: this is being withdrawn from all 406 responses for the time being, in preference // for ErrorContent as per the spec (whether that is right or wrong) public static final String NOT_ACCEPTABLE = - DSPACE_SWORD_NS + "errors/NotAcceptable"; + DSPACE_SWORD_NS + "errors/NotAcceptable"; + + /** + * Default constructor + */ + private DSpaceUriRegistry() { } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/DepositResult.java b/dspace-swordv2/src/main/java/org/dspace/sword2/DepositResult.java index d590cc8feb..66924d088a 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/DepositResult.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/DepositResult.java @@ -7,11 +7,10 @@ */ package org.dspace.sword2; -import org.dspace.content.Item; -import org.dspace.content.Bitstream; - import java.util.List; -import java.util.Map; + +import org.dspace.content.Bitstream; +import org.dspace.content.Item; /** * The DSpace class for representing the results of a deposit @@ -19,58 +18,54 @@ import java.util.Map; * components required to later build the SWORD response * * @author Richard Jones - * */ -public class DepositResult -{ - /** the item created during deposit */ +public class DepositResult { + /** + * the item created during deposit + */ private Item item; - /** Bitstream created as a result of the deposit */ + /** + * Bitstream created as a result of the deposit + */ private Bitstream originalDeposit; private List derivedResources; - /** The treatment of the item during deposit */ + /** + * The treatment of the item during deposit + */ private String treatment; - public Item getItem() - { + public Item getItem() { return item; } - public void setItem(Item item) - { + public void setItem(Item item) { this.item = item; } - public Bitstream getOriginalDeposit() - { + public Bitstream getOriginalDeposit() { return originalDeposit; } - public void setOriginalDeposit(Bitstream originalDeposit) - { + public void setOriginalDeposit(Bitstream originalDeposit) { this.originalDeposit = originalDeposit; } - public List getDerivedResources() - { + public List getDerivedResources() { return derivedResources; } - public void setDerivedResources(List derivedResources) - { + public void setDerivedResources(List derivedResources) { this.derivedResources = derivedResources; } - public String getTreatment() - { + public String getTreatment() { return treatment; } - public void setTreatment(String treatment) - { + public void setTreatment(String treatment) { this.treatment = treatment; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/FeedContentDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/FeedContentDisseminator.java index b8c9dc8f44..3dd10ec81f 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/FeedContentDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/FeedContentDisseminator.java @@ -7,16 +7,6 @@ */ package org.dspace.sword2; -import org.apache.abdera.Abdera; -import org.apache.abdera.i18n.iri.IRI; -import org.apache.abdera.model.Entry; -import org.apache.abdera.model.Feed; -import org.apache.abdera.model.Link; -import org.dspace.content.*; -import org.dspace.core.*; -import org.swordapp.server.SwordError; -import org.swordapp.server.SwordServerException; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -26,31 +16,40 @@ import java.util.Date; import java.util.List; import java.util.Map; +import org.apache.abdera.Abdera; +import org.apache.abdera.i18n.iri.IRI; +import org.apache.abdera.model.Entry; +import org.apache.abdera.model.Feed; +import org.apache.abdera.model.Link; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.Item; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.swordapp.server.SwordError; +import org.swordapp.server.SwordServerException; + public class FeedContentDisseminator extends AbstractSimpleDC - implements SwordContentDisseminator -{ + implements SwordContentDisseminator { public InputStream disseminate(Context context, Item item) - throws DSpaceSwordException, SwordError, SwordServerException - { - try - { + throws DSpaceSwordException, SwordError, SwordServerException { + try { Abdera abdera = new Abdera(); Feed feed = abdera.newFeed(); this.addMetadata(feed, item); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { List bitstreams = bundle - .getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + .getBitstreams(); + for (Bitstream bitstream : bitstreams) { Entry entry = feed.addEntry(); this.populateEntry(context, entry, - bitstream); + bitstream); } } } @@ -58,15 +57,12 @@ public class FeedContentDisseminator extends AbstractSimpleDC ByteArrayOutputStream baos = new ByteArrayOutputStream(); feed.writeTo(baos); return new ByteArrayInputStream(baos.toByteArray()); - } - catch (IOException e) - { + } catch (IOException e) { throw new DSpaceSwordException(e); } } - private void addMetadata(Feed feed, Item item) - { + private void addMetadata(Feed feed, Item item) { SimpleDCMetadata md = this.getMetadata(item); /* not necessary ... @@ -79,49 +75,40 @@ public class FeedContentDisseminator extends AbstractSimpleDC */ Map atom = md.getAtom(); - for (String element : atom.keySet()) - { - if ("author".equals(element)) - { + for (String element : atom.keySet()) { + if ("author".equals(element)) { feed.addAuthor(atom.get(element)); } } // ensure that the feed has one author or more - if (feed.getAuthors().size() == 0) - { + if (feed.getAuthors().size() == 0) { feed.addAuthor(ConfigurationManager.getProperty("dspace.name")); } } private void populateEntry(Context context, Entry entry, - Bitstream bitstream) - throws DSpaceSwordException - { + Bitstream bitstream) + throws DSpaceSwordException { BitstreamFormat format = null; - try - { + try { format = bitstream.getFormat(context); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } String contentType = null; - if (format != null) - { + if (format != null) { contentType = format.getMIMEType(); } SwordUrlManager urlManager = new SwordUrlManager( - new SwordConfigurationDSpace(), context); + new SwordConfigurationDSpace(), context); String bsUrl = urlManager.getBitstreamUrl(bitstream); entry.setId(bsUrl); entry.setTitle(bitstream.getName()); String desc = bitstream.getDescription(); - if ("".equals(desc) || desc == null) - { + if ("".equals(desc) || desc == null) { desc = bitstream.getName(); } entry.setSummary(desc); @@ -140,36 +127,30 @@ public class FeedContentDisseminator extends AbstractSimpleDC } public boolean disseminatesContentType(String contentType) - throws DSpaceSwordException, SwordError, SwordServerException - { + throws DSpaceSwordException, SwordError, SwordServerException { return "application/atom+xml".equals(contentType) || - "application/atom+xml;type=feed".equals(contentType); + "application/atom+xml;type=feed".equals(contentType); } public boolean disseminatesPackage(String contentType) - throws DSpaceSwordException, SwordError, SwordServerException - { + throws DSpaceSwordException, SwordError, SwordServerException { // we're just going to ignore packaging formats here return true; } - public void setContentType(String contentType) - { + public void setContentType(String contentType) { // we just return the one format, so ignore this } - public void setPackaging(String packaging) - { + public void setPackaging(String packaging) { // we just return the one format, so ignore this } - public String getContentType() - { + public String getContentType() { return "application/atom+xml;type=feed"; } - public String getPackaging() - { + public String getPackaging() { // no packaging return null; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/GenericStatementDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/GenericStatementDisseminator.java index 6af37a8192..cf209044b2 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/GenericStatementDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/GenericStatementDisseminator.java @@ -7,42 +7,39 @@ */ package org.dspace.sword2; -import org.dspace.content.Bitstream; -import org.dspace.content.Bundle; -import org.dspace.content.Item; -import org.dspace.core.Context; -import org.swordapp.server.OriginalDeposit; -import org.swordapp.server.ResourcePart; -import org.swordapp.server.Statement; - import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; + import org.apache.commons.lang.ArrayUtils; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Item; +import org.dspace.core.Context; import org.dspace.services.factory.DSpaceServicesFactory; +import org.swordapp.server.OriginalDeposit; +import org.swordapp.server.ResourcePart; +import org.swordapp.server.Statement; public abstract class GenericStatementDisseminator - implements SwordStatementDisseminator -{ + implements SwordStatementDisseminator { protected SwordUrlManager urlManager; protected void populateStatement(Context context, Item item, - Statement statement) - throws DSpaceSwordException - { + Statement statement) + throws DSpaceSwordException { this.urlManager = new SwordUrlManager(new SwordConfigurationDSpace(), - context); + context); List includeBundles = this.getIncludeBundles(); String originalDepositBundle = this.getOriginalDepositsBundle(); // we only list the original deposits in full if the sword bundle is in the includeBundles - if (includeBundles.contains(originalDepositBundle)) - { + if (includeBundles.contains(originalDepositBundle)) { List originalDeposits = this - .getOriginalDeposits(context, item, originalDepositBundle); + .getOriginalDeposits(context, item, originalDepositBundle); statement.setOriginalDeposits(originalDeposits); } @@ -52,7 +49,7 @@ public abstract class GenericStatementDisseminator // remove the original deposit bundle from the include bundles includeBundles.remove(originalDepositBundle); List resources = this - .getResourceParts(context, item, includeBundles); + .getResourceParts(context, item, includeBundles); statement.setResources(resources); Date lastModified = this.getLastModified(context, item); @@ -60,11 +57,9 @@ public abstract class GenericStatementDisseminator } protected List getOriginalDeposits(Context context, - Item item, String swordBundle) - throws DSpaceSwordException - { - try - { + Item item, String swordBundle) + throws DSpaceSwordException { + try { // NOTE: DSpace does not store file metadata, so we can't access the information // about who deposited what, when, on behalf of whoever. @@ -72,58 +67,45 @@ public abstract class GenericStatementDisseminator // an original deposit is everything in the SWORD bundle List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (swordBundle.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (swordBundle.equals(bundle.getName())) { List bitstreams = bundle - .getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + .getBitstreams(); + for (Bitstream bitstream : bitstreams) { // note that original deposits don't have actionable urls OriginalDeposit deposit = new OriginalDeposit( - this.urlManager.getBitstreamUrl( - bitstream)); + this.urlManager.getBitstreamUrl( + bitstream)); deposit.setMediaType(bitstream - .getFormat(context).getMIMEType()); + .getFormat(context).getMIMEType()); originalDeposits.add(deposit); } } } return originalDeposits; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } protected Map getStates(Context context, Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { SwordConfigurationDSpace config = new SwordConfigurationDSpace(); WorkflowTools wft = new WorkflowTools(); Map states = new HashMap(); - if (item.isWithdrawn()) - { + if (item.isWithdrawn()) { String uri = config.getStateUri("withdrawn"); String desc = config.getStateDescription("withdrawn"); states.put(uri, desc); - } - else if (item.isArchived()) - { + } else if (item.isArchived()) { String uri = config.getStateUri("archive"); String desc = config.getStateDescription("archive"); states.put(uri, desc); - } - else if (wft.isItemInWorkflow(context, item)) - { + } else if (wft.isItemInWorkflow(context, item)) { String uri = config.getStateUri("workflow"); String desc = config.getStateDescription("workflow"); states.put(uri, desc); - } - else if (wft.isItemInWorkspace(context, item)) - { + } else if (wft.isItemInWorkspace(context, item)) { String uri = config.getStateUri("workspace"); String desc = config.getStateDescription("workspace"); states.put(uri, desc); @@ -132,31 +114,25 @@ public abstract class GenericStatementDisseminator } protected List getResourceParts(Context context, Item item, - List includeBundles) - throws DSpaceSwordException - { - try - { + List includeBundles) + throws DSpaceSwordException { + try { // the list of resource parts is everything in the bundles to be included List resources = new ArrayList(); - for (String bundleName : includeBundles) - { + for (String bundleName : includeBundles) { List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (bundleName.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (bundleName.equals(bundle.getName())) { List bitstreams = bundle - .getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + .getBitstreams(); + for (Bitstream bitstream : bitstreams) { // note that individual bitstreams have actionable urls ResourcePart part = new ResourcePart(this.urlManager - .getActionableBitstreamUrl( - bitstream)); + .getActionableBitstreamUrl( + bitstream)); part.setMediaType(bitstream - .getFormat(context).getMIMEType()); + .getFormat(context).getMIMEType()); resources.add(part); } } @@ -164,44 +140,35 @@ public abstract class GenericStatementDisseminator } return resources; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } - protected Date getLastModified(Context context, Item item) - { + protected Date getLastModified(Context context, Item item) { return item.getLastModified(); } - private List getIncludeBundles() - { + private List getIncludeBundles() { String[] bundles = DSpaceServicesFactory.getInstance().getConfigurationService() - .getArrayProperty("swordv2-server.statement.bundles"); - if (ArrayUtils.isEmpty(bundles)) - { + .getArrayProperty("swordv2-server.statement.bundles"); + if (ArrayUtils.isEmpty(bundles)) { bundles = new String[] {"ORIGINAL", "SWORD"}; } List include = new ArrayList(); - for (String bit : bundles) - { + for (String bit : bundles) { String bundleName = bit.trim().toUpperCase(); - if (!include.contains(bundleName)) - { + if (!include.contains(bundleName)) { include.add(bundleName); } } return include; } - private String getOriginalDepositsBundle() - { + private String getOriginalDepositsBundle() { String swordBundle = DSpaceServicesFactory.getInstance().getConfigurationService() - .getProperty("swordv2-server.bundle.name"); - if (swordBundle == null) - { + .getProperty("swordv2-server.bundle.name"); + if (swordBundle == null) { swordBundle = "SWORD"; } return swordBundle; diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/MediaResourceManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/MediaResourceManagerDSpace.java index e1068f15df..59d5c4bbbf 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/MediaResourceManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/MediaResourceManagerDSpace.java @@ -7,6 +7,17 @@ */ package org.dspace.sword2; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.factory.AuthorizeServiceFactory; @@ -17,104 +28,89 @@ import org.dspace.content.Item; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.LogManager; -import org.swordapp.server.*; - -import java.io.IOException; -import java.io.InputStream; -import java.sql.SQLException; -import java.util.*; +import org.swordapp.server.AuthCredentials; +import org.swordapp.server.Deposit; +import org.swordapp.server.DepositReceipt; +import org.swordapp.server.MediaResource; +import org.swordapp.server.MediaResourceManager; +import org.swordapp.server.SwordAuthException; +import org.swordapp.server.SwordConfiguration; +import org.swordapp.server.SwordError; +import org.swordapp.server.SwordServerException; +import org.swordapp.server.UriRegistry; public class MediaResourceManagerDSpace extends DSpaceSwordAPI - implements MediaResourceManager -{ + implements MediaResourceManager { private static Logger log = Logger - .getLogger(MediaResourceManagerDSpace.class); + .getLogger(MediaResourceManagerDSpace.class); protected AuthorizeService authorizeService = AuthorizeServiceFactory - .getInstance().getAuthorizeService(); + .getInstance().getAuthorizeService(); private VerboseDescription verboseDescription = new VerboseDescription(); private boolean isAccessible(Context context, Bitstream bitstream) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { return authorizeService - .authorizeActionBoolean(context, bitstream, Constants.READ); - } - catch (SQLException e) - { + .authorizeActionBoolean(context, bitstream, Constants.READ); + } catch (SQLException e) { throw new DSpaceSwordException(e); } } private boolean isAccessible(Context context, Item item) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { return authorizeService - .authorizeActionBoolean(context, item, Constants.READ); - } - catch (SQLException e) - { + .authorizeActionBoolean(context, item, Constants.READ); + } catch (SQLException e) { throw new DSpaceSwordException(e); } } private MediaResource getBitstreamResource(Context context, - Bitstream bitstream) - throws SwordServerException, SwordAuthException - { - try - { + Bitstream bitstream) + throws SwordServerException, SwordAuthException { + try { InputStream stream = bitstreamService.retrieve(context, bitstream); MediaResource mr = new MediaResource(stream, - bitstream.getFormat(context).getMIMEType(), null, true); + bitstream.getFormat(context).getMIMEType(), null, true); mr.setContentMD5(bitstream.getChecksum()); mr.setLastModified(this.getLastModified(context, bitstream)); return mr; - } - catch (IOException | SQLException e) - { + } catch (IOException | SQLException e) { throw new SwordServerException(e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); } } private MediaResource getItemResource(Context context, Item item, - SwordUrlManager urlManager, String uri, Map accept) - throws SwordError, DSpaceSwordException, SwordServerException - { + SwordUrlManager urlManager, String uri, Map accept) + throws SwordError, DSpaceSwordException, SwordServerException { boolean feedRequest = urlManager.isFeedRequest(context, uri); SwordContentDisseminator disseminator = null; // first off, consider the accept headers. The accept argument is a map // from accept header to value. // we only care about Accept and Accept-Packaging - if (!feedRequest) - { + if (!feedRequest) { String acceptContentType = this.getHeader(accept, "Accept", null); String acceptPackaging = this.getHeader(accept, "Accept-Packaging", - UriRegistry.PACKAGE_SIMPLE_ZIP); + UriRegistry.PACKAGE_SIMPLE_ZIP); // we know that only one Accept-Packaging value is allowed, so we don't need // to do any further work on it. // we extract from the Accept header the ordered list of content types TreeMap> analysed = this - .analyseAccept(acceptContentType); + .analyseAccept(acceptContentType); // the meat of this is done by the package disseminator disseminator = SwordDisseminatorFactory - .getContentInstance(analysed, acceptPackaging); - } - else - { + .getContentInstance(analysed, acceptPackaging); + } else { // we just want to ask for the atom version, so we bypass the main content // negotiation place Map> analysed = new HashMap>(); @@ -122,39 +118,35 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI list.add("application/atom+xml"); analysed.put((float) 1.0, list); disseminator = SwordDisseminatorFactory - .getContentInstance(analysed, null); + .getContentInstance(analysed, null); } // Note that at this stage, if we don't have a desiredContentType, it will // be null, and the disseminator is free to choose the format InputStream stream = disseminator.disseminate(context, item); return new MediaResource(stream, disseminator.getContentType(), - disseminator.getPackaging()); + disseminator.getPackaging()); } public MediaResource getMediaResourceRepresentation(String uri, - Map accept, AuthCredentials authCredentials, - SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + Map accept, AuthCredentials authCredentials, + SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // all the bits we need to make this method function SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; Context ctx = null; - try - { + try { // create an unauthenticated context for our initial explorations ctx = new Context(); SwordUrlManager urlManager = config.getUrlManager(ctx, config); // is this a request for a bitstream or an item (which is the full media resource)? - if (urlManager.isActionableBitstreamUrl(ctx, uri)) - { + if (urlManager.isActionableBitstreamUrl(ctx, uri)) { // request for a bitstream Bitstream bitstream = urlManager.getBitstream(ctx, uri); - if (bitstream == null) - { + if (bitstream == null) { // bitstream not found in the database, so 404 the client. // Arguably, we should try to authenticate first, but it's not so important throw new SwordError(404); @@ -162,13 +154,12 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // find out, now we know what we're being asked for, whether this is allowed WorkflowManagerFactory.getInstance() - .retrieveBitstream(ctx, bitstream); + .retrieveBitstream(ctx, bitstream); // we can do this in principle, but now find out whether the bitstream is accessible without credentials boolean accessible = this.isAccessible(ctx, bitstream); - if (!accessible) - { + if (!accessible) { // try to authenticate, and if successful switch the contexts around sc = this.doAuth(authCredentials); ctx.abort(); @@ -179,8 +170,7 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // and re-verify its accessibility accessible = this.isAccessible(ctx, bitstream); - if (!accessible) - { + if (!accessible) { throw new SwordAuthException(); } } @@ -188,22 +178,17 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // if we get to here we are either allowed to access the bitstream without credentials, // or we have been authenticated with acceptable credentials MediaResource mr = this.getBitstreamResource(ctx, bitstream); - if (sc != null) - { + if (sc != null) { sc.abort(); } - if (ctx.isValid()) - { + if (ctx.isValid()) { ctx.abort(); } return mr; - } - else - { + } else { // request for an item Item item = urlManager.getItem(ctx, uri); - if (item == null) - { + if (item == null) { // item now found in the database, so 404 the client // Arguably, we should try to authenticate first, but it's not so important throw new SwordError(404); @@ -215,8 +200,7 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // we can do this in principle but now find out whether the item is accessible without credentials boolean accessible = this.isAccessible(ctx, item); - if (!accessible) - { + if (!accessible) { // try to authenticate, and if successful switch the contexts around sc = this.doAuth(authCredentials); ctx.abort(); @@ -226,89 +210,71 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // if we get to here we are either allowed to access the bitstream without credentials, // or we have been authenticated MediaResource mr = this - .getItemResource(ctx, item, urlManager, uri, accept); + .getItemResource(ctx, item, urlManager, uri, accept); // sc.abort(); ctx.abort(); return mr; } - } - catch (SQLException | DSpaceSwordException e) - { + } catch (SQLException | DSpaceSwordException e) { throw new SwordServerException(e); - } - finally - { + } finally { // if there is a sword context, abort it (this will abort the inner dspace context as well) - if (sc != null) - { + if (sc != null) { sc.abort(); } - if (ctx != null && ctx.isValid()) - { + if (ctx != null && ctx.isValid()) { ctx.abort(); } } } private Date getLastModified(Context context, Bitstream bitstream) - throws SQLException - { + throws SQLException { Date lm = null; List bundles = bitstream.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { List items = bundle.getItems(); - for (Item item : items) - { + for (Item item : items) { Date possible = item.getLastModified(); - if (lm == null) - { + if (lm == null) { lm = possible; - } - else if (possible.getTime() > lm.getTime()) - { + } else if (possible.getTime() > lm.getTime()) { lm = possible; } } } - if (lm == null) - { + if (lm == null) { return new Date(); } return lm; } public DepositReceipt replaceMediaResource(String emUri, Deposit deposit, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); // store up the verbose description, which we can then give back at the end if necessary this.verboseDescription - .append("Initialising verbose replace of media resource"); + .append("Initialising verbose replace of media resource"); SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "sword_replace", "")); } DepositReceipt receipt; SwordUrlManager urlManager = config.getUrlManager(context, config); - if (urlManager.isActionableBitstreamUrl(context, emUri)) - { + if (urlManager.isActionableBitstreamUrl(context, emUri)) { Bitstream bitstream = urlManager.getBitstream(context, emUri); - if (bitstream == null) - { + if (bitstream == null) { throw new SwordError(404); } @@ -320,12 +286,10 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // check that we can submit to ALL the items this bitstream is in List items = new ArrayList<>(); List bundles = bitstream.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { List bundleItems = bundle - .getItems(); - for (Item item : bundleItems) - { + .getItems(); + for (Item item : bundleItems) { this.checkAuth(sc, item); items.add(item); } @@ -333,33 +297,25 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } DepositResult result = null; - try - { + try { result = this - .replaceBitstream(sc, items, bitstream, deposit, - authCredentials, config); - } - catch (DSpaceSwordException | SwordError e) - { - if (config.isKeepPackageOnFailedIngest()) - { - try - { + .replaceBitstream(sc, items, bitstream, deposit, + authCredentials, config); + } catch (DSpaceSwordException | SwordError e) { + if (config.isKeepPackageOnFailedIngest()) { + try { this.storePackageAsFile(deposit, authCredentials, - config); - } - catch (IOException e2) - { + config); + } catch (IOException e2) { log.warn("Unable to store SWORD package as file: " + - e); + e); } } throw e; @@ -367,17 +323,14 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // now we've produced a deposit, we need to decide on its workflow state wfm.resolveState(context, deposit, null, - this.verboseDescription, false); + this.verboseDescription, false); ReceiptGenerator genny = new ReceiptGenerator(); receipt = genny.createFileReceipt(context, result, config); - } - else - { + } else { // get the deposit target Item item = this.getDSpaceTarget(context, emUri, config); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -389,50 +342,40 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager - .getHeader(context, "replace_failed_authorisation", - "user=" + - sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + .getHeader(context, "replace_failed_authorisation", + "user=" + + sc.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( - "Cannot replace the given item with this context"); + "Cannot replace the given item with this context"); } // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } - try - { + try { this.replaceContent(sc, item, deposit, authCredentials, - config); - } - catch (DSpaceSwordException | SwordError e) - { - if (config.isKeepPackageOnFailedIngest()) - { - try - { + config); + } catch (DSpaceSwordException | SwordError e) { + if (config.isKeepPackageOnFailedIngest()) { + try { this.storePackageAsFile(deposit, authCredentials, - config); - } - catch (IOException e2) - { + config); + } catch (IOException e2) { log.warn("Unable to store SWORD package as file: " + - e); + e); } } throw e; @@ -440,18 +383,18 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // now we've produced a deposit, we need to decide on its workflow state wfm.resolveState(context, deposit, null, - this.verboseDescription, false); + this.verboseDescription, false); ReceiptGenerator genny = new ReceiptGenerator(); receipt = genny - .createMediaResourceReceipt(context, item, config); + .createMediaResourceReceipt(context, item, config); } Date finish = new Date(); long delta = finish.getTime() - start.getTime(); this.verboseDescription - .append("Total time for deposit processing: " + delta + + .append("Total time for deposit processing: " + delta + " ms"); // receipt.setVerboseDescription(this.verboseDescription.toString()); @@ -460,48 +403,38 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // return the receipt for the purposes of the location return receipt; - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( - "There was a problem depositing the item", e); - } - catch (SQLException e) - { + "There was a problem depositing the item", e); + } catch (SQLException e) { throw new SwordServerException(e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public void deleteMediaResource(String emUri, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); // store up the verbose description, which we can then give back at the end if necessary this.verboseDescription - .append("Initialising verbose delete of media resource"); + .append("Initialising verbose delete of media resource"); SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "sword_delete", "")); } @@ -509,11 +442,9 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI WorkflowManager wfm = WorkflowManagerFactory.getInstance(); // get the deposit target - if (urlManager.isActionableBitstreamUrl(context, emUri)) - { + if (urlManager.isActionableBitstreamUrl(context, emUri)) { Bitstream bitstream = urlManager.getBitstream(context, emUri); - if (bitstream == null) - { + if (bitstream == null) { throw new SwordError(404); } @@ -523,12 +454,10 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // check that we can submit to ALL the items this bitstream is in List items = new ArrayList<>(); - for (Bundle bundle : bitstream.getBundles()) - { + for (Bundle bundle : bitstream.getBundles()) { List bundleItems = bundle - .getItems(); - for (Item item : bundleItems) - { + .getItems(); + for (Item item : bundleItems) { this.checkAuth(sc, item); items.add(item); } @@ -536,21 +465,17 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } this.removeBitstream(sc, bitstream, items, authCredentials, - config); - } - else - { + config); + } else { Item item = this.getDSpaceTarget(context, emUri, config); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -561,30 +486,27 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager - .getHeader(context, "replace_failed_authorisation", - "user=" + - sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + .getHeader(context, "replace_failed_authorisation", + "user=" + + sc.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( - "Cannot replace the given item with this context"); + "Cannot replace the given item with this context"); } // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } // do the business of removal @@ -593,7 +515,7 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // now we've produced a deposit, we need to decide on its workflow state wfm.resolveState(context, null, null, this.verboseDescription, - false); + false); //ReceiptGenerator genny = new ReceiptGenerator(); //DepositReceipt receipt = genny.createReceipt(context, result, config); @@ -602,7 +524,7 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI long delta = finish.getTime() - start.getTime(); this.verboseDescription - .append("Total time for deposit processing: " + delta + + .append("Total time for deposit processing: " + delta + " ms"); // receipt.setVerboseDescription(this.verboseDescription.toString()); @@ -611,55 +533,44 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // So, we don't actually return a receipt, but it was useful constructing it. Perhaps this will // change in the spec? - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( - "There was a problem depositing the item", e); - } - catch (SQLException e) - { + "There was a problem depositing the item", e); + } catch (SQLException e) { throw new SwordServerException(e); - } - finally - { + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public DepositReceipt addResource(String emUri, Deposit deposit, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordError, SwordServerException, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordError, SwordServerException, SwordAuthException { // start the timer Date start = new Date(); // store up the verbose description, which we can then give back at the end if necessary this.verboseDescription - .append("Initialising verbose add to media resource"); + .append("Initialising verbose add to media resource"); SwordContext sc = null; SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; - try - { + try { sc = this.doAuth(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager.getHeader(context, "sword_add", "")); } // get the deposit target Item item = this.getDSpaceTarget(context, emUri, config); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -671,61 +582,49 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // find out if the supplied SWORDContext can submit to the given // dspace object SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager - .getHeader(context, "replace_failed_authorisation", - "user=" + - sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + .getHeader(context, "replace_failed_authorisation", + "user=" + + sc.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( - "Cannot replace the given item with this context"); + "Cannot replace the given item with this context"); } // make a note of the authentication in the verbose string this.verboseDescription.append("Authenticated user: " + - sc.getAuthenticated().getEmail()); - if (sc.getOnBehalfOf() != null) - { + sc.getAuthenticated().getEmail()); + if (sc.getOnBehalfOf() != null) { this.verboseDescription.append("Depositing on behalf of: " + - sc.getOnBehalfOf().getEmail()); + sc.getOnBehalfOf().getEmail()); } DepositResult result; - try - { + try { result = this - .addContent(sc, item, deposit, authCredentials, config); - if (deposit.isMultipart()) - { + .addContent(sc, item, deposit, authCredentials, config); + if (deposit.isMultipart()) { ContainerManagerDSpace cm = new ContainerManagerDSpace(); result = cm - .doAddMetadata(sc, item, deposit, authCredentials, - config, result); + .doAddMetadata(sc, item, deposit, authCredentials, + config, result); } - } - catch (DSpaceSwordException | SwordError e) - { - if (config.isKeepPackageOnFailedIngest()) - { - try - { + } catch (DSpaceSwordException | SwordError e) { + if (config.isKeepPackageOnFailedIngest()) { + try { this.storePackageAsFile(deposit, authCredentials, - config); - if (deposit.isMultipart()) - { + config); + if (deposit.isMultipart()) { this.storeEntryAsFile(deposit, authCredentials, - config); + config); } - } - catch (IOException e2) - { + } catch (IOException e2) { log.warn("Unable to store SWORD package as file: " + e); } } @@ -734,7 +633,7 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // now we've produced a deposit, we need to decide on its workflow state wfm.resolveState(context, deposit, null, this.verboseDescription, - false); + false); ReceiptGenerator genny = new ReceiptGenerator(); @@ -742,14 +641,11 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI DepositReceipt receipt; // If this was a single file deposit, then we don't return a receipt, we just // want to specify the location header - if (deposit.getPackaging().equals(UriRegistry.PACKAGE_BINARY)) - { + if (deposit.getPackaging().equals(UriRegistry.PACKAGE_BINARY)) { receipt = genny.createFileReceipt(context, result, config); - } - // if, on the other-hand, this was a package, then we want to generate a - // deposit receipt proper, but with the location being for the media resource - else - { + } else { + // if, on the other-hand, this was a package, then we want to generate a + // deposit receipt proper, but with the location being for the media resource receipt = genny.createReceipt(context, result, config, true); } @@ -757,90 +653,69 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI long delta = finish.getTime() - start.getTime(); this.verboseDescription - .append("Total time for add processing: " + delta + " ms"); + .append("Total time for add processing: " + delta + " ms"); this.addVerboseDescription(receipt, this.verboseDescription); // if something hasn't killed it already (allowed), then complete the transaction sc.commit(); return receipt; - } - catch (DSpaceSwordException e) - { + } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( - "There was a problem depositing the item", e); - } - finally - { + "There was a problem depositing the item", e); + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } private void removeContent(SwordContext swordContext, Item item, - AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordAuthException - { - try - { + AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordAuthException { + try { // remove content only really means everything from the ORIGINAL bundle VersionManager vm = new VersionManager(); Iterator bundles = item.getBundles().iterator(); - while (bundles.hasNext()) - { + while (bundles.hasNext()) { Bundle bundle = bundles.next(); - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { bundles.remove(); vm.removeBundle(swordContext.getContext(), item, bundle); } } - } - catch (SQLException | IOException e) - { + } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); } } private void removeBitstream(SwordContext swordContext, Bitstream bitstream, - List items, AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordAuthException - { - try - { + List items, AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordAuthException { + try { // remove content only really means everything from the ORIGINAL bundle VersionManager vm = new VersionManager(); - for (Item item : items) - { + for (Item item : items) { vm.removeBitstream(swordContext.getContext(), item, bitstream); } - } - catch (SQLException | IOException e) - { + } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); } } private void replaceContent(SwordContext swordContext, Item item, - Deposit deposit, AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + Deposit deposit, AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { // get the things out of the service that we need Context context = swordContext.getContext(); @@ -849,43 +724,37 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // Obtain the relevant ingester from the factory SwordContentIngester si = SwordIngesterFactory - .getContentInstance(context, deposit, null); + .getContentInstance(context, deposit, null); this.verboseDescription - .append("Loaded ingester: " + si.getClass().getName()); + .append("Loaded ingester: " + si.getClass().getName()); - try - { + try { // delegate the to the version manager to get rid of any existing content and to version // if if necessary VersionManager vm = new VersionManager(); vm.removeBundle(swordContext.getContext(), item, "ORIGINAL"); - } - catch (SQLException | IOException e) - { + } catch (SQLException | IOException e) { throw new DSpaceSwordException(e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); } // do the deposit DepositResult result = si - .ingest(context, deposit, item, this.verboseDescription); + .ingest(context, deposit, item, this.verboseDescription); this.verboseDescription.append("Replace completed successfully"); // store the originals (this code deals with the possibility that that's not required) this.storeOriginals(swordConfig, context, this.verboseDescription, - deposit, result); + deposit, result); } private DepositResult replaceBitstream(SwordContext swordContext, - List items, Bitstream bitstream, Deposit deposit, - AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + List items, Bitstream bitstream, Deposit deposit, + AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { // FIXME: this is basically not possible with the existing DSpace API. // We hack around it by deleting the old bitstream and @@ -897,48 +766,39 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI Context context = swordContext.getContext(); // is the content acceptable to the items? If not, this will throw an error - for (Item item : items) - { + for (Item item : items) { this.isAcceptable(swordConfig, context, deposit, item); } // Obtain the relevant ingester from the factory SwordContentIngester si = SwordIngesterFactory - .getContentInstance(context, deposit, null); + .getContentInstance(context, deposit, null); this.verboseDescription - .append("Loaded ingester: " + si.getClass().getName()); + .append("Loaded ingester: " + si.getClass().getName()); - try - { + try { // first we delete the original bitstream this.removeBitstream(swordContext, bitstream, items, - authCredentials, swordConfig); + authCredentials, swordConfig); DepositResult result = null; boolean first = true; - for (Item item : items) - { - if (first) - { + for (Item item : items) { + if (first) { // just do this to the first item result = this.addContent(swordContext, item, deposit, - authCredentials, swordConfig); - } - else - { + authCredentials, swordConfig); + } else { // now duplicate the bitstream to all the others List bundles = item.getBundles(); - if (!bundles.isEmpty()) - { + if (!bundles.isEmpty()) { bundleService.addBitstream(context, bundles.get(0), - result.getOriginalDeposit()); - } - else - { + result.getOriginalDeposit()); + } else { Bundle bundle = bundleService.create(context, item, - Constants.CONTENT_BUNDLE_NAME); + Constants.CONTENT_BUNDLE_NAME); bundleService.addBitstream(context, bundle, - result.getOriginalDeposit()); + result.getOriginalDeposit()); } } @@ -948,23 +808,18 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI this.verboseDescription.append("Replace completed successfully"); return result; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); } } private DepositResult addContent(SwordContext swordContext, Item item, - Deposit deposit, AuthCredentials authCredentials, - SwordConfigurationDSpace swordConfig) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + Deposit deposit, AuthCredentials authCredentials, + SwordConfigurationDSpace swordConfig) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { // get the things out of the service that we need Context context = swordContext.getContext(); @@ -973,61 +828,57 @@ public class MediaResourceManagerDSpace extends DSpaceSwordAPI // Obtain the relevant ingester from the factory SwordContentIngester si = SwordIngesterFactory - .getContentInstance(context, deposit, null); + .getContentInstance(context, deposit, null); this.verboseDescription - .append("Loaded ingester: " + si.getClass().getName()); + .append("Loaded ingester: " + si.getClass().getName()); // do the deposit DepositResult result = si - .ingest(context, deposit, item, this.verboseDescription); + .ingest(context, deposit, item, this.verboseDescription); this.verboseDescription.append("Add completed successfully"); // store the originals (this code deals with the possibility that that's not required) this.storeOriginals(swordConfig, context, this.verboseDescription, - deposit, result); + deposit, result); return result; } private Item getDSpaceTarget(Context context, String editMediaUrl, - SwordConfigurationDSpace config) - throws DSpaceSwordException, SwordError - { + SwordConfigurationDSpace config) + throws DSpaceSwordException, SwordError { SwordUrlManager urlManager = config.getUrlManager(context, config); // get the target collection Item item = urlManager.getItem(context, editMediaUrl); this.verboseDescription - .append("Performing replace using edit-media URL: " + + .append("Performing replace using edit-media URL: " + editMediaUrl); this.verboseDescription - .append("Location resolves to item with handle: " + + .append("Location resolves to item with handle: " + item.getHandle()); return item; } private void checkAuth(SwordContext sc, Item item) - throws DSpaceSwordException, SwordError, SwordAuthException - { + throws DSpaceSwordException, SwordError, SwordAuthException { Context context = sc.getContext(); SwordAuthenticator auth = new SwordAuthenticator(); - if (!auth.canSubmit(sc, item, this.verboseDescription)) - { + if (!auth.canSubmit(sc, item, this.verboseDescription)) { // throw an exception if the deposit can't be made String oboEmail = "none"; - if (sc.getOnBehalfOf() != null) - { + if (sc.getOnBehalfOf() != null) { oboEmail = sc.getOnBehalfOf().getEmail(); } log.info(LogManager - .getHeader(context, "replace_failed_authorisation", - "user=" + - sc.getAuthenticated().getEmail() + - ",on_behalf_of=" + oboEmail)); + .getHeader(context, "replace_failed_authorisation", + "user=" + + sc.getAuthenticated().getEmail() + + ",on_behalf_of=" + oboEmail)); throw new SwordAuthException( - "Cannot replace the given item with this context"); + "Cannot replace the given item with this context"); } } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/OreStatementDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/OreStatementDisseminator.java index 8f8e300985..2c3a16637f 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/OreStatementDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/OreStatementDisseminator.java @@ -15,13 +15,11 @@ import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; public class OreStatementDisseminator extends GenericStatementDisseminator - implements SwordStatementDisseminator -{ + implements SwordStatementDisseminator { public Statement disseminate(Context context, Item item) - throws DSpaceSwordException, SwordError, SwordServerException - { + throws DSpaceSwordException, SwordError, SwordServerException { SwordUrlManager urlManager = new SwordUrlManager( - new SwordConfigurationDSpace(), context); + new SwordConfigurationDSpace(), context); String aggUrl = urlManager.getAggregationUrl(item); String remUrl = urlManager.getOreStatementUri(item); Statement s = new OREStatement(remUrl, aggUrl); diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/ReceiptGenerator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/ReceiptGenerator.java index b14c081a3e..caadc1db83 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/ReceiptGenerator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/ReceiptGenerator.java @@ -7,9 +7,20 @@ */ package org.dspace.sword2; +import java.sql.SQLException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.apache.abdera.i18n.iri.IRI; import org.apache.log4j.Logger; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; @@ -20,45 +31,36 @@ import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; import org.swordapp.server.UriRegistry; -import java.sql.SQLException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * @author Richard Jones * * Class to generate an ATOM Entry document for a DSpace Item */ -public class ReceiptGenerator -{ - /** logger */ +public class ReceiptGenerator { + /** + * logger + */ private static Logger log = Logger.getLogger(ReceiptGenerator.class); protected ItemService itemService = - ContentServiceFactory.getInstance() .getItemService(); + ContentServiceFactory.getInstance().getItemService(); protected DepositReceipt createFileReceipt(Context context, - DepositResult result, SwordConfigurationDSpace config) - throws DSpaceSwordException, SwordError, SwordServerException - { + DepositResult result, SwordConfigurationDSpace config) + throws DSpaceSwordException, SwordError, SwordServerException { SwordUrlManager urlManager = config.getUrlManager(context, config); DepositReceipt receipt = new DepositReceipt(); receipt.setLocation(new IRI(urlManager - .getActionableBitstreamUrl(result.getOriginalDeposit()))); + .getActionableBitstreamUrl(result.getOriginalDeposit()))); receipt.setEmpty(true); return receipt; } protected DepositReceipt createMediaResourceReceipt(Context context, - Item item, SwordConfigurationDSpace config) - throws DSpaceSwordException, SwordError, SwordServerException - { + Item item, SwordConfigurationDSpace config) + throws DSpaceSwordException, SwordError, SwordServerException { SwordUrlManager urlManager = config.getUrlManager(context, config); DepositReceipt receipt = new DepositReceipt(); receipt.setLocation(urlManager.getContentUrl(item)); @@ -66,36 +68,27 @@ public class ReceiptGenerator } protected DepositReceipt createReceipt(Context context, - DepositResult result, SwordConfigurationDSpace config) - throws DSpaceSwordException, SwordError, SwordServerException - { + DepositResult result, SwordConfigurationDSpace config) + throws DSpaceSwordException, SwordError, SwordServerException { return this.createReceipt(context, result, config, false); } /** * Construct the entry * - * @param context - * The relevant DSpace Context. - * @param result - * deposit result - * @param config - * SWORD configuration - * @param mediaResourceLocation - * set media resource URL + * @param context The relevant DSpace Context. + * @param result deposit result + * @param config SWORD configuration + * @param mediaResourceLocation set media resource URL * @return deposit receipt - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * SWORD error per SWORD spec - * @throws SwordServerException - * thrown by SWORD server implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError SWORD error per SWORD spec + * @throws SwordServerException thrown by SWORD server implementation */ protected DepositReceipt createReceipt(Context context, - DepositResult result, SwordConfigurationDSpace config, - boolean mediaResourceLocation) - throws DSpaceSwordException, SwordError, SwordServerException - { + DepositResult result, SwordConfigurationDSpace config, + boolean mediaResourceLocation) + throws DSpaceSwordException, SwordError, SwordServerException { SwordUrlManager urlManager = config.getUrlManager(context, config); DepositReceipt receipt = new DepositReceipt(); @@ -114,20 +107,15 @@ public class ReceiptGenerator receipt.setMediaFeedIRI(urlManager.getMediaFeedUrl(result.getItem())); receipt.setLastModified(result.getItem().getLastModified()); - if (mediaResourceLocation) - { + if (mediaResourceLocation) { receipt.setLocation(urlManager.getContentUrl(result.getItem())); - } - else - { + } else { receipt.setLocation(urlManager.getEditIRI(result.getItem())); } - try - { + try { Bitstream od = result.getOriginalDeposit(); - if (od != null) - { + if (od != null) { // note here that we don't provide an actionable url receipt.setOriginalDeposit( urlManager.getActionableBitstreamUrl(od), @@ -136,19 +124,15 @@ public class ReceiptGenerator Map derived = new HashMap(); List drs = result.getDerivedResources(); - if (drs != null) - { - for (Bitstream bs : result.getDerivedResources()) - { + if (drs != null) { + for (Bitstream bs : result.getDerivedResources()) { // here we provide actionable urls for the parts of the resource derived.put(urlManager.getActionableBitstreamUrl(bs), - bs.getFormat(context).getMIMEType()); + bs.getFormat(context).getMIMEType()); } } receipt.setDerivedResources(derived); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } @@ -165,15 +149,12 @@ public class ReceiptGenerator StringBuilder rightsString = new StringBuilder(); List bundles = result.getItem().getBundles(); - for (Bundle bundle : bundles) - { - if (!Constants.LICENSE_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (!Constants.LICENSE_BUNDLE_NAME.equals(bundle.getName())) { continue; } List bss = bundle.getBitstreams(); - for (Bitstream bs : bss) - { + for (Bitstream bs : bss) { String url = urlManager.getBitstreamUrl(bs); rightsString.append(url).append(" "); } @@ -192,24 +173,17 @@ public class ReceiptGenerator /** * Construct the entry * - * @param context - * The relevant DSpace Context. - * @param item - * the target item to generate the ATOM document for - * @param config - * SWORD configuration + * @param context The relevant DSpace Context. + * @param item the target item to generate the ATOM document for + * @param config SWORD configuration * @return deposit receipt - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * SWORD error per SWORD spec - * @throws SwordServerException - * thrown by SWORD server implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError SWORD error per SWORD spec + * @throws SwordServerException thrown by SWORD server implementation */ protected DepositReceipt createReceipt(Context context, Item item, - SwordConfigurationDSpace config) - throws DSpaceSwordException, SwordError, SwordServerException - { + SwordConfigurationDSpace config) + throws DSpaceSwordException, SwordError, SwordServerException { SwordUrlManager urlManager = config.getUrlManager(context, config); DepositReceipt receipt = new DepositReceipt(); @@ -233,20 +207,17 @@ public class ReceiptGenerator // add the item's metadata SwordEntryDisseminator disseminator = SwordDisseminatorFactory - .getEntryInstance(); + .getEntryInstance(); disseminator.disseminate(context, item, receipt); StringBuilder rightsString = new StringBuilder(); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (!Constants.LICENSE_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (!Constants.LICENSE_BUNDLE_NAME.equals(bundle.getName())) { continue; } List bss = bundle.getBitstreams(); - for (Bitstream bs : bss) - { + for (Bitstream bs : bss) { String url = urlManager.getBitstreamUrl(bs); rightsString.append(url).append(" "); } @@ -266,19 +237,14 @@ public class ReceiptGenerator * Add all the subject classifications from the bibliographic * metadata. * - * @param result - * represents the results of a deposit request - * @param receipt - * deposit receipt + * @param result represents the results of a deposit request + * @param receipt deposit receipt */ - protected void addCategories(DepositResult result, DepositReceipt receipt) - { + protected void addCategories(DepositResult result, DepositReceipt receipt) { List dcv = itemService.getMetadataByMetadataString( result.getItem(), "dc.subject.*"); - if (dcv != null) - { - for (MetadataValue aDcv : dcv) - { + if (dcv != null) { + for (MetadataValue aDcv : dcv) { receipt.getWrappedEntry().addCategory( UriRegistry.DC_NAMESPACE, aDcv.getValue(), aDcv.getValue()); } @@ -289,19 +255,14 @@ public class ReceiptGenerator * Add all the subject classifications from the bibliographic * metadata. * - * @param item - * target item - * @param receipt - * deposit receipt + * @param item target item + * @param receipt deposit receipt */ - protected void addCategories(Item item, DepositReceipt receipt) - { + protected void addCategories(Item item, DepositReceipt receipt) { List dcv = itemService - .getMetadataByMetadataString(item, "dc.subject.*"); - if (dcv != null) - { - for (MetadataValue aDcv : dcv) - { + .getMetadataByMetadataString(item, "dc.subject.*"); + if (dcv != null) { + for (MetadataValue aDcv : dcv) { receipt.getWrappedEntry().addCategory( UriRegistry.DC_NAMESPACE, aDcv.getValue(), aDcv.getValue()); } @@ -311,25 +272,18 @@ public class ReceiptGenerator /** * Add the date of publication from the bibliographic metadata * - * @param result - * represents the results of a deposit request - * @param receipt - * deposit receipt + * @param result represents the results of a deposit request + * @param receipt deposit receipt */ - protected void addPublishDate(DepositResult result, DepositReceipt receipt) - { + protected void addPublishDate(DepositResult result, DepositReceipt receipt) { List dcv = itemService.getMetadataByMetadataString( result.getItem(), "dc.date.issued"); - if (dcv != null && !dcv.isEmpty()) - { - try - { + if (dcv != null && !dcv.isEmpty()) { + try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date published = sdf.parse(dcv.get(0).getValue()); receipt.getWrappedEntry().setPublished(published); - } - catch (ParseException e) - { + } catch (ParseException e) { // we tried, but never mind log.warn("Couldn't add published date", e); } @@ -339,25 +293,18 @@ public class ReceiptGenerator /** * Add the date of publication from the bibliographic metadata * - * @param item - * target item - * @param receipt - * deposit receipt + * @param item target item + * @param receipt deposit receipt */ - protected void addPublishDate(Item item, DepositReceipt receipt) - { + protected void addPublishDate(Item item, DepositReceipt receipt) { List dcv = itemService.getMetadataByMetadataString( item, "dc.date.issued"); - if (dcv != null && dcv.size() == 1) - { - try - { + if (dcv != null && dcv.size() == 1) { + try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date published = sdf.parse(dcv.get(0).getValue()); receipt.getWrappedEntry().setPublished(published); - } - catch (ParseException e) - { + } catch (ParseException e) { // we tried, but never mind log.warn("Couldn't add published date", e); } @@ -367,28 +314,21 @@ public class ReceiptGenerator /** * Add the date that this item was last updated * - * @param result - * represents the results of a deposit request - * @param receipt - * deposit receipt + * @param result represents the results of a deposit request + * @param receipt deposit receipt */ protected void addLastUpdatedDate(DepositResult result, - DepositReceipt receipt) - { + DepositReceipt receipt) { String config = ConfigurationManager.getProperty( "swordv2-server", "updated.field"); List dcv = itemService.getMetadataByMetadataString( result.getItem(), config); - if (dcv != null && dcv.size() == 1) - { - try - { + if (dcv != null && dcv.size() == 1) { + try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date updated = sdf.parse(dcv.get(0).getValue()); receipt.getWrappedEntry().setUpdated(updated); - } - catch (ParseException e) - { + } catch (ParseException e) { // we tried, but never mind log.warn("Couldn't add last updated date", e); } @@ -398,27 +338,20 @@ public class ReceiptGenerator /** * Add the date that this item was last updated * - * @param item - * target item - * @param receipt - * deposit receipt + * @param item target item + * @param receipt deposit receipt */ - protected void addLastUpdatedDate(Item item, DepositReceipt receipt) - { + protected void addLastUpdatedDate(Item item, DepositReceipt receipt) { String config = ConfigurationManager.getProperty( "swordv2-server", "updated.field"); List dcv = itemService.getMetadataByMetadataString( item, config); - if (dcv != null && dcv.size() == 1) - { - try - { + if (dcv != null && dcv.size() == 1) { + try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date updated = sdf.parse(dcv.get(0).getValue()); receipt.getWrappedEntry().setUpdated(updated); - } - catch (ParseException e) - { + } catch (ParseException e) { // we tried, but never mind log.warn("Couldn't add last updated date", e); } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/ServiceDocumentManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/ServiceDocumentManagerDSpace.java index 41202ad216..ac8f73a1bb 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/ServiceDocumentManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/ServiceDocumentManagerDSpace.java @@ -7,6 +7,8 @@ */ package org.dspace.sword2; +import java.util.List; + import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.Community; @@ -26,25 +28,22 @@ import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; import org.swordapp.server.SwordWorkspace; -import java.util.List; - -public class ServiceDocumentManagerDSpace implements ServiceDocumentManager -{ - /** logger */ +public class ServiceDocumentManagerDSpace implements ServiceDocumentManager { + /** + * logger + */ private static Logger log = Logger - .getLogger(ServiceDocumentManagerDSpace.class); + .getLogger(ServiceDocumentManagerDSpace.class); protected CommunityService communityService = ContentServiceFactory - .getInstance().getCommunityService(); + .getInstance().getCommunityService(); public ServiceDocument getServiceDocument(String sdUri, - AuthCredentials authCredentials, SwordConfiguration config) - throws SwordError, SwordServerException, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration config) + throws SwordError, SwordServerException, SwordAuthException { SwordContext sc = null; - try - { + try { // first authenticate the request // note: this will build our various DSpace contexts for us SwordAuthenticator auth = new SwordAuthenticator(); @@ -54,61 +53,53 @@ public class ServiceDocumentManagerDSpace implements ServiceDocumentManager // ensure that this method is allowed WorkflowManagerFactory.getInstance().retrieveServiceDoc(context); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager - .getHeader(context, "sword_do_service_document", "")); + .getHeader(context, "sword_do_service_document", "")); } // log the request String un = authCredentials.getUsername() != null ? - authCredentials.getUsername() : - "NONE"; + authCredentials.getUsername() : + "NONE"; String obo = authCredentials.getOnBehalfOf() != null ? - authCredentials.getOnBehalfOf() : - "NONE"; + authCredentials.getOnBehalfOf() : + "NONE"; log.info(LogManager - .getHeader(context, "sword_service_document_request", - "username=" + un + ",on_behalf_of=" + obo)); + .getHeader(context, "sword_service_document_request", + "username=" + un + ",on_behalf_of=" + obo)); return this.getServiceDocument(sc, sdUri, - (SwordConfigurationDSpace) config); - } - catch (DSpaceSwordException e) - { + (SwordConfigurationDSpace) config); + } catch (DSpaceSwordException e) { log.error("caught exception: ", e); throw new SwordServerException( - "The DSpace SWORD interface experienced an error", e); - } - finally - { + "The DSpace SWORD interface experienced an error", e); + } finally { // this is a read operation only, so there's never any need to commit the context - if (sc != null) - { + if (sc != null) { sc.abort(); } } } public ServiceDocument getServiceDocument(SwordContext context, String url, - SwordConfigurationDSpace swordConfig) - throws SwordError, SwordServerException, DSpaceSwordException - { + SwordConfigurationDSpace swordConfig) + throws SwordError, SwordServerException, DSpaceSwordException { // first check that the sword context have // been set - if (context == null) - { + if (context == null) { throw new DSpaceSwordException( - "The Sword Context is null; please set it before calling getServiceDocument"); + "The Sword Context is null; please set it before calling getServiceDocument"); } // ensure that this method is allowed WorkflowManagerFactory.getInstance() - .retrieveServiceDoc(context.getContext()); + .retrieveServiceDoc(context.getContext()); // get the URL manager SwordUrlManager urlManager = swordConfig - .getUrlManager(context.getContext(), swordConfig); + .getUrlManager(context.getContext(), swordConfig); // we'll need the authenticator SwordAuthenticator swordAuth = new SwordAuthenticator(); @@ -123,8 +114,7 @@ public class ServiceDocumentManagerDSpace implements ServiceDocumentManager // set the max upload size service.setMaxUploadSize(swordConfig.getMaxUploadSize()); - if (url == null || urlManager.isBaseServiceDocumentUrl(url)) - { + if (url == null || urlManager.isBaseServiceDocumentUrl(url)) { // we are dealing with the default service document // set the title of the workspace as per the name of the DSpace installation @@ -134,67 +124,56 @@ public class ServiceDocumentManagerDSpace implements ServiceDocumentManager // next thing to do is determine whether the default is communities or collections boolean swordCommunities = ConfigurationManager - .getBooleanProperty("swordv2-server", "expose-communities"); + .getBooleanProperty("swordv2-server", "expose-communities"); - if (swordCommunities) - { + if (swordCommunities) { List comms = swordAuth - .getAllowedCommunities(context); - for (Community comm : comms) - { + .getAllowedCommunities(context); + for (Community comm : comms) { SwordCollection scol = comGen - .buildCollection(context.getContext(), comm, - swordConfig); + .buildCollection(context.getContext(), comm, + swordConfig); workspace.addCollection(scol); } - } - else - { + } else { List cols = swordAuth - .getAllowedCollections(context); - for (Collection col : cols) - { + .getAllowedCollections(context); + for (Collection col : cols) { SwordCollection scol = colGen - .buildCollection(context.getContext(), col, - swordConfig); + .buildCollection(context.getContext(), col, + swordConfig); workspace.addCollection(scol); } } service.addWorkspace(workspace); - } - else - { + } else { // we are dealing with a partial or sub-service document DSpaceObject dso = urlManager.extractDSpaceObject(url); - if (dso == null) - { + if (dso == null) { throw new SwordError(404); } - if (dso instanceof Community) - { + if (dso instanceof Community) { Community community = (Community) dso; SwordWorkspace workspace = new SwordWorkspace(); workspace.setTitle(communityService.getName(community)); List collections = swordAuth - .getAllowedCollections(context, community); - for (Collection collection : collections) - { + .getAllowedCollections(context, community); + for (Collection collection : collections) { SwordCollection scol = colGen - .buildCollection(context.getContext(), collection, - swordConfig); + .buildCollection(context.getContext(), collection, + swordConfig); workspace.addCollection(scol); } List communities = swordAuth - .getCommunities(context, community); - for (Community comm : communities) - { + .getCommunities(context, community); + for (Community comm : communities) { SwordCollection scol = comGen - .buildCollection(context.getContext(), comm, - swordConfig); + .buildCollection(context.getContext(), comm, + swordConfig); workspace.addCollection(scol); } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCEntryDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCEntryDisseminator.java index 3a3692a035..00e7e98de3 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCEntryDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCEntryDisseminator.java @@ -7,60 +7,44 @@ */ package org.dspace.sword2; +import java.util.Map; + import org.dspace.content.Item; import org.dspace.core.Context; import org.swordapp.server.DepositReceipt; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -import java.util.Map; - public class SimpleDCEntryDisseminator extends AbstractSimpleDC - implements SwordEntryDisseminator -{ - public SimpleDCEntryDisseminator() - { + implements SwordEntryDisseminator { + public SimpleDCEntryDisseminator() { } public DepositReceipt disseminate(Context context, Item item, - DepositReceipt receipt) - throws DSpaceSwordException, SwordError, SwordServerException - { + DepositReceipt receipt) + throws DSpaceSwordException, SwordError, SwordServerException { SimpleDCMetadata md = this.getMetadata(item); Map dc = md.getDublinCore(); - for (String element : dc.keySet()) - { + for (String element : dc.keySet()) { String value = dc.get(element); receipt.addDublinCore(element, value); } Map atom = md.getAtom(); - for (String element : atom.keySet()) - { + for (String element : atom.keySet()) { String value = atom.get(element); - if ("author".equals(element)) - { + if ("author".equals(element)) { receipt.getWrappedEntry().addAuthor(value); - } - else if ("published".equals(element)) - { + } else if ("published".equals(element)) { receipt.getWrappedEntry().setPublished(value); - } - else if ("rights".equals(element)) - { + } else if ("rights".equals(element)) { receipt.getWrappedEntry().setRights(value); - } - else if ("summary".equals(element)) - { + } else if ("summary".equals(element)) { receipt.getWrappedEntry().setSummary(value); - } - else if ("title".equals(element)) - { + } else if ("title".equals(element)) { receipt.getWrappedEntry().setTitle(value); - } - else if ("updated".equals(element)) - { + } else if ("updated".equals(element)) { receipt.getWrappedEntry().setUpdated(value); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCEntryIngester.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCEntryIngester.java index 63d66d6dcc..60a8365ca5 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCEntryIngester.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCEntryIngester.java @@ -7,85 +7,83 @@ */ package org.dspace.sword2; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.*; +import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.WorkspaceItem; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; -import org.swordapp.server.*; - -import java.sql.SQLException; -import java.util.Date; -import java.util.List; -import java.util.Map; -import org.apache.commons.lang.StringUtils; +import org.swordapp.server.Deposit; +import org.swordapp.server.SwordAuthException; +import org.swordapp.server.SwordEntry; +import org.swordapp.server.SwordError; +import org.swordapp.server.SwordServerException; public class SimpleDCEntryIngester extends AbstractSimpleDC - implements SwordEntryIngester -{ + implements SwordEntryIngester { private static final Logger log = Logger.getLogger(SimpleDCEntryIngester.class); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); - + protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - public SimpleDCEntryIngester() - { + public SimpleDCEntryIngester() { this.loadMetadataMaps(); } public DepositResult ingest(Context context, Deposit deposit, - DSpaceObject dso, VerboseDescription verboseDescription) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + DSpaceObject dso, VerboseDescription verboseDescription) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { return this.ingest( context, deposit, dso, verboseDescription, null, false); } public DepositResult ingest(Context context, Deposit deposit, - DSpaceObject dso, VerboseDescription verboseDescription, - DepositResult result, boolean replace) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - if (dso instanceof Collection) - { + DSpaceObject dso, VerboseDescription verboseDescription, + DepositResult result, boolean replace) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + if (dso instanceof Collection) { return this.ingestToCollection(context, deposit, (Collection) dso, - verboseDescription, result); - } - else if (dso instanceof Item) - { + verboseDescription, result); + } else if (dso instanceof Item) { return this.ingestToItem(context, deposit, (Item) dso, - verboseDescription, result, replace); + verboseDescription, result, replace); } return null; } public DepositResult ingestToItem(Context context, Deposit deposit, - Item item, VerboseDescription verboseDescription, - DepositResult result, boolean replace) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - try - { - if (result == null) - { + Item item, VerboseDescription verboseDescription, + DepositResult result, boolean replace) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + try { + if (result == null) { result = new DepositResult(); } result.setItem(item); // clean out any existing item metadata which is allowed to be replaced - if (replace) - { + if (replace) { this.removeMetadata(context, item); } @@ -110,29 +108,22 @@ public class SimpleDCEntryIngester extends AbstractSimpleDC result.setTreatment(this.getTreatment()); return result; - } - catch (SQLException | AuthorizeException e) - { + } catch (SQLException | AuthorizeException e) { throw new DSpaceSwordException(e); } } private void removeMetadata(Context context, Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { String[] replaceableMetadata = configurationService .getArrayProperty("swordv2-server.metadata.replaceable"); - for (String part : replaceableMetadata) - { + for (String part : replaceableMetadata) { MetadataValueInfo info = this.makeMetadataValueInfo(part.trim(), null); - try - { + try { itemService.clearMetadata(context, item, - info.schema, info.element, info.qualifier, Item.ANY); - } - catch (SQLException e) - { + info.schema, info.element, info.qualifier, Item.ANY); + } catch (SQLException e) { log.error("Caught exception trying to remove metadata", e); throw new DSpaceSwordException(e); } @@ -140,77 +131,61 @@ public class SimpleDCEntryIngester extends AbstractSimpleDC } private void addUniqueMetadata(Context context, MetadataValueInfo info, - Item item) throws SQLException - { + Item item) throws SQLException { String qual = info.qualifier; - if (info.qualifier == null) - { + if (info.qualifier == null) { qual = Item.ANY; } String lang = info.language; - if (info.language == null) - { + if (info.language == null) { lang = Item.ANY; } List existing = itemService.getMetadata( item, info.schema, info.element, qual, lang); - for (MetadataValue dcValue : existing) - { + for (MetadataValue dcValue : existing) { // FIXME: probably we want to be slightly more careful about qualifiers and languages // // if the submitted value is already attached to the item, just skip it - if (dcValue.getValue().equals(info.value)) - { + if (dcValue.getValue().equals(info.value)) { return; } } // if we get to here, go on and add the metadata itemService.addMetadata(context, item, info.schema, info.element, - info.qualifier, info.language, info.value); + info.qualifier, info.language, info.value); } private void addMetadataToItem(Context context, Deposit deposit, Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { // now, go through and get the metadata from the EntryPart and put it in DSpace SwordEntry se = deposit.getSwordEntry(); // first do the standard atom terms (which may get overridden later) String title = se.getTitle(); String summary = se.getSummary(); - if (title != null) - { + if (title != null) { String titleField = this.dcMap.get("title"); - if (titleField != null) - { + if (titleField != null) { MetadataValueInfo info = this.makeMetadataValueInfo(titleField, title); - try - { + try { this.addUniqueMetadata(context, info, item); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception trying to add title", e); throw new DSpaceSwordException(e); } } } - if (summary != null) - { + if (summary != null) { String abstractField = this.dcMap.get("abstract"); - if (abstractField != null) - { + if (abstractField != null) { MetadataValueInfo info = this.makeMetadataValueInfo(abstractField, summary); - try - { + try { this.addUniqueMetadata(context, info, item); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception trying to set abstract", e); throw new DSpaceSwordException(e); } @@ -218,26 +193,20 @@ public class SimpleDCEntryIngester extends AbstractSimpleDC } Map> dc = se.getDublinCore(); - for (String term : dc.keySet()) - { + for (String term : dc.keySet()) { String dsTerm = this.dcMap.get(term); - if (dsTerm == null) - { + if (dsTerm == null) { // ignore anything we don't understand continue; } // now add all the metadata terms MetadataValueInfo info = this.makeMetadataValueInfo(dsTerm, null); - for (String value : dc.get(term)) - { + for (String value : dc.get(term)) { info.value = value; - try - { + try { this.addUniqueMetadata(context, info, item); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception trying to add metadata", e); throw new DSpaceSwordException(e); } @@ -246,26 +215,20 @@ public class SimpleDCEntryIngester extends AbstractSimpleDC } public DepositResult ingestToCollection(Context context, Deposit deposit, - Collection collection, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - try - { + Collection collection, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + try { // decide whether we have a new item or an existing one Item item = null; WorkspaceItem wsi = null; - if (result != null) - { + if (result != null) { item = result.getItem(); - } - else - { + } else { result = new DepositResult(); } - if (item == null) - { + if (item == null) { // simple zip ingester uses the item template, since there is no native metadata wsi = workspaceItemService.create(context, collection, true); item = wsi.getItem(); @@ -298,30 +261,23 @@ public class SimpleDCEntryIngester extends AbstractSimpleDC result.setTreatment(this.getTreatment()); return result; - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } public MetadataValueInfo makeMetadataValueInfo(String field, String value) - throws DSpaceSwordException - { + throws DSpaceSwordException { MetadataValueInfo dcv = new MetadataValueInfo(); String[] bits = field.split("\\."); - if (bits.length < 2 || bits.length > 3) - { + if (bits.length < 2 || bits.length > 3) { throw new DSpaceSwordException("invalid DC value: " + field); } dcv.schema = bits[0]; dcv.element = bits[1]; - if (bits.length == 3) - { + if (bits.length == 3) { dcv.qualifier = bits[2]; } dcv.value = value; @@ -333,38 +289,29 @@ public class SimpleDCEntryIngester extends AbstractSimpleDC * the field in which to store this metadata in the configuration * sword.updated.field * - * @param context - * The relevant DSpace Context. - * @param item - * item to add date metadata to - * @param verboseDescription - * The description. - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @param context The relevant DSpace Context. + * @param item item to add date metadata to + * @param verboseDescription The description. + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ protected void setUpdatedDate(Context context, Item item, - VerboseDescription verboseDescription) - throws DSpaceSwordException - { + VerboseDescription verboseDescription) + throws DSpaceSwordException { String field = configurationService - .getProperty("swordv2-server.updated.field"); - if (StringUtils.isBlank(field)) - { + .getProperty("swordv2-server.updated.field"); + if (StringUtils.isBlank(field)) { throw new DSpaceSwordException( "No configuration, or configuration is invalid for: swordv2-server.updated.field"); } MetadataValueInfo info = this.makeMetadataValueInfo(field, null); - try - { + try { itemService.clearMetadata(context, item, - info.schema, info.element, info.qualifier, Item.ANY); + info.schema, info.element, info.qualifier, Item.ANY); DCDate date = new DCDate(new Date()); itemService.addMetadata(context, item, info.schema, - info.element, info.qualifier, null, date.toString()); - } - catch (SQLException e) - { + info.element, info.qualifier, null, date.toString()); + } catch (SQLException e) { log.error("Exception caught trying to set updated date", e); throw new DSpaceSwordException(e); } @@ -379,45 +326,34 @@ public class SimpleDCEntryIngester extends AbstractSimpleDC * field in which to store this metadata in the configuration * sword.slug.field * - * @param context - * The relevant DSpace Context. - * @param item - * the item to modify - * @param slugVal - * the value to store to metadata - * @param verboseDescription - * The description. - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @param context The relevant DSpace Context. + * @param item the item to modify + * @param slugVal the value to store to metadata + * @param verboseDescription The description. + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ protected void setSlug(Context context, Item item, String slugVal, - VerboseDescription verboseDescription) - throws DSpaceSwordException - { + VerboseDescription verboseDescription) + throws DSpaceSwordException { // if there isn't a slug value, don't set it - if (slugVal == null) - { + if (slugVal == null) { return; } String field = configurationService.getProperty( "swordv2-server.slug.field"); - if (StringUtils.isBlank(field)) - { + if (StringUtils.isBlank(field)) { throw new DSpaceSwordException( "No configuration, or configuration is invalid for: swordv2-server.slug.field"); } MetadataValueInfo info = this.makeMetadataValueInfo(field, null); - try - { + try { itemService.clearMetadata(context, item, - info.schema, info.element, info.qualifier, Item.ANY); + info.schema, info.element, info.qualifier, Item.ANY); itemService.addMetadata(context, item, - info.schema, info.element, info.qualifier, null, slugVal); - } - catch (SQLException e) - { + info.schema, info.element, info.qualifier, null, slugVal); + } catch (SQLException e) { log.error("Caught exception trying to set slug", e); throw new DSpaceSwordException(e); } @@ -430,16 +366,13 @@ public class SimpleDCEntryIngester extends AbstractSimpleDC * put the deposit through * * @return human readable description - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ - private String getTreatment() throws DSpaceSwordException - { + private String getTreatment() throws DSpaceSwordException { return "A metadata only item has been created"; } - private class MetadataValueInfo - { + private class MetadataValueInfo { private String schema; private String element; diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCMetadata.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCMetadata.java index 9d264ab70e..d928fb7e99 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCMetadata.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleDCMetadata.java @@ -11,29 +11,24 @@ package org.dspace.sword2; import java.util.HashMap; import java.util.Map; -public class SimpleDCMetadata -{ +public class SimpleDCMetadata { private Map dublinCore = new HashMap(); private Map atom = new HashMap(); - public void addDublinCore(String element, String value) - { + public void addDublinCore(String element, String value) { this.dublinCore.put(element, value); } - public void addAtom(String element, String value) - { + public void addAtom(String element, String value) { this.atom.put(element, value); } - public Map getDublinCore() - { + public Map getDublinCore() { return dublinCore; } - public Map getAtom() - { + public Map getAtom() { return atom; } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleZipContentDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleZipContentDisseminator.java index 5f360bb684..ce235f8318 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleZipContentDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleZipContentDisseminator.java @@ -7,6 +7,17 @@ */ package org.dspace.sword2; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; @@ -21,48 +32,31 @@ import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; import org.swordapp.server.UriRegistry; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public class SimpleZipContentDisseminator implements SwordContentDisseminator -{ +public class SimpleZipContentDisseminator implements SwordContentDisseminator { protected BitstreamService bitstreamService = ContentServiceFactory - .getInstance().getBitstreamService(); + .getInstance().getBitstreamService(); public InputStream disseminate(Context context, Item item) - throws DSpaceSwordException, SwordError, SwordServerException - { - try - { + throws DSpaceSwordException, SwordError, SwordServerException { + try { // first write everything to a temp file String tempDir = ConfigurationManager - .getProperty("upload.temp.dir"); + .getProperty("upload.temp.dir"); String fn = - tempDir + File.separator + "SWORD." + item.getID() + "." + - UUID.randomUUID().toString() + ".zip"; + tempDir + File.separator + "SWORD." + item.getID() + "." + + UUID.randomUUID().toString() + ".zip"; OutputStream outStream = new FileOutputStream(new File(fn)); ZipOutputStream zip = new ZipOutputStream(outStream); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { List bss = bundle.getBitstreams(); - for (Bitstream bitstream : bss) - { + for (Bitstream bitstream : bss) { ZipEntry ze = new ZipEntry(bitstream.getName()); zip.putNextEntry(ze); InputStream is = bitstreamService - .retrieve(context, bitstream); + .retrieve(context, bitstream); Utils.copy(is, zip); zip.closeEntry(); is.close(); @@ -72,42 +66,34 @@ public class SimpleZipContentDisseminator implements SwordContentDisseminator zip.close(); return new TempFileInputStream(new File(fn)); - } - catch (SQLException | IOException | AuthorizeException e) - { + } catch (SQLException | IOException | AuthorizeException e) { throw new DSpaceSwordException(e); } } public boolean disseminatesContentType(String contentType) - throws DSpaceSwordException, SwordError, SwordServerException - { + throws DSpaceSwordException, SwordError, SwordServerException { return "application/zip".equals(contentType); } public boolean disseminatesPackage(String contentType) - throws DSpaceSwordException, SwordError, SwordServerException - { + throws DSpaceSwordException, SwordError, SwordServerException { return UriRegistry.PACKAGE_SIMPLE_ZIP.equals(contentType); } - public void setContentType(String contentType) - { + public void setContentType(String contentType) { // this only does the one thing, so we can ignore this } - public void setPackaging(String packaging) - { + public void setPackaging(String packaging) { // this only does the one thing, so we can ignore this } - public String getContentType() - { + public String getContentType() { return "application/zip"; } - public String getPackaging() - { + public String getPackaging() { return UriRegistry.PACKAGE_SIMPLE_ZIP; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleZipContentIngester.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleZipContentIngester.java index f4e1b168dd..bd8301617b 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleZipContentIngester.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SimpleZipContentIngester.java @@ -7,22 +7,6 @@ */ package org.dspace.sword2; -import org.dspace.authorize.AuthorizeException; -import org.dspace.content.Bitstream; -import org.dspace.content.BitstreamFormat; -import org.dspace.content.Bundle; -import org.dspace.content.Collection; -import org.dspace.content.Item; -import org.dspace.content.WorkspaceItem; -import org.dspace.content.factory.ContentServiceFactory; -import org.dspace.content.service.*; -import org.dspace.core.Constants; -import org.dspace.core.Context; -import org.swordapp.server.Deposit; -import org.swordapp.server.SwordAuthException; -import org.swordapp.server.SwordError; -import org.swordapp.server.UriRegistry; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -34,40 +18,51 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; -public class SimpleZipContentIngester extends AbstractSwordContentIngester -{ +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.content.WorkspaceItem; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.BitstreamService; +import org.dspace.content.service.BundleService; +import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.swordapp.server.Deposit; +import org.swordapp.server.SwordAuthException; +import org.swordapp.server.SwordError; +import org.swordapp.server.UriRegistry; + +public class SimpleZipContentIngester extends AbstractSwordContentIngester { protected BundleService bundleService = ContentServiceFactory.getInstance() - .getBundleService(); + .getBundleService(); protected BitstreamService bitstreamService = ContentServiceFactory - .getInstance().getBitstreamService(); + .getInstance().getBitstreamService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory - .getInstance().getWorkspaceItemService(); + .getInstance().getWorkspaceItemService(); public DepositResult ingestToCollection(Context context, Deposit deposit, - Collection collection, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException - { - try - { + Collection collection, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException { + try { // get deposited file as file object File depositFile = deposit.getFile(); // decide whether we have a new item or an existing one Item item = null; WorkspaceItem wsi = null; - if (result != null) - { + if (result != null) { item = result.getItem(); - } - else - { + } else { result = new DepositResult(); } - if (item == null) - { + if (item == null) { // simple zip ingester uses the item template, since there is no native metadata wsi = workspaceItemService.create(context, collection, true); item = wsi.getItem(); @@ -76,31 +71,28 @@ public class SimpleZipContentIngester extends AbstractSwordContentIngester // get the original bundle List bundles = item.getBundles(); Bundle original = null; - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { original = bundle; break; } } - if (original == null) - { + if (original == null) { original = bundleService - .create(context, item, Constants.CONTENT_BUNDLE_NAME); + .create(context, item, Constants.CONTENT_BUNDLE_NAME); } // unzip the file into the bundle List derivedResources = this - .unzipToBundle(context, depositFile, original); + .unzipToBundle(context, depositFile, original); // now we have an item in the workspace, and we need to consider adding some metadata to it, // but since the zip file didn't contain anything, what do we do? itemService.addMetadata(context, item, "dc", "title", null, null, - "Untitled: " + deposit.getFilename()); + "Untitled: " + deposit.getFilename()); itemService - .addMetadata(context, item, "dc", "description", null, null, - "Zip file deposted by SWORD without accompanying metadata"); + .addMetadata(context, item, "dc", "description", null, null, + "Zip file deposted by SWORD without accompanying metadata"); // update the item metadata to inclue the current time as // the updated date @@ -120,7 +112,7 @@ public class SimpleZipContentIngester extends AbstractSwordContentIngester verboseDescription.append("Ingest successful"); verboseDescription - .append("Item created with internal identifier: " + + .append("Item created with internal identifier: " + item.getID()); result.setItem(item); @@ -128,35 +120,28 @@ public class SimpleZipContentIngester extends AbstractSwordContentIngester result.setDerivedResources(derivedResources); return result; - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } private List unzipToBundle(Context context, File depositFile, - Bundle target) - throws DSpaceSwordException, SwordError, SwordAuthException - { - try - { + Bundle target) + throws DSpaceSwordException, SwordError, SwordAuthException { + try { // get the zip file into a usable form ZipFile zip = new ZipFile(depositFile); List derivedResources = new ArrayList(); Enumeration zenum = zip.entries(); - while (zenum.hasMoreElements()) - { + while (zenum.hasMoreElements()) { ZipEntry entry = (ZipEntry) zenum.nextElement(); InputStream stream = zip.getInputStream(entry); Bitstream bs = bitstreamService.create(context, target, stream); BitstreamFormat format = this - .getFormat(context, entry.getName()); + .getFormat(context, entry.getName()); bs.setFormat(context, format); bs.setName(context, entry.getName()); bitstreamService.update(context, bs); @@ -164,31 +149,22 @@ public class SimpleZipContentIngester extends AbstractSwordContentIngester } return derivedResources; - } - catch (ZipException e) - { + } catch (ZipException e) { throw new SwordError(UriRegistry.ERROR_BAD_REQUEST, - "unable to unzip provided package", e); - } - catch (IOException | SQLException e) - { + "unable to unzip provided package", e); + } catch (IOException | SQLException e) { throw new DSpaceSwordException(e); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); } } public DepositResult ingestToItem(Context context, Deposit deposit, - Item item, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException - { - try - { - if (result == null) - { + Item item, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException { + try { + if (result == null) { result = new DepositResult(); } result.setItem(item); @@ -199,23 +175,20 @@ public class SimpleZipContentIngester extends AbstractSwordContentIngester // get the original bundle List bundles = item.getBundles(); Bundle original = null; - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) { original = bundle; break; } } - if (original == null) - { + if (original == null) { original = bundleService - .create(context, item, Constants.CONTENT_BUNDLE_NAME); + .create(context, item, Constants.CONTENT_BUNDLE_NAME); } // we are now free to go and unpack the new zip into the original bundle List derivedResources = this - .unzipToBundle(context, depositFile, original); + .unzipToBundle(context, depositFile, original); // update the item metadata to inclue the current time as // the updated date @@ -236,13 +209,9 @@ public class SimpleZipContentIngester extends AbstractSwordContentIngester result.setDerivedResources(derivedResources); return result; - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(e); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } @@ -252,13 +221,11 @@ public class SimpleZipContentIngester extends AbstractSwordContentIngester * put the deposit through * * @return human readable description - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ - private String getTreatment() throws DSpaceSwordException - { + private String getTreatment() throws DSpaceSwordException { return "The package has been ingested and unpacked into the item. Template metadata for " + - "the collection has been used, and a default title with the name of the file has " + - "been set"; + "the collection has been used, and a default title with the name of the file has " + + "been set"; } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/StatementManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/StatementManagerDSpace.java index 18f2008f70..1e8edd2a34 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/StatementManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/StatementManagerDSpace.java @@ -7,9 +7,15 @@ */ package org.dspace.sword2; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; -import org.dspace.authorize.AuthorizeServiceImpl; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.Item; @@ -24,55 +30,43 @@ import org.swordapp.server.SwordConfiguration; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - public class StatementManagerDSpace extends DSpaceSwordAPI - implements StatementManager -{ + implements StatementManager { private static Logger log = Logger.getLogger(StatementManagerDSpace.class); protected AuthorizeService authorizeService = AuthorizeServiceFactory - .getInstance().getAuthorizeService(); + .getInstance().getAuthorizeService(); public Statement getStatement(String stateIRI, Map accept, - AuthCredentials authCredentials, SwordConfiguration swordConfig) - throws SwordServerException, SwordError, SwordAuthException - { + AuthCredentials authCredentials, SwordConfiguration swordConfig) + throws SwordServerException, SwordError, SwordAuthException { SwordContext sc = null; - try - { + try { SwordConfigurationDSpace config = (SwordConfigurationDSpace) swordConfig; SwordAuthenticator auth = new SwordAuthenticator(); sc = auth.authenticate(authCredentials); Context context = sc.getContext(); - if (log.isDebugEnabled()) - { + if (log.isDebugEnabled()) { log.debug(LogManager - .getHeader(context, "sword_get_statement", "")); + .getHeader(context, "sword_get_statement", "")); } // log the request String un = authCredentials.getUsername() != null ? - authCredentials.getUsername() : - "NONE"; + authCredentials.getUsername() : + "NONE"; String obo = authCredentials.getOnBehalfOf() != null ? - authCredentials.getOnBehalfOf() : - "NONE"; + authCredentials.getOnBehalfOf() : + "NONE"; log.info(LogManager.getHeader(context, "sword_get_statement", - "username=" + un + ",on_behalf_of=" + obo)); + "username=" + un + ",on_behalf_of=" + obo)); // first thing is to figure out what we're being asked to work on SwordUrlManager urlManager = config.getUrlManager(context, config); Item item = urlManager.getItem(context, stateIRI); - if (item == null) - { + if (item == null) { throw new SwordError(404); } @@ -81,49 +75,39 @@ public class StatementManagerDSpace extends DSpaceSwordAPI // find out, now we know what we're being asked for, whether this is allowed WorkflowManagerFactory.getInstance() - .retrieveStatement(context, item); + .retrieveStatement(context, item); String suffix = urlManager.getTypeSuffix(context, stateIRI); SwordStatementDisseminator disseminator = null; - if (suffix != null) - { + if (suffix != null) { Map> analysed = new HashMap<>(); List list = new ArrayList<>(); list.add(suffix); analysed.put((float) 1.0, list); disseminator = SwordDisseminatorFactory - .getStatementInstance(analysed); - } - else - { + .getStatementInstance(analysed); + } else { // we rely on the content negotiation to do the work String acceptContentType = this - .getHeader(accept, "Accept", null); + .getHeader(accept, "Accept", null); // we extract from the Accept header the ordered list of content types TreeMap> analysed = this - .analyseAccept(acceptContentType); + .analyseAccept(acceptContentType); // the meat of this is done by the package disseminator disseminator = SwordDisseminatorFactory - .getStatementInstance(analysed); + .getStatementInstance(analysed); } return disseminator.disseminate(context, item); - } - catch (AuthorizeException e) - { + } catch (AuthorizeException e) { throw new SwordAuthException(); - } - catch (SQLException | DSpaceSwordException e) - { + } catch (SQLException | DSpaceSwordException e) { throw new SwordServerException(e); - } - finally - { - if (sc != null) - { + } finally { + if (sc != null) { sc.abort(); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordAuthenticator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordAuthenticator.java index 6de0b09b4a..9f82ee33e3 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordAuthenticator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordAuthenticator.java @@ -7,22 +7,32 @@ */ package org.dspace.sword2; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.dspace.authenticate.AuthenticationMethod; import org.dspace.authenticate.factory.AuthenticateServiceFactory; import org.dspace.authenticate.service.AuthenticationService; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.Bundle; +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.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.LogManager; -import org.dspace.core.Constants; -import org.dspace.authenticate.AuthenticationMethod; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import org.dspace.content.*; -import org.apache.log4j.Logger; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.services.ConfigurationService; @@ -32,25 +42,19 @@ import org.swordapp.server.SwordAuthException; import org.swordapp.server.SwordError; import org.swordapp.server.UriRegistry; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; -import java.util.ArrayList; -import org.apache.commons.lang.StringUtils; - /** * This class offers a thin wrapper for the default DSpace * authentication module for the SWORD implementation * * @author Richard Jones - * */ -public class SwordAuthenticator -{ - /** logger */ +public class SwordAuthenticator { + /** + * logger + */ private static Logger log = Logger.getLogger(SwordAuthenticator.class); - protected AuthenticationService authenticationService = + protected AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance().getAuthenticationService(); protected AuthorizeService authorizeService = @@ -67,7 +71,7 @@ public class SwordAuthenticator protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); - + protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); @@ -75,16 +79,12 @@ public class SwordAuthenticator * Does the given username and password authenticate for the * given DSpace Context? * - * @param context - * The relevant DSpace Context. - * @param un - * username - * @param pw - * password + * @param context The relevant DSpace Context. + * @param un username + * @param pw password * @return true if authenticates successfully, false if not */ - public boolean authenticates(Context context, String un, String pw) - { + public boolean authenticates(Context context, String un, String pw) { int auth = authenticationService.authenticate( context, un, pw, null, null); return auth == AuthenticationMethod.SUCCESS; @@ -95,12 +95,10 @@ public class SwordAuthenticator * using the passed IP address as part of the loggable * information * - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ private Context constructContext() - throws DSpaceSwordException - { + throws DSpaceSwordException { Context context = new Context(); // Set the session ID and IP address context.setExtraLogInfo("session_id=0"); @@ -113,29 +111,20 @@ public class SwordAuthenticator * information from the request and forwards to the appropriate authentication * method * - * @param auth - * authentication credentials + * @param auth authentication credentials * @return SWORD context - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * SWORD error per SWORD spec - * @throws SwordAuthException - * thrown if unable to authenticate + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError SWORD error per SWORD spec + * @throws SwordAuthException thrown if unable to authenticate */ public SwordContext authenticate(AuthCredentials auth) - throws DSpaceSwordException, SwordError, SwordAuthException - { + throws DSpaceSwordException, SwordError, SwordAuthException { Context context = this.constructContext(); SwordContext sc; - try - { + try { sc = this.authenticate(context, auth); - } - catch (DSpaceSwordException | SwordError | RuntimeException | SwordAuthException e) - { - if (context != null && context.isValid()) - { + } catch (DSpaceSwordException | SwordError | RuntimeException | SwordAuthException e) { + if (context != null && context.isValid()) { context.abort(); } throw e; @@ -149,71 +138,59 @@ public class SwordAuthenticator * must successfully authenticate the user, and the onBehalfOf user * must exist in the user database. * - * @param context - * The relevant DSpace Context. - * @param auth - * authentication credentials + * @param context The relevant DSpace Context. + * @param auth authentication credentials * @return a SWORD context holding the various user information - * @throws SwordAuthException - * thrown if unable to authenticate - * @throws SwordError - * SWORD error per SWORD spec - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordAuthException thrown if unable to authenticate + * @throws SwordError SWORD error per SWORD spec + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ private SwordContext authenticate(Context context, AuthCredentials auth) - throws SwordAuthException, SwordError, DSpaceSwordException - { + throws SwordAuthException, SwordError, DSpaceSwordException { String obo = auth.getOnBehalfOf(); String un = auth.getUsername(); String pw = auth.getPassword(); // smooth out the OnBehalfOf request, so that empty strings are // treated as null - if (StringUtils.isBlank(obo)) - { + if (StringUtils.isBlank(obo)) { obo = null; } // first find out if we support on-behalf-of deposit boolean mediated = configurationService - .getBooleanProperty("swordv2-server.on-behalf-of.enable", false); - if (!mediated && obo != null) - { + .getBooleanProperty("swordv2-server.on-behalf-of.enable", false); + if (!mediated && obo != null) { // user is trying to do a mediated deposit on a repository which does not support it log.error( "Attempted mediated deposit on service not configured to do so"); throw new SwordError(UriRegistry.ERROR_MEDIATION_NOT_ALLOWED, - "Mediated deposit to this service is not permitted"); + "Mediated deposit to this service is not permitted"); } log.info(LogManager.getHeader(context, "sword_authenticate", - "username=" + un + ",on_behalf_of=" + obo)); + "username=" + un + ",on_behalf_of=" + obo)); - try - { + try { // attempt to authenticate the primary user SwordContext sc = new SwordContext(); EPerson ep = null; boolean authenticated = false; - if (this.authenticates(context, un, pw)) - { + if (this.authenticates(context, un, pw)) { // if authenticated, obtain the eperson object ep = context.getCurrentUser(); - if (ep != null) - { + if (ep != null) { authenticated = true; sc.setAuthenticated(ep); // Set any special groups - invoke the authentication mgr. List specialGroups = authenticationService .getSpecialGroups(context, null); - for (Group specialGroup : specialGroups) - { + for (Group specialGroup : specialGroups) { context.setSpecialGroup(specialGroup.getID()); log.debug("Adding Special Group id=" + - specialGroup.getID()); + specialGroup.getID()); } sc.setAuthenticatorContext(context); @@ -224,16 +201,13 @@ public class SwordAuthenticator // record, and if it exists set it. If not, then the // authentication process fails EPerson epObo = null; - if (obo != null) - { + if (obo != null) { epObo = ePersonService.findByEmail(context, obo); - if (epObo == null) - { + if (epObo == null) { epObo = ePersonService.findByNetid(context, obo); } - if (epObo != null) - { + if (epObo != null) { sc.setOnBehalfOf(epObo); Context oboContext = this.constructContext(); oboContext.setCurrentUser(epObo); @@ -241,16 +215,13 @@ public class SwordAuthenticator List specialGroups = authenticationService .getSpecialGroups(oboContext, null); - for (Group specialGroup : specialGroups) - { + for (Group specialGroup : specialGroups) { oboContext.setSpecialGroup(specialGroup.getID()); log.debug("Adding Special Group id=" + - specialGroup.getID()); + specialGroup.getID()); } sc.setContext(oboContext); - } - else - { + } else { authenticated = false; throw new SwordError( UriRegistry.ERROR_TARGET_OWNER_UNKNOWN, @@ -259,32 +230,26 @@ public class SwordAuthenticator } } - if (!authenticated) - { + if (!authenticated) { // decide what kind of error to throw - if (ep != null) - { + if (ep != null) { log.info(LogManager.getHeader(context, - "sword_unable_to_set_user", "username=" + un)); + "sword_unable_to_set_user", "username=" + un)); throw new SwordAuthException( "Unable to authenticate with the supplied credentials"); - } - else - { + } else { // FIXME: this shouldn't ever happen now, but may as well leave it in just in case // there's a bug elsewhere log.info(LogManager.getHeader(context, - "sword_unable_to_set_on_behalf_of", - "username=" + un + ",on_behalf_of=" + obo)); + "sword_unable_to_set_on_behalf_of", + "username=" + un + ",on_behalf_of=" + obo)); throw new SwordAuthException( "Unable to authenticate the onBehalfOf account"); } } return sc; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("caught exception: ", e); throw new DSpaceSwordException( "There was a problem accessing the repository user database", @@ -299,29 +264,22 @@ public class SwordAuthenticator * See javadocs for individual canSubmitTo methods to see the conditions * which are applied in each situation * - * @param swordContext - * The relevant SWORD Context. - * @param dso DSpace object - * @param msg message to append result to + * @param swordContext The relevant SWORD Context. + * @param dso DSpace object + * @param msg message to append result to * @return true if can submit, false if not - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * never. + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError never. */ public boolean canSubmit(SwordContext swordContext, DSpaceObject dso, - VerboseDescription msg) - throws DSpaceSwordException, SwordError - { + VerboseDescription msg) + throws DSpaceSwordException, SwordError { // determine if we can submit boolean submit = this.canSubmitTo(swordContext, dso); - if (submit) - { + if (submit) { msg.append("User is authorised to submit to collection"); - } - else - { + } else { msg.append("User is not authorised to submit to collection"); } @@ -333,27 +291,20 @@ public class SwordAuthenticator * as asking the question of whether the given eperson is a member * of the special DSpace group Administrator, with id 1 * - * @param swordContext - * The relevant SWORD Context. + * @param swordContext The relevant SWORD Context. * @return true if administrator, false if not - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isUserAdmin(SwordContext swordContext) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { EPerson authenticated = swordContext.getAuthenticated(); - if (authenticated != null) - { + if (authenticated != null) { return authorizeService.isAdmin( swordContext.getAuthenticatorContext()); } return false; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSwordException(e); } @@ -364,27 +315,20 @@ public class SwordAuthenticator * as asking the question of whether the given eperson is a member * of the special DSpace group Administrator, with id 1 * - * @param swordContext - * The relevant SWORD Context. + * @param swordContext The relevant SWORD Context. * @return true if administrator, false if not - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isOnBehalfOfAdmin(SwordContext swordContext) - throws DSpaceSwordException - { + throws DSpaceSwordException { EPerson onBehalfOf = swordContext.getOnBehalfOf(); - try - { - if (onBehalfOf != null) - { + try { + if (onBehalfOf != null) { return authorizeService.isAdmin( swordContext.getOnBehalfOfContext()); } return false; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSwordException(e); } @@ -394,17 +338,14 @@ public class SwordAuthenticator * Is the authenticated user a member of the given group * or one of its sub groups? * - * @param swordContext - * The relevant SWORD Context. - * @param group group to search recursively + * @param swordContext The relevant SWORD Context. + * @param group group to search recursively * @return true if the authenticated user is a member of the given group - * or one of its sub groups + * or one of its sub groups */ - public boolean isUserInGroup(SwordContext swordContext, Group group) - { + public boolean isUserInGroup(SwordContext swordContext, Group group) { EPerson authenticated = swordContext.getAuthenticated(); - if (authenticated != null) - { + if (authenticated != null) { return isInGroup(group, authenticated); } return false; @@ -414,17 +355,14 @@ public class SwordAuthenticator * Is the onBehalfOf user a member of the given group or * one of its sub groups? * - * @param swordContext - * The relevant SWORD Context. - * @param group group to search recursively + * @param swordContext The relevant SWORD Context. + * @param group group to search recursively * @return true if onBehalfOf user is a member of the given group or - * one of its sub groups + * one of its sub groups */ - public boolean isOnBehalfOfInGroup(SwordContext swordContext, Group group) - { + public boolean isOnBehalfOfInGroup(SwordContext swordContext, Group group) { EPerson onBehalfOf = swordContext.getOnBehalfOf(); - if (onBehalfOf != null) - { + if (onBehalfOf != null) { return isInGroup(group, onBehalfOf); } return false; @@ -436,31 +374,25 @@ public class SwordAuthenticator * until it has exhausted the tree of groups or finds the given * eperson * - * @param group group to search recursively + * @param group group to search recursively * @param eperson EPerson to find * @return true if in group, false if not */ - public boolean isInGroup(Group group, EPerson eperson) - { + public boolean isInGroup(Group group, EPerson eperson) { List eps = group.getMembers(); List groups = group.getMemberGroups(); // is the user in the current group - for (EPerson ep : eps) - { - if (eperson.getID().equals(ep.getID())) - { + for (EPerson ep : eps) { + if (eperson.getID().equals(ep.getID())) { return true; } } // is the eperson in the sub-groups (recurse) - if (groups != null && !groups.isEmpty()) - { - for (Group group1 : groups) - { - if (isInGroup(group1, eperson)) - { + if (groups != null && !groups.isEmpty()) { + for (Group group1 : groups) { + if (isInGroup(group1, eperson)) { return true; } } @@ -478,25 +410,22 @@ public class SwordAuthenticator * are met: * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to READ - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to READ + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to READ - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to READ - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to READ + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. + * @param swordContext The relevant SWORD Context. * @return the array of allowed collections - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public List getAllowedCommunities(SwordContext swordContext) - throws DSpaceSwordException - { + throws DSpaceSwordException { // a community is allowed if the following conditions are met // // - the authenticated user is an administrator @@ -507,27 +436,24 @@ public class SwordAuthenticator // -- the on-behalf-of user is an administrator // -- the on-behalf-of user is authorised to READ // -- the on-behalf-of user is null - try - { + try { // locate all the top level communities Context context = swordContext.getContext(); List allowed = new ArrayList(); List comms = communityService.findAllTop(context); - for (Community comm : comms) - { + for (Community comm : comms) { boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } - // look up the READ policy on the community. This will include determining if the user is an administrator + // look up the READ policy on the community. This will include determining if the user is an + // administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { authAllowed = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), comm, Constants.READ); @@ -535,23 +461,19 @@ public class SwordAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { oboAllowed = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), comm, Constants.READ); } // final check to see if we are allowed to READ - if (authAllowed && oboAllowed) - { + if (authAllowed && oboAllowed) { allowed.add(comm); } } return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSwordException(e); } @@ -565,28 +487,24 @@ public class SwordAuthenticator * are met: * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to READ - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to READ + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to READ - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to READ - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to READ + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param community - * parent community to check recursively + * @param swordContext The relevant SWORD Context. + * @param community parent community to check recursively * @return the array of allowed collections - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public List getCommunities(SwordContext swordContext, - Community community) - throws DSpaceSwordException - { + Community community) + throws DSpaceSwordException { // a community is allowed if the following conditions are met // // - the authenticated user is an administrator @@ -597,26 +515,23 @@ public class SwordAuthenticator // -- the on-behalf-of user is an administrator // -- the on-behalf-of user is authorised to READ // -- the on-behalf-of user is null - try - { + try { List comms = community.getSubcommunities(); List allowed = new ArrayList<>(); - for (Community comm : comms) - { + for (Community comm : comms) { boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } - // look up the READ policy on the community. This will include determining if the user is an administrator + // look up the READ policy on the community. This will include determining if the user is an + // administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { authAllowed = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), comm, Constants.READ); @@ -624,24 +539,20 @@ public class SwordAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { oboAllowed = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), comm, Constants.READ); } // final check to see if we are allowed to READ - if (authAllowed && oboAllowed) - { + if (authAllowed && oboAllowed) { allowed.add(comm); } } return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSwordException(e); } @@ -657,16 +568,13 @@ public class SwordAuthenticator * * See that method for details of the conditions applied * - * @param swordContext - * The relevant SWORD Context. + * @param swordContext The relevant SWORD Context. * @return the array of allowed collections - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public List getAllowedCollections( - SwordContext swordContext) - throws DSpaceSwordException - { + SwordContext swordContext) + throws DSpaceSwordException { return this.getAllowedCollections(swordContext, null); } @@ -675,28 +583,24 @@ public class SwordAuthenticator * context will allow deposit onto in the given DSpace context * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to ADD - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to ADD + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to ADD - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to ADD - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to ADD + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param community - * community to check + * @param swordContext The relevant SWORD Context. + * @param community community to check * @return the array of allowed collections - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public List getAllowedCollections( - SwordContext swordContext, Community community) - throws DSpaceSwordException - { + SwordContext swordContext, Community community) + throws DSpaceSwordException { // a collection is allowed if the following conditions are met // // - the authenticated user is an administrator @@ -708,8 +612,7 @@ public class SwordAuthenticator // -- the on-behalf-of user is authorised to ADD // -- the on-behalf-of user is null - try - { + try { // get the context of the authenticated user Context authContext = swordContext.getAuthenticatorContext(); @@ -719,36 +622,30 @@ public class SwordAuthenticator List allowed = new ArrayList<>(); // now find out if the obo user is allowed to submit to any of these collections - for (Collection col : cols) - { + for (Collection col : cols) { boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { oboAllowed = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), col, Constants.ADD); } // final check to see if we are allowed to READ - if (oboAllowed) - { + if (oboAllowed) { allowed.add(col); } } return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSwordException(e); } @@ -759,28 +656,24 @@ public class SwordAuthenticator * context will allow deposit onto in the given DSpace context * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param collection - * collection to check + * @param swordContext The relevant SWORD Context. + * @param collection collection to check * @return the array of allowed collections - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public List getAllowedItems(SwordContext swordContext, - org.dspace.content.Collection collection) - throws DSpaceSwordException - { + org.dspace.content.Collection collection) + throws DSpaceSwordException { // an item is allowed if the following conditions are met // // - the authenticated user is an administrator @@ -792,57 +685,45 @@ public class SwordAuthenticator // -- the on-behalf-of user is authorised to WRITE on the item and ADD on the ORIGINAL bundle // -- the on-behalf-of user is null - try - { + try { List allowed = new ArrayList<>(); Iterator ii = itemService .findByCollection(swordContext.getContext(), collection); - while (ii.hasNext()) - { + while (ii.hasNext()) { Item item = ii.next(); boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } // get the "ORIGINAL" bundle(s) - List bundles = item.getBundles(); + List bundles = item.getBundles(Constants.CONTENT_BUNDLE_NAME); - // look up the READ policy on the community. This will include determining if the user is an administrator + // look up the READ policy on the community. This will include determining if the user is an + // administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { boolean write = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), item, Constants.WRITE); boolean add = false; - if (bundles.isEmpty()) - { + if (bundles.isEmpty()) { add = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), item, Constants.ADD); - } - else - { - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME - .equals(bundle.getName())) - { - add = authorizeService.authorizeActionBoolean( - swordContext.getAuthenticatorContext(), - bundle, Constants.ADD); - if (!add) - { - break; - } + } else { + for (Bundle bundle : bundles) { + add = authorizeService.authorizeActionBoolean( + swordContext.getAuthenticatorContext(), + bundle, Constants.ADD); + if (!add) { + break; } } } @@ -852,31 +733,24 @@ public class SwordAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { boolean write = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), item, Constants.WRITE); boolean add = false; - if (bundles.isEmpty()) - { + if (bundles.isEmpty()) { add = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), item, Constants.ADD); - } - else - { - for (Bundle bundle : bundles) - { + } else { + for (Bundle bundle : bundles) { if (Constants.CONTENT_BUNDLE_NAME - .equals(bundle.getName())) - { + .equals(bundle.getName())) { add = authorizeService.authorizeActionBoolean( - swordContext.getAuthenticatorContext(), - bundle, Constants.ADD); - if (!add) - { + swordContext.getAuthenticatorContext(), + bundle, Constants.ADD); + if (!add) { break; } } @@ -887,16 +761,13 @@ public class SwordAuthenticator } // final check to see if we are allowed to READ - if (authAllowed && oboAllowed) - { + if (authAllowed && oboAllowed) { allowed.add(item); } } return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } @@ -906,28 +777,24 @@ public class SwordAuthenticator * collection in the given DSpace Context? * * IF: the authenticated user is an administrator - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to ADD - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to ADD + * OR the on-behalf-of user is null) * OR IF: the authenticated user is authorised to ADD - * AND: - * (the on-behalf-of user is an administrator - * OR the on-behalf-of user is authorised to ADD - * OR the on-behalf-of user is null) + * AND: + * (the on-behalf-of user is an administrator + * OR the on-behalf-of user is authorised to ADD + * OR the on-behalf-of user is null) * - * @param swordContext - * The relevant SWORD Context. - * @param collection - * collection to check + * @param swordContext The relevant SWORD Context. + * @param collection collection to check * @return true if context can deposit into collection - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public boolean canSubmitTo(SwordContext swordContext, - org.dspace.content.Collection collection) - throws DSpaceSwordException - { + org.dspace.content.Collection collection) + throws DSpaceSwordException { // a user can submit to a collection in the following conditions: // // - the authenticated user is an administrator @@ -939,21 +806,18 @@ public class SwordAuthenticator // -- the on-behalf-of user is authorised to ADD/in the submission group // -- the on-behalf-of user is null - try - { + try { boolean authAllowed = false; boolean oboAllowed = false; // check for obo null - if (swordContext.getOnBehalfOf() == null) - { + if (swordContext.getOnBehalfOf() == null) { oboAllowed = true; } // look up the READ policy on the collection. This will include determining if the user is an administrator // so we do not need to check that separately - if (!authAllowed) - { + if (!authAllowed) { authAllowed = authorizeService.authorizeActionBoolean( swordContext.getAuthenticatorContext(), collection, Constants.ADD); @@ -961,8 +825,7 @@ public class SwordAuthenticator // if we have not already determined that the obo user is ok to submit, look up the READ policy on the // community. THis will include determining if the user is an administrator. - if (!oboAllowed) - { + if (!oboAllowed) { oboAllowed = authorizeService.authorizeActionBoolean( swordContext.getOnBehalfOfContext(), collection, Constants.ADD); @@ -971,17 +834,14 @@ public class SwordAuthenticator // final check to see if we are allowed to READ return (authAllowed && oboAllowed); - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSwordException(e); } } public boolean canSubmitTo(SwordContext swordContext, Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { // a context can submit to an item if the following are satisfied // // 1/ the primary authenticating user is authenticated (which is implicit @@ -992,22 +852,17 @@ public class SwordAuthenticator // 3/ If not an On-Behalf-Of request, the authenticating user is authorised // to carry out the action - try - { + try { boolean isObo = swordContext.getOnBehalfOf() != null; Context allowContext = null; - if (isObo) - { + if (isObo) { // we need to find out if the authenticated user is permitted to mediate if (!this.allowedToMediate( - swordContext.getAuthenticatorContext())) - { + swordContext.getAuthenticatorContext())) { return false; } allowContext = swordContext.getOnBehalfOfContext(); - } - else - { + } else { allowContext = swordContext.getAuthenticatorContext(); } @@ -1016,68 +871,52 @@ public class SwordAuthenticator boolean write = authorizeService .authorizeActionBoolean(allowContext, item, Constants.WRITE); - List bundles = item.getBundles(); + List bundles = item.getBundles(Constants.CONTENT_BUNDLE_NAME); boolean add = false; - if (bundles.isEmpty()) - { + if (bundles.isEmpty()) { add = authorizeService.authorizeActionBoolean( allowContext, item, Constants.ADD); - } - else - { - for (Bundle bundle : bundles) - { - if (Constants.CONTENT_BUNDLE_NAME.equals(bundle.getName())) - { - add = authorizeService.authorizeActionBoolean( - allowContext, bundle, Constants.ADD); - if (!add) - { - break; - } + } else { + for (Bundle bundle : bundles) { + add = authorizeService.authorizeActionBoolean( + allowContext, bundle, Constants.ADD); + if (!add) { + break; } } } boolean allowed = write && add; return allowed; - } - catch (SQLException e) - { + } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSwordException(e); } } - private boolean allowedToMediate(Context context) - { + private boolean allowedToMediate(Context context) { // get the configuration String[] mediators = configurationService .getArrayProperty("swordv2-server.on-behalf-of.update.mediators"); - if (mediators == null || mediators.length==0) - { + if (mediators == null || mediators.length == 0) { // if there's no explicit list of mediators, then anyone can mediate return true; } // get the email and netid of the mediator EPerson eperson = context.getCurrentUser(); - if (eperson == null) - { + if (eperson == null) { return false; } String email = eperson.getEmail(); String netid = eperson.getNetid(); - for (String mediator : mediators) - { + for (String mediator : mediators) { String m = mediator.trim(); - if (email != null && m.equals(email.trim())) - { + if (email != null && m.equals(email.trim())) { return true; } - if (netid != null && m.equals(netid.trim())) - { + if (netid != null && m.equals(netid.trim())) { return true; } } @@ -1091,22 +930,17 @@ public class SwordAuthenticator * This forwards to the individual methods for different object types; * see their documentation for details of the conditions. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object + * @param context The relevant DSpace Context. + * @param dso DSpace object * @return true if context can submit to dso - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public boolean canSubmitTo(SwordContext context, DSpaceObject dso) - throws DSpaceSwordException - { - if (dso instanceof Collection) - { + throws DSpaceSwordException { + if (dso instanceof Collection) { return this.canSubmitTo(context, (Collection) dso); - } - else + } else { return dso instanceof Item && this.canSubmitTo(context, (Item) dso); + } } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordConfigurationDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordConfigurationDSpace.java index 1182ffdc04..c4f2d03c74 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordConfigurationDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordConfigurationDSpace.java @@ -7,6 +7,12 @@ */ package org.dspace.sword2; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.content.BitstreamFormat; import org.dspace.content.Collection; @@ -15,68 +21,77 @@ import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamFormatService; import org.dspace.core.Context; +import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; import org.swordapp.server.SwordConfiguration; import org.swordapp.server.SwordError; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.ArrayUtils; -import org.dspace.services.ConfigurationService; -import org.dspace.services.factory.DSpaceServicesFactory; - -public class SwordConfigurationDSpace implements SwordConfiguration -{ - /** logger */ +public class SwordConfigurationDSpace implements SwordConfiguration { + /** + * logger + */ public static final Logger log = Logger .getLogger(SwordConfigurationDSpace.class); protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory .getInstance().getBitstreamFormatService(); - + protected ConfigurationService configurationService = DSpaceServicesFactory .getInstance().getConfigurationService(); - /** whether we can be verbose */ + /** + * whether we can be verbose + */ private boolean verbose = true; - /** what our default max upload size is */ + /** + * what our default max upload size is + */ private int maxUploadSize = -1; - /** do we support mediation */ + /** + * do we support mediation + */ private boolean mediated = false; - /** should we keep the original package as bitstream */ + /** + * should we keep the original package as bitstream + */ private boolean keepOriginal = false; - /** item bundle in which sword deposits are stored */ + /** + * item bundle in which sword deposits are stored + */ private String swordBundle = "SWORD"; - /** should we keep the original package as a file on ingest error */ + /** + * should we keep the original package as a file on ingest error + */ private boolean keepPackageOnFailedIngest = false; - /** location of directory to store packages on ingest error */ + /** + * location of directory to store packages on ingest error + */ private String failedPackageDir = null; private boolean allowCommunityDeposit = false; private boolean entryFirst = false; - /** Accepted formats */ + /** + * Accepted formats + */ private List swordaccepts; /** * Initialise the sword configuration. It is at this stage that the * object will interrogate the DSpace Configuration for details */ - public SwordConfigurationDSpace() - { + public SwordConfigurationDSpace() { // set the max upload size int mus = configurationService .getIntProperty("swordv2-server.max-upload-size"); - if (mus > 0) - { + if (mus > 0) { this.maxUploadSize = mus; } @@ -91,8 +106,7 @@ public class SwordConfigurationDSpace implements SwordConfiguration // get the sword bundle String bundle = configurationService .getProperty("swordv2-server.bundle.name"); - if (StringUtils.isBlank(bundle)) - { + if (StringUtils.isBlank(bundle)) { this.swordBundle = bundle; } @@ -108,12 +122,10 @@ public class SwordConfigurationDSpace implements SwordConfiguration String[] acceptsFormats = configurationService .getArrayProperty("swordv2-server.accepts"); swordaccepts = new ArrayList(); - if (ArrayUtils.isEmpty(acceptsFormats)) - { - acceptsFormats = new String[]{"application/zip"}; + if (ArrayUtils.isEmpty(acceptsFormats)) { + acceptsFormats = new String[] {"application/zip"}; } - for (String element : acceptsFormats) - { + for (String element : acceptsFormats) { swordaccepts.add(element.trim()); } @@ -132,38 +144,29 @@ public class SwordConfigurationDSpace implements SwordConfiguration /////////////////////////////////////////////////////////////////////////////////// public String getStringProperty(String propName, - String defaultValue, String[] allowedValues) - { - String cfg = configurationService.getProperty(propName); - if (StringUtils.isBlank(cfg)) - { + String defaultValue, String[] allowedValues) { + String cfg = configurationService.getProperty(propName); + if (StringUtils.isBlank(cfg)) { return defaultValue; } boolean allowed = false; - if (allowedValues != null) - { - for (String value : allowedValues) - { - if (cfg.equals(value)) - { + if (allowedValues != null) { + for (String value : allowedValues) { + if (cfg.equals(value)) { allowed = true; } } - } - else - { + } else { allowed = true; } - if (allowed) - { + if (allowed) { return cfg; } return defaultValue; } public String getStringProperty(String propName, - String defaultValue) - { + String defaultValue) { return this.getStringProperty(propName, defaultValue, null); } @@ -171,62 +174,51 @@ public class SwordConfigurationDSpace implements SwordConfiguration // Required by the SwordConfiguration interface ////////////////////////////////////////////////////////////////////////////////// - public boolean returnDepositReceipt() - { + public boolean returnDepositReceipt() { return true; } - public boolean returnStackTraceInError() - { + public boolean returnStackTraceInError() { return configurationService.getBooleanProperty("swordv2-server.verbose-description.error.enable"); } - public boolean returnErrorBody() - { + public boolean returnErrorBody() { return true; } - public String generator() - { + public String generator() { return this.getStringProperty("swordv2-server.generator.url", - DSpaceUriRegistry.DSPACE_SWORD_NS); + DSpaceUriRegistry.DSPACE_SWORD_NS); } - public String generatorVersion() - { + public String generatorVersion() { return this.getStringProperty("swordv2-server.generator.version", - "2.0"); + "2.0"); } - public String administratorEmail() - { + public String administratorEmail() { return this.getStringProperty("mail.admin", null); } - public String getAuthType() - { + public String getAuthType() { return this.getStringProperty("swordv2-server.auth-type", "Basic", - new String[] { "Basic", "None" }); + new String[] {"Basic", "None"}); } - public boolean storeAndCheckBinary() - { + public boolean storeAndCheckBinary() { return true; } - public String getTempDirectory() - { + public String getTempDirectory() { return this.getStringProperty("swordv2-server.upload.tempdir", null); } - public String getAlternateUrl() - { + public String getAlternateUrl() { return configurationService .getProperty("swordv2-server.error.alternate.url"); } - public String getAlternateUrlContentType() - { + public String getAlternateUrlContentType() { return configurationService .getProperty("swordv2-server.error.alternate.content-type"); } @@ -236,48 +228,39 @@ public class SwordConfigurationDSpace implements SwordConfiguration /////////////////////////////////////////////////////////////////////////////////// public SwordUrlManager getUrlManager(Context context, - SwordConfigurationDSpace config) - { + SwordConfigurationDSpace config) { return new SwordUrlManager(config, context); } public List getDisseminatePackaging() - throws DSpaceSwordException, SwordError - { + throws DSpaceSwordException, SwordError { List dps = new ArrayList(); List packagingFormats = configurationService.getPropertyKeys("swordv2-server.disseminate-packaging"); - for (String key : packagingFormats) - { + for (String key : packagingFormats) { String value = configurationService.getProperty(key); // now we want to ensure that the packaging format we offer has a disseminator // associated with it boolean disseminable = true; - try - { + try { SwordContentDisseminator disseminator = SwordDisseminatorFactory - .getContentInstance(null, value); - } - catch (SwordError e) - { + .getContentInstance(null, value); + } catch (SwordError e) { disseminable = false; } - if (disseminable) - { + if (disseminable) { dps.add(value); } } return dps; } - public boolean isEntryFirst() - { + public boolean isEntryFirst() { return this.entryFirst; } - public boolean allowCommunityDeposit() - { + public boolean allowCommunityDeposit() { return this.allowCommunityDeposit; } @@ -287,8 +270,7 @@ public class SwordConfigurationDSpace implements SwordConfiguration * * @return SWORD bundle name */ - public String getSwordBundle() - { + public String getSwordBundle() { return swordBundle; } @@ -298,8 +280,7 @@ public class SwordConfigurationDSpace implements SwordConfiguration * * @param swordBundle SWORD bundle name */ - public void setSwordBundle(String swordBundle) - { + public void setSwordBundle(String swordBundle) { this.swordBundle = swordBundle; } @@ -308,19 +289,16 @@ public class SwordConfigurationDSpace implements SwordConfiguration * * @return true if this is verbose deposit */ - public boolean isVerbose() - { + public boolean isVerbose() { return verbose; } /** * Set whether this is a verbose deposit. * - * @param verbose - * verbose deposit + * @param verbose verbose deposit */ - public void setVerbose(boolean verbose) - { + public void setVerbose(boolean verbose) { this.verbose = verbose; } @@ -329,19 +307,16 @@ public class SwordConfigurationDSpace implements SwordConfiguration * * @return max upload size */ - public int getMaxUploadSize() - { + public int getMaxUploadSize() { return maxUploadSize; } /** * Set the max upload size (in bytes) for the SWORD interface. * - * @param maxUploadSize - * max upload size to set + * @param maxUploadSize max upload size to set */ - public void setMaxUploadSize(int maxUploadSize) - { + public void setMaxUploadSize(int maxUploadSize) { this.maxUploadSize = maxUploadSize; } @@ -350,19 +325,16 @@ public class SwordConfigurationDSpace implements SwordConfiguration * * @return true if server supports mediated deposit */ - public boolean isMediated() - { + public boolean isMediated() { return mediated; } /** * Set whether the server supports mediated deposit (aka on-behalf-of). * - * @param mediated - * mediated deposit state to set + * @param mediated mediated deposit state to set */ - public void setMediated(boolean mediated) - { + public void setMediated(boolean mediated) { this.mediated = mediated; } @@ -371,30 +343,25 @@ public class SwordConfigurationDSpace implements SwordConfiguration * * @return true if should keep original package */ - public boolean isKeepOriginal() - { + public boolean isKeepOriginal() { return keepOriginal; } /** * set whether the repository should keep copies of the original package * - * @param keepOriginal - * should keep original package? + * @param keepOriginal should keep original package? */ - public void setKeepOriginal(boolean keepOriginal) - { + public void setKeepOriginal(boolean keepOriginal) { this.keepOriginal = keepOriginal; } /** * set whether the repository should write file of the original package if ingest fails * - * @param keepOriginalOnFail - * should keep original package if ingest fails? + * @param keepOriginalOnFail should keep original package if ingest fails? */ - public void setKeepPackageOnFailedIngest(boolean keepOriginalOnFail) - { + public void setKeepPackageOnFailedIngest(boolean keepOriginalOnFail) { keepPackageOnFailedIngest = keepOriginalOnFail; } @@ -403,19 +370,16 @@ public class SwordConfigurationDSpace implements SwordConfiguration * * @return whether the repository should keep original package if ingest fails */ - public boolean isKeepPackageOnFailedIngest() - { + public boolean isKeepPackageOnFailedIngest() { return keepPackageOnFailedIngest; } /** * set the directory to write file of the original package * - * @param dir - * directory where to store the original package + * @param dir directory where to store the original package */ - public void setFailedPackageDir(String dir) - { + public void setFailedPackageDir(String dir) { failedPackageDir = dir; } @@ -425,8 +389,7 @@ public class SwordConfigurationDSpace implements SwordConfiguration * * @return directory where to store the original package */ - public String getFailedPackageDir() - { + public String getFailedPackageDir() { return failedPackageDir; } @@ -434,51 +397,37 @@ public class SwordConfigurationDSpace implements SwordConfiguration * Get the list of MIME types that the given DSpace object will * accept as packages. * - * @param context - * The relevant DSpace Context. - * @param dso - * DSpace object to check + * @param context The relevant DSpace Context. + * @param dso DSpace object to check * @return list of MIME types that the given DSpace object will * accept as packages. - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public List getAccepts(Context context, DSpaceObject dso) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { List accepts = new ArrayList(); - if (dso instanceof Collection) - { - for (String format : swordaccepts) - { + if (dso instanceof Collection) { + for (String format : swordaccepts) { accepts.add(format); } - } - else if (dso instanceof Item) - { + } else if (dso instanceof Item) { // items will take any of the bitstream formats registered, plus // any swordaccepts mimetypes List bfs = bitstreamFormatService - .findNonInternal(context); - for (BitstreamFormat bf : bfs) - { + .findNonInternal(context); + for (BitstreamFormat bf : bfs) { accepts.add(bf.getMIMEType()); } - for (String format : swordaccepts) - { - if (!accepts.contains(format)) - { + for (String format : swordaccepts) { + if (!accepts.contains(format)) { accepts.add(format); } } } return accepts; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } @@ -487,14 +436,11 @@ public class SwordConfigurationDSpace implements SwordConfiguration * Get the list of mime types that a Collection will accept as packages * * @return the list of mime types - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ - public List getCollectionAccepts() throws DSpaceSwordException - { + public List getCollectionAccepts() throws DSpaceSwordException { List accepts = new ArrayList(); - for (String format : swordaccepts) - { + for (String format : swordaccepts) { accepts.add(format); } return accepts; @@ -512,13 +458,11 @@ public class SwordConfigurationDSpace implements SwordConfiguration * and the Q value is a floating point between 0 and 1 which defines * how much the server "likes" this packaging type. * - * @param col - * target collection + * @param col target collection * @return map of packaging URIs to Q values for the packaging types which * the given collection will accept. */ - public List getAcceptPackaging(Collection col) - { + public List getAcceptPackaging(Collection col) { // accept-packaging.METSDSpaceSIP = http://purl.org/net/sword-types/METSDSpaceSIP // accept-packaging.[handle].METSDSpaceSIP = http://purl.org/net/sword-types/METSDSpaceSIP String handle = col.getHandle(); @@ -527,30 +471,26 @@ public class SwordConfigurationDSpace implements SwordConfiguration // build the holding maps of identifiers String acceptPackagingPrefix = "swordv2-server.accept-packaging.collection"; List acceptFormats = configurationService.getPropertyKeys(acceptPackagingPrefix); - for (String key : acceptFormats) - { + for (String key : acceptFormats) { // extract the configuration into the holding Maps // the suffix will be [typeid] or [handle].[typeid] - String suffix = key.substring(acceptPackagingPrefix.length()+1); + String suffix = key.substring(acceptPackagingPrefix.length() + 1); // is there a handle which represents this collection? boolean withHandle = false; - if (suffix.startsWith(handle)) - { + if (suffix.startsWith(handle)) { withHandle = true; } // is there NO handle boolean general = false; - if (suffix.indexOf(".") == -1) - { + if (suffix.indexOf(".") == -1) { // a handle would be separated from the identifier of the package type general = true; } - if (withHandle || general) - { + if (withHandle || general) { String value = configurationService.getProperty(key); aps.add(value); } @@ -559,15 +499,13 @@ public class SwordConfigurationDSpace implements SwordConfiguration return aps; } - public List getItemAcceptPackaging() - { + public List getItemAcceptPackaging() { List aps = new ArrayList(); // build the holding maps of identifiers String acceptPackagingPrefix = "swordv2-server.accept-packaging.item"; List acceptFormats = configurationService.getPropertyKeys(acceptPackagingPrefix); - for (String key : acceptFormats) - { + for (String key : acceptFormats) { // extract the configuration into the holding Maps String value = configurationService.getProperty(key); aps.add(value); @@ -580,42 +518,29 @@ public class SwordConfigurationDSpace implements SwordConfiguration * Is the given packaging/media type supported by the given DSpace * object? * - * @param packageFormat - * packaging/media type to check - * @param dso - * DSpace object to check + * @param packageFormat packaging/media type to check + * @param dso DSpace object to check * @return true if supported - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * SWORD error per SWORD spec + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError SWORD error per SWORD spec */ public boolean isAcceptedPackaging(String packageFormat, DSpaceObject dso) - throws DSpaceSwordException, SwordError - { - if (packageFormat == null || "".equals(packageFormat)) - { + throws DSpaceSwordException, SwordError { + if (packageFormat == null || "".equals(packageFormat)) { return true; } - if (dso instanceof Collection) - { + if (dso instanceof Collection) { List accepts = this.getAcceptPackaging((Collection) dso); - for (String accept : accepts) - { - if (accept.equals(packageFormat)) - { + for (String accept : accepts) { + if (accept.equals(packageFormat)) { return true; } } - } - else if (dso instanceof Item) - { + } else if (dso instanceof Item) { List accepts = this.getItemAcceptPackaging(); - for (String accept : accepts) - { - if (accept.equals(packageFormat)) - { + for (String accept : accepts) { + if (accept.equals(packageFormat)) { return true; } } @@ -627,36 +552,27 @@ public class SwordConfigurationDSpace implements SwordConfiguration /** * Is the given content MIME type acceptable to the given DSpace object. * - * @param context - * The relevant DSpace Context. - * @param type - * MIME type to check - * @param dso - * DSpace object to compare to + * @param context The relevant DSpace Context. + * @param type MIME type to check + * @param dso DSpace object to compare to * @return true if acceptable - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * can be thrown by the internals of the DSpace SWORD implementation */ public boolean isAcceptableContentType(Context context, String type, - DSpaceObject dso) - throws DSpaceSwordException - { + DSpaceObject dso) + throws DSpaceSwordException { List accepts = this.getAccepts(context, dso); - for (String acc : accepts) - { - if (this.contentTypeMatches(type, acc)) - { + for (String acc : accepts) { + if (this.contentTypeMatches(type, acc)) { return true; } } return accepts.contains(type); } - private boolean contentTypeMatches(String type, String pattern) - { - if ("*/*".equals(pattern.trim())) - { + private boolean contentTypeMatches(String type, String pattern) { + if ("*/*".equals(pattern.trim())) { return true; } @@ -673,33 +589,28 @@ public class SwordConfigurationDSpace implements SwordConfiguration boolean prefixMatch = false; boolean suffixMatch = false; - if ("*".equals(prefixPattern) || prefixPattern.equals(typePrefix)) - { + if ("*".equals(prefixPattern) || prefixPattern.equals(typePrefix)) { prefixMatch = true; } - if ("*".equals(suffixPattern) || suffixPattern.equals(typeSuffix)) - { + if ("*".equals(suffixPattern) || suffixPattern.equals(typeSuffix)) { suffixMatch = true; } return prefixMatch && suffixMatch; } - public String getStateUri(String state) - { + public String getStateUri(String state) { return configurationService .getProperty("swordv2-server.state." + state + ".uri"); } - public String getStateDescription(String state) - { + public String getStateDescription(String state) { return configurationService .getProperty("swordv2-server.state." + state + ".description"); } - public boolean allowUnauthenticatedMediaAccess() - { + public boolean allowUnauthenticatedMediaAccess() { return false; } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContentDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContentDisseminator.java index 4dc1879658..a87913ad38 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContentDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContentDisseminator.java @@ -7,23 +7,22 @@ */ package org.dspace.sword2; +import java.io.InputStream; + import org.dspace.content.Item; import org.dspace.core.Context; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -import java.io.InputStream; - -public interface SwordContentDisseminator -{ +public interface SwordContentDisseminator { public InputStream disseminate(Context context, Item item) - throws DSpaceSwordException, SwordError, SwordServerException; + throws DSpaceSwordException, SwordError, SwordServerException; public boolean disseminatesContentType(String contentType) - throws DSpaceSwordException, SwordError, SwordServerException; + throws DSpaceSwordException, SwordError, SwordServerException; public boolean disseminatesPackage(String contentType) - throws DSpaceSwordException, SwordError, SwordServerException; + throws DSpaceSwordException, SwordError, SwordServerException; public void setContentType(String contentType); diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContentIngester.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContentIngester.java index 463b370a8d..1771ad0af4 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContentIngester.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContentIngester.java @@ -20,39 +20,29 @@ import org.swordapp.server.SwordServerException; * be obtained via the SwordIngesterFactory class. * * @author Richard Jones - * */ -public interface SwordContentIngester -{ +public interface SwordContentIngester { /** * Ingest the package as described in the given Deposit object * within the given DSpace Context * - * @param context - * The relevant DSpace Context. - * @param deposit - * the original deposit request - * @param target - * target DSpace object - * @param verboseDescription - * The description. + * @param context The relevant DSpace Context. + * @param deposit the original deposit request + * @param target target DSpace object + * @param verboseDescription The description. * @return the result of the deposit - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * SWORD error per SWORD spec - * @throws SwordAuthException - * thrown if unable to authenticate - * @throws SwordServerException - * thrown by SWORD server implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError SWORD error per SWORD spec + * @throws SwordAuthException thrown if unable to authenticate + * @throws SwordServerException thrown by SWORD server implementation */ DepositResult ingest(Context context, Deposit deposit, DSpaceObject target, - VerboseDescription verboseDescription) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException; + VerboseDescription verboseDescription) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException; DepositResult ingest(Context context, Deposit deposit, DSpaceObject target, - VerboseDescription verboseDescription, DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException; + VerboseDescription verboseDescription, DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContext.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContext.java index 80baf6b2e0..e5b63f6a02 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContext.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordContext.java @@ -33,51 +33,53 @@ import org.dspace.eperson.EPerson; * class * * @author Richard Jones - * */ -public class SwordContext -{ - /** The primary authenticated user for the request */ +public class SwordContext { + /** + * The primary authenticated user for the request + */ private EPerson authenticated = null; - /** The onBehalfOf user for the request */ + /** + * The onBehalfOf user for the request + */ private EPerson onBehalfOf = null; - /** The primary context, representing the on behalf of user if exists, and the authenticated user if not */ + /** + * The primary context, representing the on behalf of user if exists, and the authenticated user if not + */ private Context context; - /** the context for the authenticated user, which may not, therefore, be the primary context also */ + /** + * the context for the authenticated user, which may not, therefore, be the primary context also + */ private Context authenticatorContext; /** * @return the authenticated user */ - public EPerson getAuthenticated() - { + public EPerson getAuthenticated() { return authenticated; } /** - * @param authenticated the eperson to set + * @param authenticated the eperson to set */ - public void setAuthenticated(EPerson authenticated) - { + public void setAuthenticated(EPerson authenticated) { this.authenticated = authenticated; } /** * @return the onBehalfOf user */ - public EPerson getOnBehalfOf() - { + public EPerson getOnBehalfOf() { return onBehalfOf; } /** - * @param onBehalfOf the eperson to set + * @param onBehalfOf the eperson to set */ - public void setOnBehalfOf(EPerson onBehalfOf) - { + public void setOnBehalfOf(EPerson onBehalfOf) { this.onBehalfOf = onBehalfOf; } @@ -88,13 +90,11 @@ public class SwordContext * * @return appropriate DSpace context */ - public Context getContext() - { + public Context getContext() { return context; } - public void setContext(Context context) - { + public void setContext(Context context) { this.context = context; } @@ -109,13 +109,11 @@ public class SwordContext * * @return DSpace context of the user who authenticated */ - public Context getAuthenticatorContext() - { + public Context getAuthenticatorContext() { return authenticatorContext; } - public void setAuthenticatorContext(Context authenticatorContext) - { + public void setAuthenticatorContext(Context authenticatorContext) { this.authenticatorContext = authenticatorContext; } @@ -130,11 +128,9 @@ public class SwordContext * * @return DSpace context of the on-behalf-of user */ - public Context getOnBehalfOfContext() - { + public Context getOnBehalfOfContext() { // return the obo context if this is an obo deposit, else return null - if (this.onBehalfOf != null) - { + if (this.onBehalfOf != null) { return context; } return null; @@ -144,16 +140,13 @@ public class SwordContext * Abort all of the contexts held by this class. No changes will * be written to the database */ - public void abort() - { + public void abort() { // abort both contexts - if (context != null && context.isValid()) - { + if (context != null && context.isValid()) { context.abort(); } - if (authenticatorContext != null && authenticatorContext.isValid()) - { + if (authenticatorContext != null && authenticatorContext.isValid()) { authenticatorContext.abort(); } } @@ -165,29 +158,22 @@ public class SwordContext * operations are flushed. You should, in general, not try to commit the contexts directly * when using the sword api. * - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public void commit() - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { // commit the primary context - if (context != null && context.isValid()) - { + if (context != null && context.isValid()) { context.complete(); } // the secondary context is for filtering permissions by only, and is // never committed, so we abort here - if (authenticatorContext != null && authenticatorContext.isValid()) - { + if (authenticatorContext != null && authenticatorContext.isValid()) { authenticatorContext.abort(); } - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordDisseminatorFactory.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordDisseminatorFactory.java index 2deaf53aa7..fc32993a68 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordDisseminatorFactory.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordDisseminatorFactory.java @@ -7,54 +7,50 @@ */ package org.dspace.sword2; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.dspace.core.factory.CoreServiceFactory; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; import org.swordapp.server.UriRegistry; -import java.util.List; -import java.util.Map; -import org.apache.commons.lang.StringUtils; -import org.dspace.core.factory.CoreServiceFactory; +public class SwordDisseminatorFactory { + + /** + * Default constructor + */ + private SwordDisseminatorFactory() { } -public class SwordDisseminatorFactory -{ public static SwordContentDisseminator getContentInstance( - Map> accept, String acceptPackaging) - throws DSpaceSwordException, SwordError - { - try - { + Map> accept, String acceptPackaging) + throws DSpaceSwordException, SwordError { + try { SwordContentDisseminator disseminator = null; // first try to load disseminators based on content type - if (accept != null) - { - for (Float q : accept.keySet()) - { - for (String format : accept.get(q)) - { + if (accept != null) { + for (Float q : accept.keySet()) { + for (String format : accept.get(q)) { format = format.replace(";", - "_"); // clean up the string for the plugin manager + "_"); // clean up the string for the plugin manager format = format.replace("=", - "_"); // clean up the string for the plugin manager + "_"); // clean up the string for the plugin manager disseminator = (SwordContentDisseminator) CoreServiceFactory.getInstance().getPluginService() - .getNamedPlugin(SwordContentDisseminator.class, format); - if (disseminator == null) - { + .getNamedPlugin( + SwordContentDisseminator.class, + format); + if (disseminator == null) { continue; - } - else - { + } else { // if we find a disseminator which says it does this format, then find out if it // will do the packaging if (!disseminator - .disseminatesPackage(acceptPackaging)) - { + .disseminatesPackage(acceptPackaging)) { disseminator = null; continue; - } - else - { + } else { disseminator.setContentType(format); break; } @@ -64,41 +60,32 @@ public class SwordDisseminatorFactory } // if we have not yet found a disseminator, try looking it up by packaging type - if (disseminator == null) - { - if (acceptPackaging != null) - { + if (disseminator == null) { + if (acceptPackaging != null) { acceptPackaging = acceptPackaging.replace(";", - "_"); // clean up the string for the plugin manager + "_"); // clean up the string for the plugin manager acceptPackaging = acceptPackaging.replace("=", - "_"); // clean up the string for the plugin manager + "_"); // clean up the string for the plugin manager disseminator = (SwordContentDisseminator) CoreServiceFactory.getInstance().getPluginService() - .getNamedPlugin(SwordContentDisseminator.class, - acceptPackaging); - if (disseminator != null) - { - if (accept != null) - { + .getNamedPlugin( + SwordContentDisseminator.class, + acceptPackaging); + if (disseminator != null) { + if (accept != null) { // Find first accept format that this disseminator works with String disseminateFormat = null; - for (Float q : accept.keySet()) - { - for (String format : accept.get(q)) - { - if (disseminator.disseminatesContentType(format)) - { + for (Float q : accept.keySet()) { + for (String format : accept.get(q)) { + if (disseminator.disseminatesContentType(format)) { disseminateFormat = format; break; } } } - if (StringUtils.isNotEmpty(disseminateFormat)) - { + if (StringUtils.isNotEmpty(disseminateFormat)) { disseminator.setContentType(disseminateFormat); - } - else - { + } else { // No matching disseminator found disseminator = null; } @@ -107,66 +94,59 @@ public class SwordDisseminatorFactory } } - if (disseminator == null) - { + if (disseminator == null) { throw new SwordError(UriRegistry.ERROR_CONTENT, 406, - "No plugin can disseminate the requested formats"); + "No plugin can disseminate the requested formats"); } disseminator.setPackaging(acceptPackaging); return disseminator; - } - catch (SwordServerException e) - { + } catch (SwordServerException e) { throw new DSpaceSwordException(e); } } public static SwordStatementDisseminator getStatementInstance( - Map> accept) - throws DSpaceSwordException, SwordError - { + Map> accept) + throws DSpaceSwordException, SwordError { SwordStatementDisseminator disseminator = null; // first try to load disseminators based on content type - if (accept != null) - { - for (Float q : accept.keySet()) - { - for (String format : accept.get(q)) - { + if (accept != null) { + for (Float q : accept.keySet()) { + for (String format : accept.get(q)) { format = format.replace(";", - "_"); // clean up the string for the plugin manager + "_"); // clean up the string for the plugin manager format = format.replace("=", - "_"); // clean up the string for the plugin manager + "_"); // clean up the string for the plugin manager disseminator = (SwordStatementDisseminator) CoreServiceFactory.getInstance().getPluginService() - .getNamedPlugin(SwordStatementDisseminator.class, format); - if (disseminator != null) - { + .getNamedPlugin( + SwordStatementDisseminator.class, + format); + if (disseminator != null) { break; } } } } - if (disseminator == null) - { + if (disseminator == null) { throw new SwordError(UriRegistry.ERROR_CONTENT, 406, - "No plugin can disseminate the requested formats"); + "No plugin can disseminate the requested formats"); } return disseminator; } public static SwordEntryDisseminator getEntryInstance() - throws DSpaceSwordException, SwordError - { - SwordEntryDisseminator disseminator = (SwordEntryDisseminator) CoreServiceFactory.getInstance().getPluginService() - .getSinglePlugin(SwordEntryDisseminator.class); - if (disseminator == null) - { + throws DSpaceSwordException, SwordError { + SwordEntryDisseminator disseminator = + (SwordEntryDisseminator) CoreServiceFactory.getInstance() + .getPluginService() + .getSinglePlugin(SwordEntryDisseminator.class); + if (disseminator == null) { throw new SwordError(DSpaceUriRegistry.REPOSITORY_ERROR, - "No disseminator configured for handling sword entry documents"); + "No disseminator configured for handling sword entry documents"); } return disseminator; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordEntryDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordEntryDisseminator.java index 6da370665d..f489f0d0f0 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordEntryDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordEntryDisseminator.java @@ -13,9 +13,8 @@ import org.swordapp.server.DepositReceipt; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -public interface SwordEntryDisseminator -{ +public interface SwordEntryDisseminator { public DepositReceipt disseminate(Context context, Item item, - DepositReceipt receipt) - throws DSpaceSwordException, SwordError, SwordServerException; + DepositReceipt receipt) + throws DSpaceSwordException, SwordError, SwordServerException; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordEntryIngester.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordEntryIngester.java index 9b89f429b4..4c63ad01d0 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordEntryIngester.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordEntryIngester.java @@ -14,16 +14,15 @@ import org.swordapp.server.SwordAuthException; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -public interface SwordEntryIngester -{ +public interface SwordEntryIngester { DepositResult ingest(Context context, Deposit deposit, DSpaceObject target, - VerboseDescription verboseDescription) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException; + VerboseDescription verboseDescription) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException; DepositResult ingest(Context context, Deposit deposit, DSpaceObject target, - VerboseDescription verboseDescription, DepositResult result, - boolean replace) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException; + VerboseDescription verboseDescription, DepositResult result, + boolean replace) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordIngesterFactory.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordIngesterFactory.java index 2731b2456a..3035693588 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordIngesterFactory.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordIngesterFactory.java @@ -7,8 +7,8 @@ */ package org.dspace.sword2; -import org.dspace.core.Context; import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.core.service.PluginService; import org.swordapp.server.Deposit; @@ -20,10 +20,14 @@ import org.swordapp.server.UriRegistry; * SWORDIngester interface. * * @author Richard Jones - * */ -public class SwordIngesterFactory -{ +public class SwordIngesterFactory { + + /** + * Default constructor + */ + private SwordIngesterFactory() { } + /** * Generate an object which conforms to the SWORDIngester interface. * This Factory method may use the given DSpace context and the given @@ -34,22 +38,16 @@ public class SwordIngesterFactory * for the appropriate media types and defaults. See the SWORD configuration * documentation for more details. * - * @param context - * The relevant DSpace Context. - * @param deposit - * The original deposit request - * @param dso - * target DSpace object + * @param context The relevant DSpace Context. + * @param deposit The original deposit request + * @param dso target DSpace object * @return SWORDIngester object - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * if no suitable ingester is configured. + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError if no suitable ingester is configured. */ public static SwordContentIngester getContentInstance(Context context, - Deposit deposit, DSpaceObject dso) - throws DSpaceSwordException, SwordError - { + Deposit deposit, DSpaceObject dso) + throws DSpaceSwordException, SwordError { SwordContentIngester ingester = null; PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); @@ -57,33 +55,29 @@ public class SwordIngesterFactory // first look to see if there's an intester for the content type ingester = (SwordContentIngester) pluginService .getNamedPlugin(SwordContentIngester.class, deposit.getMimeType()); - if (ingester != null) - { + if (ingester != null) { return ingester; } - // if no ingester, then + // if no ingester, then // look to see if there's an ingester for the package format ingester = (SwordContentIngester) pluginService .getNamedPlugin(SwordContentIngester.class, deposit.getPackaging()); - if (ingester == null) - { + if (ingester == null) { throw new SwordError(UriRegistry.ERROR_CONTENT, - "No ingester configured for this package type"); + "No ingester configured for this package type"); } return ingester; } public static SwordEntryIngester getEntryInstance(Context context, - Deposit deposit, DSpaceObject dso) - throws DSpaceSwordException, SwordError - { + Deposit deposit, DSpaceObject dso) + throws DSpaceSwordException, SwordError { SwordEntryIngester ingester = (SwordEntryIngester) CoreServiceFactory.getInstance().getPluginService() - .getSinglePlugin(SwordEntryIngester.class); - if (ingester == null) - { + .getSinglePlugin(SwordEntryIngester.class); + if (ingester == null) { throw new SwordError(UriRegistry.ERROR_CONTENT, - "No ingester configured for handling SWORD entry documents"); + "No ingester configured for handling SWORD entry documents"); } return ingester; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordMETSContentIngester.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordMETSContentIngester.java index a918babb6f..fc9fb8e232 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordMETSContentIngester.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordMETSContentIngester.java @@ -10,7 +10,6 @@ package org.dspace.sword2; import java.io.File; import org.apache.log4j.Logger; - import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; @@ -24,7 +23,6 @@ import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; - import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; import org.swordapp.server.Deposit; @@ -32,9 +30,10 @@ import org.swordapp.server.SwordAuthException; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -public class SwordMETSContentIngester extends AbstractSwordContentIngester -{ - /** Log4j logger */ +public class SwordMETSContentIngester extends AbstractSwordContentIngester { + /** + * Log4j logger + */ public static final Logger log = Logger.getLogger( SwordMETSContentIngester.class); @@ -45,29 +44,25 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester ContentServiceFactory.getInstance().getCollectionService(); protected HandleService handleService = - HandleServiceFactory.getInstance() .getHandleService(); + HandleServiceFactory.getInstance().getHandleService(); public DepositResult ingest(Context context, Deposit deposit, - DSpaceObject dso, VerboseDescription verboseDescription) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { + DSpaceObject dso, VerboseDescription verboseDescription) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { return this.ingest(context, deposit, dso, verboseDescription, null); } @Override public DepositResult ingestToCollection(Context context, Deposit deposit, - Collection collection, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - try - { + Collection collection, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + try { // if we are actuall given an item in the deposit result of a previous operation // then we do an ingestToItem - if (result != null) - { + if (result != null) { Item item = result.getItem(); return this.ingestToItem( context, deposit, item, verboseDescription, result); @@ -86,10 +81,9 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester // need to add a licence file, otherwise the METS replace function raises a NullPointerException String licence = collectionService.getLicense(collection); - if (PackageUtils.findDepositLicense(context, item) == null) - { + if (PackageUtils.findDepositLicense(context, item) == null) { PackageUtils.addDepositLicense( - context, licence, item, collection); + context, licence, item, collection); } // get deposited file as InputStream @@ -97,17 +91,16 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester // load the plugin manager for the required configuration String cfg = ConfigurationManager.getProperty("swordv2-server", - "mets-ingester.package-ingester"); - if (cfg == null || "".equals(cfg)) - { + "mets-ingester.package-ingester"); + if (cfg == null || "".equals(cfg)) { cfg = "METS"; // default to METS } verboseDescription.append("Using package manifest format: " + cfg); PackageIngester pi = (PackageIngester) CoreServiceFactory.getInstance().getPluginService() - .getNamedPlugin(PackageIngester.class, cfg); + .getNamedPlugin(PackageIngester.class, cfg); verboseDescription.append("Loaded package ingester: " + - pi.getClass().getName()); + pi.getClass().getName()); // Initialize parameters to packager PackageParameters params = new PackageParameters(); @@ -117,35 +110,30 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester // Should restore mode be enabled, i.e. keep existing handle? if (ConfigurationManager.getBooleanProperty( - "swordv2-server", "restore-mode.enable", false)) - { + "swordv2-server", "restore-mode.enable", false)) { params.setRestoreModeEnabled(true); } // Whether or not to use the collection template params.setUseCollectionTemplate(ConfigurationManager - .getBooleanProperty( - "mets.default.ingest.useCollectionTemplate", false)); + .getBooleanProperty( + "mets.default.ingest.useCollectionTemplate", false)); // ingest the item from the temp file DSpaceObject ingestedObject = pi.replace( context, item, depositFile, params); - if (ingestedObject == null) - { + if (ingestedObject == null) { verboseDescription.append( "Failed to ingest the package; throwing exception"); throw new SwordError(DSpaceUriRegistry.UNPACKAGE_FAIL, - "METS package ingester failed to unpack package"); + "METS package ingester failed to unpack package"); } // Verify we have an Item as a result - if (!(ingestedObject instanceof Item)) - { + if (!(ingestedObject instanceof Item)) { throw new DSpaceSwordException( "DSpace Ingester returned wrong object type -- not an Item result."); - } - else - { + } else { //otherwise, we have an item, and a workflow should have already been started for it. verboseDescription.append("Workflow process started"); } @@ -160,7 +148,7 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester // DSpace ignores the slug value as suggested identifier, but // it does store it in the metadata this.setSlug(context, installedItem, deposit.getSlug(), - verboseDescription); + verboseDescription); // in order to write these changes, we need to bypass the // authorisation briefly, because although the user may be @@ -177,14 +165,11 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester verboseDescription.append("Ingest successful"); verboseDescription.append( "Item created with internal identifier: " + - installedItem.getID()); - if (handle != null) - { + installedItem.getID()); + if (handle != null) { verboseDescription.append( "Item created with external identifier: " + handle); - } - else - { + } else { verboseDescription.append( "No external identifier available at this stage (item in workflow)"); } @@ -194,14 +179,10 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester dr.setTreatment(this.getTreatment()); return dr; - } - catch (RuntimeException re) - { + } catch (RuntimeException re) { log.error("caught exception: ", re); throw re; - } - catch (Exception e) - { + } catch (Exception e) { log.error("caught exception: ", e); throw new DSpaceSwordException(e); } @@ -209,34 +190,30 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester @Override public DepositResult ingestToItem(Context context, Deposit deposit, - Item item, VerboseDescription verboseDescription, - DepositResult result) - throws DSpaceSwordException, SwordError, SwordAuthException, - SwordServerException - { - if (result == null) - { + Item item, VerboseDescription verboseDescription, + DepositResult result) + throws DSpaceSwordException, SwordError, SwordAuthException, + SwordServerException { + if (result == null) { result = new DepositResult(); } - try - { + try { // get deposited file as InputStream File depositFile = deposit.getFile(); // load the plugin manager for the required configuration String cfg = ConfigurationManager.getProperty( "swordv2-server", "mets-ingester.package-ingester"); - if (cfg == null || "".equals(cfg)) - { + if (cfg == null || "".equals(cfg)) { cfg = "METS"; // default to METS } verboseDescription.append("Using package manifest format: " + cfg); PackageIngester pi = (PackageIngester) CoreServiceFactory.getInstance().getPluginService() - .getNamedPlugin(PackageIngester.class, cfg); + .getNamedPlugin(PackageIngester.class, cfg); verboseDescription.append("Loaded package ingester: " + - pi.getClass().getName()); + pi.getClass().getName()); // Initialize parameters to packager PackageParameters params = new PackageParameters(); @@ -246,30 +223,27 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester // Should restore mode be enabled, i.e. keep existing handle? if (ConfigurationManager.getBooleanProperty( - "swordv2-server", "restore-mode.enable", false)) - { + "swordv2-server", "restore-mode.enable", false)) { params.setRestoreModeEnabled(true); } // Whether or not to use the collection template params.setUseCollectionTemplate(ConfigurationManager - .getBooleanProperty( - "mets.default.ingest.useCollectionTemplate", false)); + .getBooleanProperty( + "mets.default.ingest.useCollectionTemplate", false)); // ingest the item from the temp file DSpaceObject ingestedObject = pi.replace( context, item, depositFile, params); - if (ingestedObject == null) - { + if (ingestedObject == null) { verboseDescription.append( - "Failed to replace the package; throwing exception"); + "Failed to replace the package; throwing exception"); throw new SwordError(DSpaceUriRegistry.UNPACKAGE_FAIL, - "METS package ingester failed to unpack package"); + "METS package ingester failed to unpack package"); } // Verify we have an Item as a result - if (!(ingestedObject instanceof Item)) - { + if (!(ingestedObject instanceof Item)) { throw new DSpaceSwordException( "DSpace Ingester returned wrong object type -- not an Item result."); } @@ -297,14 +271,10 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester result.setTreatment(this.getTreatment()); return result; - } - catch (RuntimeException re) - { + } catch (RuntimeException re) { log.error("caught exception: ", re); throw re; - } - catch (Exception e) - { + } catch (Exception e) { log.error("caught exception: ", e); throw new DSpaceSwordException(e); } @@ -315,11 +285,9 @@ public class SwordMETSContentIngester extends AbstractSwordContentIngester * put the deposit through * * @return human readable description - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ - private String getTreatment() throws DSpaceSwordException - { + private String getTreatment() throws DSpaceSwordException { return "The package has been deposited into DSpace. Each file has been unpacked " + "and provided with a unique identifier. The metadata in the manifest has been " + "extracted and attached to the DSpace item, which has been provided with " + diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordMETSPackageIngester.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordMETSPackageIngester.java index 3dd844cf41..a9178e05ef 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordMETSPackageIngester.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordMETSPackageIngester.java @@ -7,6 +7,9 @@ */ package org.dspace.sword2; +import java.io.IOException; +import java.sql.SQLException; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.Item; @@ -16,11 +19,7 @@ import org.dspace.content.packager.PackageUtils; import org.dspace.content.packager.PackageValidationException; import org.dspace.core.Context; -import java.io.IOException; -import java.sql.SQLException; - -public class SwordMETSPackageIngester extends DSpaceMETSIngester -{ +public class SwordMETSPackageIngester extends DSpaceMETSIngester { /** * Policy: For DSpace deposit license, take deposit license * supplied by explicit argument first, else use collection's @@ -30,17 +29,14 @@ public class SwordMETSPackageIngester extends DSpaceMETSIngester * This override basically fixes a bug in the DSpaceMETSIngester which * allows (in fact enforces) a null licence during replace, but which * then requires it to be not-null here. - * */ @Override public void addLicense(Context context, Item item, String license, - Collection collection, PackageParameters params) - throws PackageValidationException, - AuthorizeException, SQLException, IOException - { + Collection collection, PackageParameters params) + throws PackageValidationException, + AuthorizeException, SQLException, IOException { if (PackageUtils.findDepositLicense(context, item) == null && - license != null) - { + license != null) { PackageUtils.addDepositLicense(context, license, item, collection); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordStatementDisseminator.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordStatementDisseminator.java index acbf24a8c2..e7e9ed29e4 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordStatementDisseminator.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordStatementDisseminator.java @@ -13,8 +13,7 @@ import org.swordapp.server.Statement; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; -public interface SwordStatementDisseminator -{ +public interface SwordStatementDisseminator { public Statement disseminate(Context context, Item item) - throws DSpaceSwordException, SwordError, SwordServerException; + throws DSpaceSwordException, SwordError, SwordServerException; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordUrlManager.java b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordUrlManager.java index b3ceebdb50..6fee60c386 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/SwordUrlManager.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/SwordUrlManager.java @@ -7,31 +7,34 @@ */ package org.dspace.sword2; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.SQLException; +import java.util.List; + import org.apache.abdera.i18n.iri.IRI; -import org.dspace.content.*; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +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.BitstreamService; import org.dspace.content.service.ItemService; -import org.dspace.handle.HandleServiceImpl; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; import org.swordapp.server.SwordError; -import java.sql.SQLException; -import java.net.URL; -import java.net.MalformedURLException; -import java.util.List; - /** * @author Richard Jones * * Class responsible for constructing and de-constructing SWORD URL space * URLs */ -public class SwordUrlManager -{ +public class SwordUrlManager { protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); @@ -41,14 +44,17 @@ public class SwordUrlManager protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); - /** the SWORD configuration */ + /** + * the SWORD configuration + */ private SwordConfigurationDSpace config; - /** the active DSpace context */ + /** + * the active DSpace context + */ private Context context; - public SwordUrlManager(SwordConfigurationDSpace config, Context context) - { + public SwordUrlManager(SwordConfigurationDSpace config, Context context) { this.config = config; this.context = context; } @@ -58,15 +64,12 @@ public class SwordUrlManager * should not be considered persistent, but will remain consistent * unless configuration changes are made to DSpace * - * @param collection - * target collection + * @param collection target collection * @return The Deposit URL - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public String getDepositLocation(Collection collection) - throws DSpaceSwordException - { + throws DSpaceSwordException { return this.getBaseCollectionUrl() + "/" + collection.getHandle(); } @@ -75,117 +78,90 @@ public class SwordUrlManager * should not be considered persistent, but will remain consistent * unless configuration changes are made to DSpace * - * @param community - * target community + * @param community target community * @return The Deposit URL - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public String getDepositLocation(Community community) - throws DSpaceSwordException - { - if (this.config.allowCommunityDeposit()) - { + throws DSpaceSwordException { + if (this.config.allowCommunityDeposit()) { return this.getBaseCollectionUrl() + "/" + community.getHandle(); } return null; } public String getSwordBaseUrl() - throws DSpaceSwordException - { + throws DSpaceSwordException { String sUrl = ConfigurationManager.getProperty("swordv2-server", "url"); - if (sUrl == null || "".equals(sUrl)) - { + if (sUrl == null || "".equals(sUrl)) { String dspaceUrl = ConfigurationManager .getProperty("dspace.baseUrl"); - if (dspaceUrl == null || "".equals(dspaceUrl)) - { + if (dspaceUrl == null || "".equals(dspaceUrl)) { throw new DSpaceSwordException( "Unable to construct service document urls, due to missing/invalid " + - "config in sword2.url and/or dspace.baseUrl"); + "config in sword2.url and/or dspace.baseUrl"); } - try - { + try { URL url = new URL(dspaceUrl); sUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), - "/swordv2").toString(); - } - catch (MalformedURLException e) - { + "/swordv2").toString(); + } catch (MalformedURLException e) { throw new DSpaceSwordException( "Unable to construct service document urls, due to invalid dspace.baseUrl " + - e.getMessage(), e); + e.getMessage(), e); } } return sUrl; } public Item getItem(Context context, String location) - throws DSpaceSwordException, SwordError - { - try - { + throws DSpaceSwordException, SwordError { + try { String baseUrl = this.getSwordBaseUrl(); String emBaseUrl = baseUrl + "/edit-media/"; String eBaseUrl = baseUrl + "/edit/"; String sBaseUrl = baseUrl + "/statement/"; String cBaseUrl = null; - if (location.startsWith(emBaseUrl)) - { + if (location.startsWith(emBaseUrl)) { cBaseUrl = emBaseUrl; - } - else if (location.startsWith(eBaseUrl)) - { + } else if (location.startsWith(eBaseUrl)) { cBaseUrl = eBaseUrl; - } - else if (location.startsWith(sBaseUrl)) - { + } else if (location.startsWith(sBaseUrl)) { cBaseUrl = sBaseUrl; - } - else - { + } else { throw new SwordError(DSpaceUriRegistry.BAD_URL, - "The item URL is invalid"); + "The item URL is invalid"); } String iid = location.substring(cBaseUrl.length()); - if (iid.endsWith(".atom")) - { + if (iid.endsWith(".atom")) { // this is the atom url, so we need to strip that to ge tthe item id iid = iid.substring(0, iid.length() - ".atom".length()); - } - else if (iid.endsWith(".rdf")) - { + } else if (iid.endsWith(".rdf")) { // this is the rdf url so we need to strip that to get the item id iid = iid.substring(0, iid.length() - ".rdf".length()); } Item item = itemService.findByIdOrLegacyId(context, iid); return item; - } - catch (SQLException e) - { + } catch (SQLException e) { // log.error("Caught exception:", e); throw new DSpaceSwordException( "There was a problem resolving the item", e); } } - public String getTypeSuffix(Context context, String location) - { + public String getTypeSuffix(Context context, String location) { String tail = location.substring(location.lastIndexOf("/")); int typeSeparator = tail.lastIndexOf("."); - if (typeSeparator == -1) - { + if (typeSeparator == -1) { return null; } return tail.substring(typeSeparator + 1); } - public boolean isFeedRequest(Context context, String url) - { + public boolean isFeedRequest(Context context, String url) { return url.endsWith(".atom"); } @@ -193,54 +169,43 @@ public class SwordUrlManager * Obtain the collection which is represented by the given * URL * - * @param context the DSpace context - * @param location the URL to resolve to a collection + * @param context the DSpace context + * @param location the URL to resolve to a collection * @return The collection to which the url resolves - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * if a proper URL cannot be calculated. + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError if a proper URL cannot be calculated. */ // FIXME: we need to generalise this to DSpaceObjects, so that we can support // Communities, Collections and Items separately public Collection getCollection(Context context, String location) - throws DSpaceSwordException, SwordError - { - try - { + throws DSpaceSwordException, SwordError { + try { String baseUrl = this.getBaseCollectionUrl(); - if (baseUrl.length() == location.length()) - { + if (baseUrl.length() == location.length()) { throw new SwordError(DSpaceUriRegistry.BAD_URL, - "The deposit URL is incomplete"); + "The deposit URL is incomplete"); } String handle = location.substring(baseUrl.length()); - if (handle.startsWith("/")) - { + if (handle.startsWith("/")) { handle = handle.substring(1); } - if ("".equals(handle)) - { + if ("".equals(handle)) { throw new SwordError(DSpaceUriRegistry.BAD_URL, - "The deposit URL is incomplete"); + "The deposit URL is incomplete"); } DSpaceObject dso = handleService.resolveToObject(context, handle); - if (dso == null) - { + if (dso == null) { return null; } - if (!(dso instanceof Collection)) - { + if (!(dso instanceof Collection)) { throw new SwordError(DSpaceUriRegistry.BAD_URL, - "The deposit URL does not resolve to a valid collection"); + "The deposit URL does not resolve to a valid collection"); } return (Collection) dso; - } - catch (SQLException e) - { + } catch (SQLException e) { // log.error("Caught exception:", e); throw new DSpaceSwordException( "There was a problem resolving the collection", e); @@ -252,15 +217,12 @@ public class SwordUrlManager * be supplied in the sword:service element of other service document * entries. * - * @param community - * target community + * @param community target community * @return service document URL - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public String constructSubServiceUrl(Community community) - throws DSpaceSwordException - { + throws DSpaceSwordException { String base = this.getBaseServiceDocumentUrl(); String handle = community.getHandle(); return base + "/" + handle; @@ -271,15 +233,12 @@ public class SwordUrlManager * be supplied in the sword:service element of other service document * entries. * - * @param collection - * target collection + * @param collection target collection * @return service document URL - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public String constructSubServiceUrl(Collection collection) - throws DSpaceSwordException - { + throws DSpaceSwordException { String base = this.getBaseServiceDocumentUrl(); String handle = collection.getHandle(); return base + "/" + handle; @@ -290,61 +249,44 @@ public class SwordUrlManager * locate a meaningful and appropriate DSpace object it will throw the * appropriate SWORD error. * - * @param url - * URL to get DSpace object from + * @param url URL to get DSpace object from * @return DSpace object from URL - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation - * @throws SwordError - * SWORD error per SWORD spec + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation + * @throws SwordError SWORD error per SWORD spec */ public DSpaceObject extractDSpaceObject(String url) - throws DSpaceSwordException, SwordError - { - try - { + throws DSpaceSwordException, SwordError { + try { String sdBase = this.getBaseServiceDocumentUrl(); // String mlBase = this.getBaseMediaLinkUrl(); - if (url.startsWith(sdBase)) - { + if (url.startsWith(sdBase)) { // we are dealing with a service document request // first, let's find the beginning of the handle url = url.substring(sdBase.length()); - if (url.startsWith("/")) - { + if (url.startsWith("/")) { url = url.substring(1); } - if (url.endsWith("/")) - { + if (url.endsWith("/")) { url = url.substring(0, url.length() - 1); } DSpaceObject dso = handleService.resolveToObject(context, url); - if (dso == null) - { + if (dso == null) { return null; - } - else if (dso instanceof Collection || dso instanceof Community) - { + } else if (dso instanceof Collection || dso instanceof Community) { return dso; - } - else - { + } else { throw new SwordError(DSpaceUriRegistry.BAD_URL, - "Service Document request does not refer to a DSpace Collection or Community"); + "Service Document request does not refer to a DSpace Collection or Community"); } - } - else - { + } else { throw new SwordError(DSpaceUriRegistry.BAD_URL, - "Unable to recognise URL as a valid service document: " + - url); + "Unable to recognise URL as a valid service document: " + + url); } - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } @@ -353,36 +295,29 @@ public class SwordUrlManager * Get the base URL for service document requests. * * @return service document base URL - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public String getBaseServiceDocumentUrl() - throws DSpaceSwordException - { + throws DSpaceSwordException { String sdUrl = ConfigurationManager .getProperty("swordv2-server", "servicedocument.url"); - if (sdUrl == null || "".equals(sdUrl)) - { + if (sdUrl == null || "".equals(sdUrl)) { String dspaceUrl = ConfigurationManager .getProperty("dspace.baseUrl"); - if (dspaceUrl == null || "".equals(dspaceUrl)) - { + if (dspaceUrl == null || "".equals(dspaceUrl)) { throw new DSpaceSwordException( "Unable to construct service document urls, due to missing/invalid " + - "config in swordv2-server.cfg servicedocument.url and/or dspace.baseUrl"); + "config in swordv2-server.cfg servicedocument.url and/or dspace.baseUrl"); } - try - { + try { URL url = new URL(dspaceUrl); sdUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), - "/swordv2/servicedocument").toString(); - } - catch (MalformedURLException e) - { + "/swordv2/servicedocument").toString(); + } catch (MalformedURLException e) { throw new DSpaceSwordException( "Unable to construct service document urls, due to invalid dspace.baseUrl " + - e.getMessage(), e); + e.getMessage(), e); } } return sdUrl; @@ -402,36 +337,29 @@ public class SwordUrlManager * where dspace.baseUrl is also in the configuration file. * * @return the base URL for SWORD deposit - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public String getBaseCollectionUrl() - throws DSpaceSwordException - { + throws DSpaceSwordException { String depositUrl = ConfigurationManager .getProperty("swordv2-server", "collection.url"); - if (depositUrl == null || "".equals(depositUrl)) - { + if (depositUrl == null || "".equals(depositUrl)) { String dspaceUrl = ConfigurationManager .getProperty("dspace.baseUrl"); - if (dspaceUrl == null || "".equals(dspaceUrl)) - { + if (dspaceUrl == null || "".equals(dspaceUrl)) { throw new DSpaceSwordException( "Unable to construct deposit urls, due to missing/invalid config in " + - "swordv2-server.cfg deposit.url and/or dspace.baseUrl"); + "swordv2-server.cfg deposit.url and/or dspace.baseUrl"); } - try - { + try { URL url = new URL(dspaceUrl); depositUrl = new URL(url.getProtocol(), url.getHost(), - url.getPort(), "/swordv2/collection").toString(); - } - catch (MalformedURLException e) - { + url.getPort(), "/swordv2/collection").toString(); + } catch (MalformedURLException e) { throw new DSpaceSwordException( "Unable to construct deposit urls, due to invalid dspace.baseUrl " + - e.getMessage(), e); + e.getMessage(), e); } } @@ -441,15 +369,12 @@ public class SwordUrlManager /** * Is the given URL the base service document URL? * - * @param url - * URL to check + * @param url URL to check * @return true if URL is service document base URL - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isBaseServiceDocumentUrl(String url) - throws DSpaceSwordException - { + throws DSpaceSwordException { return this.getBaseServiceDocumentUrl().equals(url); } @@ -457,85 +382,65 @@ public class SwordUrlManager * Central location for constructing usable URLs for DSpace bitstreams. * There is no place in the main DSpace codebase for doing this. * - * @param bitstream - * target bitstream + * @param bitstream target bitstream * @return URL of given bitstream - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public String getBitstreamUrl(Bitstream bitstream) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { List bundles = bitstream.getBundles(); Bundle parent = null; - if (!bundles.isEmpty()) - { + if (!bundles.isEmpty()) { parent = bundles.get(0); - } - else - { + } else { throw new DSpaceSwordException( "Encountered orphaned bitstream"); } List items = parent.getItems(); Item item; - if (!items.isEmpty()) - { + if (!items.isEmpty()) { item = items.get(0); - } - else - { + } else { throw new DSpaceSwordException("Encountered orphaned bundle"); } String handle = item.getHandle(); String bsLink = ConfigurationManager.getProperty("dspace.url"); - if (handle != null && !"".equals(handle)) - { + if (handle != null && !"".equals(handle)) { bsLink = bsLink + "/bitstream/" + handle + "/" + bitstream.getSequenceID() + "/" + bitstream.getName(); - } - else - { + } else { bsLink = bsLink + "/retrieve/" + bitstream.getID() + "/" + - bitstream.getName(); + bitstream.getName(); } return bsLink; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } public String getActionableBitstreamUrl(Bitstream bitstream) - throws DSpaceSwordException - { + throws DSpaceSwordException { return this.getSwordBaseUrl() + "/edit-media/bitstream/" + bitstream.getID() + "/" + bitstream.getName(); } - public boolean isActionableBitstreamUrl(Context context, String url) - { + public boolean isActionableBitstreamUrl(Context context, String url) { return url.contains("/edit-media/bitstream/"); } public Bitstream getBitstream(Context context, String location) - throws DSpaceSwordException, SwordError - { - try - { + throws DSpaceSwordException, SwordError { + try { String baseUrl = this.getSwordBaseUrl(); String emBaseUrl = baseUrl + "/edit-media/bitstream/"; - if (!location.startsWith(emBaseUrl)) - { + if (!location.startsWith(emBaseUrl)) { throw new SwordError(DSpaceUriRegistry.BAD_URL, - "The bitstream URL is invalid"); + "The bitstream URL is invalid"); } String bitstreamParts = location.substring(emBaseUrl.length()); @@ -546,9 +451,7 @@ public class SwordUrlManager Bitstream bitstream = bitstreamService.findByIdOrLegacyId(context, bid); return bitstream; - } - catch (SQLException e) - { + } catch (SQLException e) { // log.error("Caught exception:", e); throw new DSpaceSwordException( "There was a problem resolving the collection", e); @@ -557,72 +460,55 @@ public class SwordUrlManager // FIXME: we need a totally new kind of URL scheme; perhaps we write the identifier into the item public String getAtomStatementUri(Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { return this.getSwordBaseUrl() + "/statement/" + item.getID() + ".atom"; } public String getOreStatementUri(Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { return this.getSwordBaseUrl() + "/statement/" + item.getID() + ".rdf"; } public String getAggregationUrl(Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { return this.getOreStatementUri(item) + "#aggregation"; } public IRI getEditIRI(Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { return new IRI(this.getSwordBaseUrl() + "/edit/" + item.getID()); } public String getSplashUrl(Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { WorkflowTools wft = new WorkflowTools(); - // if the item is in the workspace, we need to give it it's own - // special identifier - if (wft.isItemInWorkspace(context, item)) - { + // if the item is in the workspace, we need to give it it's own special identifier + if (wft.isItemInWorkspace(context, item)) { String urlTemplate = ConfigurationManager - .getProperty("swordv2-server", "workspace.url-template"); - if (urlTemplate != null) - { + .getProperty("swordv2-server", "workspace.url-template"); + if (urlTemplate != null) { return urlTemplate.replace("#wsid#", Integer.toString( wft.getWorkspaceItem(context, item).getID())); } - } - // otherwise, it may be in the workflow, in which case there is - // no identifier - else if (wft.isItemInWorkflow(context, item)) - { - // do nothing + } else if (wft.isItemInWorkflow(context, item)) { + // otherwise, it may be in the workflow, in which case there is no identifier return null; - } - // finally, otherwise we need to just return the handle of the - // item - else - { + } else { + // finally, otherwise we need to just return the handle of the item return handleService.getCanonicalForm(item.getHandle()); } return null; } public IRI getContentUrl(Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { return new IRI(this.getSwordBaseUrl() + "/edit-media/" + item.getID()); } public IRI getMediaFeedUrl(Item item) - throws DSpaceSwordException - { + throws DSpaceSwordException { return new IRI(this.getSwordBaseUrl() + "/edit-media/" + item.getID() + - ".atom"); + ".atom"); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/TempFileInputStream.java b/dspace-swordv2/src/main/java/org/dspace/sword2/TempFileInputStream.java index 379365cab3..4c2fff227b 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/TempFileInputStream.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/TempFileInputStream.java @@ -12,20 +12,17 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -public class TempFileInputStream extends FileInputStream -{ +public class TempFileInputStream extends FileInputStream { private String path; public TempFileInputStream(File file) - throws FileNotFoundException - { + throws FileNotFoundException { super(file); this.path = file.getAbsolutePath(); } public void close() - throws IOException - { + throws IOException { super.close(); File file = new File(this.path); file.delete(); diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/VerboseDescription.java b/dspace-swordv2/src/main/java/org/dspace/sword2/VerboseDescription.java index 6253f178e9..86004d9a32 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/VerboseDescription.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/VerboseDescription.java @@ -10,28 +10,23 @@ package org.dspace.sword2; import java.text.SimpleDateFormat; import java.util.Date; -public class VerboseDescription -{ +public class VerboseDescription { private StringBuilder sb; - public VerboseDescription() - { + public VerboseDescription() { this.sb = new StringBuilder(); } - public VerboseDescription append(String s) - { + public VerboseDescription append(String s) { this.sb.append(this.getDatePrefix() + s + "\n"); return this; } - public String toString() - { + public String toString() { return this.sb.toString(); } - private String getDatePrefix() - { + private String getDatePrefix() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return "[" + sdf.format(new Date()) + "] "; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/VersionManager.java b/dspace-swordv2/src/main/java/org/dspace/sword2/VersionManager.java index fc3e90729b..7212d8caaa 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/VersionManager.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/VersionManager.java @@ -7,6 +7,13 @@ */ package org.dspace.sword2; +import java.io.IOException; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; @@ -18,35 +25,24 @@ import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; -import java.io.IOException; -import java.sql.SQLException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -public class VersionManager -{ +public class VersionManager { protected ItemService itemService = ContentServiceFactory.getInstance() - .getItemService(); + .getItemService(); protected BundleService bundleService = ContentServiceFactory.getInstance() - .getBundleService(); + .getBundleService(); protected BitstreamService bitstreamService = ContentServiceFactory - .getInstance().getBitstreamService(); + .getInstance().getBitstreamService(); public void removeBundle(Context context, Item item, String name) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { boolean keep = ConfigurationManager - .getBooleanProperty("swordv2-server", "versions.keep"); + .getBooleanProperty("swordv2-server", "versions.keep"); Iterator bundles = item.getBundles().iterator(); - while (bundles.hasNext()) - { + while (bundles.hasNext()) { Bundle b = bundles.next(); - if (name.equals(b.getName())) - { + if (name.equals(b.getName())) { bundles.remove(); this.removeBundle(context, item, b, keep); } @@ -54,32 +50,28 @@ public class VersionManager } public void removeBundle(Context context, Item item, Bundle source) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { boolean keep = ConfigurationManager - .getBooleanProperty("swordv2-server", "versions.keep"); + .getBooleanProperty("swordv2-server", "versions.keep"); this.removeBundle(context, item, source, keep); } public void removeBundle(Context context, Item item, Bundle source, - boolean archive) - throws SQLException, AuthorizeException, IOException - { + boolean archive) + throws SQLException, AuthorizeException, IOException { // archive the bundle contents if desired - if (archive) - { + if (archive) { this.archiveBundle(context, item, source); } // remove all the bitstreams from the bundle Iterator bitstreams = source.getBitstreams() - .iterator(); - while (bitstreams.hasNext()) - { + .iterator(); + while (bitstreams.hasNext()) { Bitstream bitstream = bitstreams.next(); bitstreams.remove(); bundleService.removeBitstream(context, source, - bitstream); + bitstream); } // delete the bundle itself @@ -87,35 +79,30 @@ public class VersionManager } public void removeBitstream(Context context, Item item, Bitstream bitstream) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { boolean keep = ConfigurationManager - .getBooleanProperty("swordv2-server", "versions.keep"); + .getBooleanProperty("swordv2-server", "versions.keep"); this.removeBitstream(context, item, bitstream, keep); } public void removeBitstream(Context context, Item item, Bitstream bitstream, - boolean keep) - throws SQLException, AuthorizeException, IOException - { + boolean keep) + throws SQLException, AuthorizeException, IOException { Bundle exempt = null; - if (keep) - { + if (keep) { exempt = this.archiveBitstream(context, item, bitstream); } Iterator bundles = bitstream.getBundles() - .iterator(); - while (bundles.hasNext()) - { + .iterator(); + while (bundles.hasNext()) { Bundle bundle = bundles.next(); if (exempt != null && - bundle.getID() != exempt.getID()) - { + bundle.getID() != exempt.getID()) { bundles.remove(); bundleService - .removeBitstream(context, bundle, - bitstream); + .removeBitstream(context, bundle, + bitstream); } } @@ -124,8 +111,7 @@ public class VersionManager SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); String desc = bitstream.getDescription(); String newDesc = "[Deleted on: " + sdf.format(new Date()) + "] "; - if (desc != null) - { + if (desc != null) { newDesc += desc; } bitstream.setDescription(context, newDesc); @@ -133,28 +119,23 @@ public class VersionManager } private Bundle archiveBitstream(Context context, Item item, - Bitstream bitstream) - throws SQLException, AuthorizeException, IOException - { + Bitstream bitstream) + throws SQLException, AuthorizeException, IOException { String swordBundle = ConfigurationManager - .getProperty("swordv2-server", "bundle.deleted"); - if (swordBundle == null) - { + .getProperty("swordv2-server", "bundle.deleted"); + if (swordBundle == null) { swordBundle = "DELETED"; } List bundles = item.getBundles(); Bundle archive = null; - for (Bundle bundle : bundles) - { - if (swordBundle.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (swordBundle.equals(bundle.getName())) { archive = bundle; break; } } - if (archive == null) - { + if (archive == null) { archive = bundleService.create(context, item, swordBundle); } this.archiveBitstream(context, archive, bitstream); @@ -162,15 +143,13 @@ public class VersionManager } private void archiveBitstream(Context context, Bundle target, - Bitstream bitstream) - throws SQLException, AuthorizeException, IOException - { + Bitstream bitstream) + throws SQLException, AuthorizeException, IOException { bundleService.addBitstream(context, target, bitstream); } private void archiveBundle(Context context, Item item, Bundle source) - throws SQLException, AuthorizeException, IOException - { + throws SQLException, AuthorizeException, IOException { // get the datestamped root bundle name SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String oldName = "VER" + sdf.format(new Date()); @@ -178,22 +157,18 @@ public class VersionManager Bundle old = bundleService.create(context, item, oldName); List bitstreams = source.getBitstreams(); - for (Bitstream bitstream : bitstreams) - { + for (Bitstream bitstream : bitstreams) { bundleService - .addBitstream(context, old, bitstream); + .addBitstream(context, old, bitstream); } } private String getNumberedName(Item item, String name, int number) - throws SQLException - { + throws SQLException { String nName = name + "." + Integer.toString(number); List bundles = item.getBundles(); - for (Bundle bundle : bundles) - { - if (nName.equals(bundle.getName())) - { + for (Bundle bundle : bundles) { + if (nName.equals(bundle.getName())) { return this.getNumberedName(item, name, number + 1); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManager.java b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManager.java index a53a050760..15da8960f8 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManager.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManager.java @@ -14,63 +14,62 @@ import org.dspace.core.Context; import org.swordapp.server.Deposit; import org.swordapp.server.SwordError; -public interface WorkflowManager -{ +public interface WorkflowManager { public void retrieveServiceDoc(Context context) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void listCollectionContents(Context context, Collection collection) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void createResource(Context context, Collection collection) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void retrieveContent(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void retrieveBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void replaceResourceContent(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void replaceBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void replaceMetadata(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void replaceMetadataAndMediaResource(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void deleteMediaResource(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void deleteBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void addResourceContent(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void addMetadata(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void deleteItem(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void retrieveStatement(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void modifyState(Context context, Item item) - throws SwordError, DSpaceSwordException; + throws SwordError, DSpaceSwordException; public void resolveState(Context context, Deposit deposit, - DepositResult result, VerboseDescription verboseDescription) - throws DSpaceSwordException; + DepositResult result, VerboseDescription verboseDescription) + throws DSpaceSwordException; public void resolveState(Context context, Deposit deposit, - DepositResult result, VerboseDescription verboseDescription, - boolean containerOperation) - throws DSpaceSwordException; + DepositResult result, VerboseDescription verboseDescription, + boolean containerOperation) + throws DSpaceSwordException; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerDefault.java b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerDefault.java index b1a73509f0..f463116dd5 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerDefault.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerDefault.java @@ -7,7 +7,13 @@ */ package org.dspace.sword2; -import org.dspace.content.*; +import java.sql.SQLException; +import java.util.List; + +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Item; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -15,277 +21,233 @@ import org.swordapp.server.Deposit; import org.swordapp.server.SwordError; import org.swordapp.server.UriRegistry; -import java.sql.SQLException; -import java.util.List; - /** * This implementation of WorkflowManager is restricted and only allows UPDATE and DELETE operations * on items which are not in workflow, in archive, or withdrawn. These operations can only be * performed on items which are in the deposit phase. */ -public class WorkflowManagerDefault implements WorkflowManager -{ - public void retrieveServiceDoc(Context context) throws SwordError - { +public class WorkflowManagerDefault implements WorkflowManager { + public void retrieveServiceDoc(Context context) throws SwordError { // do nothing - operation allowed } public void listCollectionContents(Context context, Collection collection) - throws SwordError - { + throws SwordError { // do nothing - operation allowed } public void createResource(Context context, Collection collection) - throws SwordError - { + throws SwordError { // do nothing - operation allowed } - public void retrieveContent(Context context, Item item) throws SwordError - { + public void retrieveContent(Context context, Item item) throws SwordError { // do nothing - operation allowed } public void retrieveBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void replaceResourceContent(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { WorkflowTools wft = new WorkflowTools(); - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been archived, and can no longer be modified"); + "The item has already been archived, and can no longer be modified"); } - if (wft.isItemInWorkflow(context, item)) - { + if (wft.isItemInWorkflow(context, item)) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been injected into the review workflow, and can no longer be modified"); + "The item has already been injected into the review workflow, and can no longer be " + + "modified"); } } public void replaceMetadata(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { boolean allowUpdate = ConfigurationManager - .getBooleanProperty("swordv2-server", - "workflowmanagerdefault.always-update-metadata"); - if (allowUpdate) - { + .getBooleanProperty("swordv2-server", + "workflowmanagerdefault.always-update-metadata"); + if (allowUpdate) { // all updates are allowed return; } // otherwise, go ahead and figure out the state WorkflowTools wft = new WorkflowTools(); - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been archived, and can no longer be modified"); + "The item has already been archived, and can no longer be modified"); } - if (wft.isItemInWorkflow(context, item)) - { + if (wft.isItemInWorkflow(context, item)) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been injected into the review workflow, and can no longer be modified"); + "The item has already been injected into the review workflow, and can no longer be " + + "modified"); } } public void replaceMetadataAndMediaResource(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { this.replaceResourceContent(context, item); this.replaceMetadata(context, item); } public void deleteMediaResource(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { WorkflowTools wft = new WorkflowTools(); - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been archived, and can no longer be modified"); + "The item has already been archived, and can no longer be modified"); } - if (wft.isItemInWorkflow(context, item)) - { + if (wft.isItemInWorkflow(context, item)) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been injected into the review workflow, and can no longer be modified"); + "The item has already been injected into the review workflow, and can no longer be " + + "modified"); } } public void deleteBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // this is equivalent to asking whether the media resource in the item can be deleted - try - { + try { List bundles = bitstream.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { // is the bitstream in the ORIGINAL bundle? If not, it can't be worked on if (!Constants.CONTENT_BUNDLE_NAME - .equals(bundle.getName())) - { + .equals(bundle.getName())) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The file is not in a bundle which can be modified"); + "The file is not in a bundle which can be modified"); } List items = bundle.getItems(); - for (Item item : items) - { + for (Item item : items) { this.deleteMediaResource(context, item); } } - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } public void replaceBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // File replace with DSpace actually violates the RESTful environment, so it is // turned off by default, and strongly advised against. Nonetheless, it is used // by some DepositMO aware extensions, so must be supported (as shown below) boolean fileReplace = ConfigurationManager - .getBooleanProperty("swordv2-server", - "workflowmanagerdefault.file-replace.enable"); - if (!fileReplace) - { + .getBooleanProperty("swordv2-server", + "workflowmanagerdefault.file-replace.enable"); + if (!fileReplace) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "DSpace does not support file replace; you should DELETE the original file and PUT the new one"); + "DSpace does not support file replace; you should DELETE the original file and PUT " + + "the new one"); } // this is equivalent to asking whether the media resource in the item can be deleted - try - { + try { List bundles = bitstream.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { // is the bitstream in the ORIGINAL bundle? If not, it can't be worked on if (!Constants.CONTENT_BUNDLE_NAME - .equals(bundle.getName())) - { + .equals(bundle.getName())) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The file is not in a bundle which can be modified"); + "The file is not in a bundle which can be modified"); } - for (Item item : bundle.getItems()) - { + for (Item item : bundle.getItems()) { this.replaceResourceContent(context, item); } } - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } public void addResourceContent(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { WorkflowTools wft = new WorkflowTools(); - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been archived, and can no longer be modified"); + "The item has already been archived, and can no longer be modified"); } - if (wft.isItemInWorkflow(context, item)) - { + if (wft.isItemInWorkflow(context, item)) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been injected into the review workflow, and can no longer be modified"); + "The item has already been injected into the review workflow, and can no longer be " + + "modified"); } } public void addMetadata(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { boolean allowUpdate = ConfigurationManager - .getBooleanProperty("swordv2-server", - "workflowmanagerdefault.always-update-metadata"); - if (allowUpdate) - { + .getBooleanProperty("swordv2-server", + "workflowmanagerdefault.always-update-metadata"); + if (allowUpdate) { // all updates are allowed return; } // otherwise, lookup the state of the item WorkflowTools wft = new WorkflowTools(); - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been archived, and can no longer be modified"); + "The item has already been archived, and can no longer be modified"); } - if (wft.isItemInWorkflow(context, item)) - { + if (wft.isItemInWorkflow(context, item)) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been injected into the review workflow, and can no longer be modified"); + "The item has already been injected into the review workflow, and can no longer be " + + "modified"); } } public void deleteItem(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { WorkflowTools wft = new WorkflowTools(); - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been archived, and can no longer be modified"); + "The item has already been archived, and can no longer be modified"); } - if (wft.isItemInWorkflow(context, item)) - { + if (wft.isItemInWorkflow(context, item)) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been injected into the review workflow, and can no longer be modified"); + "The item has already been injected into the review workflow, and can no longer be " + + "modified"); } } public void retrieveStatement(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void modifyState(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { WorkflowTools wft = new WorkflowTools(); - if (item.isArchived() || item.isWithdrawn()) - { + if (item.isArchived() || item.isWithdrawn()) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been archived, and can no longer be modified"); + "The item has already been archived, and can no longer be modified"); } - if (wft.isItemInWorkflow(context, item)) - { + if (wft.isItemInWorkflow(context, item)) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The item has already been injected into the review workflow, and can no longer be modified"); + "The item has already been injected into the review workflow, and can no longer be " + + "modified"); } } public void resolveState(Context context, Deposit deposit, - DepositResult result, VerboseDescription verboseDescription) - throws DSpaceSwordException - { + DepositResult result, VerboseDescription verboseDescription) + throws DSpaceSwordException { this.resolveState(context, deposit, result, verboseDescription, true); } public void resolveState(Context context, Deposit deposit, - DepositResult result, VerboseDescription verboseDescription, - boolean containerOperation) - throws DSpaceSwordException - { + DepositResult result, VerboseDescription verboseDescription, + boolean containerOperation) + throws DSpaceSwordException { // the containerOperation flag tells us whether this method was called by an operation which happened on the // container. This workflow implementation only changes workflow states on contaner operations, not media // resource operations, so we just bounce this right back. - if (!containerOperation) - { + if (!containerOperation) { return; } @@ -301,38 +263,40 @@ public class WorkflowManagerDefault implements WorkflowManager boolean inarch = item.isArchived() || item.isWithdrawn(); // in progress inws inwf inarch action description - // 0 0 0 1 NOTHING the deposit finished, and the item is in the archive; - // 0 0 1 0 NOTHING the deposit finished, and the item is in the workflow. Carry on as normal - // 0 1 0 0 START WF the deposit is finished, and the item is in the workflow, so we start it - // 1 0 0 1 NOTHING the deposit is not finished, and the item is in the archive; - // 1 0 1 0 STOP WF the deposit is not finished, and it is in the workflow. Pull it out into the workspace - // 1 1 0 0 NOTHING the deposit is not finished, and is in the workspace; leave it there + // 0 0 0 1 NOTHING the deposit finished, and the item is in the + // archive; + // 0 0 1 0 NOTHING the deposit finished, and the item is in the + // workflow. Carry on as normal + // 0 1 0 0 START WF the deposit is finished, and the item is in the + // workflow, so we start it + // 1 0 0 1 NOTHING the deposit is not finished, and the item is in + // the archive; + // 1 0 1 0 STOP WF the deposit is not finished, and it is in the + // workflow. Pull it out into the workspace + // 1 1 0 0 NOTHING the deposit is not finished, and is in the + // workspace; leave it there - if (!deposit.isInProgress() && inarch) - { + if (!deposit.isInProgress() && inarch) { verboseDescription - .append("The deposit is finished, and the item is already in the archive"); + .append("The deposit is finished, and the item is already in the archive"); // throw new DSpaceSwordException("Invalid workflow state"); } - if (!deposit.isInProgress() && inws) - { + if (!deposit.isInProgress() && inws) { verboseDescription - .append("The deposit is finished: moving it from the workspace to the workflow"); + .append("The deposit is finished: moving it from the workspace to the workflow"); wft.startWorkflow(context, item); } - if (deposit.isInProgress() && inarch) - { + if (deposit.isInProgress() && inarch) { verboseDescription - .append("The deposit is not finished, and the item is already in the archive"); + .append("The deposit is not finished, and the item is already in the archive"); // throw new DSpaceSwordException("Invalid workflow state"); } - if (deposit.isInProgress() && inwf) - { + if (deposit.isInProgress() && inwf) { verboseDescription - .append("The deposit is in progress, but is in the workflow; returning to the workspace"); + .append("The deposit is in progress, but is in the workflow; returning to the workspace"); wft.stopWorkflow(context, item); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerFactory.java b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerFactory.java index ce235deb2b..dad3933345 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerFactory.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerFactory.java @@ -10,17 +10,26 @@ package org.dspace.sword2; import org.dspace.core.factory.CoreServiceFactory; import org.swordapp.server.SwordError; -public class WorkflowManagerFactory -{ +public class WorkflowManagerFactory { + + /** + * Default constructor + */ + private WorkflowManagerFactory() { } + + /** + * Get an instance of WorkflowManager + * @return WorkflowManager + * @throws DSpaceSwordException + * @throws SwordError + */ public static WorkflowManager getInstance() - throws DSpaceSwordException, SwordError - { + throws DSpaceSwordException, SwordError { WorkflowManager manager = (WorkflowManager) CoreServiceFactory.getInstance().getPluginService() - .getSinglePlugin(WorkflowManager.class); - if (manager == null) - { + .getSinglePlugin(WorkflowManager.class); + if (manager == null) { throw new SwordError(DSpaceUriRegistry.REPOSITORY_ERROR, - "No workflow manager configured"); + "No workflow manager configured"); } return manager; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerUnrestricted.java b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerUnrestricted.java index 9e238023f5..21f79c7450 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerUnrestricted.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerUnrestricted.java @@ -7,181 +7,152 @@ */ package org.dspace.sword2; -import org.dspace.content.*; +import java.sql.SQLException; +import java.util.List; + +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Item; import org.dspace.core.Constants; import org.dspace.core.Context; import org.swordapp.server.Deposit; import org.swordapp.server.SwordError; import org.swordapp.server.UriRegistry; -import java.sql.SQLException; -import java.util.List; - /** * This implementation of WorkflowManager is unrestricted and allows UPDATE and DELETE operations * on items in any state (in workflow, in archive, or withdrawn). */ -public class WorkflowManagerUnrestricted implements WorkflowManager -{ - public void retrieveServiceDoc(Context context) throws SwordError - { +public class WorkflowManagerUnrestricted implements WorkflowManager { + public void retrieveServiceDoc(Context context) throws SwordError { // do nothing - operation allowed } public void listCollectionContents(Context context, Collection collection) - throws SwordError - { + throws SwordError { // do nothing - operation allowed } public void createResource(Context context, Collection collection) - throws SwordError - { + throws SwordError { // do nothing - operation allowed } - public void retrieveContent(Context context, Item item) throws SwordError - { + public void retrieveContent(Context context, Item item) throws SwordError { // do nothing - operation allowed } public void retrieveBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void replaceResourceContent(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void replaceMetadata(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void replaceMetadataAndMediaResource(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void deleteMediaResource(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void deleteBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // this is equivalent to asking whether the media resource in the item can be deleted - try - { + try { List bundles = bitstream.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { // is the bitstream in the ORIGINAL bundle? If not, it can't be worked on if (!Constants.CONTENT_BUNDLE_NAME - .equals(bundle.getName())) - { + .equals(bundle.getName())) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The file is not in a bundle which can be modified"); + "The file is not in a bundle which can be modified"); } List items = bundle.getItems(); - for (Item item : items) - { + for (Item item : items) { this.deleteMediaResource(context, item); } } - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } public void replaceBitstream(Context context, Bitstream bitstream) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // this is equivalent to asking whether the media resource in the item can be deleted - try - { + try { List bundles = bitstream.getBundles(); - for (Bundle bundle : bundles) - { + for (Bundle bundle : bundles) { // is the bitstream in the ORIGINAL bundle? If not, it can't be worked on if (!Constants.CONTENT_BUNDLE_NAME - .equals(bundle.getName())) - { + .equals(bundle.getName())) { throw new SwordError(UriRegistry.ERROR_METHOD_NOT_ALLOWED, - "The file is not in a bundle which can be modified"); + "The file is not in a bundle which can be modified"); } List items = bundle.getItems(); - for (Item item : items) - { + for (Item item : items) { this.replaceResourceContent(context, item); } } - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } public void addResourceContent(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void addMetadata(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void deleteItem(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void retrieveStatement(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void modifyState(Context context, Item item) - throws SwordError, DSpaceSwordException - { + throws SwordError, DSpaceSwordException { // do nothing - operation allowed } public void resolveState(Context context, Deposit deposit, - DepositResult result, VerboseDescription verboseDescription) - throws DSpaceSwordException - { + DepositResult result, VerboseDescription verboseDescription) + throws DSpaceSwordException { this.resolveState(context, deposit, result, verboseDescription, true); } public void resolveState(Context context, Deposit deposit, - DepositResult result, VerboseDescription verboseDescription, - boolean containerOperation) - throws DSpaceSwordException - { + DepositResult result, VerboseDescription verboseDescription, + boolean containerOperation) + throws DSpaceSwordException { // the containerOperation flag tells us whether this method was called by an operation which happened on the // container. This workflow implementation only changes workflow states on contaner operations, not media // resource operations, so we just bounce this right back. - if (!containerOperation) - { + if (!containerOperation) { return; } @@ -197,38 +168,40 @@ public class WorkflowManagerUnrestricted implements WorkflowManager boolean inarch = item.isArchived() || item.isWithdrawn(); // in progress inws inwf inarch action description - // 0 0 0 1 NOTHING the deposit finished, and the item is in the archive; - // 0 0 1 0 NOTHING the deposit finished, and the item is in the workflow. Carry on as normal - // 0 1 0 0 START WF the deposit is finished, and the item is in the workflow, so we start it - // 1 0 0 1 NOTHING the deposit is not finished, and the item is in the archive; - // 1 0 1 0 STOP WF the deposit is not finished, and it is in the workflow. Pull it out into the workspace - // 1 1 0 0 NOTHING the deposit is not finished, and is in the workspace; leave it there + // 0 0 0 1 NOTHING the deposit finished, and the item is in the + // archive; + // 0 0 1 0 NOTHING the deposit finished, and the item is in the + // workflow. Carry on as normal + // 0 1 0 0 START WF the deposit is finished, and the item is in the + // workflow, so we start it + // 1 0 0 1 NOTHING the deposit is not finished, and the item is in + // the archive; + // 1 0 1 0 STOP WF the deposit is not finished, and it is in the + // workflow. Pull it out into the workspace + // 1 1 0 0 NOTHING the deposit is not finished, and is in the + // workspace; leave it there - if (!deposit.isInProgress() && inarch) - { + if (!deposit.isInProgress() && inarch) { verboseDescription - .append("The deposit is finished, and the item is already in the archive"); + .append("The deposit is finished, and the item is already in the archive"); // throw new DSpaceSwordException("Invalid workflow state"); } - if (!deposit.isInProgress() && inws) - { + if (!deposit.isInProgress() && inws) { verboseDescription - .append("The deposit is finished: moving it from the workspace to the workflow"); + .append("The deposit is finished: moving it from the workspace to the workflow"); wft.startWorkflow(context, item); } - if (deposit.isInProgress() && inarch) - { + if (deposit.isInProgress() && inarch) { verboseDescription - .append("The deposit is not finished, and the item is already in the archive"); + .append("The deposit is not finished, and the item is already in the archive"); // throw new DSpaceSwordException("Invalid workflow state"); } - if (deposit.isInProgress() && inwf) - { + if (deposit.isInProgress() && inwf) { verboseDescription - .append("The deposit is in progress, but is in the workflow; returning to the workspace"); + .append("The deposit is in progress, but is in the workflow; returning to the workspace"); wft.stopWorkflow(context, item); } } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowTools.java b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowTools.java index b3da189fc4..eb44e9f2d3 100644 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowTools.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowTools.java @@ -7,6 +7,9 @@ */ package org.dspace.sword2; +import java.io.IOException; +import java.sql.SQLException; + import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; @@ -20,11 +23,7 @@ import org.dspace.workflow.WorkflowItemService; import org.dspace.workflow.WorkflowService; import org.dspace.workflow.factory.WorkflowServiceFactory; -import java.io.IOException; -import java.sql.SQLException; - -public class WorkflowTools -{ +public class WorkflowTools { protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); @@ -40,23 +39,16 @@ public class WorkflowTools * This method queries the database directly to determine if this is the * case rather than using the DSpace API (which is very slow). * - * @param context - * The relevant DSpace Context. - * @param item - * item to check + * @param context The relevant DSpace Context. + * @param item item to check * @return true if item is in workflow - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isItemInWorkflow(Context context, Item item) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { return workflowItemService.findByItem(context, item) != null; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } @@ -67,23 +59,16 @@ public class WorkflowTools * This method queries the database directly to determine if this is the * case rather than using the DSpace API (which is very slow). * - * @param context - * The relevant DSpace Context. - * @param item - * item to check + * @param context The relevant DSpace Context. + * @param item item to check * @return true if item is in workspace - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public boolean isItemInWorkspace(Context context, Item item) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { return workspaceItemService.findByItem(context, item) != null; - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } @@ -94,23 +79,16 @@ public class WorkflowTools * This method queries the database directly to determine if this is the * case rather than using the DSpace API (which is very slow). * - * @param context - * The relevant DSpace Context. - * @param item - * item to check + * @param context The relevant DSpace Context. + * @param item item to check * @return workflow item - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public WorkflowItem getWorkflowItem(Context context, Item item) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { return workflowItemService.findByItem(context, item); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } @@ -121,23 +99,16 @@ public class WorkflowTools * This method queries the database directly to determine if this is the * case rather than using the DSpace API (which is very slow). * - * @param context - * The relevant DSpace Context. - * @param item - * item to check + * @param context The relevant DSpace Context. + * @param item item to check * @return workspace item - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public WorkspaceItem getWorkspaceItem(Context context, Item item) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { return workspaceItemService.findByItem(context, item); - } - catch (SQLException e) - { + } catch (SQLException e) { throw new DSpaceSwordException(e); } } @@ -145,35 +116,25 @@ public class WorkflowTools /** * Start the DSpace workflow on the given item * - * @param context - * The relevant DSpace Context. - * @param item - * item to check - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @param context The relevant DSpace Context. + * @param item item to check + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public void startWorkflow(Context context, Item item) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { // obtain the workspace item which should therefore exist WorkspaceItem wsi = this.getWorkspaceItem(context, item); // kick off the workflow boolean notify = ConfigurationManager - .getBooleanProperty("swordv2-server", "workflow.notify"); - if (notify) - { + .getBooleanProperty("swordv2-server", "workflow.notify"); + if (notify) { workflowService.start(context, wsi); - } - else - { + } else { workflowService.startWithoutNotify(context, wsi); } - } - catch (SQLException | WorkflowException | IOException | AuthorizeException e) - { + } catch (SQLException | WorkflowException | IOException | AuthorizeException e) { throw new DSpaceSwordException(e); } } @@ -181,29 +142,21 @@ public class WorkflowTools /** * Stop the DSpace workflow, and return the item to the user workspace * - * @param context - * The relevant DSpace Context. - * @param item - * item to check - * @throws DSpaceSwordException - * can be thrown by the internals of the DSpace SWORD implementation + * @param context The relevant DSpace Context. + * @param item item to check + * @throws DSpaceSwordException can be thrown by the internals of the DSpace SWORD implementation */ public void stopWorkflow(Context context, Item item) - throws DSpaceSwordException - { - try - { + throws DSpaceSwordException { + try { // find the item in the workflow if it exists WorkflowItem wfi = this.getWorkflowItem(context, item); // abort the workflow - if (wfi != null) - { + if (wfi != null) { workflowService.abort(context, wfi, context.getCurrentUser()); } - } - catch (SQLException | AuthorizeException | IOException e) - { + } catch (SQLException | AuthorizeException | IOException e) { throw new DSpaceSwordException(e); } } diff --git a/dspace-swordv2/src/main/webapp/WEB-INF/web.xml b/dspace-swordv2/src/main/webapp/WEB-INF/web.xml index 6f1a81f584..52feaf240a 100644 --- a/dspace-swordv2/src/main/webapp/WEB-INF/web.xml +++ b/dspace-swordv2/src/main/webapp/WEB-INF/web.xml @@ -8,156 +8,138 @@ http://www.dspace.org/license/ --> - + - - - DSpace SWORD 2.0 Server + DSpace SWORD 2.0 Server + The location of the DSpace home directory dspace.dir ${dspace.dir} - - The location of the DSpace home directory - - + - - service-document-impl - org.dspace.sword2.ServiceDocumentManagerDSpace - - The ServiceDocumentManager server implementation class name - - + + The ServiceDocumentManager server implementation class name + service-document-impl + org.dspace.sword2.ServiceDocumentManagerDSpace + - - - collection-list-impl - org.dspace.sword2.CollectionListManagerDSpace - - The CollectionListManager server implementation class name - - + + + The CollectionListManager server implementation class name + collection-list-impl + org.dspace.sword2.CollectionListManagerDSpace + - - collection-deposit-impl - org.dspace.sword2.CollectionDepositManagerDSpace - - The CollectionDepositManager server implementation class name - - + + The CollectionDepositManager server implementation class name + collection-deposit-impl + org.dspace.sword2.CollectionDepositManagerDSpace + - - media-resource-impl - org.dspace.sword2.MediaResourceManagerDSpace - - The MediaResourceManager server implementation class name - - + + The MediaResourceManager server implementation class name + media-resource-impl + org.dspace.sword2.MediaResourceManagerDSpace + - - container-impl - org.dspace.sword2.ContainerManagerDSpace - - The ContainerManager server implementation class name - - + + The ContainerManager server implementation class name + container-impl + org.dspace.sword2.ContainerManagerDSpace + - - statement-impl - org.dspace.sword2.StatementManagerDSpace - - The StatementManager server implementation class name - - + + The StatementManager server implementation class name + statement-impl + org.dspace.sword2.StatementManagerDSpace + - - - config-impl - org.dspace.sword2.SwordConfigurationDSpace - - The SwordConfiguration server implementation class name - - + + + The SwordConfiguration server implementation class name + config-impl + org.dspace.sword2.SwordConfigurationDSpace + - - authentication-method - Basic - - The type of authentication used : [Basic|None] - - + + The type of authentication used : [Basic|None] + authentication-method + Basic + - - - - org.dspace.app.util.DSpaceContextListener - - - - - org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener - - + + + + org.dspace.app.util.DSpaceContextListener + + + + + org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener + + - - - servicedocument - org.swordapp.server.servlets.ServiceDocumentServletDefault - + + + servicedocument + org.swordapp.server.servlets.ServiceDocumentServletDefault + - - collection - org.swordapp.server.servlets.CollectionServletDefault - + + collection + org.swordapp.server.servlets.CollectionServletDefault + - - mediaresource - org.swordapp.server.servlets.MediaResourceServletDefault - + + mediaresource + org.swordapp.server.servlets.MediaResourceServletDefault + - - container - org.swordapp.server.servlets.ContainerServletDefault - + + container + org.swordapp.server.servlets.ContainerServletDefault + - - statement - org.swordapp.server.servlets.StatementServletDefault - + + statement + org.swordapp.server.servlets.StatementServletDefault + - + - - servicedocument - /servicedocument/* - + + servicedocument + /servicedocument/* + - - collection - /collection/* - + + collection + /collection/* + - - mediaresource - /edit-media/* - + + mediaresource + /edit-media/* + - - container - /edit/* - + + container + /edit/* + - - statement - /statement/* - + + statement + /statement/* + diff --git a/dspace/config/crosswalks/oai/xoai.xml b/dspace/config/crosswalks/oai/xoai.xml index 5716163324..868382ccf0 100644 --- a/dspace/config/crosswalks/oai/xoai.xml +++ b/dspace/config/crosswalks/oai/xoai.xml @@ -29,9 +29,7 @@ diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index abbe59a145..f8a4930e61 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -28,15 +28,11 @@ dspace.hostname = localhost # DSpace base host URL. Include port number etc. dspace.baseUrl = http://localhost:8080 -# The user interface you will be using for DSpace. Common usage is either xmlui or jspui -dspace.ui = xmlui - # Full link your end users will use to access DSpace. In most cases, this will be the baseurl followed by # the context path to the UI you are using. # # Alternatively, you can use a url redirect or deploy the web application under the servlet container root. -# In this case, make sure to remove the /${dspace.ui} from the dspace.url property. -dspace.url = ${dspace.baseUrl}/${dspace.ui} +dspace.url = ${dspace.baseUrl} # Optional: DSpace URL for mobile access # This @@ -99,12 +95,6 @@ db.maxwait = 5000 # (default = 10) db.maxidle = 10 -# Specify a configured database connection pool to be fetched from a -# directory. This overrides the pool and driver settings above. If -# none can be found, then DSpace will use the above settings to create a -# pool. -#db.jndi = jdbc/dspace - # Whether or not to allow for an entire 'clean' of the DSpace database. # By default, this setting is 'true', which ensures that the 'dspace database clean' command # does nothing (except return an error message saying clean is disabled) @@ -827,7 +817,7 @@ cc.api.rooturl = http://api.creativecommons.org/rest/1.5 # Metadata field to hold CC license URI of selected license # NB: DSpace (both JSPUI and XMLUI) presentation code expects 'dc.rights.uri' to hold CC data. If you change -# this to another field, please consult documentation on how to update UI configuration +# this to another field, please consult documentation on how to update UI configuration cc.license.uri = dc.rights.uri # Metadata field to hold CC license name of selected license (if defined) @@ -841,7 +831,7 @@ cc.submit.setname = true # Store license bitstream (RDF license text) during web submission cc.submit.addbitstream = true -# ONLY JSPUI, enable Creative Commons admin +# ONLY JSPUI, enable Creative Commons admin webui.submit.enable-cc = false # A list of license classes that should be excluded from selection process @@ -938,7 +928,7 @@ webui.preview.brand.fontpoint = 12 ##### Settings for item count (strength) information #### # Whether to display collection and community strengths (i.e. item counts) -# XMLUI only makes strengths available to themes if this is set to true! +# XMLUI only makes strengths available to themes if this is set to true! # To show strengths in the XMLUI, you also need to create or use a theme which # displays them. webui.strengths.show = false @@ -956,7 +946,7 @@ webui.strengths.show = false ###### ItemCounter Configuration ###### # # Define the DAO class to use. This must correspond to your choice of -# storage for the browse system (Solr is only option at this time). +# storage for the browse system (Solr is only option at this time). # By default, the Solr implementation is used. # # Solr: @@ -965,7 +955,7 @@ webui.strengths.show = false ###### Browse Configuration ###### # -# Define the DAO class to use this must meet your storage choice for +# Define the DAO class to use this must meet your storage choice for # the browse system (Solr is only option at this time). # By default, the Solr implementation is used # @@ -1378,7 +1368,6 @@ websvc.opensearch.formats = html,atom,rss # The 'webui.*' setting is for the JSPUI, and # the 'xmlui.*' setting is for the XMLUI webui.content_disposition_threshold = 8388608 -xmlui.content_disposition_threshold = 8388608 #### Multi-file HTML document/site settings ##### @@ -1443,6 +1432,10 @@ sherpa.romeo.url = http://www.sherpa.ac.uk/romeo/api29.php #plugin.named.org.dspace.content.authority.ChoiceAuthority = \ # org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority +# URL of ORCID API +# Defaults to using the Public API (pub.orcid.org) +orcid.api.url = https://pub.orcid.org/v2.1 + ## The DCInputAuthority plugin is automatically configured with every ## value-pairs element in input-forms.xml, namely: ## common_identifiers, common_types, common_iso_languages @@ -1458,9 +1451,9 @@ sherpa.romeo.url = http://www.sherpa.ac.uk/romeo/api29.php ## ## An example using "srsc" can be found later in this section -#plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \ -# org.dspace.content.authority.DCInputAuthority, \ -# org.dspace.content.authority.DSpaceControlledVocabulary +plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \ + org.dspace.content.authority.DCInputAuthority, \ + org.dspace.content.authority.DSpaceControlledVocabulary ## configure LC Names plugin #lcname.url = http://alcme.oclc.org/srw/search/lcnaf @@ -1501,8 +1494,6 @@ authority.minconfidence = ambiguous ## demo: subject code autocomplete, using srsc as authority ## (DSpaceControlledVocabulary plugin must be enabled) ## Warning: when enabling this feature any controlled vocabulary configuration in the input-forms.xml for the metadata field will be overridden. -#choices.plugin.dc.subject = srsc -#choices.presentation.dc.subject = select #vocabulary.plugin.srsc.hierarchy.store = true #vocabulary.plugin.srsc.hierarchy.suggest = true #vocabulary.plugin.srsc.delimiter = "::" @@ -1516,14 +1507,6 @@ authority.minconfidence = ambiguous #choices.presentation.dc.title.alternative = suggest #authority.controlled.dc.title.alternative = true -## demo: use choice authority (without authority-control) to restrict dc.type on EditItemMetadata page -#choices.plugin.dc.type = common_types -#choices.presentation.dc.type = select - -## demo: same idea for dc.language.iso -#choices.plugin.dc.language.iso = common_iso_languages -#choices.presentation.dc.language.iso = select - # Change number of choices shown in the select in Choices lookup popup #xmlui.lookup.select.size = 12 @@ -1823,7 +1806,7 @@ webui.suggest.enable = false # inside that snipet is your Google Analytics key usually found in this line: # _uacct = "UA-XXXXXXX-X" # Take this key (just the UA-XXXXXX-X part) and place it here in this parameter. -# jspui.google.analytics.key=UA-XXXXXX-X +# google.analytics.key=UA-XXXXXX-X #---------------------------------------------------------------# #--------------XMLUI SPECIFIC CONFIGURATIONS--------------------# @@ -1929,15 +1912,6 @@ mirage2.item-view.bitstream.href.label.2 = title #xmlui.bitstream.mods = true #xmlui.bitstream.mets = true -# If you would like to use Google Analytics to track general website statistics then -# use the following parameter to provide your Analytics key. First sign up for an -# account at http://analytics.google.com, then create an entry for your repository -# website. Analytics will give you a snipet of JavaScript code to place on your site, -# inside that snipet is your Google Analytics key usually found in this line: -# _uacct = "UA-XXXXXXX-X" -# Take this key (just the UA-XXXXXX-X part) and place it here in this parameter. -#xmlui.google.analytics.key=UA-XXXXXX-X - # Assign how many page views will be recorded and displayed in the control panel's # activity viewer. The activity tab allows an administrator to debug problems in a # running DSpace by understanding who and how their dspace is currently being used. @@ -2010,7 +1984,6 @@ include = ${module_dir}/clamav.cfg include = ${module_dir}/controlpanel.cfg include = ${module_dir}/curate.cfg include = ${module_dir}/discovery.cfg -include = ${module_dir}/elastic-search-statistics.cfg include = ${module_dir}/fetchccdata.cfg include = ${module_dir}/google-analytics.cfg include = ${module_dir}/healthcheck.cfg diff --git a/dspace/config/hibernate-ehcache-config.xml b/dspace/config/hibernate-ehcache-config.xml index 45d75fe1a5..c63fd22d69 100644 --- a/dspace/config/hibernate-ehcache-config.xml +++ b/dspace/config/hibernate-ehcache-config.xml @@ -8,175 +8,11 @@ http://www.dspace.org/license/ --> - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dspace/config/item-submission.dtd b/dspace/config/item-submission.dtd index 26c822018e..0ca7755932 100644 --- a/dspace/config/item-submission.dtd +++ b/dspace/config/item-submission.dtd @@ -18,14 +18,18 @@ - - + + - - - + + + diff --git a/dspace/config/item-submission.xml b/dspace/config/item-submission.xml index 76a7117fbd..5756e9c4e8 100644 --- a/dspace/config/item-submission.xml +++ b/dspace/config/item-submission.xml @@ -1,286 +1,155 @@ - + - - + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.dspace.submit.step.SelectCollectionStep - org.dspace.app.webui.submit.step.JSPSelectCollectionStep - org.dspace.app.xmlui.aspect.submission.submit.SelectCollectionStep - false - - - - - - - - - - - - - - - - submit.progressbar.complete - org.dspace.submit.step.CompleteStep - org.dspace.app.webui.submit.step.JSPCompleteStep - false - - - - - Sample - org.dspace.submit.step.SampleStep - org.dspace.app.webui.submit.step.JSPSampleStep - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + org.dspace.app.rest.submit.step.CollectionStep + collection + submission + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.describe.steptwo + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.upload + org.dspace.app.rest.submit.step.UploadStep + upload + + + submit.progressbar.license + org.dspace.app.rest.submit.step.LicenseStep + license + submission + - - - org.dspace.submit.step.SkipInitialQuestionsStep - - - - - - - - submit.progressbar.describe - org.dspace.submit.step.DescribeStep - org.dspace.app.webui.submit.step.JSPDescribeStep - org.dspace.app.xmlui.aspect.submission.submit.DescribeStep - true - - - - - - - submit.progressbar.upload - org.dspace.submit.step.UploadStep - org.dspace.app.webui.submit.step.JSPUploadStep - org.dspace.app.xmlui.aspect.submission.submit.UploadStep - true - - - - - - - - submit.progressbar.verify - org.dspace.submit.step.VerifyStep - org.dspace.app.webui.submit.step.JSPVerifyStep - org.dspace.app.xmlui.aspect.submission.submit.ReviewStep - true - - - - - - - - - submit.progressbar.license - org.dspace.submit.step.LicenseStep - org.dspace.app.webui.submit.step.JSPLicenseStep - org.dspace.app.xmlui.aspect.submission.submit.LicenseStep - false - + - - + + + - + + + + + + + + + + + + Sample + org.dspace.submit.step.SampleStep + sample + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/launcher.xml b/dspace/config/launcher.xml index ab337941eb..ff8839ca08 100644 --- a/dspace/config/launcher.xml +++ b/dspace/config/launcher.xml @@ -317,13 +317,6 @@ org.dspace.statistics.util.StatisticsImporter - - stats-log-importer-elasticsearch - Import solr-format converted log files into Elastic Search statistics - - org.dspace.statistics.util.StatisticsImporterElasticSearch - - stats-util Statistics Client for Maintenance of Solr Statistics Indexes diff --git a/dspace/config/local.cfg.EXAMPLE b/dspace/config/local.cfg.EXAMPLE index 778ac1c4c6..2bf60a0281 100644 --- a/dspace/config/local.cfg.EXAMPLE +++ b/dspace/config/local.cfg.EXAMPLE @@ -36,15 +36,11 @@ dspace.hostname = localhost # DSpace base host URL. Include port number etc. dspace.baseUrl = http://localhost:8080 -# The user interface you will be using for DSpace. Common usage is either xmlui or jspui -dspace.ui = xmlui - # Full link your end users will use to access DSpace. In most cases, this will be the baseurl followed by # the context path to the UI you are using. # # Alternatively, you can use a url redirect or deploy the web application under the servlet container root. -# In this case, make sure to remove the /${dspace.ui} from the dspace.url property. -#dspace.url = ${dspace.baseUrl}/${dspace.ui} +#dspace.url = ${dspace.baseUrl} # Name of the site dspace.name = DSpace at My University diff --git a/dspace/config/log4j.properties b/dspace/config/log4j.properties index 238d0d8fbf..5acdacd310 100644 --- a/dspace/config/log4j.properties +++ b/dspace/config/log4j.properties @@ -30,6 +30,7 @@ loglevel.dspace=INFO # Defaults to INFO loglevel.other=INFO + ########################################################################### # A1 is the name of the appender for most DSpace activity. ########################################################################### @@ -40,8 +41,10 @@ log4j.rootCategory=${loglevel.other}, A1 # This line sets the logging level for DSpace code. Set this to DEBUG to see # extra detailed logging for DSpace code. log4j.logger.org.dspace=${loglevel.dspace}, A1 -# Do not change this line + +# Do not change these "additivity" lines log4j.additivity.org.dspace=false + # The name of the file appender log4j.appender.A1=org.dspace.app.util.DailyFileAppender # The filename of the log file created. A date stamp is appended to this @@ -76,31 +79,6 @@ log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%m%n -########################################################################### -# A3 is the name of the appender for Cocoon (XMLUI only) -########################################################################### -# These lines sets the logging level for the cocoon log file. -# Set these to DEBUG to see extra detailed logging. -log4j.logger.org.apache.cocoon=INFO, A3 -log4j.logger.cocoon=INFO, A3 -log4j.logger.org.springframework=INFO, A3 -# Do not change these lines -log4j.additivity.org.apache.cocoon=false -log4j.additivity.cocoon=false -log4j.additivity.org.springframework=false -# The name of the file appender -log4j.appender.A3=org.dspace.app.util.DailyFileAppender -# The filename of the log file created. A date stamp is appended to this -log4j.appender.A3.File=${log.dir}/cocoon.log -# Set this to yyyy-MM-DD for daily log files, or yyyy-MM for monthly files -log4j.appender.A3.DatePattern=yyyy-MM-dd -# The number of log files to keep, or 0 to keep them all -log4j.appender.A3.MaxLogs=14 -# A2 uses PatternLayout. -log4j.appender.A3.layout=org.apache.log4j.PatternLayout -log4j.appender.A3.layout.ConversionPattern=%d %-5p %c %x - %m%n - - ########################################################################### # Other settings ########################################################################### diff --git a/dspace/config/modules/authentication.cfg b/dspace/config/modules/authentication.cfg index f9828a1d5e..d5d010af6d 100644 --- a/dspace/config/modules/authentication.cfg +++ b/dspace/config/modules/authentication.cfg @@ -47,4 +47,36 @@ # Authentication by Password (encrypted in DSpace's database). See authentication-password.cfg for default configuration. # Enabled by default (to disable, either comment out, or define a new list of AuthenticationMethod plugins in your local.cfg) -plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.PasswordAuthentication \ No newline at end of file +plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.PasswordAuthentication + + +#---------------------------------------------------------------# +#---------------Stateless JWT Authentication--------------------# +#---------------------------------------------------------------# + +# Server key part that is a part of the key used to sign the authentication tokens. +# If this property is not set or empty, DSpace will generate a random key on startup. +# IF YOU ARE RUNNING DSPACE IN A CLUSTER, you need to set a value for this property here or as an environment variable +# jwt.token.secret = + +# This property enables/disables encryption of the payload in a stateless token. Enabling this makes the data encrypted +# and unreadable by the receiver, but makes the token larger in size. false by default +jwt.encryption.enabled = false + +# Encryption key to use when JWT token encryption is enabled (JWE). Note that encrypting tokens might required additional +# configuration in the REST clients +# jwt.encryption.secret = + +# This enables compression of the payload of a jwt, enabling this will make the jwt token a little smaller at the cost +# of some performance, this setting WILL ONLY BE used when encrypting the jwt. +jwt.compression.enabled = true + +# Expiration time of a token in minutes +jwt.token.expiration = 30 + +# Restrict tokens to a specific ip-address to prevent theft/session hijacking. This is achieved by making the ip-address +# a part of the JWT siging key. If this property is set to false then the ip-address won't be used as part of +# the signing key of a jwt token and tokens can be shared over multiple ip-addresses. +# For security reasons, this defaults to true +jwt.token.include.ip = true + diff --git a/dspace/config/modules/citation-page.cfg b/dspace/config/modules/citation-page.cfg index 309631f8bb..9ad2184ca3 100644 --- a/dspace/config/modules/citation-page.cfg +++ b/dspace/config/modules/citation-page.cfg @@ -21,6 +21,11 @@ #citation-page.citation_as_first_page=true # Customize the text/appearance of the citation PDF + +# Citation page format, either LETTER or A4 +#default => LETTER +#citation-page.page_format = LETTER + # First row of header, perhaps put your institution/university name # A comma separator will create a header with multiple sections on one line. #citation-page.header1=DSpace Institution diff --git a/dspace/config/modules/clamav.cfg b/dspace/config/modules/clamav.cfg index ff6cd880b1..48c4737340 100644 --- a/dspace/config/modules/clamav.cfg +++ b/dspace/config/modules/clamav.cfg @@ -11,7 +11,7 @@ clamav.service.host = 127.0.0.1 clamav.service.port = 3310 # Initial timeout value (in milliseconds) used when the socket is connecting -clamav.socket.timeout = 120 +clamav.socket.timeout = 360000 # Flag indicating whether a scan should stop when the first infected bitstream # is detected within an item. Normally a complete scan is desired, so default diff --git a/dspace/config/modules/elastic-search-statistics.cfg b/dspace/config/modules/elastic-search-statistics.cfg deleted file mode 100644 index 3992ad3d76..0000000000 --- a/dspace/config/modules/elastic-search-statistics.cfg +++ /dev/null @@ -1,19 +0,0 @@ -#---------------------------------------------------------------# -#---------ELASTIC SEARCH STATISTICS CONFIGURATIONS--------------# -#---------------------------------------------------------------# -# Configuration properties used solely by the ElasticSearch # -# Statistics Engine. By default, DSpace uses a Solr-based # -# Statistics Engine (see solr-statistics.cfg) and since # -# DSpace 6 this ElasticSearch-based module has been DEPRECATED # -# in favour of the older, Solr-based module. # -# See also: usage-statistics.cfg # -#---------------------------------------------------------------# -# -## Elastic Search Engine for UsageEvent Statistics -#elastic-search-statistics.clusterName = dspacestatslogging -#elastic-search-statistics.indexName = dspaceindex -#elastic-search-statistics.indexType = stats - -## Elastic Search can connect via TransportClient, for external ES service. -#elastic-search-statistics.address = 127.0.0.1 -#elastic-search-statistics.port = 9300 diff --git a/dspace/config/modules/publication-lookup.cfg b/dspace/config/modules/publication-lookup.cfg index 8258b292e3..dc1660f150 100644 --- a/dspace/config/modules/publication-lookup.cfg +++ b/dspace/config/modules/publication-lookup.cfg @@ -9,7 +9,7 @@ # importServices will be used. # # Example, this setting will ONLY used the PubMedImportService -# publication-lookup.url = http://eutils.ncbi.nlm.nih.gov/entrez/eutils/ +# publication-lookup.url = https://eutils.ncbi.nlm.nih.gov/entrez/eutils/ # # Default value is * (which uses all import services) # publication-lookup.url = * diff --git a/dspace/config/modules/rest.cfg b/dspace/config/modules/rest.cfg index 124f572118..c8ac235dc9 100644 --- a/dspace/config/modules/rest.cfg +++ b/dspace/config/modules/rest.cfg @@ -7,11 +7,6 @@ # record stats in DSpace statistics module rest.stats = true -##### Enable/disable authorization for the hierarchy listing. ##### -# By default, the DSpace REST API will only return communities/collections/items that are accessible to a particular user. -# Set the rest.hierarchy-authenticate option to false to bypass authorization -# rest.hierarchy-authenticate = false - #------------------------------------------------------------------# # REST API Reporting Tools # #------------------------------------------------------------------# @@ -31,13 +26,6 @@ rest.stats = true # tools can be configured to bypass DSpace authorization when # reporting on collections and items. -##### Enable/disable authorization for the reporting tools. ##### -# By default, the DSpace REST API will only return communities/collections/items that are accessible to a particular user. -# If the REST API has been deployed in a protected manner, the reporting tools can be configured to bypass authorization checks. -# This will allow all items/collections/communities to be returned to the report user. -# Set the rest-reporting-authenticate option to false to bypass authorization -# rest.reporting-authenticate = false - ##### Configure the report pages that can be requested by name ##### # Create a map of named reports that are available to a report tool user # Each map entry should be prefixed with rest-report-url @@ -52,10 +40,11 @@ rest.report-url.item-query = static/reports/query.html #rest.report-url.custom = ##### database specific way to format a regex SQL clause ##### -# The REST Report Tools may pass a regular expression test to the database. +# The REST Report Tools may pass a regular expression test to the database. # The following configuration setting will construct a SQL regular expression test appropriate to your database engine rest.regex-clause = text_value ~ ? + ##### Configure REST Report Filters ##### # A filter contains a set of tests that will be applied to an item to determine its inclusion in a particular report. # Private items and withdrawn items are frequently excluded from DSpace reports. @@ -146,3 +135,6 @@ rest.report-regex-xml-entity = ^.*&#.*$ # regex to identify non ascii characters in metadata rest.report-regex-non-ascii = ^.*[^\\p{ASCII}].*$ + +# The maximum number of results to return for 1 request +rest.search.max.results = 100 \ No newline at end of file diff --git a/dspace/config/modules/spring.cfg b/dspace/config/modules/spring.cfg index 70bbf20776..451e69a9a3 100644 --- a/dspace/config/modules/spring.cfg +++ b/dspace/config/modules/spring.cfg @@ -7,5 +7,4 @@ # The class names of the modules which the dspace servicemanager will attempt to retrieve. # These classes contain the paths to where to spring files are loaded spring.springloader.modules=org.dspace.app.configuration.APISpringLoader,\ - org.dspace.app.xmlui.configuration.XMLUISpringLoader,\ - org.dspace.app.webui.configuration.JSPUISpringLoader + org.dspace.app.rest.configuration.RESTSpringLoader diff --git a/dspace/config/modules/usage-statistics.cfg b/dspace/config/modules/usage-statistics.cfg index 335355a3c7..9e363a9e38 100644 --- a/dspace/config/modules/usage-statistics.cfg +++ b/dspace/config/modules/usage-statistics.cfg @@ -2,13 +2,12 @@ #--------------USAGE STATISTICS CONFIGURATIONS------------------# #---------------------------------------------------------------# # These configs are only used by the DSpace interfaces which # -# track usage statistics (Solr or Elastic Search) # +# track usage statistics (Solr) # # See also: solr-statistics.cfg # -# elastic-search-statistics.cfg # #---------------------------------------------------------------# # The location for the Geo Database retrieved on update/installation -usage-statistics.dbfile = ${dspace.dir}/config/GeoLiteCity.dat +usage-statistics.dbfile = ${dspace.dir}/config/GeoLite2-City.mmdb # Timeout for the resolver in the DNS lookup # Time in milliseconds, defaults to 200 for backward compatibility @@ -38,4 +37,4 @@ usage-statistics.authorization.admin.workflow=true # Enable/disable if a matching for a bot should be case sensitive # Setting this value to true will increase cpu usage, but bots will be found more accurately -#usage-statistics.bots.case-insensitive = false \ No newline at end of file +#usage-statistics.bots.case-insensitive = false diff --git a/dspace/config/registries/bitstream-formats.xml b/dspace/config/registries/bitstream-formats.xml index ba532add0e..e7d69b9313 100644 --- a/dspace/config/registries/bitstream-formats.xml +++ b/dspace/config/registries/bitstream-formats.xml @@ -316,6 +316,33 @@ qt + + video/mp4 + Video MP4 + Video MP4 + 1 + false + mp4 + + + + video/ogg + Video OGG + Video OGG + 1 + false + ogg + + + + video/webm + Video WEBM + Video WEBM + 1 + false + webm + + audio/x-mpeg MPEG Audio @@ -736,4 +763,22 @@ epub + + video/mp4 + mp4 + mpeg4 + 1 + false + mp4 + + + + audio/mpeg + mp3 + MPEG audio + 1 + false + mp3 + + diff --git a/dspace/config/spring/api/access-conditions.xml b/dspace/config/spring/api/access-conditions.xml new file mode 100644 index 0000000000..5050db1dab --- /dev/null +++ b/dspace/config/spring/api/access-conditions.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/spring/api/core-hibernate.xml b/dspace/config/spring/api/core-hibernate.xml index 1e8a6841ea..09094de971 100644 --- a/dspace/config/spring/api/core-hibernate.xml +++ b/dspace/config/spring/api/core-hibernate.xml @@ -17,21 +17,13 @@ ${db.dialect} ${db.schema} + + file:${dspace.dir}/config/hibernate-ehcache-config.xml + - - - - - - net.sf.ehcache.configurationResourceName - file:${dspace.dir}/config/hibernate-ehcache-config.xml - - - - diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 2c6160f55f..f25cb5ea20 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -92,10 +92,6 @@ - - - - diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index 183b1e892d..ba57e659ea 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -1,4 +1,15 @@ + + + + + + @@ -101,6 +115,8 @@ + + @@ -113,6 +129,7 @@ + @@ -153,11 +170,14 @@ + @@ -208,6 +228,8 @@ + + @@ -220,6 +242,7 @@ + @@ -250,11 +273,14 @@ + @@ -362,6 +388,8 @@ dc.title + + @@ -372,9 +400,13 @@ dc.creator - + + + + + @@ -384,10 +416,11 @@ dc.subject.* - + + @@ -398,8 +431,13 @@ + + + + + @@ -411,6 +449,23 @@ + + + + + + + + + + + + + + + + + @@ -422,5 +477,8 @@ - + + + + diff --git a/dspace/config/spring/api/metadata-extractors.xml b/dspace/config/spring/api/metadata-extractors.xml new file mode 100644 index 0000000000..22f28b1816 --- /dev/null +++ b/dspace/config/spring/api/metadata-extractors.xml @@ -0,0 +1,30 @@ + + + + + + + + + bibtex + bib + + + + + + + diff --git a/dspace/config/spring/api/orcid-authority-services.xml b/dspace/config/spring/api/orcid-authority-services.xml index 80c5cd1115..d551300c86 100644 --- a/dspace/config/spring/api/orcid-authority-services.xml +++ b/dspace/config/spring/api/orcid-authority-services.xml @@ -18,7 +18,7 @@ - + @@ -32,9 +32,9 @@ - - + + - \ No newline at end of file + diff --git a/dspace-api/src/main/resources/spring/spring-dspace-addon-discovery-services.xml b/dspace/config/spring/api/solr-services.xml similarity index 64% rename from dspace-api/src/main/resources/spring/spring-dspace-addon-discovery-services.xml rename to dspace/config/spring/api/solr-services.xml index 22aef82959..0377d5bd58 100644 --- a/dspace-api/src/main/resources/spring/spring-dspace-addon-discovery-services.xml +++ b/dspace/config/spring/api/solr-services.xml @@ -9,19 +9,15 @@ --> + default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> - - @@ -29,4 +25,8 @@ + + + + diff --git a/dspace/config/spring/api/step-processing-listener.xml b/dspace/config/spring/api/step-processing-listener.xml new file mode 100644 index 0000000000..eb016c5133 --- /dev/null +++ b/dspace/config/spring/api/step-processing-listener.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/spring/api/workflow-actions.xml b/dspace/config/spring/api/workflow-actions.xml index c63ffe7644..8d9a25ff04 100644 --- a/dspace/config/spring/api/workflow-actions.xml +++ b/dspace/config/spring/api/workflow-actions.xml @@ -3,8 +3,8 @@ xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" - xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd - http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"> + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> diff --git a/dspace/config/spring/rest/README.md b/dspace/config/spring/rest/README.md new file mode 100644 index 0000000000..df27c0a2e2 --- /dev/null +++ b/dspace/config/spring/rest/README.md @@ -0,0 +1 @@ +You should only add Spring XML definition files here if there is really no way to load them through automatic component scanning. \ No newline at end of file diff --git a/dspace/config/spring/rest/event-service-listeners.xml b/dspace/config/spring/rest/event-service-listeners.xml new file mode 100644 index 0000000000..6d62e60f17 --- /dev/null +++ b/dspace/config/spring/rest/event-service-listeners.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dspace/config/spring/rest/rest-external-services.xml b/dspace/config/spring/rest/rest-external-services.xml new file mode 100644 index 0000000000..9f7330fc1e --- /dev/null +++ b/dspace/config/spring/rest/rest-external-services.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/dspace/config/spring/xmlui/workflow-actions-xmlui.xml b/dspace/config/spring/xmlui/workflow-actions-xmlui.xml index a7ef40f070..d4e0e1ca6c 100644 --- a/dspace/config/spring/xmlui/workflow-actions-xmlui.xml +++ b/dspace/config/spring/xmlui/workflow-actions-xmlui.xml @@ -3,8 +3,8 @@ xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" - xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd - http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"> + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> diff --git a/dspace/config/input-forms.dtd b/dspace/config/submission-forms.dtd similarity index 77% rename from dspace/config/input-forms.dtd rename to dspace/config/submission-forms.dtd index bb6a3f762b..7c94d133aa 100644 --- a/dspace/config/input-forms.dtd +++ b/dspace/config/submission-forms.dtd @@ -1,20 +1,14 @@ - - - - - + - + + - - - + + @@ -23,10 +17,12 @@ + + @@ -57,3 +53,5 @@ + + diff --git a/dspace/config/submission-forms.xml b/dspace/config/submission-forms.xml new file mode 100644 index 0000000000..10e9578c88 --- /dev/null +++ b/dspace/config/submission-forms.xml @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + +
    + + + dc + title + + false + + onebox + Enter the name of the file. + You must enter a main title for this item. + + + + + dc + description + true + + textarea + Enter a description for the file + + + +
    + +
    + + + dc + contributor + author + true + + name + Enter the names of the authors of this item. + + + + + + dc + title + + false + + onebox + Enter the main title of the item. + You must enter a main title for this item. + + + + + + dc + title + alternative + true + + onebox + If the item has any alternative titles, please enter them here. + + + + + + dc + date + issued + false + + + date + Please give the date of previous publication or public distribution. + You can leave out the day and/or month if they aren't + applicable. + You must enter at least the year. + + + + dc + publisher + + false + + + onebox + Enter the name of the publisher of the previously issued instance of this item. + + + + + + dc + identifier + citation + false + + onebox + Enter the standard citation for the previously issued instance of this item. + + + + + + dc + relation + ispartofseries + true + + series + Enter the series and number assigned to this item by your community. + + + + + + dc + identifier + + + true + + qualdrop_value + If the item has any identification numbers or codes associated with +it, please enter the types and the actual numbers or codes. + + + + + + dc + type + + true + + dropdown + Select the type(s) of content of the item. To select more than one value in the list, you may have to hold down the "CTRL" or "Shift" key. + + + + + + dc + language + iso + false + + dropdown + Select the language of the main content of the item. If the language does not appear in the list, please select 'Other'. If the content does not really have a language (for example, if it is a dataset or an image) please select 'N/A'. + + + +
    + +
    + + + dc + subject + + + true + + twobox + Enter appropriate subject keywords or phrases. + + srsc + + + + + dc + description + abstract + false + + textarea + Enter the abstract of the item. + + + + + + dc + description + sponsorship + false + + textarea + Enter the names of any sponsors and/or funding codes in the box. + + + + + + dc + description + + false + + textarea + Enter any other description or comments in this box. + + + +
    + +
    + + + + + + + + + + + + + + + + + + + ISSN + issn + + + Other + other + + + ISMN + ismn + + + Gov't Doc # + govdoc + + + URI + uri + + + ISBN + isbn + + + + + + Animation + Animation + + + Article + Article + + + Book + Book + + + Book chapter + Book chapter + + + Dataset + Dataset + + + Learning Object + Learning Object + + + Image + Image + + + Image, 3-D + Image, 3-D + + + Map + Map + + + Musical Score + Musical Score + + + Plan or blueprint + Plan or blueprint + + + Preprint + Preprint + + + Presentation + Presentation + + + Recording, acoustical + Recording, acoustical + + + Recording, musical + Recording, musical + + + Recording, oral + Recording, oral + + + Software + Software + + + Technical Report + Technical Report + + + Thesis + Thesis + + + Video + Video + + + Working Paper + Working Paper + + + Other + Other + + + + + + + N/A + + + + English (United States) + en_US + + + English + en + + + Spanish + es + + + German + de + + + French + fr + + + Italian + it + + + Japanese + ja + + + Chinese + zh + + + Turkish + tr + + + (Other) + other + + + + + +
    diff --git a/dspace/modules/additions/pom.xml b/dspace/modules/additions/pom.xml index ebc3963a0a..d02b33a8b9 100644 --- a/dspace/modules/additions/pom.xml +++ b/dspace/modules/additions/pom.xml @@ -58,7 +58,7 @@
    javax.servlet - servlet-api + javax.servlet-api provided diff --git a/dspace/modules/oai/pom.xml b/dspace/modules/oai/pom.xml index 2dc97f96bc..441846e8ce 100644 --- a/dspace/modules/oai/pom.xml +++ b/dspace/modules/oai/pom.xml @@ -127,7 +127,7 @@ javax.servlet - servlet-api + javax.servlet-api provided @@ -146,6 +146,14 @@ + + + + + org.hamcrest + hamcrest-all + compile +
    diff --git a/dspace/modules/rdf/pom.xml b/dspace/modules/rdf/pom.xml index 5a5ab808bf..297d165a6d 100644 --- a/dspace/modules/rdf/pom.xml +++ b/dspace/modules/rdf/pom.xml @@ -104,7 +104,7 @@ javax.servlet - servlet-api + javax.servlet-api provided diff --git a/dspace/modules/rest/pom.xml b/dspace/modules/rest/pom.xml index 636adc7e18..4b9c4a2a24 100644 --- a/dspace/modules/rest/pom.xml +++ b/dspace/modules/rest/pom.xml @@ -143,7 +143,7 @@ javax.servlet - servlet-api + javax.servlet-api provided diff --git a/dspace/modules/spring-rest/src/main/webapp/.gitignore b/dspace/modules/spring-rest/src/main/webapp/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dspace/modules/sword/pom.xml b/dspace/modules/sword/pom.xml index 3ed2e4cc10..a8498483ce 100644 --- a/dspace/modules/sword/pom.xml +++ b/dspace/modules/sword/pom.xml @@ -121,7 +121,7 @@ javax.servlet - servlet-api + javax.servlet-api provided diff --git a/dspace/modules/swordv2/pom.xml b/dspace/modules/swordv2/pom.xml index 63ef48427d..11f0b684b5 100644 --- a/dspace/modules/swordv2/pom.xml +++ b/dspace/modules/swordv2/pom.xml @@ -135,7 +135,7 @@ javax.servlet - servlet-api + javax.servlet-api provided diff --git a/dspace/pom.xml b/dspace/pom.xml index 95fc78afec..9c22c27523 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -1,3 +1,4 @@ + 4.0.0 org.dspace @@ -26,7 +27,7 @@ - + build @@ -38,7 +39,7 @@ modules - + @@ -102,7 +103,7 @@ false - + + + org.jacoco + jacoco-maven-plugin + + + aggregate-test-report + post-integration-test + + report-aggregate + + + + + + **/jacoco-ut.exec + **/jacoco-it.exec + + + ${project.reporting.outputDirectory}/jacoco-aggregated + + + + + + + org.eluder.coveralls + coveralls-maven-plugin + + + report-test-coverage + verify + + report + + + false + + ${project.reporting.outputDirectory}/jacoco-aggregated/jacoco.xml + + + ${project.parent.basedir}/dspace-api/src/main/java + ${project.parent.basedir}/dspace-api/target/generated-sources/annotations + ${project.parent.basedir}/dspace-oai/src/main/java + ${project.parent.basedir}/dspace-rdf/src/main/java + ${project.parent.basedir}/dspace-rest/src/main/java + ${project.parent.basedir}/dspace-services/src/main/java + ${project.parent.basedir}/dspace-spring-rest/src/main/java + ${project.parent.basedir}/dspace-sword/src/main/java + ${project.parent.basedir}/dspace-swordv2/src/main/java + + + + + + + + + + + org.dspace + dspace-api + compile + + + org.dspace + dspace-oai + classes + compile + + + org.dspace + dspace-rdf + war + compile + + + org.dspace + dspace-rest + classes + compile + + + org.dspace + dspace-services + compile + + + org.dspace + dspace-spring-rest + war + compile + + + org.dspace + dspace-sword + classes + compile + + + org.dspace + dspace-swordv2 + classes + compile + + + + @@ -189,7 +321,7 @@ command. --> javax.servlet - servlet-api + javax.servlet-api diff --git a/dspace/solr/oai/conf/schema.xml b/dspace/solr/oai/conf/schema.xml index 6fe6804994..73a69a17db 100644 --- a/dspace/solr/oai/conf/schema.xml +++ b/dspace/solr/oai/conf/schema.xml @@ -166,7 +166,9 @@ - + + + diff --git a/dspace/solr/search/conf/schema.xml b/dspace/solr/search/conf/schema.xml index 4b2f0ee88d..b08510798f 100644 --- a/dspace/solr/search/conf/schema.xml +++ b/dspace/solr/search/conf/schema.xml @@ -578,6 +578,8 @@ + + diff --git a/dspace/solr/statistics/conf/schema.xml b/dspace/solr/statistics/conf/schema.xml index 1f34744821..428ade7fc5 100644 --- a/dspace/solr/statistics/conf/schema.xml +++ b/dspace/solr/statistics/conf/schema.xml @@ -296,8 +296,8 @@ - - + + diff --git a/dspace/src/main/assembly/assembly.xml b/dspace/src/main/assembly/assembly.xml index ddb3c85fca..b016d850a3 100644 --- a/dspace/src/main/assembly/assembly.xml +++ b/dspace/src/main/assembly/assembly.xml @@ -81,6 +81,9 @@ *:jar:* + + org.glassfish.hk2.external:bean-validator:jar:* + lib false @@ -95,7 +98,7 @@ org.dspace.modules:*:jar:* - + true lib false @@ -105,6 +108,9 @@ *:jar:* + + org.glassfish.hk2.external:bean-validator:jar:* + diff --git a/dspace/src/main/config/build.xml b/dspace/src/main/config/build.xml index 561d917dbc..ec4782aa5d 100644 --- a/dspace/src/main/config/build.xml +++ b/dspace/src/main/config/build.xml @@ -9,10 +9,7 @@ --> @@ -82,8 +79,8 @@ Common usage: - - + + @@ -893,9 +890,18 @@ Common usage: Downloading: ${geolite} - - - + + + + + + + + @@ -913,9 +919,9 @@ ant update_geolite OR You may manually install this file by following these steps: -(1) Download the file from ${geolite} -(2) Unzip it to create a file named 'GeoLiteCity.dat' -(3) Copy that file to '${dspace.dir}/config/GeoLiteCity.dat' +(1) Download the latest database archive from ${geolite} +(2) Unpack it.' +(3) Copy the file 'GeoLite2-City.mmdb' to '${usage-statistics.dbfile}'. ==================================================================== @@ -927,7 +933,7 @@ You may manually install this file by following these steps: - + diff --git a/dspace/src/main/docker/local.cfg b/dspace/src/main/docker/local.cfg new file mode 100644 index 0000000000..6d2162b13b --- /dev/null +++ b/dspace/src/main/docker/local.cfg @@ -0,0 +1,8 @@ +# ------------------------------------------------------------------------ +# This file contains the localized properties for published DSpace images. +# See https://github.com/DSpace-Labs/DSpace-Docker-Images for usage information. +# ------------------------------------------------------------------------ +dspace.dir = /dspace +db.url = jdbc:postgresql://dspacedb:5432/dspace +dspace.hostname = localhost +dspace.baseUrl = http://localhost:8080 diff --git a/dspace/src/main/docker/test/rest_web.xml b/dspace/src/main/docker/test/rest_web.xml new file mode 100644 index 0000000000..05a6268692 --- /dev/null +++ b/dspace/src/main/docker/test/rest_web.xml @@ -0,0 +1,118 @@ + + + + + + + dspace.request + org.dspace.utils.servlet.DSpaceWebappServletFilter + + + + dspace.request + /* + + + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + + + springSecurityFilterChain + /* + + + + + DSpace REST API + + org.glassfish.jersey.servlet.ServletContainer + + + javax.ws.rs.Application + org.dspace.rest.DSpaceRestApplication + + 1 + + + + DSpace REST API + /* + + + + default + /static/* + + + + + + + + + The location of the DSpace home directory + + dspace.dir + ${dspace.dir} + + + + contextConfigLocation + + /WEB-INF/applicationContext.xml, + /WEB-INF/security-applicationContext.xml + + + + + org.dspace.app.util.DSpaceContextListener + + + + + org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener + + + + + org.springframework.web.context.ContextLoaderListener + + + + + org.dspace.app.util.DSpaceWebappListener + + + + \ No newline at end of file diff --git a/dspace/src/main/docker/test/solr_web.xml b/dspace/src/main/docker/test/solr_web.xml new file mode 100644 index 0000000000..4329317c53 --- /dev/null +++ b/dspace/src/main/docker/test/solr_web.xml @@ -0,0 +1,209 @@ + + + + + + + + + + + + + solr/home + ${dspace.dir}/solr + java.lang.String + + + + + + log4j.configuration + ${dspace.dir}/config/log4j-solr.properties + URL locating a Log4J configuration file (properties or XML). + + + + + LocalHostRestrictionFilter + org.dspace.solr.filters.LocalHostRestrictionFilter + + + + + SolrRequestFilter + org.apache.solr.servlet.SolrDispatchFilter + + + + + + + + + SolrRequestFilter + /* + + + + + + org.dspace.solr.filters.ConfigureLog4jListener + + + + Zookeeper + org.apache.solr.servlet.ZookeeperInfoServlet + + + + LoadAdminUI + org.apache.solr.servlet.LoadAdminUiServlet + + + + + + RedirectOldAdminUI + org.apache.solr.servlet.RedirectServlet + + destination + ${context}/#/ + + + + + RedirectOldZookeeper + org.apache.solr.servlet.RedirectServlet + + destination + ${context}/zookeeper + + + + + RedirectLogging + org.apache.solr.servlet.RedirectServlet + + destination + ${context}/#/~logging + + + + + SolrRestApi + org.restlet.ext.servlet.ServerServlet + + org.restlet.application + org.apache.solr.rest.SolrRestApi + + + + + RedirectOldAdminUI + /admin/ + + + RedirectOldAdminUI + /admin + + + RedirectOldZookeeper + /zookeeper.jsp + + + RedirectLogging + /logging + + + + + Zookeeper + /zookeeper + + + + LoadAdminUI + /admin.html + + + + SolrRestApi + /schema/* + + + + .xsl + + application/xslt+xml + + + + admin.html + + + diff --git a/pom.xml b/pom.xml index 9682d8df9b..1bdfe1dcae 100644 --- a/pom.xml +++ b/pom.xml @@ -24,11 +24,15 @@ UTF-8 ${project.build.sourceEncoding} 1.8 - 9.4.1211 + 3.17 + 42.2.1 4.10.4 2.13.0 1.7.22 + 2.8.11 + 2.26 5.2.8.Final + 5.4.2.Final 4.3.6.RELEASE @@ -56,11 +60,11 @@ ${java.version} - + - + @@ -78,9 +82,27 @@ maven-compiler-plugin 3.5.1 + + javac-with-errorprone + true ${java.version} ${java.version} + + + + org.codehaus.plexus + plexus-compiler-javac-errorprone + 2.8.2 + + + + com.google.errorprone + error_prone_core + 2.1.1 + + @@ -121,7 +143,7 @@ - ${test.argLine} + ${test.argLine} ${surefireJacoco} **/Abstract* @@ -141,7 +163,7 @@ - ${test.argLine} + ${test.argLine} ${failsafeJacoco} **/Abstract* @@ -157,6 +179,45 @@ + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.0.0 + + + verify-style + + verify + + check + + + + + + src/main/java + + ${root.basedir}/checkstyle.xml + ${project.build.sourceEncoding} + true + true + + true + + ${root.basedir}/checkstyle-suppressions.xml + checkstyle.suppressions.file + + + + + com.puppycrawl.tools + checkstyle + 8.8 + + + org.codehaus.mojo findbugs-maven-plugin @@ -227,6 +288,16 @@ maven-gpg-plugin 1.6 + + org.jacoco + jacoco-maven-plugin + 0.7.9 + + + org.eluder.coveralls + coveralls-maven-plugin + 4.3.0 + @@ -258,10 +329,10 @@ src/** - true - **/src/test/resources/** @@ -275,9 +346,10 @@ **/README* **/readme* **/.gitignore + **/src/main/resources/rebel.xml - - XML_STYLE XML_STYLE @@ -285,7 +357,7 @@ XML_STYLE SCRIPT_STYLE TEXT - + UTF-8 true @@ -300,14 +372,21 @@ + org.apache.maven.plugins maven-enforcer-plugin + + + + org.apache.maven.plugins + maven-checkstyle-plugin + - + @@ -342,8 +421,8 @@ test-argLine @@ -358,8 +437,8 @@ generate-test-env @@ -401,7 +480,69 @@ - + + org.jacoco + jacoco-maven-plugin + + + + pre-unit-test + + prepare-agent + + + + ${project.build.directory}/coverage-reports/jacoco-ut.exec + + surefireJacoco + + + + + + pre-integration-test + pre-integration-test + + prepare-agent + + + + ${project.build.directory}/coverage-reports/jacoco-it.exec + + failsafeJacoco + + + + + + + + + org.apache.maven.plugins @@ -884,20 +1024,41 @@ [6.0.0,7.0.0) war - + + + + + org.apache.zookeeper + zookeeper + 3.4.11 + + org.hibernate hibernate-core ${hibernate.version} + + org.hibernate + hibernate-jpamodelgen + ${hibernate.version} + + org.hibernate hibernate-ehcache ${hibernate.version} + + org.hibernate + hibernate-validator + + ${hibernate-validator.version} + + org.springframework spring-orm @@ -960,7 +1121,7 @@ org.apache.ant ant - 1.7.0 + 1.9.1 org.apache.jena @@ -1004,11 +1165,18 @@ commons-codec 1.10 + + org.apache.commons + commons-collections4 + 4.1 + + commons-collections commons-collections 3.2.2 - commons-configuration @@ -1028,7 +1196,7 @@ commons-fileupload commons-fileupload - 1.3.1 + 1.3.3 commons-io @@ -1056,6 +1224,11 @@ commons-validator 1.5.0 + + joda-time + joda-time + 2.9.2 + javax.mail mail @@ -1063,8 +1236,8 @@ javax.servlet - servlet-api - 2.5 + javax.servlet-api + 3.1.0 @@ -1116,17 +1289,22 @@ org.apache.poi poi - 3.13 + ${poi-version} org.apache.poi poi-scratchpad - 3.13 + ${poi-version} org.apache.poi poi-ooxml - 3.13 + ${poi-version} + + + org.apache.poi + poi-ooxml-schemas + ${poi-version} rome @@ -1141,7 +1319,7 @@ xalan xalan - 2.7.2 + 2.7.0 xerces @@ -1251,7 +1429,13 @@ junit junit - 4.11 + 4.12 + test + + + org.hamcrest + hamcrest-all + 1.3 test @@ -1267,13 +1451,6 @@ 1.4.187 test - - - org.databene - contiperf - 2.3.4 - test - com.google.code.gson gson @@ -1284,22 +1461,22 @@ com.google.apis google-api-services-analytics - v3-rev123-1.21.0 + v3-rev145-1.23.0 com.google.api-client google-api-client - 1.21.0 + 1.23.0 com.google.http-client google-http-client - 1.21.0 + 1.23.0 com.google.http-client google-http-client-jackson2 - 1.21.0 + 1.23.0 jackson-core @@ -1314,7 +1491,7 @@ com.google.oauth-client google-oauth-client - 1.21.0 + 1.23.0 @@ -1335,6 +1512,52 @@ 1.10.19 test + + + com.fasterxml + classmate + 1.3.0 + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + 2.8.11.1 + + + com.google.guava + guava + 19.0 + + + com.lyncode + builder-commons + 1.0.2 + + + org.javassist + javassist + 3.20.0-GA + + + org.jboss.logging + jboss-logging + 3.3.0.Final + + + xom + xom + 1.2.5 + @@ -1454,6 +1677,21 @@ + + + + maven-snapshots + http://oss.sonatype.org/content/repositories/snapshots + default + + false + + + true + + + + org.apache.poi